diff --git a/src/ast.cpp b/src/ast.cpp index e86ab68..5207d9b 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -68,6 +68,21 @@ namespace AST { return out.str(); } + std::string ListInitializerExpression::formatted() { + std::stringstream out{ "" }; + out << "{ "; + + int counter = 0; + for (auto& expr : this->m_expressions) { + if (counter++ > 0) + out << ", "; + out << expr->formatted(); + } + + out << " }"; + 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 189f1c1..4eb27ef 100644 --- a/src/ast.h +++ b/src/ast.h @@ -245,6 +245,30 @@ namespace AST { ) override; }; + class ListInitializerExpression : public Expression { + private: + std::vector> m_expressions; + std::shared_ptr m_ty; + public: + ListInitializerExpression( + token::Metadata meta, + std::vector> expressions, + std::shared_ptr type) + : Expression{ meta } + , m_expressions{ std::move(expressions) } + , m_ty{ type } { + } + virtual ~ListInitializerExpression() override = default; + virtual std::string formatted() override; + virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; + virtual std::shared_ptr get_codegen_type(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 991e89c..811ec4f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -190,14 +190,6 @@ namespace AST { auto expr = this->m_expr->codegen(builder, scope); auto cast = types::find_cast(scope.casts, expr.ty, this->m_ty); if (cast) { - // if (cast->target_ty->m_kind == types::TypeKind::Pointer && cast->casted_ty->m_kind == types::TypeKind::Array) { - // auto allocated = builder.builder->CreateAlloca(cast->casted_ty->codegen(builder)); - // builder.builder->CreateStore(expr.value, allocated); - // return codegen::StackValue{ - // cast->codegen(builder, cast->target_ty, allocated), - // cast->target_ty - // }; - // } return codegen::StackValue{ cast->codegen(builder, cast->target_ty, expr.value), cast->target_ty @@ -331,6 +323,44 @@ namespace AST { } + + std::shared_ptr ListInitializerExpression::get_codegen_type(codegen::Scope&) { + return this->m_ty; + } + + codegen::StackValue ListInitializerExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) { + auto array_ptr = builder.builder->CreateAlloca(this->m_ty->codegen(builder)); + + if (this->m_ty->m_kind == types::TypeKind::Array) { + auto array_ty = dynamic_cast(this->m_ty.get()); + + int counter = 0; + for (auto& expr : this->m_expressions) { + std::vector indices{}; + indices.push_back(llvm::ConstantInt::get(builder.builder->getInt32Ty(), counter++)); + auto gep = builder.builder->CreateGEP( + array_ty->m_inner->codegen(builder), array_ptr, indices, "GEP"); + builder.builder->CreateStore(expr->codegen(builder, scope).value, gep); + } + + auto ptr_ty = std::shared_ptr{ + new types::PointerType{this->m_ty} + }; + + if (scope.is_lvalue) { + return codegen::StackValue{ array_ptr, ptr_ty }; + } + else { + auto loaded = ptr_ty->load(builder, array_ptr); + return codegen::StackValue{ loaded.first, loaded.second }; + } + } + else { + throw CompileError("Tried to list-initialize a non-array!", this->m_meta); + } + } + + void ReturnStatement::codegen(codegen::Builder& builder, codegen::Scope& scope) { if (!builder.block) return; diff --git a/src/typechecker.cpp b/src/typechecker.cpp index 5e77bd4..e4b8a31 100644 --- a/src/typechecker.cpp +++ b/src/typechecker.cpp @@ -309,6 +309,64 @@ namespace AST { }; } + std::shared_ptr ListInitializerExpression::typecheck( + typecheck::State& state, + typecheck::Scope& scope, + std::optional> expected_ty + ) { + if (expected_ty) { + if ((*expected_ty)->m_kind == types::TypeKind::Array) { + auto array_ty = dynamic_cast(expected_ty->get()); + for (auto& expr : this->m_expressions) { + auto expr_ty = expr->typecheck(state, scope, array_ty->m_inner); + auto expr_res = check_type(state, expr_ty, array_ty->m_inner); + expr = handle_res(std::move(expr), expr_res, state); + } + + this->m_ty = std::shared_ptr{ + new types::ArrayType{ + array_ty->m_inner, + static_cast(this->m_expressions.size()) + } + }; + } + else { + return std::shared_ptr { + new types::FundamentalType{ types::FundamentalTypeKind::Void } + }; + } + + return this->m_ty; + } + + // No expected ty, try to infer array type from elements + + if (this->m_expressions.size() == 0) { + this->m_ty = std::shared_ptr{ + new types::ArrayType{ + std::make_shared(types::FundamentalTypeKind::Void), + 0 + } + }; + return this->m_ty; + } + else { + auto first_expr_ty = this->m_expressions[0]->typecheck(state, scope, {}); + for (int i = 1; i < static_cast(this->m_expressions.size()); i++) { + auto expr_ty = this->m_expressions[i]->typecheck(state, scope, first_expr_ty); + auto expr_res = check_type(state, expr_ty, first_expr_ty); + this->m_expressions[i] = handle_res(std::move(this->m_expressions[i]), expr_res, state); + } + this->m_ty = std::shared_ptr{ + new types::ArrayType{ + first_expr_ty, + static_cast(this->m_expressions.size()) + } + }; + return this->m_ty; + } + } + void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty);