Add const-ability to types

This commit is contained in:
Sofia 2026-04-16 19:43:36 +03:00
parent f9208a525d
commit 8e6980715e
8 changed files with 105 additions and 82 deletions

View File

@ -52,7 +52,7 @@ namespace AST {
: Expression{ meta }
, m_value{ value }
, m_ty{ { std::shared_ptr<types::Type>{
new types::FundamentalType{types::FundamentalTypeKind::Int}
new types::FundamentalType{true, types::FundamentalTypeKind::Int}
} } } {
}
virtual ~IntLiteralExpression() override = default;

View File

@ -6,11 +6,11 @@ namespace types {
std::vector<BinopDefinition> definitions{};
auto int_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Int } };
new types::FundamentalType{ false, types::FundamentalTypeKind::Int } };
auto char_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Char } };
new types::FundamentalType{ false, types::FundamentalTypeKind::Char } };
auto bool_ty = std::shared_ptr<types::Type>{
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<types::Type>, std::shared_ptr<types::Type>) {
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
}
});
@ -51,7 +51,7 @@ namespace types {
},
[](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
}
});
}
@ -65,7 +65,7 @@ namespace types {
},
[](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
}
});
@ -76,7 +76,7 @@ namespace types {
},
[](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
}
});
}

View File

@ -7,11 +7,11 @@ namespace types {
std::vector<CastDefinition> casts{};
auto int_ty = std::shared_ptr<Type>{
new FundamentalType{ FundamentalTypeKind::Int } };
new FundamentalType{ false, FundamentalTypeKind::Int } };
auto char_ty = std::shared_ptr<Type>{
new FundamentalType{ FundamentalTypeKind::Char } };
new FundamentalType{ false, FundamentalTypeKind::Char } };
auto bool_ty = std::shared_ptr<Type>{
new FundamentalType{ FundamentalTypeKind::Bool } };
new FundamentalType{ false, FundamentalTypeKind::Bool } };
auto numerical_types = { int_ty, char_ty, bool_ty };

View File

@ -31,7 +31,7 @@ namespace AST {
std::shared_ptr<types::Type> StringLiteralExpression::get_codegen_type(codegen::Scope&) {
auto stack_type = new types::ArrayType{
std::make_unique<types::FundamentalType>(types::FundamentalTypeKind::Char),
std::make_shared<types::FundamentalType>(true, types::FundamentalTypeKind::Char),
static_cast<uint32_t>(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::FundamentalType>(types::FundamentalTypeKind::Char),
std::make_shared<types::FundamentalType>(true, types::FundamentalTypeKind::Char),
static_cast<uint32_t>(this->m_value.size()) + 1,
true
};
@ -52,7 +52,7 @@ namespace AST {
return codegen::StackValue{
global_str,
std::unique_ptr<types::Type>{
new types::PointerType { std::shared_ptr<types::Type> {stack_type } }
new types::PointerType { false, std::shared_ptr<types::Type> {stack_type } }
},
};
}
@ -205,7 +205,7 @@ namespace AST {
std::shared_ptr<types::Type> RefExpression::get_codegen_type(codegen::Scope& scope) {
return std::shared_ptr<types::Type> {
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<types::Type>{
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<types::Type>{
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<types::Type>{
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<types::Type>{
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<types::Type>{ new types::PointerType{ this->m_type } };
auto ptr_ty = std::shared_ptr<types::Type>{
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<types::Type>{ new types::FunctionType{ ret_ty_ptr, param_ty_ptrs, this->m_is_vararg } };
auto fn_ty_ptr = std::shared_ptr<types::Type>{
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<types::Type>{
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);

View File

@ -12,6 +12,11 @@ namespace parsing {
Result<std::shared_ptr<types::Type>, 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<types::Type> 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<types::StructType*>(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<types::Type>{ ty };
}
else {
@ -64,16 +76,37 @@ namespace parsing {
auto original_ty = scope.structs[*struct_name];
auto original_struct_ty = dynamic_cast<types::StructType*>(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<types::Type>{ 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<types::Type>{ 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<types::Type>{ 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<types::Type>{ 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<types::Type>{ 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<types::Type>{ 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<types::Type>{ ty };
}
@ -162,7 +200,7 @@ namespace parsing {
before_meta + inner.metadata(),
std::move(expressions),
std::shared_ptr<types::Type> {
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<types::Type>{
new types::ArrayType(ty, *postfix, false)
};
}
else {
ty = std::shared_ptr<types::Type>{
new types::PointerType(ty)
};
}
ty = std::shared_ptr<types::Type>{
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<types::Type>{
new types::PointerType(param_ty)
new types::PointerType(true, param_ty)
};
}
postfix = parse_array_postfix(inner, true, scope);

View File

@ -136,7 +136,7 @@ namespace AST {
std::optional<std::shared_ptr<types::Type>>
) {
auto char_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Char }
new types::FundamentalType{ true, types::FundamentalTypeKind::Char }
};
auto ptr_ty = new types::ArrayType{ char_ty, static_cast<uint32_t>(this->m_value.size()) + 1, true };
return { std::shared_ptr<types::Type>{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<types::Type>{
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<types::Type>{
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<types::Type> {
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<types::Type> { 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<types::Type> {
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<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue };
}
auto ptr_ty = dynamic_cast<types::PointerType*>(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<types::Type> {
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<types::Type> {
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<types::Type> {
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<types::Type> {
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<types::Type> {
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<types::Type> {
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<types::Type>{
new types::ArrayType{
std::make_shared<types::FundamentalType>(types::FundamentalTypeKind::Void),
std::make_shared<types::FundamentalType>(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<types::Type>{
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<types::Type>{ function_ty };
typecheck::Scope inner{ scope };

View File

@ -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<Type> m_ret_ty;
std::vector<std::shared_ptr<Type>> m_param_tys;
bool m_vararg;
FunctionType(std::shared_ptr<Type> ret_ty, std::vector<std::shared_ptr<Type>> param_tys, bool vararg)
: Type(TypeKind::Function)
FunctionType(bool is_const, std::shared_ptr<Type> ret_ty, std::vector<std::shared_ptr<Type>> 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<Type> m_inner;
PointerType(std::shared_ptr<Type> inner)
: Type(TypeKind::Pointer), m_inner{ std::move(inner) } {
PointerType(bool is_const, std::shared_ptr<Type> 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<Type> 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<std::string> name, std::optional<std::vector<StructField>> 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<std::string> name, std::optional<std::vector<StructField>> 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<types::Type> m_referred;
// StructRef(std::string name, std::shared_ptr<types::Type> 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<llvm::Value*, std::shared_ptr<Type>> load(codegen::Builder& builder, llvm::Value* ptr, codegen::TypeMap& structs) override;
// virtual uint32_t size() override;
// };
bool types_equal(std::shared_ptr<types::Type> type1, std::shared_ptr<types::Type> type2);
}

2
test.c
View File

@ -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;
}