From 8e6980715e0f12501a278d5a31f4bc5e275c203e Mon Sep 17 00:00:00 2001 From: Sofia Date: Thu, 16 Apr 2026 19:43:36 +0300 Subject: [PATCH] Add const-ability to types --- src/ast.h | 2 +- src/binops.cpp | 14 ++++----- src/casting.cpp | 6 ++-- src/codegen.cpp | 26 ++++++++++------- src/parsing.cpp | 71 ++++++++++++++++++++++++++++++++------------- src/typechecker.cpp | 31 ++++++++++---------- src/types.h | 35 +++++++--------------- test.c | 2 +- 8 files changed, 105 insertions(+), 82 deletions(-) diff --git a/src/ast.h b/src/ast.h index e322257..8296517 100644 --- a/src/ast.h +++ b/src/ast.h @@ -52,7 +52,7 @@ namespace AST { : Expression{ meta } , m_value{ value } , m_ty{ { std::shared_ptr{ - new types::FundamentalType{types::FundamentalTypeKind::Int} + new types::FundamentalType{true, types::FundamentalTypeKind::Int} } } } { } virtual ~IntLiteralExpression() override = default; diff --git a/src/binops.cpp b/src/binops.cpp index d1ffb78..dcbf0d2 100644 --- a/src/binops.cpp +++ b/src/binops.cpp @@ -6,11 +6,11 @@ namespace types { std::vector definitions{}; auto int_ty = std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Int } }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Int } }; auto char_ty = std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Char } }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Char } }; auto bool_ty = std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Bool } }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; // Integer arithmetic binops for (auto& ty : { int_ty, char_ty, bool_ty }) { @@ -40,7 +40,7 @@ namespace types { }, [](BinopDefinition&, std::shared_ptr, std::shared_ptr) { return std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Bool } }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; } }); @@ -51,7 +51,7 @@ namespace types { }, [](BinopDefinition&, std::shared_ptr, std::shared_ptr) { return std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Bool } }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; } }); } @@ -65,7 +65,7 @@ namespace types { }, [](BinopDefinition&, std::shared_ptr, std::shared_ptr) { return std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Bool } }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; } }); @@ -76,7 +76,7 @@ namespace types { }, [](BinopDefinition&, std::shared_ptr, std::shared_ptr) { return std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Bool } }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; } }); } diff --git a/src/casting.cpp b/src/casting.cpp index 6d21ca7..2559245 100644 --- a/src/casting.cpp +++ b/src/casting.cpp @@ -7,11 +7,11 @@ namespace types { std::vector casts{}; auto int_ty = std::shared_ptr{ - new FundamentalType{ FundamentalTypeKind::Int } }; + new FundamentalType{ false, FundamentalTypeKind::Int } }; auto char_ty = std::shared_ptr{ - new FundamentalType{ FundamentalTypeKind::Char } }; + new FundamentalType{ false, FundamentalTypeKind::Char } }; auto bool_ty = std::shared_ptr{ - new FundamentalType{ FundamentalTypeKind::Bool } }; + new FundamentalType{ false, FundamentalTypeKind::Bool } }; auto numerical_types = { int_ty, char_ty, bool_ty }; diff --git a/src/codegen.cpp b/src/codegen.cpp index 857c498..6ff32c2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -31,7 +31,7 @@ namespace AST { std::shared_ptr StringLiteralExpression::get_codegen_type(codegen::Scope&) { auto stack_type = new types::ArrayType{ - std::make_unique(types::FundamentalTypeKind::Char), + std::make_shared(true, types::FundamentalTypeKind::Char), static_cast(this->m_value.size()) + 1, true }; @@ -40,7 +40,7 @@ namespace AST { codegen::StackValue StringLiteralExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) { auto stack_type = new types::ArrayType{ - std::make_unique(types::FundamentalTypeKind::Char), + std::make_shared(true, types::FundamentalTypeKind::Char), static_cast(this->m_value.size()) + 1, true }; @@ -52,7 +52,7 @@ namespace AST { return codegen::StackValue{ global_str, std::unique_ptr{ - new types::PointerType { std::shared_ptr {stack_type } } + new types::PointerType { false, std::shared_ptr {stack_type } } }, }; } @@ -205,7 +205,7 @@ namespace AST { std::shared_ptr RefExpression::get_codegen_type(codegen::Scope& scope) { return std::shared_ptr { - new types::PointerType{ this->m_expr->get_codegen_type(scope) } + new types::PointerType{ false, this->m_expr->get_codegen_type(scope) } }; } @@ -283,7 +283,7 @@ namespace AST { auto gep_value = builder.builder->CreateGEP(array_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP"); auto ptr_ty = std::shared_ptr{ - new types::PointerType { array_ty->m_inner} + new types::PointerType { array_ty->m_inner->m_const, array_ty->m_inner} }; if (scope.is_lvalue) { @@ -347,7 +347,7 @@ namespace AST { ptr_ty->m_inner->codegen(builder, scope.structs), struct_ptr.value, idx); auto ptr_ty = std::shared_ptr{ - new types::PointerType { field_ty } + new types::PointerType { field_ty->m_const, field_ty } }; if (scope.is_lvalue) { @@ -392,7 +392,7 @@ namespace AST { } auto ptr_ty = std::shared_ptr{ - new types::PointerType{this->m_ty} + new types::PointerType{this->m_ty->m_const, this->m_ty} }; if (scope.is_lvalue) { @@ -416,7 +416,7 @@ namespace AST { } auto ptr_ty = std::shared_ptr{ - new types::PointerType{this->m_ty} + new types::PointerType{this->m_ty->m_const, this->m_ty} }; if (scope.is_lvalue) { @@ -481,7 +481,9 @@ namespace AST { builder.builder->CreateStore(value.value, ptr, false); } - auto ptr_ty = std::shared_ptr{ new types::PointerType{ this->m_type } }; + auto ptr_ty = std::shared_ptr{ + new types::PointerType{ this->m_type->m_const, this->m_type } + }; scope.values[this->m_name] = codegen::StackValue{ ptr, ptr_ty }; } @@ -530,7 +532,9 @@ namespace AST { param_ty_ptrs.push_back(param.second); } - auto fn_ty_ptr = std::shared_ptr{ new types::FunctionType{ ret_ty_ptr, param_ty_ptrs, this->m_is_vararg } }; + auto fn_ty_ptr = std::shared_ptr{ + new types::FunctionType{ true, ret_ty_ptr, param_ty_ptrs, this->m_is_vararg } + }; auto fn_ty = fn_ty_ptr->codegen(builder, scope.structs); auto function = llvm::Function::Create( @@ -568,7 +572,7 @@ namespace AST { builder.builder->SetInsertPoint(BB); auto arg_ptr = builder.builder->CreateAlloca(param_ty_ptrs[counter]->codegen(builder, scope.structs)); auto param_ty_ptr = std::shared_ptr{ - new types::PointerType { param_ty_ptrs[counter]} + new types::PointerType { true, param_ty_ptrs[counter]} }; auto arg = function->getArg(counter++); builder.builder->CreateStore(arg, arg_ptr); diff --git a/src/parsing.cpp b/src/parsing.cpp index f3c5365..d23da96 100644 --- a/src/parsing.cpp +++ b/src/parsing.cpp @@ -12,6 +12,11 @@ namespace parsing { Result, std::string> parse_type(token::TokenStream& stream, Scope& scope) { token::TokenStream inner{ stream }; try { + bool is_const = false; + if (inner.peek().type == token::Type::Ident && inner.peek().content == "const") { + is_const = true; + } + auto token = inner.expect(token::Type::Ident); std::shared_ptr returned{}; @@ -56,7 +61,14 @@ namespace parsing { if (struct_name && !maybe_fields && scope.structs.find(*struct_name) != scope.structs.end()) { auto original_ty = scope.structs[*struct_name]; auto original_struct_ty = dynamic_cast(original_ty.get()); - auto ty = new types::StructType{ struct_name, original_struct_ty->m_fields, true, false, original_struct_ty->m_id }; + auto ty = new types::StructType{ + is_const, + struct_name, + original_struct_ty->m_fields, + true, + false, + original_struct_ty->m_id + }; returned = std::shared_ptr{ ty }; } else { @@ -64,16 +76,37 @@ namespace parsing { auto original_ty = scope.structs[*struct_name]; auto original_struct_ty = dynamic_cast(original_ty.get()); if (!original_struct_ty->m_fields.has_value()) { - auto ty = new types::StructType{ struct_name, maybe_fields, false, true, original_struct_ty->m_id }; + auto ty = new types::StructType{ + is_const, + struct_name, + maybe_fields, + false, + true, + original_struct_ty->m_id + }; returned = std::shared_ptr{ ty }; } else { - auto ty = new types::StructType{ struct_name, maybe_fields, false, false, struct_id_counter++ }; + auto ty = new types::StructType{ + is_const, + struct_name, + maybe_fields, + false, + false, + struct_id_counter++ + }; returned = std::shared_ptr{ ty }; } } else { - auto ty = new types::StructType{ struct_name, maybe_fields, false, false, struct_id_counter++ }; + auto ty = new types::StructType{ + is_const, + struct_name, + maybe_fields, + false, + false, + struct_id_counter++ + }; returned = std::shared_ptr{ ty }; } } @@ -83,15 +116,15 @@ namespace parsing { std::string type_name = token.content; if (type_name == "int") { - auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Int }; + auto ty = new types::FundamentalType{ is_const, types::FundamentalTypeKind::Int }; returned = std::shared_ptr{ ty }; } else if (type_name == "char") { - auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Char }; + auto ty = new types::FundamentalType{ is_const, types::FundamentalTypeKind::Char }; returned = std::shared_ptr{ ty }; } else if (type_name == "void") { - auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Void }; + auto ty = new types::FundamentalType{ is_const, types::FundamentalTypeKind::Void }; returned = std::shared_ptr{ ty }; } else { @@ -101,7 +134,12 @@ namespace parsing { while (inner.peek().type == token::Type::Symbol && inner.peek().content == "*") { inner.next(); - auto ty = new types::PointerType{ std::move(returned) }; + auto ptr_const = false; + if (inner.peek().type == token::Type::Ident && inner.peek().content == "const") { + inner.next(); + ptr_const = true; + } + auto ty = new types::PointerType{ ptr_const, std::move(returned) }; returned = std::shared_ptr{ ty }; } @@ -162,7 +200,7 @@ namespace parsing { before_meta + inner.metadata(), std::move(expressions), std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Any } + new types::FundamentalType{ true, types::FundamentalTypeKind::Any } }) }; } @@ -390,16 +428,9 @@ namespace parsing { auto array_postfix = parse_array_postfix(inner, false, scope); while (array_postfix.ok()) { auto postfix = array_postfix.unwrap(); - if (postfix) { - ty = std::shared_ptr{ - new types::ArrayType(ty, *postfix, false) - }; - } - else { - ty = std::shared_ptr{ - new types::PointerType(ty) - }; - } + ty = std::shared_ptr{ + new types::ArrayType(ty, *postfix, false) + }; array_postfix = parse_array_postfix(inner, false, scope); } @@ -516,7 +547,7 @@ namespace parsing { } else { param_ty = std::shared_ptr{ - new types::PointerType(param_ty) + new types::PointerType(true, param_ty) }; } postfix = parse_array_postfix(inner, true, scope); diff --git a/src/typechecker.cpp b/src/typechecker.cpp index ce7b976..1c1bf99 100644 --- a/src/typechecker.cpp +++ b/src/typechecker.cpp @@ -136,7 +136,7 @@ namespace AST { std::optional> ) { auto char_ty = std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Char } + new types::FundamentalType{ true, types::FundamentalTypeKind::Char } }; auto ptr_ty = new types::ArrayType{ char_ty, static_cast(this->m_value.size()) + 1, true }; return { std::shared_ptr{ptr_ty}, true, false }; @@ -155,7 +155,7 @@ namespace AST { state.errors.push_back(CompileError("Value " + this->m_name + " not defined", this->m_meta)); return { std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, true }; } @@ -255,7 +255,7 @@ namespace AST { this->m_meta)); return { std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Void } }, false, false }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, false }; } void FunctionCallExpression::typecheck_preprocess(typecheck::Scope& scope) { @@ -275,7 +275,7 @@ namespace AST { if (expr_ty->m_kind != types::TypeKind::Function) { state.errors.push_back(CompileError("Tried calling a non-function", this->m_meta)); return { std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, false }; } @@ -324,6 +324,7 @@ namespace AST { + expr_ty->formatted() + "to type " + this->m_ty->formatted() + " is not permitted", this->m_meta)); return { std::shared_ptr { new types::FundamentalType{ + false, types::FundamentalTypeKind::Void } }, false, false }; } @@ -339,7 +340,7 @@ namespace AST { ) { auto expr_ty = this->m_expr->typecheck(state, scope, {}).type; return { std::shared_ptr { - new types::PointerType{ expr_ty } + new types::PointerType{ false, expr_ty } }, false, false }; } @@ -357,7 +358,7 @@ namespace AST { state.errors.push_back( CompileError("Tried to deref " + expr_ty.type->formatted(), this->m_meta)); return { std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, expr_ty.lvalue }; } auto ptr_ty = dynamic_cast(expr_ty.type.get()); @@ -378,7 +379,7 @@ namespace AST { state.errors.push_back( CompileError("Tried to index " + expr_ty.type->formatted(), this->m_meta)); return { std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, expr_ty.lvalue }; } if (expr_ty.type->m_kind == types::TypeKind::Pointer) { @@ -392,7 +393,7 @@ namespace AST { // Default return type return { std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, expr_ty.lvalue }; } @@ -410,7 +411,7 @@ namespace AST { state.errors.push_back( CompileError("Tried to access " + expr_ty.type->formatted() + "." + this->m_field, this->m_meta)); return { std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, expr_ty.lvalue }; } @@ -423,13 +424,13 @@ namespace AST { } state.errors.push_back(CompileError("No such field", this->m_meta)); return { std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, expr_ty.lvalue }; } state.errors.push_back(CompileError("Cannot access fields of opaque struct", this->m_meta)); return { std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, expr_ty.lvalue }; } @@ -499,7 +500,7 @@ namespace AST { } else { return { std::shared_ptr { - new types::FundamentalType{ types::FundamentalTypeKind::Void } + new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, true, false }; } @@ -511,7 +512,7 @@ namespace AST { if (this->m_expressions.size() == 0) { this->m_ty = std::shared_ptr{ new types::ArrayType{ - std::make_shared(types::FundamentalTypeKind::Void), + std::make_shared(true, types::FundamentalTypeKind::Void), 0, true } @@ -585,7 +586,7 @@ namespace AST { void IfStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { auto bool_ty = std::shared_ptr{ - new types::FundamentalType{ types::FundamentalTypeKind::Bool } }; + new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; auto expr_ty = this->m_condition->typecheck(state, scope, bool_ty).type; auto check_res = check_type(state, expr_ty, bool_ty); @@ -617,7 +618,7 @@ namespace AST { param_tys.push_back(param.second); } - auto function_ty = new types::FunctionType{ return_ty, param_tys, this->m_is_vararg }; + auto function_ty = new types::FunctionType{ true, return_ty, param_tys, this->m_is_vararg }; scope.symbols[this->m_name] = std::shared_ptr{ function_ty }; typecheck::Scope inner{ scope }; diff --git a/src/types.h b/src/types.h index 706e1e3..a1562fe 100644 --- a/src/types.h +++ b/src/types.h @@ -27,7 +27,9 @@ namespace types { class Type { public: TypeKind m_kind; - Type(TypeKind kind) : m_kind{ kind } {} + bool m_const; + + Type(TypeKind kind, bool is_const) : m_kind{ kind }, m_const{ is_const } {} virtual ~Type() = default; virtual std::string formatted() = 0; virtual llvm::Type* codegen(codegen::Builder& builder, codegen::TypeMap& structs) = 0; @@ -40,7 +42,7 @@ namespace types { class FundamentalType : public Type { public: FundamentalTypeKind m_ty; - FundamentalType(FundamentalTypeKind kind) : Type(TypeKind::Fundamental), m_ty{ kind } {} + FundamentalType(bool is_const, FundamentalTypeKind kind) : Type(TypeKind::Fundamental, is_const), m_ty{ kind } {} virtual ~FundamentalType() override = default; virtual std::string formatted() override; virtual llvm::Type* codegen(codegen::Builder& builder, codegen::TypeMap& structs) override; @@ -55,8 +57,8 @@ namespace types { std::shared_ptr m_ret_ty; std::vector> m_param_tys; bool m_vararg; - FunctionType(std::shared_ptr ret_ty, std::vector> param_tys, bool vararg) - : Type(TypeKind::Function) + FunctionType(bool is_const, std::shared_ptr ret_ty, std::vector> param_tys, bool vararg) + : Type(TypeKind::Function, is_const) , m_ret_ty{ std::move(ret_ty) } , m_param_tys{ std::move(param_tys) } , m_vararg{ vararg } { @@ -73,8 +75,8 @@ namespace types { public: std::shared_ptr m_inner; - PointerType(std::shared_ptr inner) - : Type(TypeKind::Pointer), m_inner{ std::move(inner) } { + PointerType(bool is_const, std::shared_ptr inner) + : Type(TypeKind::Pointer, is_const), m_inner{ std::move(inner) } { } virtual ~PointerType() override = default; virtual std::string formatted() override; @@ -90,7 +92,7 @@ namespace types { bool m_raw; ArrayType(std::shared_ptr inner, uint32_t size, bool raw) - : Type(TypeKind::Array), m_inner{ std::move(inner) }, m_size{ size }, m_raw{ raw } { + : Type(TypeKind::Array, true), m_inner{ std::move(inner) }, m_size{ size }, m_raw{ raw } { } virtual ~ArrayType() override = default; virtual std::string formatted() override; @@ -109,8 +111,8 @@ namespace types { bool m_is_def; uint32_t m_id; - StructType(std::optional name, std::optional> fields, bool is_ref, bool is_def, uint32_t id) - : Type(TypeKind::Struct), m_name{ name }, m_fields{ fields }, m_is_ref{ is_ref }, m_is_def{ is_def }, m_id{ id } { + StructType(bool is_const, std::optional name, std::optional> fields, bool is_ref, bool is_def, uint32_t id) + : Type(TypeKind::Struct, is_const), m_name{ name }, m_fields{ fields }, m_is_ref{ is_ref }, m_is_def{ is_def }, m_id{ id } { } virtual ~StructType() override = default; virtual std::string formatted() override; @@ -119,21 +121,6 @@ namespace types { virtual uint32_t size() override; }; - // class StructRef : public Type { - // public: - // std::string m_name; - // std::shared_ptr m_referred; - - // StructRef(std::string name, std::shared_ptr referred) - // : Type(TypeKind::StructRef), m_name{ name }, m_referred{ referred } { - // } - // virtual ~StructRef() override = default; - // virtual std::string formatted() override; - // virtual llvm::Type* codegen(codegen::Builder& builder, codegen::TypeMap& structs) override; - // virtual std::pair> load(codegen::Builder& builder, llvm::Value* ptr, codegen::TypeMap& structs) override; - // virtual uint32_t size() override; - // }; - bool types_equal(std::shared_ptr type1, std::shared_ptr type2); } diff --git a/test.c b/test.c index a6784cd..d6d8ae9 100644 --- a/test.c +++ b/test.c @@ -6,7 +6,7 @@ int fibonacci(int n) { return fibonacci(n - 1) + fibonacci(n - 2); } -void change_first(char otus[]) { +void change_first(char* otus) { otus[0] = 115; }