From 26779414a7f88a23233c490b9520df9f350583ac Mon Sep 17 00:00:00 2001 From: Sofia Date: Tue, 14 Apr 2026 15:55:13 +0300 Subject: [PATCH] Implement arrays --- src/ast.cpp | 7 ++++++ src/ast.h | 24 ++++++++++++++++++++ src/codegen.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 2 ++ src/parsing.cpp | 33 ++++++++++++++++----------- src/typechecker.cpp | 28 +++++++++++++++++++++++ test.c | 7 +++--- 7 files changed, 139 insertions(+), 16 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index 38b6a5f..e86ab68 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -61,6 +61,13 @@ namespace AST { return out.str(); } + std::string IndexAccessExpression::formatted() { + std::stringstream out{ "" }; + out << this->m_expr->formatted(); + out << "[" << this->m_num << "]"; + return out.str(); + } + std::string ExpressionStatement::formatted() { std::stringstream out{ "" }; out << this->m_expr->formatted(); diff --git a/src/ast.h b/src/ast.h index 2528c17..b898eb9 100644 --- a/src/ast.h +++ b/src/ast.h @@ -211,6 +211,30 @@ namespace AST { ) override; }; + /// @brief Same as value[num] + class IndexAccessExpression : public Expression { + private: + std::unique_ptr m_expr; + uint32_t m_num; + public: + IndexAccessExpression( + token::Metadata meta, + std::unique_ptr expr, + uint32_t num) + : Expression{ meta } + , m_expr{ std::move(expr) } + , m_num{ num } { + } + virtual ~IndexAccessExpression() override = default; + virtual std::string formatted() override; + virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual std::shared_ptr typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) override; + }; + class ReturnStatement : public Statement { private: diff --git a/src/codegen.cpp b/src/codegen.cpp index a8a6190..cf4424c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -131,6 +131,60 @@ namespace AST { } + codegen::StackValue IndexAccessExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) { + auto lvalue_scope = scope.with_lvalue(); + auto value = this->m_expr->codegen(builder, lvalue_scope); + std::shared_ptr inner_ty{}; + + std::vector idx_list{ }; + idx_list.push_back(llvm::ConstantInt::get(builder.builder->getInt32Ty(), this->m_num)); + + if (value.ty->m_kind == types::TypeKind::Pointer) { + auto ptr_ty = dynamic_cast(value.ty.get()); + + if (ptr_ty->m_inner->m_kind == types::TypeKind::Pointer) { + auto inner_ptr_ty = dynamic_cast(ptr_ty->m_inner.get()); + + auto gep_value = builder.builder->CreateGEP(inner_ptr_ty->m_inner->codegen(builder), value.value, idx_list, "GEP"); + if (scope.is_lvalue) { + return codegen::StackValue{ + gep_value, + value.ty, + }; + } + else { + auto loaded = value.ty->load(builder, gep_value); + return codegen::StackValue{ + loaded.first, + loaded.second + }; + } + } + + // Must be an array otherwise + auto arr_ty = dynamic_cast(ptr_ty->m_inner.get()); + std::cout << arr_ty->m_inner->formatted() << std::endl; + auto gep_value = builder.builder->CreateGEP(arr_ty->m_inner->codegen(builder), value.value, idx_list, "GEP"); + if (scope.is_lvalue) { + return codegen::StackValue{ + gep_value, + value.ty, + }; + } + else { + auto inner_ptr_ty = types::PointerType{ arr_ty->m_inner }; + auto loaded = inner_ptr_ty.load(builder, gep_value); + return codegen::StackValue{ + loaded.first, + loaded.second + }; + } + } + + throw CompileError("Tried indexing a non-pointer", this->m_meta); + } + + void ReturnStatement::codegen(codegen::Builder& builder, codegen::Scope& scope) { if (!builder.block) return; diff --git a/src/main.cpp b/src/main.cpp index a56c040..afdaa2c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -162,6 +162,8 @@ std::optional compile(std::string_view in_filename) { builder.mod->print(llvm_ir_dest, nullptr); llvm_ir_dest.flush(); + std::cout << llvm_ir_string << std::endl; + // Print output to obj-file std::error_code EC; std::string obj_string; diff --git a/src/parsing.cpp b/src/parsing.cpp index 2d3326e..bb8a3f9 100644 --- a/src/parsing.cpp +++ b/src/parsing.cpp @@ -160,22 +160,29 @@ namespace parsing { } auto plain_expr = parse_plain_expression(inner); - while (inner.peek().content == "(") { - inner.next(); + while (inner.peek().content == "(" || inner.peek().content == "[") { + if (inner.peek().content == "(") { + inner.next(); - std::vector> args{}; + std::vector> args{}; - int counter = 0; - while (inner.peek().content != ")") { - if (counter++ > 0) - inner.expect(token::Type::Symbol, ","); - args.push_back(parse_expression(inner).unwrap()); + int counter = 0; + while (inner.peek().content != ")") { + if (counter++ > 0) + inner.expect(token::Type::Symbol, ","); + args.push_back(parse_expression(inner).unwrap()); + } + + inner.expect(token::Type::Symbol, ")"); + + auto fn_call = new AST::FunctionCallExpression{ before_meta + inner.metadata(), plain_expr.unwrap(), std::move(args) }; + plain_expr = std::unique_ptr{ fn_call }; + } + else if (auto postfix = parse_array_postfix(inner, false); postfix.ok()) { + auto idx_expr = new AST::IndexAccessExpression{ + before_meta + inner.metadata(), plain_expr.unwrap(), *postfix.unwrap() }; + plain_expr = std::unique_ptr{ idx_expr }; } - - inner.expect(token::Type::Symbol, ")"); - - auto fn_call = new AST::FunctionCallExpression{ before_meta + inner.metadata(), plain_expr.unwrap(), std::move(args) }; - plain_expr = std::unique_ptr{ fn_call }; } diff --git a/src/typechecker.cpp b/src/typechecker.cpp index 51c552b..c2b74fd 100644 --- a/src/typechecker.cpp +++ b/src/typechecker.cpp @@ -281,6 +281,34 @@ namespace AST { return ptr_ty->m_inner; } + std::shared_ptr IndexAccessExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> + ) { + auto expr_ty = this->m_expr->typecheck(state, scope, {}); + if (expr_ty->m_kind != types::TypeKind::Pointer && expr_ty->m_kind != types::TypeKind::Array) { + state.errors.push_back( + CompileError("Tried to index " + expr_ty->formatted(), this->m_meta)); + return std::shared_ptr { + new types::FundamentalType{ types::FundamentalTypeKind::Void } + }; + } + if (expr_ty->m_kind == types::TypeKind::Pointer) { + auto ptr_ty = dynamic_cast(expr_ty.get()); + return ptr_ty->m_inner; + } + else if (expr_ty->m_kind == types::TypeKind::Array) { + auto ptr_ty = dynamic_cast(expr_ty.get()); + return ptr_ty->m_inner; + } + + // Default return type + return std::shared_ptr { + new types::FundamentalType{ types::FundamentalTypeKind::Void } + }; + } + void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty); diff --git a/test.c b/test.c index 918bbf5..8e656e6 100644 --- a/test.c +++ b/test.c @@ -15,7 +15,8 @@ int main() { char somelist[5]; - char res = 10; - modify_value(&res); - return res; + somelist[0] = 15; + somelist[1] = 20; + + return somelist[0]; } \ No newline at end of file