diff options
Diffstat (limited to 'src/ast.c')
-rw-r--r-- | src/ast.c | 229 |
1 files changed, 139 insertions, 90 deletions
@@ -4,37 +4,38 @@ #include "../include/std/hash.h" #include <assert.h> -#define throw(result) do { longjmp(context->env, (result)); } while(0) +#define throw(result) do { throw_debug_msg; longjmp(context->env, (result)); } while(0) #define throw_if_error(result) \ -do { \ - int return_if_result; \ - return_if_result = (result); \ - if((return_if_result) != 0) \ - throw(return_if_result); \ -} while(0) + do { \ + int return_if_result; \ + return_if_result = (result); \ + if((return_if_result) != 0) \ + throw(return_if_result); \ + } while(0) static void ast_resolve(Ast *self, AstCompilerContext *context); -Ast ast_none() { - Ast ast; - ast.value.func_decl = NULL; - ast.type = AST_NONE; - ast.resolve_status = AST_NOT_RESOLVED; - ast.resolved_type = NULL; - return ast; +static void resolve_data_init(AstResolveData *self) { + self->status = AST_NOT_RESOLVED; + self->type = NULL; } -void ast_init(Ast *self, void *value, AstType type) { - self->value.data = value; - self->type = type; - self->resolve_status = AST_NOT_RESOLVED; - self->resolved_type = NULL; +int ast_create(ScopedAllocator *allocator, void *value, AstType type, Ast **result) { + return_if_error(scoped_allocator_alloc(allocator, sizeof(Ast), (void**)result)); + (*result)->value.data = value; + (*result)->type = type; + resolve_data_init(&(*result)->resolve_data); + return 0; +} + +static bool ast_is_decl(Ast *self) { + /* TODO: Add more types as they are introduced */ + return self->type == AST_FUNCTION_DECL || self->type == AST_STRUCT_DECL; } BufferView ast_get_name(Ast *self) { BufferView name; switch(self->type) { - case AST_NONE: case AST_FUNCTION_DECL: case AST_STRUCT_DECL: case AST_IMPORT: @@ -87,7 +88,7 @@ int lhsexpr_init(LhsExpr *self, bool is_pub, bool is_const, BufferView var_name, self->is_const = is_const; variable_init(&self->type, create_buffer_view_null()); self->var_name = var_name; - self->rhs_expr = ast_none(); + self->rhs_expr = NULL; if(is_pub && allocator) return_if_error(scoped_allocator_create_mutex(allocator, &self->mutex)); else @@ -116,15 +117,15 @@ void variable_init(Variable *self, BufferView name) { } void binop_init(Binop *self) { - self->lhs = ast_none(); - self->rhs = ast_none(); + self->lhs = NULL; + self->rhs = NULL; self->type = BINOP_ADD; self->grouped = bool_false; } int scope_init(Scope *self, Scope *parent, ScopedAllocator *allocator) { return_if_error(buffer_init(&self->ast_objects, allocator)); - return_if_error(hash_map_init(&self->named_objects, allocator, sizeof(Ast), hash_compare_string, amal_hash_string)); + return_if_error(hash_map_init(&self->named_objects, allocator, sizeof(Ast*), hash_compare_string, amal_hash_string)); self->parent = parent; return 0; } @@ -143,7 +144,7 @@ int file_scope_reference_init(FileScopeReference *self, BufferView canonical_pat } int scope_add_child(Scope *self, Ast *child) { - Ast existing_child; + Ast *existing_child; bool child_already_exists; /* TODO: Implement for parameter */ @@ -154,9 +155,9 @@ int scope_add_child(Scope *self, Ast *child) { if(child_already_exists) return AST_ERR_DEF_DUP; - cleanup_if_error(hash_map_insert(&self->named_objects, var_name, child)); + cleanup_if_error(hash_map_insert(&self->named_objects, var_name, &child)); } - cleanup_if_error(buffer_append(&self->ast_objects, child, sizeof(Ast))); + cleanup_if_error(buffer_append(&self->ast_objects, &child, sizeof(Ast*))); return 0; cleanup: @@ -164,20 +165,20 @@ int scope_add_child(Scope *self, Ast *child) { } void scope_resolve(Scope *self, AstCompilerContext *context) { - Ast *ast; - Ast *ast_end; + Ast **ast; + Ast **ast_end; ast = buffer_start(&self->ast_objects); ast_end = buffer_end(&self->ast_objects); context->scope = self; for(; ast != ast_end; ++ast) { - ast_resolve(ast, context); + ast_resolve(*ast, context); } context->scope = self->parent; } static LhsExpr* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) { - Ast result; + Ast *result; bool exists; Scope *prev_scope; @@ -200,54 +201,82 @@ static LhsExpr* scope_get_resolved_variable(Scope *self, AstCompilerContext *con */ prev_scope = context->scope; context->scope = self; - ast_resolve(&result, context); + ast_resolve(result, context); context->scope = prev_scope; - assert(result.type == AST_LHS); - return result.value.lhs_expr; + assert(result->type == AST_LHS); + return result->value.lhs_expr; } -/* @resolved_type is the same field as the ast resolved_type for the variable @self */ -static void variable_resolve(Variable *self, AstCompilerContext *context, LhsExpr **resolved_type) { - /* TODO: Verify this is correct in all cases */ - *resolved_type = scope_get_resolved_variable(context->scope, context, self->name); +static void variable_resolve(Variable *self, AstCompilerContext *context, AstResolveData *resolve_data) { + if(!resolve_data->type) + resolve_data->type = scope_get_resolved_variable(context->scope, context, self->name); } -static void lhsexpr_resolve(Ast *self, AstCompilerContext *context) { - LhsExpr *lhs_expr; - lhs_expr = self->value.lhs_expr; +static LhsExpr* lhsexpr_resolve_rhs(Ast *ast, AstCompilerContext *context, LhsExpr *lhs_expr) { + LhsExpr *rhs_resolved_type; + ast_resolve(ast, context); + if(ast_is_decl(ast)) + rhs_resolved_type = lhs_expr; + else + rhs_resolved_type = ast->resolve_data.type; + return rhs_resolved_type; +} - if(lhs_expr->type.name.data) - variable_resolve(&lhs_expr->type, context, &self->resolved_type); - self->resolve_status = AST_RESOLVED; - ast_resolve(&lhs_expr->rhs_expr, context); +static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { + LhsExpr *self; + LhsExpr *rhs_resolve_type; - if(self->resolved_type && - lhs_expr->rhs_expr.type != AST_NONE && - self->resolved_type != lhs_expr->rhs_expr.resolved_type) { - tokenizer_print_error(&context->parser->tokenizer, - tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self).data), - "Variable type and variable assignment type (right-hand side) do not match"); - throw(AST_ERR); + assert(ast->type == AST_LHS); + self = ast->value.lhs_expr; + rhs_resolve_type = NULL; + + if(self->type.name.data) + variable_resolve(&self->type, context, &ast->resolve_data); + + /* + TODO: When parameters and return types are implemented, AST_RESOLVE_END should be set after + the parameters and return types have been resolved as recursive function calls should + 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) + ast->resolve_data.status = AST_RESOLVED; + + rhs_resolve_type = lhsexpr_resolve_rhs(self->rhs_expr, context, self); + + /* self->rhs_expr can be null here because this is valid: var num: i32; */ + if(ast->resolve_data.type && + self->rhs_expr && + ast->resolve_data.type != rhs_resolve_type) { + tokenizer_print_error(&context->parser->tokenizer, + tokenizer_get_code_reference_index(&context->parser->tokenizer, self->type.name.data), + "Variable type and variable assignment type (right-hand side) do not match"); + throw(AST_ERR); + } } - self->resolved_type = lhs_expr->rhs_expr.resolved_type; + + if(rhs_resolve_type) + ast->resolve_data.type = rhs_resolve_type; } /* LhsExpr has to be resolved before this is called */ +#if 0 static Scope* lhsexpr_get_scope(LhsExpr *self) { - switch(self->rhs_expr.type) { + switch(self->rhs_expr->type) { case AST_FUNCTION_DECL: - return &self->rhs_expr.value.func_decl->body; + return &self->rhs_expr->value.func_decl->body; case AST_STRUCT_DECL: - return &self->rhs_expr.value.struct_decl->body; + return &self->rhs_expr->value.struct_decl->body; case AST_IMPORT: - return self->rhs_expr.value.import->file_scope->scope; + return self->rhs_expr->value.import->file_scope->scope; default: break; } assert(bool_false && "Expected lhsexpr_get_scope to only be called for function decl and struct decl"); return NULL; } +#endif static void import_resolve(Ast *self, AstCompilerContext *context) { Import *import; @@ -258,32 +287,27 @@ static void import_resolve(Ast *self, AstCompilerContext *context) { /* TODO: Convert all scopes to structs and set import->resolved_type to import->file_scope->scope; */ } -static void funcdecl_resolve(Ast *self, AstCompilerContext *context) { - /* TODO: Implement */ - FunctionDecl *func_decl; - assert(self->type == AST_FUNCTION_DECL); - func_decl = self->value.func_decl; - self->resolve_status = AST_RESOLVED; - scope_resolve(&func_decl->body, context); +static void funcdecl_resolve(FunctionDecl *self, AstCompilerContext *context) { + /* TODO: Implement parameters and return types */ + scope_resolve(&self->body, context); } static void funccall_resolve(Ast *self, AstCompilerContext *context) { FunctionCall *func_call; - Ast *ast; - Ast *ast_end; + Ast **ast; + Ast **ast_end; func_call = self->value.func_call; - variable_resolve(&func_call->func, context, &self->resolved_type); + variable_resolve(&func_call->func, context, &self->resolve_data); ast = buffer_start(&func_call->args); ast_end = buffer_end(&func_call->args); for(; ast != ast_end; ++ast) { - ast_resolve(ast, context); + ast_resolve(*ast, context); } } static void structdecl_resolve(Ast *self, AstCompilerContext *context) { - /* TODO: What to do with resolved_type? */ StructDecl *struct_decl; struct_decl = self->value.struct_decl; scope_resolve(&struct_decl->body, context); @@ -293,26 +317,52 @@ static void structfield_resolve(Ast *self, AstCompilerContext *context) { /* TODO: Implement */ StructField *struct_field; struct_field = self->value.struct_field; - variable_resolve(&struct_field->type, context, &self->resolved_type); + variable_resolve(&struct_field->type, context, &self->resolve_data); } -static void binop_resolve(Binop *self, AstCompilerContext *context) { - /* TODO: Implement */ - ast_resolve(&self->lhs, context); - if(self->rhs.type == AST_VARIABLE) { - Scope *prev_scope; - assert(self->lhs.resolved_type); - prev_scope = context->scope; - context->scope = lhsexpr_get_scope(self->lhs.resolved_type); - assert(context->scope); - ast_resolve(&self->rhs, context); - context->scope = prev_scope; +static void binop_resolve(Ast *ast, AstCompilerContext *context) { + Binop *self; + assert(ast->type == AST_BINOP); + self = ast->value.binop; + ast_resolve(self->lhs, context); + #if 0 /* TODO: Readd this once mutex has been added for types */ + if(self->type == BINOP_DOT && self->rhs->type == AST_VARIABLE) { + Scope *lhs_scope; + lhs_scope = lhsexpr_get_scope(self->lhs->resolve_data.type); + self->rhs->resolve_data.type = scope_get_resolved_variable(lhs_scope, context, self->rhs->value.variable->name); + self->rhs->resolve_data.status = AST_RESOLVED; + ast->resolve_data.type = self->rhs->resolve_data.type; } else { - ast_resolve(&self->rhs, context); + ast_resolve(self->rhs, context); + /* TODO: Convert types that can be safely converted */ + if(self->lhs->resolve_data.type != self->rhs->resolve_data.type) { + /* + 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. + */ + tokenizer_print_error(&context->parser->tokenizer, + tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self->lhs).data), + "Right-hand side and left-hand side are different types"); + tokenizer_print_error(&context->parser->tokenizer, + tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self->lhs).data), + "Left-hand side is of type %.*s", + self->rhs->resolve_data.type->var_name.size, + self->lhs->resolve_data.type->var_name.data); + tokenizer_print_error(&context->parser->tokenizer, + tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self->rhs).data), + "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 + ast_resolve(self->rhs, context); + #endif } void ast_resolve(Ast *self, AstCompilerContext *context) { + assert(self); /* TODO: Move these to the types that need checks for recursive dependency (function declaration, struct declaration) For function declaration, it should be marked as resolved when the signature has been resolved @@ -320,23 +370,22 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { because the body can have function call that calls functions that are resolving or even recursive function call, which should be allowed. */ - if(self->resolve_status == AST_RESOLVED) { + if(self->resolve_data.status == AST_RESOLVED) { return; - } else if(self->resolve_status == AST_RESOLVING) { + } else if(self->resolve_data.status == AST_RESOLVING) { tokenizer_print_error(&context->parser->tokenizer, tokenizer_get_code_reference_index(&context->parser->tokenizer, ast_get_code_reference(self).data), "Found recursive dependency"); throw(AST_ERR); } - self->resolve_status = AST_RESOLVING; + self->resolve_data.status = AST_RESOLVING; switch(self->type) { - case AST_NONE: case AST_NUMBER: /* Nothing to resolve for numbers */ break; case AST_FUNCTION_DECL: - funcdecl_resolve(self, context); + funcdecl_resolve(self->value.func_decl, context); break; case AST_FUNCTION_CALL: funccall_resolve(self, context); @@ -358,12 +407,12 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { /* TODO: Convert special combinations. For example \n to newline */ break; case AST_VARIABLE: - variable_resolve(self->value.variable, context, &self->resolved_type); + variable_resolve(self->value.variable, context, &self->resolve_data); break; case AST_BINOP: - binop_resolve(self->value.binop, context); + binop_resolve(self, context); break; } /* TODO: See comment at the top of this function */ - self->resolve_status = AST_RESOLVED; + self->resolve_data.status = AST_RESOLVED; } |