Compare commits

..

No commits in common. "c3e12b087a745169d794085d961227cd9f4e87dd" and "f0607a2310882084c291a1b8e953b902eddde3eb" have entirely different histories.

11 changed files with 283 additions and 388 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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{true, types::FundamentalTypeKind::Int} new types::FundamentalType{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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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 typecheck::ExpressionType typecheck( virtual std::shared_ptr<types::Type> 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{ false, types::FundamentalTypeKind::Int } }; new types::FundamentalType{ types::FundamentalTypeKind::Int } };
auto char_ty = std::shared_ptr<types::Type>{ auto char_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ false, types::FundamentalTypeKind::Char } }; new types::FundamentalType{ types::FundamentalTypeKind::Char } };
auto bool_ty = std::shared_ptr<types::Type>{ auto bool_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ 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{ false, types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ 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{ false, types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ 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{ false, types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ 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{ false, types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ 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{ false, FundamentalTypeKind::Int } }; new FundamentalType{ FundamentalTypeKind::Int } };
auto char_ty = std::shared_ptr<Type>{ auto char_ty = std::shared_ptr<Type>{
new FundamentalType{ false, FundamentalTypeKind::Char } }; new FundamentalType{ FundamentalTypeKind::Char } };
auto bool_ty = std::shared_ptr<Type>{ auto bool_ty = std::shared_ptr<Type>{
new FundamentalType{ false, FundamentalTypeKind::Bool } }; new FundamentalType{ FundamentalTypeKind::Bool } };
auto numerical_types = { int_ty, char_ty, bool_ty }; auto numerical_types = { int_ty, char_ty, bool_ty };

View File

@ -31,18 +31,16 @@ 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_shared<types::FundamentalType>(true, types::FundamentalTypeKind::Char), std::make_unique<types::FundamentalType>(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_shared<types::FundamentalType>(true, types::FundamentalTypeKind::Char), std::make_unique<types::FundamentalType>(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() };
@ -52,7 +50,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 { false, std::shared_ptr<types::Type> {stack_type } } new types::PointerType { std::shared_ptr<types::Type> {stack_type } }
}, },
}; };
} }
@ -205,7 +203,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{ false, this->m_expr->get_codegen_type(scope) } new types::PointerType{ this->m_expr->get_codegen_type(scope) }
}; };
} }
@ -266,38 +264,58 @@ 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());
auto gep_value = builder.builder->CreateGEP(ptr_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP"); if (ptr_ty->m_inner->m_kind == types::TypeKind::Pointer) {
auto inner_ptr_ty = dynamic_cast<types::PointerType*>(ptr_ty->m_inner.get());
auto loaded = value.ty->load(builder, gep_value, scope.structs); auto gep_value = builder.builder->CreateGEP(inner_ptr_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP");
return codegen::StackValue{ if (scope.is_lvalue) {
loaded.first, return codegen::StackValue{
loaded.second gep_value,
}; value.ty,
} };
else if (value.ty->m_kind == types::TypeKind::Array) { }
auto array_ty = dynamic_cast<types::ArrayType*>(value.ty.get()); else {
if (array_ty->m_raw) { auto loaded = value.ty->load(builder, gep_value, scope.structs);
throw CompileError("Tried indexing a raw array", this->m_meta); return codegen::StackValue{
loaded.first,
loaded.second
};
}
} }
else if (ptr_ty->m_inner->m_kind == types::TypeKind::Array) {
auto gep_value = builder.builder->CreateGEP(array_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP"); // Must be an array otherwise
auto arr_ty = dynamic_cast<types::ArrayType*>(ptr_ty->m_inner.get());
auto ptr_ty = std::shared_ptr<types::Type>{ auto gep_value = builder.builder->CreateGEP(arr_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP");
new types::PointerType { array_ty->m_inner->m_const, array_ty->m_inner} if (scope.is_lvalue) {
}; return codegen::StackValue{
gep_value,
if (scope.is_lvalue) { value.ty,
return codegen::StackValue{ };
gep_value, }
ptr_ty, else {
}; 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 loaded = ptr_ty->load(builder, gep_value, scope.structs); auto gep_value = builder.builder->CreateGEP(ptr_ty->m_inner->codegen(builder, scope.structs), value.value, idx_list, "GEP");
return codegen::StackValue{ if (scope.is_lvalue) {
loaded.first, return codegen::StackValue{
loaded.second gep_value,
}; value.ty,
};
}
else {
auto loaded = value.ty->load(builder, gep_value, scope.structs);
return codegen::StackValue{
loaded.first,
loaded.second
};
}
} }
} }
@ -347,7 +365,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->m_const, field_ty } new types::PointerType { field_ty }
}; };
if (scope.is_lvalue) { if (scope.is_lvalue) {
@ -392,7 +410,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->m_const, this->m_ty} new types::PointerType{this->m_ty}
}; };
if (scope.is_lvalue) { if (scope.is_lvalue) {
@ -416,7 +434,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->m_const, this->m_ty} new types::PointerType{this->m_ty}
}; };
if (scope.is_lvalue) { if (scope.is_lvalue) {
@ -458,22 +476,6 @@ 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()) {
@ -481,9 +483,7 @@ namespace AST {
builder.builder->CreateStore(value.value, ptr, false); builder.builder->CreateStore(value.value, ptr, false);
} }
auto ptr_ty = std::shared_ptr<types::Type>{ auto ptr_ty = std::shared_ptr<types::Type>{ new types::PointerType{ this->m_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,9 +532,7 @@ 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>{ auto fn_ty_ptr = std::shared_ptr<types::Type>{ new types::FunctionType{ ret_ty_ptr, param_ty_ptrs, this->m_is_vararg } };
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(
@ -554,34 +552,32 @@ 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::Array) { if (param.second->m_kind == types::TypeKind::Pointer) {
auto array_ty = dynamic_cast<types::ArrayType*>(param.second.get()); auto ty = param_ty_ptrs[counter];
if (!array_ty->m_raw) { auto arg = function->getArg(counter++);
auto ty = param_ty_ptrs[counter]; if (param.first) {
auto arg = function->getArg(counter++); arg->setName(*param.first);
if (param.first) { inner_scope.values[*param.first] = codegen::StackValue{
arg->setName(*param.first); arg,
inner_scope.values[*param.first] = codegen::StackValue{ ty,
arg, };
ty,
};
}
continue;
} }
} }
builder.builder->SetInsertPoint(BB); else {
auto arg_ptr = builder.builder->CreateAlloca(param_ty_ptrs[counter]->codegen(builder, scope.structs)); builder.builder->SetInsertPoint(BB);
auto param_ty_ptr = std::shared_ptr<types::Type>{ auto arg_ptr = builder.builder->CreateAlloca(param_ty_ptrs[counter]->codegen(builder, scope.structs));
new types::PointerType { true, param_ty_ptrs[counter]} auto param_ty_ptr = std::shared_ptr<types::Type>{
}; 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,
};
}
} }
} }
@ -641,9 +637,7 @@ namespace types {
} }
llvm::Type* ArrayType::codegen(codegen::Builder& builder, codegen::TypeMap& structs) { llvm::Type* ArrayType::codegen(codegen::Builder& builder, codegen::TypeMap& structs) {
if (this->m_raw) return llvm::ArrayType::get(this->m_inner->codegen(builder, structs), this->m_size);
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,12 +12,6 @@ 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{};
@ -62,14 +56,7 @@ 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{ auto ty = new types::StructType{ struct_name, original_struct_ty->m_fields, true, false, original_struct_ty->m_id };
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 {
@ -77,37 +64,16 @@ 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{ auto ty = new types::StructType{ struct_name, maybe_fields, false, true, original_struct_ty->m_id };
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{ auto ty = new types::StructType{ struct_name, maybe_fields, false, false, struct_id_counter++ };
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{ auto ty = new types::StructType{ struct_name, maybe_fields, false, false, struct_id_counter++ };
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 };
} }
} }
@ -117,15 +83,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{ is_const, types::FundamentalTypeKind::Int }; auto ty = new types::FundamentalType{ 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{ is_const, types::FundamentalTypeKind::Char }; auto ty = new types::FundamentalType{ 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{ is_const, types::FundamentalTypeKind::Void }; auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Void };
returned = std::shared_ptr<types::Type>{ ty }; returned = std::shared_ptr<types::Type>{ ty };
} }
else { else {
@ -135,12 +101,7 @@ 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 ptr_const = false; auto ty = new types::PointerType{ std::move(returned) };
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 };
} }
@ -201,7 +162,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{ true, types::FundamentalTypeKind::Any } new types::FundamentalType{ types::FundamentalTypeKind::Any }
}) })
}; };
} }
@ -429,9 +390,16 @@ 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();
ty = std::shared_ptr<types::Type>{ if (postfix) {
new types::ArrayType(ty, *postfix, false) ty = std::shared_ptr<types::Type>{
}; 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);
} }
@ -543,12 +511,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::ArrayType(param_ty, *array_postfix, false) new types::PointerType(param_ty)
}; };
} }
else { else {
param_ty = std::shared_ptr<types::Type>{ param_ty = std::shared_ptr<types::Type>{
new types::PointerType(true, param_ty) new types::PointerType(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,33 +14,6 @@ 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) {
@ -179,27 +152,9 @@ namespace token {
std::string content{}; std::string content{};
c = text[++i]; // Skip initial " c = text[++i]; // Skip initial "
do { do {
if (c == '\\') { content += c;
std::string escaped_content{}; if ((i + 1) >= text_length) break;
if ((i + 1) >= text_length) break; c = text[++i];
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);
} }
typecheck::ExpressionType IntLiteralExpression::typecheck( std::shared_ptr<types::Type> 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, false, false }; return this->m_ty;
} }
void StringLiteralExpression::typecheck_preprocess(typecheck::Scope&) {} void StringLiteralExpression::typecheck_preprocess(typecheck::Scope&) {}
typecheck::ExpressionType StringLiteralExpression::typecheck( std::shared_ptr<types::Type> 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{ true, types::FundamentalTypeKind::Char } new types::FundamentalType{ types::FundamentalTypeKind::Char }
}; };
auto ptr_ty = new types::ArrayType{ char_ty, static_cast<uint32_t>(this->m_value.size()) + 1, true }; auto ptr_ty = new types::ArrayType{ char_ty, static_cast<uint32_t>(this->m_value.size()) + 1 };
return { std::shared_ptr<types::Type>{ptr_ty}, true, false }; return std::shared_ptr<types::Type>{ptr_ty};
} }
void ValueReferenceExpression::typecheck_preprocess(typecheck::Scope&) {} void ValueReferenceExpression::typecheck_preprocess(typecheck::Scope&) {}
typecheck::ExpressionType ValueReferenceExpression::typecheck( std::shared_ptr<types::Type> 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], false, true }; return scope.symbols[this->m_name];
} }
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{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ types::FundamentalTypeKind::Void }
}, false, true }; };
} }
void BinaryOperationExpression::typecheck_preprocess(typecheck::Scope& scope) { void BinaryOperationExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -164,28 +164,20 @@ namespace AST {
this->m_rhs->typecheck_preprocess(scope); this->m_rhs->typecheck_preprocess(scope);
} }
typecheck::ExpressionType BinaryOperationExpression::typecheck( std::shared_ptr<types::Type> 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_res = this->m_lhs->typecheck(state, scope, {}); auto lhs_ty = this->m_lhs->typecheck(state, scope, {});
auto lhs_ty = lhs_res.type; auto rhs_ty = this->m_rhs->typecheck(state, scope, {});
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).type; auto rhs_ty = this->m_rhs->typecheck(state, scope, lhs_ty);
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, false, false }; return lhs_ty;
} }
// Try to find a binop that matches exactly // Try to find a binop that matches exactly
@ -197,7 +189,7 @@ namespace AST {
); );
if (binop) { if (binop) {
return { binop->result(*binop, lhs_ty, rhs_ty), false, false }; return binop->result(*binop, lhs_ty, rhs_ty);
} }
// 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
@ -217,7 +209,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), false, false }; return binop.result(binop, lhs_ty, rhs_ty);
} }
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);
@ -225,7 +217,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), false, false }; return binop.result(binop, lhs_ty, rhs_ty);
} }
} }
@ -243,7 +235,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), false, false }; return binop.result(binop, lhs_ty, rhs_ty);
} }
// No suitable binops found :( // No suitable binops found :(
@ -254,8 +246,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{ false, types::FundamentalTypeKind::Void } }, false, false }; new types::FundamentalType{ types::FundamentalTypeKind::Void } };
} }
void FunctionCallExpression::typecheck_preprocess(typecheck::Scope& scope) { void FunctionCallExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -265,18 +257,18 @@ namespace AST {
} }
} }
typecheck::ExpressionType FunctionCallExpression::typecheck( std::shared_ptr<types::Type> 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, {}).type; auto expr_ty = this->m_fn_expr->typecheck(state, scope, {});
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{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ 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());
@ -291,7 +283,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).type; auto param_ty = this->m_args[i]->typecheck(state, scope, expected_param_ty);
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);
@ -302,7 +294,7 @@ namespace AST {
} }
} }
return { fn_ty->m_ret_ty, false, false }; return fn_ty->m_ret_ty;
} }
void CastExpression::typecheck_preprocess(typecheck::Scope& scope) { void CastExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -310,128 +302,127 @@ namespace AST {
this->m_expr->typecheck_preprocess(scope); this->m_expr->typecheck_preprocess(scope);
} }
typecheck::ExpressionType CastExpression::typecheck( std::shared_ptr<types::Type> 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, {}).type; auto expr_ty = this->m_expr->typecheck(state, scope, {});
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, false, false }; return cast->target_ty;
} }
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);
} }
typecheck::ExpressionType RefExpression::typecheck( std::shared_ptr<types::Type> 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, {}).type; auto expr_ty = this->m_expr->typecheck(state, scope, {});
return { std::shared_ptr<types::Type> { return std::shared_ptr<types::Type> {
new types::PointerType{ false, expr_ty } new types::PointerType{ 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);
} }
typecheck::ExpressionType DerefExpression::typecheck( std::shared_ptr<types::Type> 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.type->m_kind != types::TypeKind::Pointer) { if (expr_ty->m_kind != types::TypeKind::Pointer) {
state.errors.push_back( state.errors.push_back(
CompileError("Tried to deref " + expr_ty.type->formatted(), this->m_meta)); CompileError("Tried to deref " + expr_ty->formatted(), this->m_meta));
return { std::shared_ptr<types::Type> { return std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue }; };
} }
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.type.get()); auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.get());
return { ptr_ty->m_inner, false, expr_ty.lvalue }; return ptr_ty->m_inner;
} }
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);
} }
typecheck::ExpressionType IndexAccessExpression::typecheck( std::shared_ptr<types::Type> 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.type->m_kind != types::TypeKind::Pointer && expr_ty.type->m_kind != types::TypeKind::Array) { if (expr_ty->m_kind != types::TypeKind::Pointer && expr_ty->m_kind != types::TypeKind::Array) {
state.errors.push_back( state.errors.push_back(
CompileError("Tried to index " + expr_ty.type->formatted(), this->m_meta)); CompileError("Tried to index " + expr_ty->formatted(), this->m_meta));
return { std::shared_ptr<types::Type> { return std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue }; };
} }
if (expr_ty.type->m_kind == types::TypeKind::Pointer) { if (expr_ty->m_kind == types::TypeKind::Pointer) {
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.type.get()); auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.get());
return { ptr_ty->m_inner, false, expr_ty.lvalue }; return ptr_ty->m_inner;
} }
else if (expr_ty.type->m_kind == types::TypeKind::Array) { else if (expr_ty->m_kind == types::TypeKind::Array) {
auto ptr_ty = dynamic_cast<types::ArrayType*>(expr_ty.type.get()); auto ptr_ty = dynamic_cast<types::ArrayType*>(expr_ty.get());
return { ptr_ty->m_inner, false, expr_ty.lvalue }; return ptr_ty->m_inner;
} }
// Default return type // Default return type
return { std::shared_ptr<types::Type> { return std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ 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);
} }
typecheck::ExpressionType FieldAccessExpression::typecheck( std::shared_ptr<types::Type> 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.type->m_kind != types::TypeKind::Struct) { if (expr_ty->m_kind != types::TypeKind::Struct) {
state.errors.push_back( state.errors.push_back(
CompileError("Tried to access " + expr_ty.type->formatted() + "." + this->m_field, this->m_meta)); CompileError("Tried to access " + expr_ty->formatted() + "." + this->m_field, this->m_meta));
return { std::shared_ptr<types::Type> { return std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue }; };
} }
auto struct_ty = dynamic_cast<types::StructType*>(expr_ty.type.get()); auto struct_ty = dynamic_cast<types::StructType*>(expr_ty.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, false, expr_ty.lvalue }; return field.second;
} }
} }
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{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ 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{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue }; };
} }
void ListInitializerExpression::typecheck_preprocess(typecheck::Scope& scope) { void ListInitializerExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -441,7 +432,7 @@ namespace AST {
} }
} }
typecheck::ExpressionType ListInitializerExpression::typecheck( std::shared_ptr<types::Type> 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
@ -450,7 +441,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).type; auto expr_ty = expr->typecheck(state, scope, array_ty->m_inner);
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);
} }
@ -458,8 +449,7 @@ 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
} }
}; };
} }
@ -471,40 +461,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, true, false }; return *expected_ty;
} }
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).type; auto expr_ty = this->m_expressions[i]->typecheck(state, scope, expected_field.second);
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, true, false }; return this->m_ty;
} }
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, true, false }; return *expected_ty;
} }
else { else {
this->m_ty = *expected_ty; this->m_ty = *expected_ty;
return { this->m_ty, true, false }; return this->m_ty;
} }
} }
} }
else { else {
return { std::shared_ptr<types::Type> { return std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void } new types::FundamentalType{ types::FundamentalTypeKind::Void }
}, true, false }; };
} }
return { this->m_ty, true, false }; return this->m_ty;
} }
// No expected ty, try to infer array type from elements // No expected ty, try to infer array type from elements
@ -512,28 +502,26 @@ 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>(true, types::FundamentalTypeKind::Void), std::make_shared<types::FundamentalType>(types::FundamentalTypeKind::Void),
0, 0
true
} }
}; };
return { this->m_ty, true, false }; return this->m_ty;
} }
else { else {
auto first_expr_ty = this->m_expressions[0]->typecheck(state, scope, {}).type; auto first_expr_ty = this->m_expressions[0]->typecheck(state, scope, {});
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).type; auto expr_ty = this->m_expressions[i]->typecheck(state, scope, first_expr_ty);
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, true, false }; return this->m_ty;
} }
} }
@ -542,7 +530,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).type; auto res_ty = this->m_expr->typecheck(state, scope, scope.return_ty);
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);
@ -558,12 +546,7 @@ 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);
if (this->m_type->m_kind == types::TypeKind::Array && !expr_ty.array_initializer) { auto check_res = check_type(state, expr_ty, this->m_type);
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;
@ -586,8 +569,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{ false, types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
auto expr_ty = this->m_condition->typecheck(state, scope, bool_ty).type; auto expr_ty = this->m_condition->typecheck(state, scope, bool_ty);
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);
@ -618,7 +601,7 @@ namespace AST {
param_tys.push_back(param.second); param_tys.push_back(param.second);
} }
auto function_ty = new types::FunctionType{ true, return_ty, param_tys, this->m_is_vararg }; auto function_ty = new types::FunctionType{ 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,12 +20,6 @@ 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,27 +42,18 @@ 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:
out << "Int"; return "Int";
break;
case FundamentalTypeKind::Bool: case FundamentalTypeKind::Bool:
out << "Bool"; return "Bool";
break;
case FundamentalTypeKind::Char: case FundamentalTypeKind::Char:
out << "Char"; return "Char";
break;
case FundamentalTypeKind::Void: case FundamentalTypeKind::Void:
out << "Void"; return "Void";
break;
default: default:
out << "Unknown"; return "Unknown";
break;
} }
return out.str();
} }
std::optional<std::shared_ptr<Type>> Type::return_type() { std::optional<std::shared_ptr<Type>> Type::return_type() {
@ -105,9 +96,6 @@ 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;
@ -143,9 +131,6 @@ 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();
} }
@ -162,7 +147,6 @@ 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();
@ -179,9 +163,6 @@ 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)";
@ -221,6 +202,22 @@ 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,9 +27,7 @@ namespace types {
class Type { class Type {
public: public:
TypeKind m_kind; TypeKind m_kind;
bool m_const; Type(TypeKind kind) : m_kind{ kind } {}
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;
@ -42,7 +40,7 @@ namespace types {
class FundamentalType : public Type { class FundamentalType : public Type {
public: public:
FundamentalTypeKind m_ty; FundamentalTypeKind m_ty;
FundamentalType(bool is_const, FundamentalTypeKind kind) : Type(TypeKind::Fundamental, is_const), m_ty{ kind } {} FundamentalType(FundamentalTypeKind kind) : Type(TypeKind::Fundamental), 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;
@ -57,8 +55,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(bool is_const, std::shared_ptr<Type> ret_ty, std::vector<std::shared_ptr<Type>> param_tys, bool vararg) FunctionType(std::shared_ptr<Type> ret_ty, std::vector<std::shared_ptr<Type>> param_tys, bool vararg)
: Type(TypeKind::Function, is_const) : Type(TypeKind::Function)
, 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 } {
@ -75,8 +73,8 @@ namespace types {
public: public:
std::shared_ptr<Type> m_inner; std::shared_ptr<Type> m_inner;
PointerType(bool is_const, std::shared_ptr<Type> inner) PointerType(std::shared_ptr<Type> inner)
: Type(TypeKind::Pointer, is_const), m_inner{ std::move(inner) } { : Type(TypeKind::Pointer), m_inner{ std::move(inner) } {
} }
virtual ~PointerType() override = default; virtual ~PointerType() override = default;
virtual std::string formatted() override; virtual std::string formatted() override;
@ -89,10 +87,9 @@ 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, bool raw) ArrayType(std::shared_ptr<Type> inner, uint32_t size)
: Type(TypeKind::Array, true), m_inner{ std::move(inner) }, m_size{ size }, m_raw{ raw } { : Type(TypeKind::Array), m_inner{ std::move(inner) }, m_size{ size } {
} }
virtual ~ArrayType() override = default; virtual ~ArrayType() override = default;
virtual std::string formatted() override; virtual std::string formatted() override;
@ -111,8 +108,8 @@ namespace types {
bool m_is_def; bool m_is_def;
uint32_t m_id; uint32_t m_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) StructType(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 } { : Type(TypeKind::Struct), 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;
@ -121,6 +118,21 @@ 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,35 +13,27 @@ void change_first(char otus[5]) {
struct Otus; struct Otus;
struct Otus {
int field;
};
void update(struct Otus potus) { void update(struct Otus potus) {
potus.field = 20; potus.field = 20;
} }
struct Otus {
void update_ptr(char* ptr) { int field;
*ptr = 50; };
}
int main() { int main() {
char text[30] = "10th fibonacci number is %d!\n"; char text[29] = "10th fibonacci number is %d!";
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!\n", somelist[0]); printf(" first element: %d!", somelist[0]);
struct Otus otus = { 5 }; struct Otus otus = { 5 };
update(otus); update(otus);
printf("first field: %d!\n", otus.field); printf(" first field: %d!", otus.field);
char hello = 10;
update_ptr(&hello);
printf("hello: %d!\n", hello);
return 0; return 0;
} }