aboutsummaryrefslogtreecommitdiff
path: root/src/ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast.c')
-rw-r--r--src/ast.c129
1 files changed, 89 insertions, 40 deletions
diff --git a/src/ast.c b/src/ast.c
index 69243f8..35ece2e 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -23,8 +23,8 @@ static void resolve_data_init(AstResolveData *self) {
self->type = NULL;
}
-int ast_create(ScopedAllocator *allocator, void *value, AstType type, Ast **result) {
- return_if_error(scoped_allocator_alloc(allocator, sizeof(Ast), (void**)result));
+int ast_create(ArenaAllocator *allocator, void *value, AstType type, Ast **result) {
+ return_if_error(arena_allocator_alloc(allocator, sizeof(Ast), (void**)result));
(*result)->value.data = value;
(*result)->type = type;
resolve_data_init(&(*result)->resolve_data);
@@ -75,18 +75,23 @@ static BufferView ast_get_code_reference(Ast *self) {
return ast_get_name(self);
}
-int funcdecl_init(FunctionDecl *self, FunctionSignature *signature, Scope *parent, ScopedAllocator *allocator) {
+void function_signature_init(FunctionSignature *self) {
+ self->params = 0;
+ self->resolved = bool_false;
+}
+
+int funcdecl_init(FunctionDecl *self, FunctionSignature *signature, Scope *parent, ArenaAllocator *allocator) {
self->signature = signature;
self->ssa_func_index = 0;
return scope_init(&self->body, parent, allocator);
}
-int funccall_init(FunctionCall *self, BufferView name, ScopedAllocator *allocator) {
+int funccall_init(FunctionCall *self, BufferView name, ArenaAllocator *allocator) {
variable_init(&self->func, name);
return buffer_init(&self->args, allocator);
}
-int structdecl_init(StructDecl *self, Scope *parent, ScopedAllocator *allocator) {
+int structdecl_init(StructDecl *self, Scope *parent, ArenaAllocator *allocator) {
return scope_init(&self->body, parent, allocator);
}
@@ -139,24 +144,24 @@ void binop_init(Binop *self) {
self->grouped = bool_false;
}
-int if_statement_init(IfStatement *self, Scope *parent, ScopedAllocator *allocator) {
+int if_statement_init(IfStatement *self, Scope *parent, ArenaAllocator *allocator) {
self->condition = NULL;
self->else_if_stmt = NULL;
return scope_init(&self->body, parent, allocator);
}
-int else_if_statement_init(ElseIfStatement *self, Scope *parent, ScopedAllocator *allocator) {
+int else_if_statement_init(ElseIfStatement *self, Scope *parent, ArenaAllocator *allocator) {
self->condition = NULL;
self->next_else_if_stmt = NULL;
return scope_init(&self->body, parent, allocator);
}
-int while_statement_init(WhileStatement *self, Scope *parent, ScopedAllocator *allocator) {
+int while_statement_init(WhileStatement *self, Scope *parent, ArenaAllocator *allocator) {
self->condition = NULL;
return scope_init(&self->body, parent, allocator);
}
-int scope_init(Scope *self, Scope *parent, ScopedAllocator *allocator) {
+int scope_init(Scope *self, Scope *parent, ArenaAllocator *allocator) {
return_if_error(buffer_init(&self->ast_objects, allocator));
return_if_error(hash_map_init(&self->named_objects, allocator, sizeof(Ast*), hash_map_compare_string, amal_hash_string));
self->parent = parent;
@@ -164,7 +169,7 @@ int scope_init(Scope *self, Scope *parent, ScopedAllocator *allocator) {
return 0;
}
-int file_scope_reference_init(FileScopeReference *self, BufferView canonical_path, ScopedAllocator *allocator) {
+int file_scope_reference_init(FileScopeReference *self, BufferView canonical_path, ArenaAllocator *allocator) {
char null_terminator;
null_terminator = '\0';
self->parser = NULL;
@@ -273,15 +278,17 @@ static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context
static void function_signature_resolve(FunctionSignature *self, AstCompilerContext *context) {
/* TODO: Implement */
+ if(self->resolved)
+ return;
+ self->resolved = bool_true;
(void)self;
(void)context;
}
static void variable_resolve(Variable *self, AstCompilerContext *context, AstResolveData *resolve_data) {
- if(!self->resolved_var) {
+ if(!self->resolved_var)
self->resolved_var = scope_get_resolved_variable(context->scope, context, self->name);
- resolve_data->type = self->resolved_var->resolve_data.type;
- }
+ resolve_data->type = self->resolved_var->resolve_data.type;
}
static LhsExpr* variable_get_resolved_type(Variable *self) {
@@ -289,15 +296,18 @@ static LhsExpr* variable_get_resolved_type(Variable *self) {
return self->resolved_var->value.lhs_expr;
}
-static void variable_type_resolve(VariableType *self, AstCompilerContext *context, AstResolveData *resolve_data) {
- switch(self->type) {
+static void variable_type_resolve(LhsExpr *self, AstCompilerContext *context, AstResolveData *resolve_data) {
+ VariableType *lhs_expr_type;
+ lhs_expr_type = &self->type;
+ switch(lhs_expr_type->type) {
case VARIABLE_TYPE_NONE:
return;
case VARIABLE_TYPE_VARIABLE:
- variable_resolve(self->value.variable, context, resolve_data);
+ variable_resolve(lhs_expr_type->value.variable, context, resolve_data);
break;
case VARIABLE_TYPE_SIGNATURE:
- function_signature_resolve(self->value.signature, context);
+ function_signature_resolve(lhs_expr_type->value.signature, context);
+ resolve_data->type = self;
break;
}
}
@@ -333,13 +343,11 @@ static LhsExpr* lhsexpr_resolve_rhs(LhsExpr *self, AstCompilerContext *context)
static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
LhsExpr *self;
- LhsExpr *rhs_resolve_type;
assert(ast->type == AST_LHS);
self = ast->value.lhs_expr;
- rhs_resolve_type = NULL;
- variable_type_resolve(&self->type, context, &ast->resolve_data);
+ variable_type_resolve(self, context, &ast->resolve_data);
/*
TODO: When parameters and return types are implemented, AST_RESOLVE_END should be set after
@@ -347,8 +355,22 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
be allowed but recursive function calls still require parameters and return types to be known.
*/
if(self->rhs_expr) {
- if(self->rhs_expr->type == AST_FUNCTION_DECL)
+ LhsExpr *rhs_resolve_type;
+ if(self->rhs_expr->type == AST_FUNCTION_DECL) {
+ /*
+ The function declaration itself always resolves the signature, but we also do it here because we
+ want to have the signature solved before setting the lhs expr as solved. Also function signatures can exist
+ without lhs expr (anonymous function).
+ */
+ function_signature_resolve(self->rhs_expr->value.func_decl->signature, context);
ast->resolve_data.status = AST_RESOLVED;
+ /*
+ If rhs is a function declaration then there is no need to wait until it has been resolved before setting the type as the type
+ is @self (the lhs). We still need to continue after this, so rhs can be resolved.
+ */
+ if(!ast->resolve_data.type)
+ ast->resolve_data.type = self;
+ }
rhs_resolve_type = lhsexpr_resolve_rhs(self, context);
@@ -365,10 +387,8 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) {
"Variable type and variable assignment type (right-hand side) do not match");
throw(AST_ERR);
}
- }
-
- if(rhs_resolve_type)
ast->resolve_data.type = rhs_resolve_type;
+ }
}
static LhsExpr* binop_get_lhs_expr(Binop *self) {
@@ -443,18 +463,20 @@ static void import_resolve(Ast *ast, AstCompilerContext *context) {
static Scope* lhsexpr_get_scope(LhsExpr *self) {
AstValue value;
- value = self->rhs_expr->value;
- switch(self->rhs_expr->type) {
- case AST_FUNCTION_DECL:
- return &value.func_decl->body;
- case AST_STRUCT_DECL:
- return &value.struct_decl->body;
- case AST_IMPORT:
- return &value.import->file_scope->parser->struct_decl.body;
- default:
- break;
+ if(self->rhs_expr) {
+ value = self->rhs_expr->value;
+ switch(self->rhs_expr->type) {
+ case AST_FUNCTION_DECL:
+ return &value.func_decl->body;
+ case AST_STRUCT_DECL:
+ return &value.struct_decl->body;
+ case AST_IMPORT:
+ return &value.import->file_scope->parser->struct_decl.body;
+ default:
+ break;
+ }
}
- assert(bool_false && "Expected lhsexpr_get_scope to only be called for function decl, struct decl and import");
+ assert(bool_false && "Expected lhsexpr_get_scope to only be called for non-extern function declaration, struct declaration and import");
return NULL;
}
@@ -466,9 +488,20 @@ static Parser* get_resolved_type_parser(Ast *self) {
static void funcdecl_resolve(FunctionDecl *self, AstCompilerContext *context) {
/* TODO: Implement parameters and return types */
+ function_signature_resolve(self->signature, context);
scope_resolve(&self->body, context);
}
+/*
+ Dont need to check if @self is resolved, since it will always be partially resolved when called from @funccall_resolve.
+ Meaning the resolve status wont be set to solved but the resolve type will be set.
+*/
+static bool is_func_decl(Ast *self) {
+ const LhsExpr *resolved_type = self->resolve_data.type;
+ return (resolved_type->rhs_expr && resolved_type->rhs_expr->type == AST_FUNCTION_DECL) ||
+ resolved_type->type.type == VARIABLE_TYPE_SIGNATURE;
+}
+
static void funccall_resolve(Ast *self, AstCompilerContext *context) {
FunctionCall *func_call;
Ast **ast;
@@ -477,7 +510,7 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) {
func_call = self->value.func_call;
variable_resolve(&func_call->func, context, &self->resolve_data);
/* Attemping to use call syntax (variable_name ( ) ) with a variable that is not a function */
- if(self->resolve_data.type->rhs_expr->type != AST_FUNCTION_DECL) {
+ if(!is_func_decl(self)) {
Parser *caller_parser;
Parser *callee_parser;
BufferView callee_code_ref;
@@ -514,6 +547,12 @@ static void structfield_resolve(Ast *self, AstCompilerContext *context) {
variable_resolve(&struct_field->type, context, &self->resolve_data);
}
+static bool is_struct_decl(Ast *self) {
+ const LhsExpr *resolved_type = self->resolve_data.type;
+ assert(self->resolve_data.status == AST_RESOLVED);
+ return resolved_type->rhs_expr && resolved_type->rhs_expr->type == AST_STRUCT_DECL;
+}
+
static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) {
Binop *self;
Scope *lhs_scope;
@@ -541,7 +580,7 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) {
caller_code_ref = ast_get_code_reference(self->rhs);
callee_code_ref = self->rhs->resolve_data.type->var_name;
- if(self->lhs->resolve_data.type->rhs_expr->type != AST_STRUCT_DECL) {
+ if(!is_struct_decl(self->lhs)) {
parser_print_error(caller_parser, caller_code_ref.data, "Can only access field of structs");
/* TODO: use tokenizer_print_note, once it has been added */
/* TODO: Print type */
@@ -583,6 +622,8 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) {
/*
TODO: For this first error, only print the line without a reference to code.
This requires change in tokenizer_print_error to be able to take a line as reference.
+
+ TODO: Use note for the additional information instead of error.
*/
Parser *parser;
parser = scope_get_parser(context->scope);
@@ -597,6 +638,14 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) {
"Right-hand side is of type %.*s",
self->rhs->resolve_data.type->var_name.size, self->rhs->resolve_data.type->var_name.data);
throw(AST_ERR);
+ } else if(!is_arithmetic_type(self->lhs->resolve_data.type, context->compiler)) { /* TODO: Optimize this? store arithmetic type in the LhsExpr itself? */
+ /* TODO: Point the error at the binop instead of LHS */
+ Parser *parser;
+ parser = scope_get_parser(context->scope);
+ parser_print_error(parser, ast_get_code_reference(self->lhs).data,
+ "Arithmetic operation can only be performed with the types i8, u8, i16, u16, i32, u32, i64, u64, isize and usize",
+ self->lhs->resolve_data.type->var_name.size, self->lhs->resolve_data.type->var_name.data);
+ throw(AST_ERR);
}
ast->resolve_data.type = self->lhs->resolve_data.type;
}
@@ -655,9 +704,9 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
number = self->value.number;
/* TODO: Support other number types */
if(number->is_integer)
- self->resolve_data.type = context->compiler->default_types.i64;
+ self->resolve_data.type = (LhsExpr*)context->compiler->default_types.i64;
else
- self->resolve_data.type = context->compiler->default_types.f64;
+ self->resolve_data.type = (LhsExpr*)context->compiler->default_types.f64;
break;
}
case AST_FUNCTION_DECL:
@@ -684,7 +733,7 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
break;
case AST_STRING:
/* TODO: Convert special combinations. For example \n to newline */
- self->resolve_data.type = context->compiler->default_types.str;
+ self->resolve_data.type = (LhsExpr*)context->compiler->default_types.str;
break;
case AST_VARIABLE:
variable_resolve(self->value.variable, context, &self->resolve_data);