Compare commits
11 Commits
f0607a2310
...
c3e12b087a
| Author | SHA1 | Date | |
|---|---|---|---|
| c3e12b087a | |||
| c4837ca9b0 | |||
| 63584525f2 | |||
| 28be145a70 | |||
| 53872373bf | |||
| efb4ce85ac | |||
| 8e6980715e | |||
| f9208a525d | |||
| 6dad36e34a | |||
| d79151380f | |||
| 238577e9ca |
26
src/ast.h
26
src/ast.h
@ -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
|
||||||
|
|||||||
@ -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 } };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 };
|
||||||
|
|
||||||
|
|||||||
172
src/codegen.cpp
172
src/codegen.cpp
@ -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) {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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) });
|
||||||
|
|||||||
@ -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 };
|
||||||
|
|||||||
@ -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
|
||||||
@ -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;
|
||||||
|
|||||||
38
src/types.h
38
src/types.h
@ -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
20
test.c
@ -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;
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user