diff options
author | dec05eba <dec05eba@protonmail.com> | 2019-08-17 02:57:08 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-07-25 14:36:46 +0200 |
commit | 81c5f8e750fcda6a2451fb54604130431434f88f (patch) | |
tree | 944fa06c781d57b1db90e9153080f411a1c34a55 /src/ast.c | |
parent | 20662a1d203ffb9e05d6694347fd258115b41d0a (diff) |
Implement more instructions, implement function parameters and arguments
Diffstat (limited to 'src/ast.c')
-rw-r--r-- | src/ast.c | 494 |
1 files changed, 368 insertions, 126 deletions
@@ -15,12 +15,118 @@ throw(return_if_result); \ } while(0) +static void variable_type_resolve(VariableType *self, AstCompilerContext *context, AstResolvedType *resolved_type); static void ast_resolve(Ast *self, AstCompilerContext *context); +static BufferView variable_type_get_name(VariableType *self); + +static void scope_named_object_init(ScopeNamedObject *self) { + self->type = NAMED_OBJECT_NONE; + self->value.lhs_expr = NULL; + self->resolve_data = NULL; +} + +/* TODO: Remove these? */ +#if 0 +static bool scope_named_object_equals(ScopeNamedObject *self, ScopeNamedObject *other) { + /* This should be fine, without checking ScopeNamedObject type, since they are only equal if the types are equal as well */ + return self->value.lhs_expr == other->value.lhs_expr; +} + +static BufferView scope_named_object_get_type_name(ScopeNamedObject *self) { + BufferView result; + switch(self->type) { + case NAMED_OBJECT_NONE: + result = create_buffer_view("", 0); + break; + case NAMED_OBJECT_LHS_EXPR: + result = variable_type_get_name(&self->value.lhs_expr->type); + break; + case NAMED_OBJECT_FUNC_PARAM: + result = variable_type_get_name(&self->value.func_param->type); + break; + } + return result; +} +#endif + +static BufferView ast_resolved_type_get_name(AstResolvedType *self) { + BufferView result; + switch(self->type) { + case RESOLVED_TYPE_NONE: + result = create_buffer_view("", 0); + break; + case RESOLVED_TYPE_LHS_EXPR: + result = variable_type_get_name(&self->value.lhs_expr->type); + break; + case RESOLVED_TYPE_FUNC_SIG: { + if(!self->value.func_sig->func_decl || !self->value.func_sig->func_decl->lhs_expr) { + /* + TODO: Use function signature string from the source file, which will also help with error reference. + Currently this would point to an invalid location in the source file + */ + result = create_buffer_view("fn()", 0); + break; + } + result = self->value.func_sig->func_decl->lhs_expr->var_name; + break; + } + } + return result; +} + +static void ast_resolved_type_init(AstResolvedType *self) { + self->value.lhs_expr = NULL; + self->type = RESOLVED_TYPE_NONE; +} + +static bool ast_resolved_type_equals(AstResolvedType *self, AstResolvedType *other) { + /* This should be fine, without checking AstResolvedType type, since they are only equal if the types are equal as well */ + return self->value.lhs_expr == other->value.lhs_expr; +} + +static AstResolvedType lhs_expr_get_resolved_type(LhsExpr *self, AstCompilerContext *context) { + AstResolvedType result; + variable_type_resolve(&self->type, context, &result); + if(result.type != RESOLVED_TYPE_NONE) + return result; + + assert(self->rhs_expr); + ast_resolve(self->rhs_expr, context); + return self->rhs_expr->resolve_data.type; +} + +/* TODO: Detect recursive dependency? is it even possible for function parameters? (it would normally be a recursive dependency on the function declaration) */ +static void function_parameter_resolve(FunctionParameter *self, AstCompilerContext *context) { + if(self->resolve_data.status == AST_RESOLVED) + return; + self->resolve_data.status = AST_RESOLVING; + variable_type_resolve(&self->type, context, &self->resolve_data.type); + self->resolve_data.status = AST_RESOLVED; +} + +static AstResolvedType scope_named_object_get_resolved_type(ScopeNamedObject *self, AstCompilerContext *context) { + AstResolvedType result; + switch(self->type) { + case NAMED_OBJECT_NONE: + /* Type not resolved */ + assert(bool_false); + ast_resolved_type_init(&result); + return result; + case NAMED_OBJECT_LHS_EXPR: + result = lhs_expr_get_resolved_type(self->value.lhs_expr, context); + break; + case NAMED_OBJECT_FUNC_PARAM: + function_parameter_resolve(self->value.func_param, context); + result = self->value.func_param->resolve_data.type; + break; + } + return result; +} static void resolve_data_init(AstResolveData *self) { self->status = AST_NOT_RESOLVED; - self->parser = NULL; - self->type = NULL; + ast_resolved_type_init(&self->type); + self->ssa_reg = 0; } int ast_create(ArenaAllocator *allocator, void *value, AstType type, Ast **result) { @@ -28,7 +134,7 @@ int ast_create(ArenaAllocator *allocator, void *value, AstType type, Ast **resul (*result)->value.data = value; (*result)->type = type; resolve_data_init(&(*result)->resolve_data); - (*result)->ssa_reg = 0; + (*result)->parser = NULL; return 0; } @@ -47,6 +153,7 @@ BufferView ast_get_name(Ast *self) { case AST_BINOP: case AST_IF_STATEMENT: case AST_WHILE_STATEMENT: + case AST_RETURN: name = create_buffer_view_null(); break; case AST_NUMBER: @@ -75,12 +182,47 @@ static BufferView ast_get_code_reference(Ast *self) { return ast_get_name(self); } -void function_signature_init(FunctionSignature *self) { - self->params = 0; +int function_signature_init(FunctionSignature *self, ArenaAllocator *allocator) { self->resolved = bool_false; + self->func_decl = NULL; + return_if_error(buffer_init(&self->parameters, allocator)); + return buffer_init(&self->return_types, allocator); +} + +static FunctionParameter* function_signature_get_parameter_by_name(FunctionSignature *self, BufferView name) { + FunctionParameter *param, *param_end; + param = buffer_begin(&self->parameters); + param_end = buffer_end(&self->parameters); + for(; param != param_end; ++param) { + if(buffer_view_equals(&name, ¶m->name)) + return param; + } + return NULL; +} + +int function_signature_add_parameter(FunctionSignature *self, const FunctionParameter *new_param) { + const FunctionParameter *existing_param = function_signature_get_parameter_by_name(self, new_param->name); + if(existing_param) + return AST_ERR_DEF_DUP; + return buffer_append(&self->parameters, new_param, sizeof(FunctionParameter)); +} + +int function_signature_add_return_type(FunctionSignature *self, const VariableType *var_type) { + FunctionReturnType return_type; + return_type.type = *var_type; + ast_resolved_type_init(&return_type.resolved_type); + return buffer_append(&self->return_types, &return_type, sizeof(return_type)); +} + +void function_parameter_init(FunctionParameter *self) { + self->name = create_buffer_view_null(); + self->type.type = VARIABLE_TYPE_NONE; + self->type.value.variable = NULL; + resolve_data_init(&self->resolve_data); } int funcdecl_init(FunctionDecl *self, FunctionSignature *signature, Scope *parent, ArenaAllocator *allocator) { + self->lhs_expr = NULL; self->signature = signature; self->ssa_func_index = 0; return scope_init(&self->body, parent, allocator); @@ -102,9 +244,9 @@ LhsExpr* structdecl_get_field_by_name(StructDecl *self, BufferView field_name) { return result->value.lhs_expr; } -void structfield_init(StructField *self, BufferView name, BufferView type_name) { +void structfield_init(StructField *self, BufferView name, VariableType *type) { self->name = name; - variable_init(&self->type, type_name); + self->type = *type; } void lhsexpr_init(LhsExpr *self, DeclFlag decl_flag, BufferView var_name) { @@ -140,7 +282,7 @@ void number_init(Number *self, i64 value, bool is_integer, BufferView code_ref) void variable_init(Variable *self, BufferView name) { self->name = name; - self->resolved_var = NULL; + scope_named_object_init(&self->resolved_var); } void binop_init(Binop *self) { @@ -167,11 +309,16 @@ int while_statement_init(WhileStatement *self, Scope *parent, ArenaAllocator *al return scope_init(&self->body, parent, allocator); } +void return_expr_init(ReturnExpr *self, Ast *rhs_expr) { + self->rhs_expr = rhs_expr; +} + 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; self->parser = NULL; + self->function_signature = NULL; return 0; } @@ -192,7 +339,6 @@ int scope_add_child(Scope *self, Ast *child) { Ast *existing_child; bool child_already_exists; - /* TODO: Implement for parameter */ if(child->type == AST_LHS) { BufferView var_name; var_name = child->value.lhs_expr->var_name; @@ -213,14 +359,16 @@ int scope_add_child(Scope *self, Ast *child) { void scope_resolve(Scope *self, AstCompilerContext *context) { Ast **ast; Ast **ast_end; + Scope *prev_scope; ast = buffer_begin(&self->ast_objects); ast_end = buffer_end(&self->ast_objects); + prev_scope = context->scope; context->scope = self; for(; ast != ast_end; ++ast) { ast_resolve(*ast, context); } - context->scope = self->parent; + context->scope = prev_scope; } static Parser* scope_get_parser(Scope *scope) { @@ -247,78 +395,114 @@ static void parser_print_error(Parser *parser, const char *ref, const char *fmt, va_end(args); } -static Ast* __scope_get_resolved_variable(Scope *self, Scope *start, AstCompilerContext *context, BufferView name) { - Ast *result; +static void __scope_get_resolved_variable(Scope *self, Scope *start, AstCompilerContext *context, BufferView name, ScopeNamedObject *result) { + Ast *ast_result; bool exists; Scope *prev_scope; assert(self); - exists = hash_map_get(&self->named_objects, name, &result); + exists = hash_map_get(&self->named_objects, name, &ast_result); if(!exists) { - Parser *parser; - if(self->parent) - return __scope_get_resolved_variable(self->parent, start, context, name); + if(self->function_signature) { + FunctionParameter *func_param; + func_param = function_signature_get_parameter_by_name(self->function_signature, name); + if(func_param) { + prev_scope = context->scope; + context->scope = self; + function_parameter_resolve(func_param, context); + context->scope = prev_scope; + + result->type = NAMED_OBJECT_FUNC_PARAM; + result->value.func_param = func_param; + result->resolve_data = &func_param->resolve_data; + return; + } + } - parser = scope_get_parser(start); - parser_print_error(parser, name.data, "Undefined reference to variable \"%.*s\"", name.size, name.data); - throw(AST_ERR); + if(self->parent) { + __scope_get_resolved_variable(self->parent, start, context, name, result); + return; + } + + { + Parser *parser; + parser = scope_get_parser(start); + parser_print_error(parser, name.data, "Undefined reference to variable \"%.*s\"", name.size, name.data); + throw(AST_ERR); + } } /* - Need to change scope here because we are changing the visible scope - and the ast object may be in another scope than the current - resolving ast. + Need to change scope here because we are changing the visible scope + and the ast object may be in another scope than the current + resolving ast. */ prev_scope = context->scope; context->scope = self; - ast_resolve(result, context); + ast_resolve(ast_result, context); context->scope = prev_scope; - assert(result->type == AST_LHS); - return result; + assert(ast_result->type == AST_LHS); + result->type = NAMED_OBJECT_LHS_EXPR; + result->value.lhs_expr = ast_result->value.lhs_expr; + result->resolve_data = &ast_result->resolve_data; } -static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) { - return __scope_get_resolved_variable(self, self, context, name); +static void scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name, ScopeNamedObject *result) { + __scope_get_resolved_variable(self, self, context, name, result); +} + +static void function_return_type_resolve(FunctionReturnType *self, AstCompilerContext *context) { + variable_type_resolve(&self->type, context, &self->resolved_type); } 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) - self->resolved_var = scope_get_resolved_variable(context->scope, context, self->name); - resolve_data->type = self->resolved_var->resolve_data.type; + { + FunctionParameter *param, *param_end; + param = buffer_begin(&self->parameters); + param_end = buffer_end(&self->parameters); + for(; param != param_end; ++param) { + function_parameter_resolve(param, context); + } + } + { + FunctionReturnType *return_type, *return_type_end; + return_type = buffer_begin(&self->return_types); + return_type_end = buffer_end(&self->return_types); + for(; return_type != return_type_end; ++return_type) { + function_return_type_resolve(return_type, context); + } + } + + self->resolved = bool_true; } -static LhsExpr* variable_get_resolved_type(Variable *self) { - assert(self->resolved_var); - return self->resolved_var->value.lhs_expr; +static void variable_resolve(Variable *self, AstCompilerContext *context, AstResolvedType *resolved_type) { + if(self->resolved_var.type == NAMED_OBJECT_NONE) + scope_get_resolved_variable(context->scope, context, self->name, &self->resolved_var); + *resolved_type = scope_named_object_get_resolved_type(&self->resolved_var, context); } -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) { +void variable_type_resolve(VariableType *self, AstCompilerContext *context, AstResolvedType *resolved_type) { + switch(self->type) { case VARIABLE_TYPE_NONE: + ast_resolved_type_init(resolved_type); return; case VARIABLE_TYPE_VARIABLE: - variable_resolve(lhs_expr_type->value.variable, context, resolve_data); + variable_resolve(self->value.variable, context, resolved_type); break; case VARIABLE_TYPE_SIGNATURE: - function_signature_resolve(lhs_expr_type->value.signature, context); - resolve_data->type = self; + function_signature_resolve(self->value.signature, context); + resolved_type->type = RESOLVED_TYPE_FUNC_SIG; + resolved_type->value.func_sig = self->value.signature; break; } } -static BufferView variable_type_get_name(VariableType *self) { +BufferView variable_type_get_name(VariableType *self) { BufferView result; switch(self->type) { case VARIABLE_TYPE_NONE: @@ -337,14 +521,14 @@ static BufferView variable_type_get_name(VariableType *self) { return result; } -static LhsExpr* lhsexpr_resolve_rhs(LhsExpr *self, AstCompilerContext *context) { - LhsExpr *rhs_resolved_type; +static void lhsexpr_resolve_rhs(LhsExpr *self, AstCompilerContext *context, AstResolvedType *result) { ast_resolve(self->rhs_expr, context); - if(ast_is_decl(self->rhs_expr)) - rhs_resolved_type = self; - else - rhs_resolved_type = self->rhs_expr->resolve_data.type; - return rhs_resolved_type; + if(ast_is_decl(self->rhs_expr)) { + result->type = RESOLVED_TYPE_LHS_EXPR; + result->value.lhs_expr = self; + } else { + *result = self->rhs_expr->resolve_data.type; + } } static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { @@ -353,7 +537,7 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { assert(ast->type == AST_LHS); self = ast->value.lhs_expr; - variable_type_resolve(self, context, &ast->resolve_data); + variable_type_resolve(&self->type, context, &ast->resolve_data.type); /* TODO: When parameters and return types are implemented, AST_RESOLVE_END should be set after @@ -361,7 +545,7 @@ 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) { - LhsExpr *rhs_resolve_type; + AstResolvedType 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 @@ -371,17 +555,19 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { 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 rhs is a function declaration then there is no need to wait until it has been resolved before setting the type. + We still need to continue after this, so rhs can be resolved. */ - if(!ast->resolve_data.type) - ast->resolve_data.type = self; + if(ast->resolve_data.type.type == RESOLVED_TYPE_NONE) { + ast->resolve_data.type.type = RESOLVED_TYPE_FUNC_SIG; + ast->resolve_data.type.value.func_sig = self->rhs_expr->value.func_decl->signature; + } } - rhs_resolve_type = lhsexpr_resolve_rhs(self, context); + lhsexpr_resolve_rhs(self, context, &rhs_resolve_type); /* TODO: Add casting */ - if(ast->resolve_data.type && ast->resolve_data.type != rhs_resolve_type) { + if(ast->resolve_data.type.type == RESOLVED_TYPE_LHS_EXPR && !ast_resolved_type_equals(&ast->resolve_data.type, &rhs_resolve_type)) { Parser *parser; parser = scope_get_parser(context->scope); /* @@ -413,23 +599,29 @@ static LhsExpr* binop_get_lhs_expr(Binop *self) { static void assignmentexpr_resolve(Ast *ast, AstCompilerContext *context) { AssignmentExpr *self; - LhsExpr *lhs_source; + bool is_lhs_const; + is_lhs_const = bool_false; assert(ast->type == AST_ASSIGN); self = ast->value.assign_expr; - lhs_source = NULL; ast_resolve(self->lhs_expr, context); ast_resolve(self->rhs_expr, context); - if(self->lhs_expr->type == AST_VARIABLE) - lhs_source = variable_get_resolved_type(self->lhs_expr->value.variable); - else if(self->lhs_expr->type == AST_BINOP) - lhs_source = binop_get_lhs_expr(self->lhs_expr->value.binop); + if(self->lhs_expr->type == AST_VARIABLE) { + /* TODO: Allow non-const function param */ + const ScopeNamedObject *resolved_var = &self->lhs_expr->value.variable->resolved_var; + if(resolved_var->type == NAMED_OBJECT_FUNC_PARAM || LHS_EXPR_IS_CONST(resolved_var->value.lhs_expr)) + is_lhs_const = bool_true; + } else if(self->lhs_expr->type == AST_BINOP) { + LhsExpr *lhs_expr; + lhs_expr = binop_get_lhs_expr(self->lhs_expr->value.binop); + is_lhs_const = LHS_EXPR_IS_CONST(lhs_expr); + } /* This also covers extern variables, since extern variables are always const */ /* TODO: var.field type expressions should also be checked */ - if(lhs_source && LHS_EXPR_IS_CONST(lhs_source)) { + if(is_lhs_const) { Parser *parser; parser = scope_get_parser(context->scope); parser_print_error(parser, ast_get_code_reference(self->lhs_expr).data, "Can't assign to a const value"); @@ -437,14 +629,14 @@ static void assignmentexpr_resolve(Ast *ast, AstCompilerContext *context) { } /* TODO: Add casting */ - if(self->lhs_expr->resolve_data.type != self->rhs_expr->resolve_data.type) { + if(!ast_resolved_type_equals(&self->lhs_expr->resolve_data.type, &self->rhs_expr->resolve_data.type)) { Parser *parser; BufferView rhs_type_name; BufferView lhs_type_name; parser = scope_get_parser(context->scope); - rhs_type_name = variable_type_get_name(&self->rhs_expr->resolve_data.type->type); - lhs_type_name = variable_type_get_name(&self->lhs_expr->resolve_data.type->type); + rhs_type_name = ast_resolved_type_get_name(&self->rhs_expr->resolve_data.type); + lhs_type_name = ast_resolved_type_get_name(&self->lhs_expr->resolve_data.type); /* TODO: Instead of using self->var_name, using type name. This cant be done right now because type can be function signature. @@ -462,39 +654,54 @@ static void import_resolve(Ast *ast, AstCompilerContext *context) { assert(ast->type == AST_IMPORT); (void)context; self = ast->value.import; - ast->resolve_data.type = &self->file_scope->parser->file_decl; - assert(ast->resolve_data.type); + ast->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; + ast->resolve_data.type.value.lhs_expr = &self->file_scope->parser->file_decl; } static Scope* lhsexpr_get_scope(LhsExpr *self) { AstValue value; - 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; - } + 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 non-extern function declaration, struct declaration and import"); return NULL; } +static Scope* ast_resolved_type_get_scope(AstResolvedType *self) { + switch(self->type) { + case RESOLVED_TYPE_NONE: + assert(bool_false && "Expected ast_resolved_type_get_scope to only be called for a resolved object"); + return NULL; + case RESOLVED_TYPE_LHS_EXPR: + return lhsexpr_get_scope(self->value.lhs_expr); + case RESOLVED_TYPE_FUNC_SIG: + assert(self->value.func_sig->func_decl); + return &self->value.func_sig->func_decl->body; + } + return NULL; +} + /* @self has to have a resolved type before calling this */ static Parser* get_resolved_type_parser(Ast *self) { - assert(self->resolve_data.type); - return scope_get_parser(lhsexpr_get_scope(self->resolve_data.type)); + assert(self->resolve_data.type.type == RESOLVED_TYPE_LHS_EXPR && "Expected get_resolved_type_parser to only be called for non-extern function declaration, struct declaration and import"); + return scope_get_parser(lhsexpr_get_scope(self->resolve_data.type.value.lhs_expr)); } -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); +static void funcdecl_resolve(Ast *self, AstCompilerContext *context) { + FunctionDecl *func_decl; + func_decl = self->value.func_decl; + function_signature_resolve(func_decl->signature, context); + scope_resolve(&func_decl->body, context); + self->resolve_data.type.type = RESOLVED_TYPE_FUNC_SIG; + self->resolve_data.type.value.func_sig = self->value.func_decl->signature; } /* @@ -502,7 +709,10 @@ static void funcdecl_resolve(FunctionDecl *self, AstCompilerContext *context) { Meaning the resolve status wont be set to solved but the resolve type will be set. */ bool resolved_type_is_func_decl(Ast *self) { - const LhsExpr *resolved_type = self->resolve_data.type; + LhsExpr *resolved_type; + if(self->resolve_data.type.type != RESOLVED_TYPE_LHS_EXPR) + return bool_false; + resolved_type = self->resolve_data.type.value.lhs_expr; return (resolved_type->rhs_expr && resolved_type->rhs_expr->type == AST_FUNCTION_DECL) || resolved_type->type.type == VARIABLE_TYPE_SIGNATURE; } @@ -513,16 +723,16 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) { Ast **ast_end; func_call = self->value.func_call; - variable_resolve(&func_call->func, context, &self->resolve_data); + variable_resolve(&func_call->func, context, &self->resolve_data.type); /* Attemping to use call syntax (variable_name ( ) ) with a variable that is not a function */ - if(!resolved_type_is_func_decl(self)) { + if(self->resolve_data.type.type != RESOLVED_TYPE_FUNC_SIG) { Parser *caller_parser; Parser *callee_parser; BufferView callee_code_ref; caller_parser = scope_get_parser(context->scope); callee_parser = get_resolved_type_parser(self); - callee_code_ref = self->resolve_data.type->var_name; + callee_code_ref = ast_resolved_type_get_name(&self->resolve_data.type); parser_print_error(caller_parser, func_call->func.name.data, "\"%.*s\" is not a function. Only functions can be called", func_call->func.name.size, func_call->func.name.data); @@ -549,11 +759,14 @@ 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->resolve_data); + variable_type_resolve(&struct_field->type, context, &self->resolve_data.type); } static bool is_struct_decl(Ast *self) { - const LhsExpr *resolved_type = self->resolve_data.type; + LhsExpr *resolved_type; + if(self->resolve_data.type.type != RESOLVED_TYPE_LHS_EXPR) + return bool_false; + resolved_type = self->resolve_data.type.value.lhs_expr; assert(self->resolve_data.status == AST_RESOLVED); return resolved_type->rhs_expr && resolved_type->rhs_expr->type == AST_STRUCT_DECL; } @@ -565,6 +778,7 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { Parser *callee_parser; BufferView caller_code_ref; BufferView callee_code_ref; + ScopeNamedObject rhs_resolved_var; assert(ast->type == AST_BINOP); self = ast->value.binop; @@ -578,12 +792,13 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { throw(AST_ERR); } - 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)->resolve_data.type; + lhs_scope = ast_resolved_type_get_scope(&self->lhs->resolve_data.type); + scope_get_resolved_variable(lhs_scope, context, self->rhs->value.variable->name, &rhs_resolved_var); + self->rhs->resolve_data.type = scope_named_object_get_resolved_type(&rhs_resolved_var, context); callee_parser = get_resolved_type_parser(self->rhs); caller_code_ref = ast_get_code_reference(self->rhs); - callee_code_ref = self->rhs->resolve_data.type->var_name; + callee_code_ref = ast_resolved_type_get_name(&self->rhs->resolve_data.type); if(!is_struct_decl(self->lhs)) { parser_print_error(caller_parser, caller_code_ref.data, "Can only access field of structs"); @@ -593,7 +808,7 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { throw(AST_ERR); } - if(!LHS_EXPR_IS_PUB(self->rhs->resolve_data.type)) { + if(self->rhs->resolve_data.type.type != RESOLVED_TYPE_LHS_EXPR || !LHS_EXPR_IS_PUB(self->rhs->resolve_data.type.value.lhs_expr)) { parser_print_error(caller_parser, caller_code_ref.data, "Can't access non-public field \"%.*s\"", caller_code_ref.size, caller_code_ref.data); /* TODO: use tokenizer_print_note, once it has been added */ /* TODO: Print type */ @@ -612,7 +827,7 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) { /* Only function call has extra data that needs to be resolved (args) */ if(self->rhs->type == AST_FUNCTION_CALL) { Scope *prev_scope = context->scope; - context->scope = lhsexpr_get_scope(self->lhs->resolve_data.type); + context->scope = ast_resolved_type_get_scope(&self->lhs->resolve_data.type); ast_resolve(self->rhs, context); context->scope = prev_scope; } @@ -621,35 +836,43 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) { } else { ast_resolve(self->rhs, context); /* TODO: Convert types that can be safely converted */ - assert(self->lhs->resolve_data.type); - assert(self->rhs->resolve_data.type); - if(self->rhs->resolve_data.type != self->lhs->resolve_data.type) { + assert(self->lhs->resolve_data.type.type != RESOLVED_TYPE_NONE); + assert(self->rhs->resolve_data.type.type != RESOLVED_TYPE_NONE); + if(!ast_resolved_type_equals(&self->rhs->resolve_data.type, &self->lhs->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. TODO: Use note for the additional information instead of error. */ + BufferView lhs_type_name, rhs_type_name; Parser *parser; + + lhs_type_name = ast_resolved_type_get_name(&self->lhs->resolve_data.type); + rhs_type_name = ast_resolved_type_get_name(&self->rhs->resolve_data.type); parser = scope_get_parser(context->scope); parser_print_error(parser, ast_get_code_reference(self->rhs).data, "Can't cast type \"%.*s\" to type \"%.*s\"", - self->rhs->resolve_data.type->var_name.size, self->rhs->resolve_data.type->var_name.data, - self->lhs->resolve_data.type->var_name.size, self->lhs->resolve_data.type->var_name.data); + rhs_type_name.size, rhs_type_name.data, + lhs_type_name.size, lhs_type_name.data); parser_print_error(parser, ast_get_code_reference(self->lhs).data, "Left-hand side is of type %.*s", - self->lhs->resolve_data.type->var_name.size, self->lhs->resolve_data.type->var_name.data); + lhs_type_name.size, lhs_type_name.data); parser_print_error(parser, 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); + rhs_type_name.size, rhs_type_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: Optimize this? store arithmetic type in the LhsExpr itself? */ + } else if(self->lhs->resolve_data.type.type != RESOLVED_TYPE_LHS_EXPR || !is_arithmetic_type(self->lhs->resolve_data.type.value.lhs_expr, context->compiler)) { /* TODO: Point the error at the binop instead of LHS */ + BufferView lhs_type_name; Parser *parser; + + lhs_type_name = ast_resolved_type_get_name(&self->lhs->resolve_data.type); 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); + lhs_type_name.size, lhs_type_name.data); throw(AST_ERR); } ast->resolve_data.type = self->lhs->resolve_data.type; @@ -678,23 +901,36 @@ static void while_statement_resolve(WhileStatement *while_stmt, AstCompilerConte scope_resolve(&while_stmt->body, context); } +static void return_expr_resolve(ReturnExpr *self, AstCompilerContext *context) { + ast_resolve(self->rhs_expr, context); +} + void ast_resolve(Ast *self, AstCompilerContext *context) { assert(self); assert(context->parser); /* - 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 - instead of the whole function declaration including the body - because the body can have function call that calls functions that are resolving - or even recursive function call, which should be allowed. + 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 + instead of the whole function declaration including the body + because the body can have function call that calls functions that are resolving + or even recursive function call, which should be allowed. */ /* - This check is outside lhs_expr mutex for optimization purpose as most times there wont be - a race in multiple threads to resolve an AST expression. + This check is outside lhs_expr mutex for optimization purpose as most times there wont be + a race in multiple threads to resolve an AST expression. */ if(self->resolve_data.status == AST_RESOLVED) { return; - } else if(self->resolve_data.status == AST_RESOLVING && self->resolve_data.parser == context->parser) { + /* + NOTE!!!: There is a data race here and it's fine! + A recursive dependency can be missed here in one thread, but it's fine because that + can only happen if another thread is also resolving the same ast, in which case that thread will finally + report the recursive dependency. Note that this can mean that different files can report the + recursive dependency everytime you compile code with recursive dependency. However this can happen + even without a data race since files are compile in parallel so one file might resolve the ast with the issue + before another file has done it, and it can be different everytime the files are compiled. + */ + } else if(self->resolve_data.status == AST_RESOLVING && self->parser == context->parser) { Parser *parser; parser = scope_get_parser(context->scope); parser_print_error(parser, ast_get_code_reference(self).data, "Found recursive dependency"); @@ -702,20 +938,21 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { } self->resolve_data.status = AST_RESOLVING; - self->resolve_data.parser = context->parser; + self->parser = context->parser; switch(self->type) { case AST_NUMBER: { Number *number; number = self->value.number; /* TODO: Support other number types */ + self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; if(number->is_integer) - self->resolve_data.type = (LhsExpr*)context->compiler->default_types.i64; + self->resolve_data.type.value.lhs_expr = (LhsExpr*)context->compiler->default_types.i64; else - self->resolve_data.type = (LhsExpr*)context->compiler->default_types.f64; + self->resolve_data.type.value.lhs_expr = (LhsExpr*)context->compiler->default_types.f64; break; } case AST_FUNCTION_DECL: - funcdecl_resolve(self->value.func_decl, context); + funcdecl_resolve(self, context); break; case AST_FUNCTION_CALL: funccall_resolve(self, context); @@ -738,10 +975,11 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { break; case AST_STRING: /* TODO: Convert special combinations. For example \n to newline */ - self->resolve_data.type = (LhsExpr*)context->compiler->default_types.str; + self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; + self->resolve_data.type.value.lhs_expr = (LhsExpr*)context->compiler->default_types.str; break; case AST_VARIABLE: - variable_resolve(self->value.variable, context, &self->resolve_data); + variable_resolve(self->value.variable, context, &self->resolve_data.type); break; case AST_BINOP: binop_resolve(self, context); @@ -752,7 +990,11 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { case AST_WHILE_STATEMENT: while_statement_resolve(self->value.while_stmt, context); break; + case AST_RETURN: + return_expr_resolve(self->value.return_expr, context); + break; } /* TODO: See comment at the top of this function */ + /*assert(self->resolve_data.type.type != RESOLVED_TYPE_NONE);*/ self->resolve_data.status = AST_RESOLVED; } |