diff options
Diffstat (limited to 'src/ast.c')
-rw-r--r-- | src/ast.c | 129 |
1 files changed, 89 insertions, 40 deletions
@@ -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); |