Compare commits

...

11 Commits

11 changed files with 388 additions and 283 deletions

View File

@ -27,7 +27,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) = 0; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) = 0;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) = 0; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) = 0;
virtual void typecheck_preprocess(typecheck::Scope& scope) = 0; virtual void typecheck_preprocess(typecheck::Scope& scope) = 0;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -52,7 +52,7 @@ namespace AST {
: Expression{ meta } : Expression{ meta }
, m_value{ value } , m_value{ value }
, m_ty{ { std::shared_ptr<types::Type>{ , m_ty{ { std::shared_ptr<types::Type>{
new types::FundamentalType{types::FundamentalTypeKind::Int} new types::FundamentalType{true, types::FundamentalTypeKind::Int}
} } } { } } } {
} }
virtual ~IntLiteralExpression() override = default; virtual ~IntLiteralExpression() override = default;
@ -60,7 +60,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -78,7 +78,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -96,7 +96,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -125,7 +125,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -151,7 +151,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -177,7 +177,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -200,7 +200,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -223,7 +223,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -249,7 +249,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -275,7 +275,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -301,7 +301,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override; virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override; virtual std::shared_ptr<types::Type> get_codegen_type(codegen::Scope& scope) override;
virtual void typecheck_preprocess(typecheck::Scope& scope) override; virtual void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck( virtual typecheck::ExpressionType typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty

View File

@ -6,11 +6,11 @@ namespace types {
std::vector<BinopDefinition> definitions{}; std::vector<BinopDefinition> definitions{};
auto int_ty = std::shared_ptr<types::Type>{ 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>{ 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>{ auto bool_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
// Integer arithmetic binops // Integer arithmetic binops
for (auto& ty : { int_ty, char_ty, bool_ty }) { 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>) { [](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return 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>) { [](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return 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>) { [](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return 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>) { [](BinopDefinition&, std::shared_ptr<types::Type>, std::shared_ptr<types::Type>) {
return 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{}; std::vector<CastDefinition> casts{};
auto int_ty = std::shared_ptr<Type>{ auto int_ty = std::shared_ptr<Type>{
new FundamentalType{ FundamentalTypeKind::Int } }; new FundamentalType{ false, FundamentalTypeKind::Int } };
auto char_ty = std::shared_ptr<Type>{ auto char_ty = std::shared_ptr<Type>{
new FundamentalType{ FundamentalTypeKind::Char } }; new FundamentalType{ false, FundamentalTypeKind::Char } };
auto bool_ty = std::shared_ptr<Type>{ 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 }; auto numerical_types = { int_ty, char_ty, bool_ty };

View File

@ -31,16 +31,18 @@ namespace AST {
std::shared_ptr<types::Type> StringLiteralExpression::get_codegen_type(codegen::Scope&) { std::shared_ptr<types::Type> StringLiteralExpression::get_codegen_type(codegen::Scope&) {
auto stack_type = new types::ArrayType{ 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 static_cast<uint32_t>(this->m_value.size()) + 1,
true
}; };
return std::shared_ptr<types::Type> {stack_type}; return std::shared_ptr<types::Type> {stack_type};
} }
codegen::StackValue StringLiteralExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) { codegen::StackValue StringLiteralExpression::codegen(codegen::Builder& builder, codegen::Scope& scope) {
auto stack_type = new types::ArrayType{ 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 static_cast<uint32_t>(this->m_value.size()) + 1,
true
}; };
auto str = llvm::StringRef{ this->m_value.c_str() }; auto str = llvm::StringRef{ this->m_value.c_str() };
@ -50,7 +52,7 @@ namespace AST {
return codegen::StackValue{ return codegen::StackValue{
global_str, global_str,
std::unique_ptr<types::Type>{ 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 } }
}, },
}; };
} }
@ -203,7 +205,7 @@ namespace AST {
std::shared_ptr<types::Type> RefExpression::get_codegen_type(codegen::Scope& scope) { std::shared_ptr<types::Type> RefExpression::get_codegen_type(codegen::Scope& scope) {
return std::shared_ptr<types::Type> { 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) }
}; };
} }
@ -264,58 +266,38 @@ namespace AST {
if (value.ty->m_kind == types::TypeKind::Pointer) { if (value.ty->m_kind == types::TypeKind::Pointer) {
auto ptr_ty = dynamic_cast<types::PointerType*>(value.ty.get()); auto ptr_ty = dynamic_cast<types::PointerType*>(value.ty.get());
if (ptr_ty->m_inner->m_kind == types::TypeKind::Pointer) { auto gep_value = builder.builder->CreateGEP(ptr_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP");
auto inner_ptr_ty = dynamic_cast<types::PointerType*>(ptr_ty->m_inner.get());
auto gep_value = builder.builder->CreateGEP(inner_ptr_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP"); auto loaded = value.ty->load(builder, gep_value, scope.structs);
if (scope.is_lvalue) { return codegen::StackValue{
return codegen::StackValue{ loaded.first,
gep_value, loaded.second
value.ty, };
}; }
} else if (value.ty->m_kind == types::TypeKind::Array) {
else { auto array_ty = dynamic_cast<types::ArrayType*>(value.ty.get());
auto loaded = value.ty->load(builder, gep_value, scope.structs); if (array_ty->m_raw) {
return codegen::StackValue{ throw CompileError("Tried indexing a raw array", this->m_meta);
loaded.first,
loaded.second
};
}
} }
else if (ptr_ty->m_inner->m_kind == types::TypeKind::Array) {
// Must be an array otherwise auto gep_value = builder.builder->CreateGEP(array_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP");
auto arr_ty = dynamic_cast<types::ArrayType*>(ptr_ty->m_inner.get());
auto gep_value = builder.builder->CreateGEP(arr_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP"); auto ptr_ty = std::shared_ptr<types::Type>{
if (scope.is_lvalue) { new types::PointerType { array_ty->m_inner->m_const, array_ty->m_inner}
return codegen::StackValue{ };
gep_value,
value.ty, if (scope.is_lvalue) {
}; return codegen::StackValue{
} gep_value,
else { ptr_ty,
auto inner_ptr_ty = types::PointerType{ arr_ty->m_inner }; };
auto loaded = inner_ptr_ty.load(builder, gep_value, scope.structs);
return codegen::StackValue{
loaded.first,
loaded.second
};
}
} }
else { else {
auto gep_value = builder.builder->CreateGEP(ptr_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP"); auto loaded = ptr_ty->load(builder, gep_value, scope.structs);
if (scope.is_lvalue) { return codegen::StackValue{
return codegen::StackValue{ loaded.first,
gep_value, loaded.second
value.ty, };
};
}
else {
auto loaded = value.ty->load(builder, gep_value, scope.structs);
return codegen::StackValue{
loaded.first,
loaded.second
};
}
} }
} }
@ -365,7 +347,7 @@ namespace AST {
ptr_ty->m_inner->codegen(builder, scope.structs), struct_ptr.value, idx); ptr_ty->m_inner->codegen(builder, scope.structs), struct_ptr.value, idx);
auto ptr_ty = std::shared_ptr<types::Type>{ 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) { if (scope.is_lvalue) {
@ -410,7 +392,7 @@ namespace AST {
} }
auto ptr_ty = std::shared_ptr<types::Type>{ 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) { if (scope.is_lvalue) {
@ -434,7 +416,7 @@ namespace AST {
} }
auto ptr_ty = std::shared_ptr<types::Type>{ 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) { if (scope.is_lvalue) {
@ -476,6 +458,22 @@ namespace AST {
builder.builder->SetInsertPoint(builder.block); builder.builder->SetInsertPoint(builder.block);
if (this->m_type->m_kind == types::TypeKind::Array) {
auto array_ty = dynamic_cast<types::ArrayType*>(this->m_type.get());
if (!array_ty->m_raw) {
auto raw_ty = types::ArrayType{ array_ty->m_inner, array_ty->m_size, true };
auto raw_llvm_ty = raw_ty.codegen(builder, scope.structs);
auto ptr = builder.builder->CreateAlloca(raw_llvm_ty);
if (this->m_expr.has_value()) {
auto value = this->m_expr->get()->codegen(builder, scope);
builder.builder->CreateStore(value.value, ptr, false);
}
scope.values[this->m_name] = codegen::StackValue{ ptr, this->m_type };
return;
}
}
auto ty = this->m_type->codegen(builder, scope.structs); auto ty = this->m_type->codegen(builder, scope.structs);
auto ptr = builder.builder->CreateAlloca(ty); auto ptr = builder.builder->CreateAlloca(ty);
if (this->m_expr.has_value()) { if (this->m_expr.has_value()) {
@ -483,7 +481,9 @@ namespace AST {
builder.builder->CreateStore(value.value, ptr, false); 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 }; scope.values[this->m_name] = codegen::StackValue{ ptr, ptr_ty };
} }
@ -532,7 +532,9 @@ namespace AST {
param_ty_ptrs.push_back(param.second); 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 fn_ty = fn_ty_ptr->codegen(builder, scope.structs);
auto function = llvm::Function::Create( auto function = llvm::Function::Create(
@ -552,32 +554,34 @@ namespace AST {
int counter = 0; int counter = 0;
for (auto& param : this->m_params) { for (auto& param : this->m_params) {
if (param.second->m_kind == types::TypeKind::Pointer) { if (param.second->m_kind == types::TypeKind::Array) {
auto ty = param_ty_ptrs[counter]; auto array_ty = dynamic_cast<types::ArrayType*>(param.second.get());
auto arg = function->getArg(counter++); if (!array_ty->m_raw) {
if (param.first) { auto ty = param_ty_ptrs[counter];
arg->setName(*param.first); auto arg = function->getArg(counter++);
inner_scope.values[*param.first] = codegen::StackValue{ if (param.first) {
arg, arg->setName(*param.first);
ty, inner_scope.values[*param.first] = codegen::StackValue{
}; arg,
ty,
};
}
continue;
} }
} }
else { builder.builder->SetInsertPoint(BB);
builder.builder->SetInsertPoint(BB); auto arg_ptr = builder.builder->CreateAlloca(param_ty_ptrs[counter]->codegen(builder, scope.structs));
auto arg_ptr = builder.builder->CreateAlloca(param_ty_ptrs[counter]->codegen(builder, scope.structs)); auto param_ty_ptr = std::shared_ptr<types::Type>{
auto param_ty_ptr = std::shared_ptr<types::Type>{ new types::PointerType { true, param_ty_ptrs[counter]}
new types::PointerType { param_ty_ptrs[counter]} };
auto arg = function->getArg(counter++);
builder.builder->CreateStore(arg, arg_ptr);
if (param.first) {
arg->setName(*param.first);
inner_scope.values[*param.first] = codegen::StackValue{
arg_ptr,
param_ty_ptr,
}; };
auto arg = function->getArg(counter++);
builder.builder->CreateStore(arg, arg_ptr);
if (param.first) {
arg->setName(*param.first);
inner_scope.values[*param.first] = codegen::StackValue{
arg_ptr,
param_ty_ptr,
};
}
} }
} }
@ -637,7 +641,9 @@ namespace types {
} }
llvm::Type* ArrayType::codegen(codegen::Builder& builder, codegen::TypeMap& structs) { llvm::Type* ArrayType::codegen(codegen::Builder& builder, codegen::TypeMap& structs) {
return llvm::ArrayType::get(this->m_inner->codegen(builder, structs), this->m_size); if (this->m_raw)
return llvm::ArrayType::get(this->m_inner->codegen(builder, structs), this->m_size);
return llvm::PointerType::get(*builder.context, 0);
} }
llvm::Type* StructType::codegen(codegen::Builder& builder, codegen::TypeMap& structs) { llvm::Type* StructType::codegen(codegen::Builder& builder, codegen::TypeMap& structs) {

View File

@ -12,6 +12,12 @@ namespace parsing {
Result<std::shared_ptr<types::Type>, std::string> parse_type(token::TokenStream& stream, Scope& scope) { Result<std::shared_ptr<types::Type>, std::string> parse_type(token::TokenStream& stream, Scope& scope) {
token::TokenStream inner{ stream }; token::TokenStream inner{ stream };
try { try {
bool is_const = false;
if (inner.peek().type == token::Type::Ident && inner.peek().content == "const") {
is_const = true;
inner.next();
}
auto token = inner.expect(token::Type::Ident); auto token = inner.expect(token::Type::Ident);
std::shared_ptr<types::Type> returned{}; std::shared_ptr<types::Type> returned{};
@ -56,7 +62,14 @@ namespace parsing {
if (struct_name && !maybe_fields && scope.structs.find(*struct_name) != scope.structs.end()) { if (struct_name && !maybe_fields && scope.structs.find(*struct_name) != scope.structs.end()) {
auto original_ty = scope.structs[*struct_name]; auto original_ty = scope.structs[*struct_name];
auto original_struct_ty = dynamic_cast<types::StructType*>(original_ty.get()); 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 }; returned = std::shared_ptr<types::Type>{ ty };
} }
else { else {
@ -64,16 +77,37 @@ namespace parsing {
auto original_ty = scope.structs[*struct_name]; auto original_ty = scope.structs[*struct_name];
auto original_struct_ty = dynamic_cast<types::StructType*>(original_ty.get()); auto original_struct_ty = dynamic_cast<types::StructType*>(original_ty.get());
if (!original_struct_ty->m_fields.has_value()) { 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 }; returned = std::shared_ptr<types::Type>{ ty };
} }
else { 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 }; returned = std::shared_ptr<types::Type>{ ty };
} }
} }
else { 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 }; returned = std::shared_ptr<types::Type>{ ty };
} }
} }
@ -83,15 +117,15 @@ namespace parsing {
std::string type_name = token.content; std::string type_name = token.content;
if (type_name == "int") { 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 }; returned = std::shared_ptr<types::Type>{ ty };
} }
else if (type_name == "char") { 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 }; returned = std::shared_ptr<types::Type>{ ty };
} }
else if (type_name == "void") { 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 }; returned = std::shared_ptr<types::Type>{ ty };
} }
else { else {
@ -101,7 +135,12 @@ namespace parsing {
while (inner.peek().type == token::Type::Symbol && inner.peek().content == "*") { while (inner.peek().type == token::Type::Symbol && inner.peek().content == "*") {
inner.next(); 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 }; returned = std::shared_ptr<types::Type>{ ty };
} }
@ -162,7 +201,7 @@ namespace parsing {
before_meta + inner.metadata(), before_meta + inner.metadata(),
std::move(expressions), std::move(expressions),
std::shared_ptr<types::Type> { std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Any } new types::FundamentalType{ true, types::FundamentalTypeKind::Any }
}) })
}; };
} }
@ -390,16 +429,9 @@ namespace parsing {
auto array_postfix = parse_array_postfix(inner, false, scope); auto array_postfix = parse_array_postfix(inner, false, scope);
while (array_postfix.ok()) { while (array_postfix.ok()) {
auto postfix = array_postfix.unwrap(); auto postfix = array_postfix.unwrap();
if (postfix) { ty = std::shared_ptr<types::Type>{
ty = std::shared_ptr<types::Type>{ new types::ArrayType(ty, *postfix, false)
new types::ArrayType(ty, *postfix) };
};
}
else {
ty = std::shared_ptr<types::Type>{
new types::PointerType(ty)
};
}
array_postfix = parse_array_postfix(inner, false, scope); array_postfix = parse_array_postfix(inner, false, scope);
} }
@ -511,12 +543,12 @@ namespace parsing {
auto array_postfix = postfix.unwrap(); auto array_postfix = postfix.unwrap();
if (array_postfix) { if (array_postfix) {
param_ty = std::shared_ptr<types::Type>{ param_ty = std::shared_ptr<types::Type>{
new types::PointerType(param_ty) new types::ArrayType(param_ty, *array_postfix, false)
}; };
} }
else { else {
param_ty = std::shared_ptr<types::Type>{ 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); postfix = parse_array_postfix(inner, true, scope);

View File

@ -5,7 +5,7 @@
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <optional>
static bool iswhitespace(char& character) { static bool iswhitespace(char& character) {
return character == ' ' return character == ' '
@ -14,6 +14,33 @@ static bool iswhitespace(char& character) {
|| character == '\r'; || character == '\r';
} }
static std::optional<char> get_escaped(std::string_view inspected) {
if (inspected == "n")
return '\n';
if (inspected == "r")
return '\r';
if (inspected == "t")
return '\t';
if (inspected == "\\")
return '\\';
if (inspected.size() <= 3) {
for (char c : inspected) {
std::cout << c << std::endl;
if (!std::isdigit(c))
return {};
if (std::stoi(std::string{ c }) > 8)
return {};
}
unsigned int x;
std::stringstream ss;
ss << std::oct << inspected;
ss >> x;
return static_cast<char>(x);
}
return {};
}
namespace token { namespace token {
std::string type_name(Type& type) { std::string type_name(Type& type) {
switch (type) { switch (type) {
@ -152,9 +179,27 @@ namespace token {
std::string content{}; std::string content{};
c = text[++i]; // Skip initial " c = text[++i]; // Skip initial "
do { do {
content += c; if (c == '\\') {
if ((i + 1) >= text_length) break; std::string escaped_content{};
c = text[++i]; if ((i + 1) >= text_length) break;
auto potential = get_escaped(escaped_content + text[++i]);
while (potential.has_value() && (i + 1) < text_length) {
escaped_content += text[i];
potential = get_escaped(escaped_content + text[++i]);
}
if (escaped_content.size() > 0) {
auto escaped = get_escaped(escaped_content);
if (escaped.has_value())
content += *escaped;
}
c = text[i];
}
else {
content += c;
if ((i + 1) >= text_length) break;
c = text[++i];
}
} while (c != '\"'); } while (c != '\"');
i++; // Skip second " i++; // Skip second "
tokens.push_back(token::Token{ token::Type::LiteralStr, content, meta + (content.size() + 2) }); tokens.push_back(token::Token{ token::Type::LiteralStr, content, meta + (content.size() + 2) });

View File

@ -105,7 +105,7 @@ namespace AST {
this->m_ty = refresh_type(scope, this->m_ty); this->m_ty = refresh_type(scope, this->m_ty);
} }
std::shared_ptr<types::Type> IntLiteralExpression::typecheck( typecheck::ExpressionType IntLiteralExpression::typecheck(
typecheck::State&, typecheck::State&,
typecheck::Scope&, typecheck::Scope&,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -125,38 +125,38 @@ namespace AST {
} }
} }
return this->m_ty; return { this->m_ty, false, false };
} }
void StringLiteralExpression::typecheck_preprocess(typecheck::Scope&) {} void StringLiteralExpression::typecheck_preprocess(typecheck::Scope&) {}
std::shared_ptr<types::Type> StringLiteralExpression::typecheck( typecheck::ExpressionType StringLiteralExpression::typecheck(
typecheck::State&, typecheck::State&,
typecheck::Scope&, typecheck::Scope&,
std::optional<std::shared_ptr<types::Type>> std::optional<std::shared_ptr<types::Type>>
) { ) {
auto char_ty = 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 }; 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}; return { std::shared_ptr<types::Type>{ptr_ty}, true, false };
} }
void ValueReferenceExpression::typecheck_preprocess(typecheck::Scope&) {} void ValueReferenceExpression::typecheck_preprocess(typecheck::Scope&) {}
std::shared_ptr<types::Type> ValueReferenceExpression::typecheck( typecheck::ExpressionType ValueReferenceExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> std::optional<std::shared_ptr<types::Type>>
) { ) {
if (scope.symbols.find(this->m_name) != scope.symbols.end()) { if (scope.symbols.find(this->m_name) != scope.symbols.end()) {
return scope.symbols[this->m_name]; return { scope.symbols[this->m_name], false, true };
} }
state.errors.push_back(CompileError("Value " + this->m_name + " not defined", this->m_meta)); state.errors.push_back(CompileError("Value " + this->m_name + " not defined", this->m_meta));
return std::shared_ptr<types::Type>{ return { std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Void } new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}; }, false, true };
} }
void BinaryOperationExpression::typecheck_preprocess(typecheck::Scope& scope) { void BinaryOperationExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -164,20 +164,28 @@ namespace AST {
this->m_rhs->typecheck_preprocess(scope); this->m_rhs->typecheck_preprocess(scope);
} }
std::shared_ptr<types::Type> BinaryOperationExpression::typecheck( typecheck::ExpressionType BinaryOperationExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
) { ) {
auto lhs_ty = this->m_lhs->typecheck(state, scope, {}); auto lhs_res = this->m_lhs->typecheck(state, scope, {});
auto rhs_ty = this->m_rhs->typecheck(state, scope, {}); auto lhs_ty = lhs_res.type;
auto rhs_ty = this->m_rhs->typecheck(state, scope, {}).type;
if (this->m_binop == types::BinOp::Assignment) { if (this->m_binop == types::BinOp::Assignment) {
if (!lhs_res.lvalue) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
else if (lhs_ty->m_const) {
state.errors.push_back(CompileError("Value must be a modifiable l-value", this->m_lhs->m_meta));
}
// Re-typecheck rhs to actually match lhs // Re-typecheck rhs to actually match lhs
auto rhs_ty = this->m_rhs->typecheck(state, scope, lhs_ty); auto rhs_ty = this->m_rhs->typecheck(state, scope, lhs_ty).type;
auto rhs_ty_res = check_type(state, rhs_ty, lhs_ty); auto rhs_ty_res = check_type(state, rhs_ty, lhs_ty);
this->m_rhs = handle_res(std::move(this->m_rhs), rhs_ty_res, state); this->m_rhs = handle_res(std::move(this->m_rhs), rhs_ty_res, state);
return lhs_ty; return { lhs_ty, false, false };
} }
// Try to find a binop that matches exactly // Try to find a binop that matches exactly
@ -189,7 +197,7 @@ namespace AST {
); );
if (binop) { if (binop) {
return binop->result(*binop, lhs_ty, rhs_ty); return { binop->result(*binop, lhs_ty, rhs_ty), false, false };
} }
// If that fails, try to find binop that matches on one side perfectly // If that fails, try to find binop that matches on one side perfectly
@ -209,7 +217,7 @@ namespace AST {
// Skip if not implicitly castable to lhs // Skip if not implicitly castable to lhs
continue; continue;
this->m_rhs = handle_res(std::move(this->m_rhs), rhs_res, state); this->m_rhs = handle_res(std::move(this->m_rhs), rhs_res, state);
return binop.result(binop, lhs_ty, rhs_ty); return { binop.result(binop, lhs_ty, rhs_ty), false, false };
} }
else if (types::types_equal(binop.rhs, rhs_ty)) { else if (types::types_equal(binop.rhs, rhs_ty)) {
auto lhs_res = check_type(state, lhs_ty, binop.lhs); auto lhs_res = check_type(state, lhs_ty, binop.lhs);
@ -217,7 +225,7 @@ namespace AST {
// Skip if not implicitly castable to rhs // Skip if not implicitly castable to rhs
continue; continue;
this->m_lhs = handle_res(std::move(this->m_lhs), lhs_res, state); this->m_lhs = handle_res(std::move(this->m_lhs), lhs_res, state);
return binop.result(binop, lhs_ty, rhs_ty); return { binop.result(binop, lhs_ty, rhs_ty), false, false };
} }
} }
@ -235,7 +243,7 @@ namespace AST {
auto rhs_result = check_type(state, rhs_ty, binop.rhs); auto rhs_result = check_type(state, rhs_ty, binop.rhs);
this->m_lhs = handle_res(std::move(this->m_lhs), lhs_result, state); this->m_lhs = handle_res(std::move(this->m_lhs), lhs_result, state);
this->m_rhs = handle_res(std::move(this->m_rhs), lhs_result, state); this->m_rhs = handle_res(std::move(this->m_rhs), lhs_result, state);
return binop.result(binop, lhs_ty, rhs_ty); return { binop.result(binop, lhs_ty, rhs_ty), false, false };
} }
// No suitable binops found :( // No suitable binops found :(
@ -246,8 +254,8 @@ namespace AST {
+ rhs_ty->formatted(), + rhs_ty->formatted(),
this->m_meta)); this->m_meta));
return std::shared_ptr<types::Type>{ return { std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Void } }; new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, false };
} }
void FunctionCallExpression::typecheck_preprocess(typecheck::Scope& scope) { void FunctionCallExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -257,18 +265,18 @@ namespace AST {
} }
} }
std::shared_ptr<types::Type> FunctionCallExpression::typecheck( typecheck::ExpressionType FunctionCallExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> std::optional<std::shared_ptr<types::Type>>
) { ) {
auto expr_ty = this->m_fn_expr->typecheck(state, scope, {}); auto expr_ty = this->m_fn_expr->typecheck(state, scope, {}).type;
if (expr_ty->m_kind != types::TypeKind::Function) { if (expr_ty->m_kind != types::TypeKind::Function) {
state.errors.push_back(CompileError("Tried calling a non-function", this->m_meta)); state.errors.push_back(CompileError("Tried calling a non-function", this->m_meta));
return std::shared_ptr<types::Type> { return { std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void } new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}; }, false, false };
} }
auto fn_ty = dynamic_cast<types::FunctionType*>(expr_ty.get()); auto fn_ty = dynamic_cast<types::FunctionType*>(expr_ty.get());
@ -283,7 +291,7 @@ namespace AST {
for (int i = 0; i < static_cast<int>(this->m_args.size()); i++) { for (int i = 0; i < static_cast<int>(this->m_args.size()); i++) {
if (i < static_cast<int>(fn_ty->m_param_tys.size())) { if (i < static_cast<int>(fn_ty->m_param_tys.size())) {
auto expected_param_ty = fn_ty->m_param_tys[i]; auto expected_param_ty = fn_ty->m_param_tys[i];
auto param_ty = this->m_args[i]->typecheck(state, scope, expected_param_ty); auto param_ty = this->m_args[i]->typecheck(state, scope, expected_param_ty).type;
auto check_res = check_type(state, param_ty, expected_param_ty); auto check_res = check_type(state, param_ty, expected_param_ty);
this->m_args[i] = handle_res(std::move(this->m_args[i]), check_res, state); this->m_args[i] = handle_res(std::move(this->m_args[i]), check_res, state);
@ -294,7 +302,7 @@ namespace AST {
} }
} }
return fn_ty->m_ret_ty; return { fn_ty->m_ret_ty, false, false };
} }
void CastExpression::typecheck_preprocess(typecheck::Scope& scope) { void CastExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -302,127 +310,128 @@ namespace AST {
this->m_expr->typecheck_preprocess(scope); this->m_expr->typecheck_preprocess(scope);
} }
std::shared_ptr<types::Type> CastExpression::typecheck( typecheck::ExpressionType CastExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> std::optional<std::shared_ptr<types::Type>>
) { ) {
auto expr_ty = this->m_expr->typecheck(state, scope, {}); auto expr_ty = this->m_expr->typecheck(state, scope, {}).type;
auto cast = types::find_cast(state.casts, expr_ty, this->m_ty); auto cast = types::find_cast(state.casts, expr_ty, this->m_ty);
if (cast) { if (cast) {
return cast->target_ty; return { cast->target_ty, false, false };
} }
state.errors.push_back(CompileError("Cast from type " state.errors.push_back(CompileError("Cast from type "
+ expr_ty->formatted() + "to type " + this->m_ty->formatted() + expr_ty->formatted() + "to type " + this->m_ty->formatted()
+ " is not permitted", this->m_meta)); + " is not permitted", this->m_meta));
return std::shared_ptr<types::Type> { new types::FundamentalType{ return { std::shared_ptr<types::Type> { new types::FundamentalType{
false,
types::FundamentalTypeKind::Void types::FundamentalTypeKind::Void
} }; } }, false, false };
} }
void RefExpression::typecheck_preprocess(typecheck::Scope& scope) { void RefExpression::typecheck_preprocess(typecheck::Scope& scope) {
this->m_expr->typecheck_preprocess(scope); this->m_expr->typecheck_preprocess(scope);
} }
std::shared_ptr<types::Type> RefExpression::typecheck( typecheck::ExpressionType RefExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> std::optional<std::shared_ptr<types::Type>>
) { ) {
auto expr_ty = this->m_expr->typecheck(state, scope, {}); auto expr_ty = this->m_expr->typecheck(state, scope, {}).type;
return std::shared_ptr<types::Type> { return { std::shared_ptr<types::Type> {
new types::PointerType{ expr_ty } new types::PointerType{ false, expr_ty }
}; }, false, false };
} }
void DerefExpression::typecheck_preprocess(typecheck::Scope& scope) { void DerefExpression::typecheck_preprocess(typecheck::Scope& scope) {
this->m_expr->typecheck_preprocess(scope); this->m_expr->typecheck_preprocess(scope);
} }
std::shared_ptr<types::Type> DerefExpression::typecheck( typecheck::ExpressionType DerefExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> std::optional<std::shared_ptr<types::Type>>
) { ) {
auto expr_ty = this->m_expr->typecheck(state, scope, {}); auto expr_ty = this->m_expr->typecheck(state, scope, {});
if (expr_ty->m_kind != types::TypeKind::Pointer) { if (expr_ty.type->m_kind != types::TypeKind::Pointer) {
state.errors.push_back( state.errors.push_back(
CompileError("Tried to deref " + expr_ty->formatted(), this->m_meta)); CompileError("Tried to deref " + expr_ty.type->formatted(), this->m_meta));
return std::shared_ptr<types::Type> { 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.get()); auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.type.get());
return ptr_ty->m_inner; return { ptr_ty->m_inner, false, expr_ty.lvalue };
} }
void IndexAccessExpression::typecheck_preprocess(typecheck::Scope& scope) { void IndexAccessExpression::typecheck_preprocess(typecheck::Scope& scope) {
this->m_expr->typecheck_preprocess(scope); this->m_expr->typecheck_preprocess(scope);
} }
std::shared_ptr<types::Type> IndexAccessExpression::typecheck( typecheck::ExpressionType IndexAccessExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> std::optional<std::shared_ptr<types::Type>>
) { ) {
auto expr_ty = this->m_expr->typecheck(state, scope, {}); auto expr_ty = this->m_expr->typecheck(state, scope, {});
if (expr_ty->m_kind != types::TypeKind::Pointer && expr_ty->m_kind != types::TypeKind::Array) { if (expr_ty.type->m_kind != types::TypeKind::Pointer && expr_ty.type->m_kind != types::TypeKind::Array) {
state.errors.push_back( state.errors.push_back(
CompileError("Tried to index " + expr_ty->formatted(), this->m_meta)); CompileError("Tried to index " + expr_ty.type->formatted(), this->m_meta));
return std::shared_ptr<types::Type> { 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->m_kind == types::TypeKind::Pointer) { if (expr_ty.type->m_kind == types::TypeKind::Pointer) {
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.get()); auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.type.get());
return ptr_ty->m_inner; return { ptr_ty->m_inner, false, expr_ty.lvalue };
} }
else if (expr_ty->m_kind == types::TypeKind::Array) { else if (expr_ty.type->m_kind == types::TypeKind::Array) {
auto ptr_ty = dynamic_cast<types::ArrayType*>(expr_ty.get()); auto ptr_ty = dynamic_cast<types::ArrayType*>(expr_ty.type.get());
return ptr_ty->m_inner; return { ptr_ty->m_inner, false, expr_ty.lvalue };
} }
// Default return type // Default return type
return std::shared_ptr<types::Type> { return { std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void } new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}; }, false, expr_ty.lvalue };
} }
void FieldAccessExpression::typecheck_preprocess(typecheck::Scope& scope) { void FieldAccessExpression::typecheck_preprocess(typecheck::Scope& scope) {
this->m_expr->typecheck_preprocess(scope); this->m_expr->typecheck_preprocess(scope);
} }
std::shared_ptr<types::Type> FieldAccessExpression::typecheck( typecheck::ExpressionType FieldAccessExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> std::optional<std::shared_ptr<types::Type>>
) { ) {
auto expr_ty = this->m_expr->typecheck(state, scope, {}); auto expr_ty = this->m_expr->typecheck(state, scope, {});
if (expr_ty->m_kind != types::TypeKind::Struct) { if (expr_ty.type->m_kind != types::TypeKind::Struct) {
state.errors.push_back( state.errors.push_back(
CompileError("Tried to access " + expr_ty->formatted() + "." + this->m_field, this->m_meta)); CompileError("Tried to access " + expr_ty.type->formatted() + "." + this->m_field, this->m_meta));
return std::shared_ptr<types::Type> { return { std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void } new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}; }, false, expr_ty.lvalue };
} }
auto struct_ty = dynamic_cast<types::StructType*>(expr_ty.get()); auto struct_ty = dynamic_cast<types::StructType*>(expr_ty.type.get());
if (struct_ty->m_fields) { if (struct_ty->m_fields) {
for (auto& field : *struct_ty->m_fields) { for (auto& field : *struct_ty->m_fields) {
if (field.first == this->m_field) { if (field.first == this->m_field) {
return field.second; return { field.second, false, expr_ty.lvalue };
} }
} }
state.errors.push_back(CompileError("No such field", this->m_meta)); state.errors.push_back(CompileError("No such field", this->m_meta));
return std::shared_ptr<types::Type> { 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)); state.errors.push_back(CompileError("Cannot access fields of opaque struct", this->m_meta));
return std::shared_ptr<types::Type> { return { std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void } new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}; }, false, expr_ty.lvalue };
} }
void ListInitializerExpression::typecheck_preprocess(typecheck::Scope& scope) { void ListInitializerExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -432,7 +441,7 @@ namespace AST {
} }
} }
std::shared_ptr<types::Type> ListInitializerExpression::typecheck( typecheck::ExpressionType ListInitializerExpression::typecheck(
typecheck::State& state, typecheck::State& state,
typecheck::Scope& scope, typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty std::optional<std::shared_ptr<types::Type>> expected_ty
@ -441,7 +450,7 @@ namespace AST {
if ((*expected_ty)->m_kind == types::TypeKind::Array) { if ((*expected_ty)->m_kind == types::TypeKind::Array) {
auto array_ty = dynamic_cast<types::ArrayType*>(expected_ty->get()); auto array_ty = dynamic_cast<types::ArrayType*>(expected_ty->get());
for (auto& expr : this->m_expressions) { for (auto& expr : this->m_expressions) {
auto expr_ty = expr->typecheck(state, scope, array_ty->m_inner); auto expr_ty = expr->typecheck(state, scope, array_ty->m_inner).type;
auto expr_res = check_type(state, expr_ty, 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); expr = handle_res(std::move(expr), expr_res, state);
} }
@ -449,7 +458,8 @@ namespace AST {
this->m_ty = std::shared_ptr<types::Type>{ this->m_ty = std::shared_ptr<types::Type>{
new types::ArrayType{ new types::ArrayType{
array_ty->m_inner, array_ty->m_inner,
static_cast<uint32_t>(this->m_expressions.size()) static_cast<uint32_t>(this->m_expressions.size()),
true
} }
}; };
} }
@ -461,40 +471,40 @@ namespace AST {
state.errors.push_back(CompileError( state.errors.push_back(CompileError(
"Too many initializer values for " + struct_ty->formatted(), "Too many initializer values for " + struct_ty->formatted(),
this->m_meta)); this->m_meta));
return *expected_ty; return { *expected_ty, true, false };
} }
for (int i = 0; i < static_cast<int>(this->m_expressions.size()); i++) { for (int i = 0; i < static_cast<int>(this->m_expressions.size()); i++) {
auto expected_field = (*struct_ty->m_fields)[i]; auto expected_field = (*struct_ty->m_fields)[i];
auto expr_ty = this->m_expressions[i]->typecheck(state, scope, expected_field.second); auto expr_ty = this->m_expressions[i]->typecheck(state, scope, expected_field.second).type;
auto res = check_type(state, expr_ty, expected_field.second); auto res = check_type(state, expr_ty, expected_field.second);
this->m_expressions[i] = handle_res(std::move(this->m_expressions[i]), res, state); this->m_expressions[i] = handle_res(std::move(this->m_expressions[i]), res, state);
} }
this->m_ty = *expected_ty; this->m_ty = *expected_ty;
return this->m_ty; return { this->m_ty, true, false };
} }
else { else {
if (this->m_expressions.size() > 0) { if (this->m_expressions.size() > 0) {
state.errors.push_back(CompileError( state.errors.push_back(CompileError(
"Too many initializer values for " + struct_ty->formatted(), "Too many initializer values for " + struct_ty->formatted(),
this->m_meta)); this->m_meta));
return *expected_ty; return { *expected_ty, true, false };
} }
else { else {
this->m_ty = *expected_ty; this->m_ty = *expected_ty;
return this->m_ty; return { this->m_ty, true, false };
} }
} }
} }
else { else {
return std::shared_ptr<types::Type> { return { std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void } new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}; }, true, false };
} }
return this->m_ty; return { this->m_ty, true, false };
} }
// No expected ty, try to infer array type from elements // No expected ty, try to infer array type from elements
@ -502,26 +512,28 @@ namespace AST {
if (this->m_expressions.size() == 0) { if (this->m_expressions.size() == 0) {
this->m_ty = std::shared_ptr<types::Type>{ this->m_ty = std::shared_ptr<types::Type>{
new types::ArrayType{ new types::ArrayType{
std::make_shared<types::FundamentalType>(types::FundamentalTypeKind::Void), std::make_shared<types::FundamentalType>(true, types::FundamentalTypeKind::Void),
0 0,
true
} }
}; };
return this->m_ty; return { this->m_ty, true, false };
} }
else { else {
auto first_expr_ty = this->m_expressions[0]->typecheck(state, scope, {}); auto first_expr_ty = this->m_expressions[0]->typecheck(state, scope, {}).type;
for (int i = 1; i < static_cast<int>(this->m_expressions.size()); i++) { for (int i = 1; i < static_cast<int>(this->m_expressions.size()); i++) {
auto expr_ty = this->m_expressions[i]->typecheck(state, scope, first_expr_ty); auto expr_ty = this->m_expressions[i]->typecheck(state, scope, first_expr_ty).type;
auto expr_res = check_type(state, expr_ty, 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_expressions[i] = handle_res(std::move(this->m_expressions[i]), expr_res, state);
} }
this->m_ty = std::shared_ptr<types::Type>{ this->m_ty = std::shared_ptr<types::Type>{
new types::ArrayType{ new types::ArrayType{
first_expr_ty, first_expr_ty,
static_cast<uint32_t>(this->m_expressions.size()) static_cast<uint32_t>(this->m_expressions.size()),
true
} }
}; };
return this->m_ty; return { this->m_ty, true, false };
} }
} }
@ -530,7 +542,7 @@ namespace AST {
} }
void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { void ReturnStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty); auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty).type;
if (scope.return_ty) { if (scope.return_ty) {
auto check_res = check_type(state, res_ty, *scope.return_ty); auto check_res = check_type(state, res_ty, *scope.return_ty);
this->m_expr = handle_res(std::move(this->m_expr), check_res, state); this->m_expr = handle_res(std::move(this->m_expr), check_res, state);
@ -546,7 +558,12 @@ namespace AST {
void InitializationStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { void InitializationStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
if (this->m_expr) { if (this->m_expr) {
auto expr_ty = (*this->m_expr)->typecheck(state, scope, this->m_type); auto expr_ty = (*this->m_expr)->typecheck(state, scope, this->m_type);
auto check_res = check_type(state, expr_ty, this->m_type); if (this->m_type->m_kind == types::TypeKind::Array && !expr_ty.array_initializer) {
state.errors.push_back(
CompileError("Arrays can only be initialized with list-initializers or strings", this->m_meta)
);
}
auto check_res = check_type(state, expr_ty.type, this->m_type);
this->m_expr = handle_res(std::move(*this->m_expr), check_res, state); this->m_expr = handle_res(std::move(*this->m_expr), check_res, state);
} }
scope.symbols[this->m_name] = this->m_type; scope.symbols[this->m_name] = this->m_type;
@ -569,8 +586,8 @@ namespace AST {
void IfStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { void IfStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
auto bool_ty = std::shared_ptr<types::Type>{ 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); auto expr_ty = this->m_condition->typecheck(state, scope, bool_ty).type;
auto check_res = check_type(state, expr_ty, bool_ty); auto check_res = check_type(state, expr_ty, bool_ty);
this->m_condition = handle_res(std::move(this->m_condition), check_res, state); this->m_condition = handle_res(std::move(this->m_condition), check_res, state);
@ -601,7 +618,7 @@ namespace AST {
param_tys.push_back(param.second); 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 }; scope.symbols[this->m_name] = std::shared_ptr<types::Type>{ function_ty };
typecheck::Scope inner{ scope }; typecheck::Scope inner{ scope };

View File

@ -20,6 +20,12 @@ namespace typecheck {
std::vector<types::CastDefinition> casts; std::vector<types::CastDefinition> casts;
std::vector<CompileError> errors; std::vector<CompileError> errors;
}; };
struct ExpressionType {
std::shared_ptr<types::Type> type;
bool array_initializer;
bool lvalue;
};
} }
#endif #endif

View File

@ -42,18 +42,27 @@ namespace types {
} }
std::string FundamentalType::formatted() { std::string FundamentalType::formatted() {
std::stringstream out{ "" };
if (this->m_const)
out << "const ";
switch (this->m_ty) { switch (this->m_ty) {
case FundamentalTypeKind::Int: case FundamentalTypeKind::Int:
return "Int"; out << "Int";
break;
case FundamentalTypeKind::Bool: case FundamentalTypeKind::Bool:
return "Bool"; out << "Bool";
break;
case FundamentalTypeKind::Char: case FundamentalTypeKind::Char:
return "Char"; out << "Char";
break;
case FundamentalTypeKind::Void: case FundamentalTypeKind::Void:
return "Void"; out << "Void";
break;
default: default:
return "Unknown"; out << "Unknown";
break;
} }
return out.str();
} }
std::optional<std::shared_ptr<Type>> Type::return_type() { std::optional<std::shared_ptr<Type>> Type::return_type() {
@ -96,6 +105,9 @@ namespace types {
std::string FunctionType::formatted() { std::string FunctionType::formatted() {
std::stringstream out{ "" }; std::stringstream out{ "" };
if (this->m_const)
out << "const ";
out << "("; out << "(";
int counter = 0; int counter = 0;
@ -131,6 +143,9 @@ namespace types {
std::string PointerType::formatted() { std::string PointerType::formatted() {
std::stringstream out{ "" }; std::stringstream out{ "" };
out << this->m_inner->formatted() << "*"; out << this->m_inner->formatted() << "*";
if (this->m_const)
out << " const";
return out.str(); return out.str();
} }
@ -147,6 +162,7 @@ namespace types {
std::string ArrayType::formatted() { std::string ArrayType::formatted() {
std::stringstream out{ "" }; std::stringstream out{ "" };
// Arrays are always constant, no reason to format it.
out << this->m_inner->formatted(); out << this->m_inner->formatted();
out << "[" << this->m_size << "]"; out << "[" << this->m_size << "]";
return out.str(); return out.str();
@ -163,6 +179,9 @@ namespace types {
std::string StructType::formatted() { std::string StructType::formatted() {
std::stringstream out{ "" }; std::stringstream out{ "" };
if (this->m_const)
out << "const ";
out << "struct(" << this->m_id << ")"; out << "struct(" << this->m_id << ")";
if (this->m_is_ref) if (this->m_is_ref)
out << "(ref)"; out << "(ref)";
@ -202,22 +221,6 @@ namespace types {
return size; return size;
} }
// std::string StructRef::formatted() {
// std::stringstream out{ "" };
// out << "struct(ref) " << this->m_name;
// return out.str();
// }
// std::pair<llvm::Value*, std::shared_ptr<Type>> StructRef::load(codegen::Builder&, llvm::Value* ptr, codegen::TypeMap&) {
// auto self = std::make_shared<StructRef>(*this);
// return std::pair(ptr, self);
// }
// uint32_t StructRef::size() {
// return this->m_referred->size();
// }
bool types_equal(std::shared_ptr<types::Type> type1, std::shared_ptr<types::Type> type2) { bool types_equal(std::shared_ptr<types::Type> type1, std::shared_ptr<types::Type> type2) {
if (type1->m_kind != type2->m_kind) if (type1->m_kind != type2->m_kind)
return false; return false;

View File

@ -27,7 +27,9 @@ namespace types {
class Type { class Type {
public: public:
TypeKind m_kind; 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 ~Type() = default;
virtual std::string formatted() = 0; virtual std::string formatted() = 0;
virtual llvm::Type* codegen(codegen::Builder& builder, codegen::TypeMap& structs) = 0; virtual llvm::Type* codegen(codegen::Builder& builder, codegen::TypeMap& structs) = 0;
@ -40,7 +42,7 @@ namespace types {
class FundamentalType : public Type { class FundamentalType : public Type {
public: public:
FundamentalTypeKind m_ty; 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 ~FundamentalType() override = default;
virtual std::string formatted() override; virtual std::string formatted() override;
virtual llvm::Type* codegen(codegen::Builder& builder, codegen::TypeMap& structs) 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::shared_ptr<Type> m_ret_ty;
std::vector<std::shared_ptr<Type>> m_param_tys; std::vector<std::shared_ptr<Type>> m_param_tys;
bool m_vararg; bool m_vararg;
FunctionType(std::shared_ptr<Type> ret_ty, std::vector<std::shared_ptr<Type>> param_tys, bool vararg) FunctionType(bool is_const, std::shared_ptr<Type> ret_ty, std::vector<std::shared_ptr<Type>> param_tys, bool vararg)
: Type(TypeKind::Function) : Type(TypeKind::Function, is_const)
, m_ret_ty{ std::move(ret_ty) } , m_ret_ty{ std::move(ret_ty) }
, m_param_tys{ std::move(param_tys) } , m_param_tys{ std::move(param_tys) }
, m_vararg{ vararg } { , m_vararg{ vararg } {
@ -73,8 +75,8 @@ namespace types {
public: public:
std::shared_ptr<Type> m_inner; std::shared_ptr<Type> m_inner;
PointerType(std::shared_ptr<Type> inner) PointerType(bool is_const, std::shared_ptr<Type> inner)
: Type(TypeKind::Pointer), m_inner{ std::move(inner) } { : Type(TypeKind::Pointer, is_const), m_inner{ std::move(inner) } {
} }
virtual ~PointerType() override = default; virtual ~PointerType() override = default;
virtual std::string formatted() override; virtual std::string formatted() override;
@ -87,9 +89,10 @@ namespace types {
public: public:
std::shared_ptr<Type> m_inner; std::shared_ptr<Type> m_inner;
uint32_t m_size; uint32_t m_size;
bool m_raw;
ArrayType(std::shared_ptr<Type> inner, uint32_t size) ArrayType(std::shared_ptr<Type> inner, uint32_t size, bool raw)
: Type(TypeKind::Array), m_inner{ std::move(inner) }, m_size{ size } { : Type(TypeKind::Array, true), m_inner{ std::move(inner) }, m_size{ size }, m_raw{ raw } {
} }
virtual ~ArrayType() override = default; virtual ~ArrayType() override = default;
virtual std::string formatted() override; virtual std::string formatted() override;
@ -108,8 +111,8 @@ namespace types {
bool m_is_def; bool m_is_def;
uint32_t m_id; 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) 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), m_name{ name }, m_fields{ fields }, m_is_ref{ is_ref }, m_is_def{ is_def }, m_id{ 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 ~StructType() override = default;
virtual std::string formatted() override; virtual std::string formatted() override;
@ -118,21 +121,6 @@ namespace types {
virtual uint32_t size() override; 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); bool types_equal(std::shared_ptr<types::Type> type1, std::shared_ptr<types::Type> type2);
} }

20
test.c
View File

@ -13,27 +13,35 @@ void change_first(char otus[5]) {
struct Otus; struct Otus;
void update(struct Otus potus) {
potus.field = 20;
}
struct Otus { struct Otus {
int field; int field;
}; };
void update(struct Otus potus) {
potus.field = 20;
}
void update_ptr(char* ptr) {
*ptr = 50;
}
int main() { int main() {
char text[29] = "10th fibonacci number is %d!"; char text[30] = "10th fibonacci number is %d!\n";
printf(text, fibonacci(10)); printf(text, fibonacci(10));
char somelist[5] = { 1, 2, 3, 4, 5 }; char somelist[5] = { 1, 2, 3, 4, 5 };
change_first(somelist); change_first(somelist);
printf(" first element: %d!", somelist[0]); printf("first element: %d!\n", somelist[0]);
struct Otus otus = { 5 }; struct Otus otus = { 5 };
update(otus); update(otus);
printf(" first field: %d!", otus.field); printf("first field: %d!\n", otus.field);
char hello = 10;
update_ptr(&hello);
printf("hello: %d!\n", hello);
return 0; return 0;
} }