Compare commits

...

11 Commits

11 changed files with 388 additions and 283 deletions

View File

@ -27,7 +27,7 @@ namespace AST {
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) = 0;
virtual std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty
@ -52,7 +52,7 @@ namespace AST {
: Expression{ meta }
, m_value{ value }
, m_ty{ { std::shared_ptr<types::Type>{
new types::FundamentalType{types::FundamentalTypeKind::Int}
new types::FundamentalType{true, types::FundamentalTypeKind::Int}
} } } {
}
virtual ~IntLiteralExpression() override = default;
@ -60,7 +60,7 @@ namespace AST {
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 void typecheck_preprocess(typecheck::Scope& scope) override;
virtual std::shared_ptr<types::Type> typecheck(
virtual typecheck::ExpressionType typecheck(
typecheck::State& state,
typecheck::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
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 std::shared_ptr<types::Type> get_codegen_type(codegen::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::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@
#include <vector>
#include <iostream>
#include <sstream>
#include <optional>
static bool iswhitespace(char& character) {
return character == ' '
@ -14,6 +14,33 @@ static bool iswhitespace(char& character) {
|| 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 {
std::string type_name(Type& type) {
switch (type) {
@ -152,9 +179,27 @@ namespace token {
std::string content{};
c = text[++i]; // Skip initial "
do {
content += c;
if ((i + 1) >= text_length) break;
c = text[++i];
if (c == '\\') {
std::string escaped_content{};
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 != '\"');
i++; // Skip second "
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);
}
std::shared_ptr<types::Type> IntLiteralExpression::typecheck(
typecheck::ExpressionType IntLiteralExpression::typecheck(
typecheck::State&,
typecheck::Scope&,
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&) {}
std::shared_ptr<types::Type> StringLiteralExpression::typecheck(
typecheck::ExpressionType StringLiteralExpression::typecheck(
typecheck::State&,
typecheck::Scope&,
std::optional<std::shared_ptr<types::Type>>
) {
auto char_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Char }
new types::FundamentalType{ true, types::FundamentalTypeKind::Char }
};
auto ptr_ty = new types::ArrayType{ char_ty, static_cast<uint32_t>(this->m_value.size()) + 1 };
return std::shared_ptr<types::Type>{ptr_ty};
auto ptr_ty = new types::ArrayType{ char_ty, static_cast<uint32_t>(this->m_value.size()) + 1, true };
return { std::shared_ptr<types::Type>{ptr_ty}, true, false };
}
void ValueReferenceExpression::typecheck_preprocess(typecheck::Scope&) {}
std::shared_ptr<types::Type> ValueReferenceExpression::typecheck(
typecheck::ExpressionType ValueReferenceExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>>
) {
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));
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
return { std::shared_ptr<types::Type>{
new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}, false, true };
}
void BinaryOperationExpression::typecheck_preprocess(typecheck::Scope& scope) {
@ -164,20 +164,28 @@ namespace AST {
this->m_rhs->typecheck_preprocess(scope);
}
std::shared_ptr<types::Type> BinaryOperationExpression::typecheck(
typecheck::ExpressionType BinaryOperationExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty
) {
auto lhs_ty = this->m_lhs->typecheck(state, scope, {});
auto rhs_ty = this->m_rhs->typecheck(state, scope, {});
auto lhs_res = this->m_lhs->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 (!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
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);
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
@ -189,7 +197,7 @@ namespace AST {
);
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
@ -209,7 +217,7 @@ namespace AST {
// Skip if not implicitly castable to lhs
continue;
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)) {
auto lhs_res = check_type(state, lhs_ty, binop.lhs);
@ -217,7 +225,7 @@ namespace AST {
// Skip if not implicitly castable to rhs
continue;
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);
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);
return binop.result(binop, lhs_ty, rhs_ty);
return { binop.result(binop, lhs_ty, rhs_ty), false, false };
}
// No suitable binops found :(
@ -246,8 +254,8 @@ namespace AST {
+ rhs_ty->formatted(),
this->m_meta));
return std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Void } };
return { std::shared_ptr<types::Type>{
new types::FundamentalType{ false, types::FundamentalTypeKind::Void } }, false, false };
}
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::Scope& scope,
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) {
state.errors.push_back(CompileError("Tried calling a non-function", this->m_meta));
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
return { std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}, false, false };
}
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++) {
if (i < static_cast<int>(fn_ty->m_param_tys.size())) {
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);
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) {
@ -302,127 +310,128 @@ namespace AST {
this->m_expr->typecheck_preprocess(scope);
}
std::shared_ptr<types::Type> CastExpression::typecheck(
typecheck::ExpressionType CastExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
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);
if (cast) {
return cast->target_ty;
return { cast->target_ty, false, false };
}
state.errors.push_back(CompileError("Cast from type "
+ expr_ty->formatted() + "to type " + this->m_ty->formatted()
+ " 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
} };
} }, false, false };
}
void RefExpression::typecheck_preprocess(typecheck::Scope& scope) {
this->m_expr->typecheck_preprocess(scope);
}
std::shared_ptr<types::Type> RefExpression::typecheck(
typecheck::ExpressionType RefExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>>
) {
auto expr_ty = this->m_expr->typecheck(state, scope, {});
return std::shared_ptr<types::Type> {
new types::PointerType{ expr_ty }
};
auto expr_ty = this->m_expr->typecheck(state, scope, {}).type;
return { std::shared_ptr<types::Type> {
new types::PointerType{ false, expr_ty }
}, false, false };
}
void DerefExpression::typecheck_preprocess(typecheck::Scope& scope) {
this->m_expr->typecheck_preprocess(scope);
}
std::shared_ptr<types::Type> DerefExpression::typecheck(
typecheck::ExpressionType DerefExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>>
) {
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(
CompileError("Tried to deref " + expr_ty->formatted(), this->m_meta));
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
CompileError("Tried to deref " + expr_ty.type->formatted(), this->m_meta));
return { std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue };
}
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.get());
return ptr_ty->m_inner;
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.type.get());
return { ptr_ty->m_inner, false, expr_ty.lvalue };
}
void IndexAccessExpression::typecheck_preprocess(typecheck::Scope& scope) {
this->m_expr->typecheck_preprocess(scope);
}
std::shared_ptr<types::Type> IndexAccessExpression::typecheck(
typecheck::ExpressionType IndexAccessExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>>
) {
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(
CompileError("Tried to index " + expr_ty->formatted(), this->m_meta));
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
CompileError("Tried to index " + expr_ty.type->formatted(), this->m_meta));
return { std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue };
}
if (expr_ty->m_kind == types::TypeKind::Pointer) {
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.get());
return ptr_ty->m_inner;
if (expr_ty.type->m_kind == types::TypeKind::Pointer) {
auto ptr_ty = dynamic_cast<types::PointerType*>(expr_ty.type.get());
return { ptr_ty->m_inner, false, expr_ty.lvalue };
}
else if (expr_ty->m_kind == types::TypeKind::Array) {
auto ptr_ty = dynamic_cast<types::ArrayType*>(expr_ty.get());
return ptr_ty->m_inner;
else if (expr_ty.type->m_kind == types::TypeKind::Array) {
auto ptr_ty = dynamic_cast<types::ArrayType*>(expr_ty.type.get());
return { ptr_ty->m_inner, false, expr_ty.lvalue };
}
// Default return type
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
return { std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue };
}
void FieldAccessExpression::typecheck_preprocess(typecheck::Scope& scope) {
this->m_expr->typecheck_preprocess(scope);
}
std::shared_ptr<types::Type> FieldAccessExpression::typecheck(
typecheck::ExpressionType FieldAccessExpression::typecheck(
typecheck::State& state,
typecheck::Scope& scope,
std::optional<std::shared_ptr<types::Type>>
) {
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(
CompileError("Tried to access " + expr_ty->formatted() + "." + this->m_field, this->m_meta));
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
CompileError("Tried to access " + expr_ty.type->formatted() + "." + this->m_field, this->m_meta));
return { std::shared_ptr<types::Type> {
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) {
for (auto& field : *struct_ty->m_fields) {
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));
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
return { std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue };
}
state.errors.push_back(CompileError("Cannot access fields of opaque struct", this->m_meta));
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
return { std::shared_ptr<types::Type> {
new types::FundamentalType{ false, types::FundamentalTypeKind::Void }
}, false, expr_ty.lvalue };
}
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::Scope& scope,
std::optional<std::shared_ptr<types::Type>> expected_ty
@ -441,7 +450,7 @@ namespace AST {
if ((*expected_ty)->m_kind == types::TypeKind::Array) {
auto array_ty = dynamic_cast<types::ArrayType*>(expected_ty->get());
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);
expr = handle_res(std::move(expr), expr_res, state);
}
@ -449,7 +458,8 @@ namespace AST {
this->m_ty = std::shared_ptr<types::Type>{
new types::ArrayType{
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(
"Too many initializer values for " + struct_ty->formatted(),
this->m_meta));
return *expected_ty;
return { *expected_ty, true, false };
}
for (int i = 0; i < static_cast<int>(this->m_expressions.size()); 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);
this->m_expressions[i] = handle_res(std::move(this->m_expressions[i]), res, state);
}
this->m_ty = *expected_ty;
return this->m_ty;
return { this->m_ty, true, false };
}
else {
if (this->m_expressions.size() > 0) {
state.errors.push_back(CompileError(
"Too many initializer values for " + struct_ty->formatted(),
this->m_meta));
return *expected_ty;
return { *expected_ty, true, false };
}
else {
this->m_ty = *expected_ty;
return this->m_ty;
return { this->m_ty, true, false };
}
}
}
else {
return std::shared_ptr<types::Type> {
new types::FundamentalType{ types::FundamentalTypeKind::Void }
};
return { std::shared_ptr<types::Type> {
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
@ -502,26 +512,28 @@ namespace AST {
if (this->m_expressions.size() == 0) {
this->m_ty = std::shared_ptr<types::Type>{
new types::ArrayType{
std::make_shared<types::FundamentalType>(types::FundamentalTypeKind::Void),
0
std::make_shared<types::FundamentalType>(true, types::FundamentalTypeKind::Void),
0,
true
}
};
return this->m_ty;
return { this->m_ty, true, false };
}
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++) {
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);
this->m_expressions[i] = handle_res(std::move(this->m_expressions[i]), expr_res, state);
}
this->m_ty = std::shared_ptr<types::Type>{
new types::ArrayType{
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) {
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) {
auto check_res = check_type(state, res_ty, *scope.return_ty);
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) {
if (this->m_expr) {
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);
}
scope.symbols[this->m_name] = this->m_type;
@ -569,8 +586,8 @@ namespace AST {
void IfStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
auto bool_ty = std::shared_ptr<types::Type>{
new types::FundamentalType{ types::FundamentalTypeKind::Bool } };
auto expr_ty = this->m_condition->typecheck(state, scope, bool_ty);
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
auto expr_ty = this->m_condition->typecheck(state, scope, bool_ty).type;
auto check_res = check_type(state, expr_ty, bool_ty);
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);
}
auto function_ty = new types::FunctionType{ return_ty, param_tys, this->m_is_vararg };
auto function_ty = new types::FunctionType{ true, return_ty, param_tys, this->m_is_vararg };
scope.symbols[this->m_name] = std::shared_ptr<types::Type>{ function_ty };
typecheck::Scope inner{ scope };

View File

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

View File

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

View File

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

20
test.c
View File

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