diff options
Diffstat (limited to 'src/ast.c')
-rw-r--r-- | src/ast.c | 210 |
1 files changed, 196 insertions, 14 deletions
@@ -44,6 +44,8 @@ BufferView ast_get_name(Ast *self) { case AST_IMPORT: case AST_STRING: case AST_BINOP: + case AST_IF_STATEMENT: + case AST_WHILE_STATEMENT: name = create_buffer_view_null(); break; case AST_NUMBER: @@ -52,6 +54,9 @@ BufferView ast_get_name(Ast *self) { case AST_LHS: name = self->value.lhs_expr->var_name; break; + case AST_ASSIGN: + name = ast_get_name(self->value.assign_expr->lhs_expr); + break; case AST_FUNCTION_CALL: name = self->value.func_call->func.name; break; @@ -69,7 +74,8 @@ static BufferView ast_get_code_reference(Ast *self) { return ast_get_name(self); } -int funcdecl_init(FunctionDecl *self, Scope *parent, ScopedAllocator *allocator) { +int funcdecl_init(FunctionDecl *self, FunctionSignature *signature, Scope *parent, ScopedAllocator *allocator) { + self->signature = signature; self->ssa_func_index = 0; return scope_init(&self->body, parent, allocator); } @@ -88,16 +94,23 @@ void structfield_init(StructField *self, BufferView name, BufferView type_name) variable_init(&self->type, type_name); } -int lhsexpr_init(LhsExpr *self, bool is_pub, bool is_const, BufferView var_name, ScopedAllocator *allocator) { +int lhsexpr_init(LhsExpr *self, bool is_extern, bool is_pub, bool is_const, BufferView var_name, ScopedAllocator *allocator) { + self->is_extern = is_extern; self->is_pub = is_pub; self->is_const = is_const; - variable_init(&self->type, create_buffer_view_null()); + self->type.type = VARIABLE_TYPE_NONE; + self->type.value.variable = NULL; self->var_name = var_name; self->rhs_expr = NULL; return_if_error(scoped_allocator_create_mutex(allocator, &self->mutex)); return 0; } +void assignmentexpr_init(AssignmentExpr *self, Ast *lhs_expr, Ast *rhs_expr) { + self->lhs_expr = lhs_expr; + self->rhs_expr = rhs_expr; +} + void import_init(Import *self, BufferView path) { self->path = path; self->file_scope = NULL; @@ -117,6 +130,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; } void binop_init(Binop *self) { @@ -126,6 +140,23 @@ void binop_init(Binop *self) { self->grouped = bool_false; } +int if_statement_init(IfStatement *self, Scope *parent, ScopedAllocator *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) { + 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) { + self->condition = NULL; + return scope_init(&self->body, parent, allocator); +} + 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)); @@ -195,17 +226,18 @@ static void parser_print_error(Parser *parser, const char *ref, const char *fmt, va_list args; va_start(args, fmt); if(parser) { - tokenizer_print_error(&parser->tokenizer, + tokenizer_print_error_args(&parser->tokenizer, tokenizer_get_code_reference_index(&parser->tokenizer, ref), fmt, args); } else { /* TODO: Redirect error to compiler error callback if set */ + amal_log_error("TODO: Fix this:"); amal_log_error(fmt, args); } va_end(args); } -static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) { +static Ast* __scope_get_resolved_variable(Scope *self, Scope *start, AstCompilerContext *context, BufferView name) { Ast *result; bool exists; Scope *prev_scope; @@ -215,16 +247,16 @@ static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context if(!exists) { Parser *parser; if(self->parent) - return scope_get_resolved_variable(self->parent, context, name); + return __scope_get_resolved_variable(self->parent, start, context, name); - parser = scope_get_parser(self); + 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 + and the ast object may be in another scope than the current resolving ast. */ prev_scope = context->scope; @@ -236,9 +268,58 @@ static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context return result; } +static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) { + return __scope_get_resolved_variable(self, self, context, name); +} + +static void function_signature_resolve(FunctionSignature *self, AstCompilerContext *context) { + /* TODO: Implement */ + (void)self; + (void)context; +} + 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)->resolve_data.type; + 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; + } +} + +static LhsExpr* variable_get_resolved_type(Variable *self) { + assert(self->resolved_var); + return self->resolved_var->value.lhs_expr; +} + +static void variable_type_resolve(VariableType *self, AstCompilerContext *context, AstResolveData *resolve_data) { + switch(self->type) { + case VARIABLE_TYPE_NONE: + return; + case VARIABLE_TYPE_VARIABLE: + variable_resolve(self->value.variable, context, resolve_data); + break; + case VARIABLE_TYPE_SIGNATURE: + function_signature_resolve(self->value.signature, context); + break; + } +} + +static BufferView variable_type_get_name(VariableType *self) { + BufferView result; + switch(self->type) { + case VARIABLE_TYPE_NONE: + result.data = NULL; + result.size = 0; + break; + case VARIABLE_TYPE_VARIABLE: + result = self->value.variable->name; + break; + case VARIABLE_TYPE_SIGNATURE: + /* TODO: Save reference to signature in code in the FunctionSignature type */ + result.data = "fn()"; + result.size = 4; + break; + } + return result; } static LhsExpr* lhsexpr_resolve_rhs(LhsExpr *self, AstCompilerContext *context) { @@ -259,8 +340,7 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { self = ast->value.lhs_expr; rhs_resolve_type = NULL; - if(self->type.name.data) - variable_resolve(&self->type, context, &ast->resolve_data); + variable_type_resolve(&self->type, context, &ast->resolve_data); /* TODO: When parameters and return types are implemented, AST_RESOLVE_END should be set after @@ -274,10 +354,15 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { rhs_resolve_type = lhsexpr_resolve_rhs(self, context); /* self->rhs_expr can be null here because this is valid: var num: i32; */ + /* TODO: Add casting */ if(ast->resolve_data.type && self->rhs_expr && ast->resolve_data.type != rhs_resolve_type) { Parser *parser; parser = scope_get_parser(context->scope); - parser_print_error(parser, self->type.name.data, + /* + TODO: Instead of using self->var_name, using type name. This cant be done right now because + type can be function signature. + */ + parser_print_error(parser, self->var_name.data, "Variable type and variable assignment type (right-hand side) do not match"); throw(AST_ERR); } @@ -287,6 +372,67 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { ast->resolve_data.type = rhs_resolve_type; } +static LhsExpr* binop_get_lhs_expr(Binop *self) { + if(self->rhs) { + if(self->rhs->type == AST_LHS) + return self->rhs->value.lhs_expr; + else if(self->rhs->type == AST_BINOP) + return binop_get_lhs_expr(self->rhs->value.binop); + } else { + if(self->lhs->type == AST_LHS) + return self->lhs->value.lhs_expr; + else if(self->lhs->type == AST_BINOP) + return binop_get_lhs_expr(self->lhs->value.binop); + } + return NULL; +} + +static void assignmentexpr_resolve(Ast *ast, AstCompilerContext *context) { + AssignmentExpr *self; + LhsExpr *lhs_source; + + 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); + + /* This also covers extern variables, since extern variables are always const */ + /* TODO: var.field type expressions should also be checked */ + if(lhs_source && lhs_source->is_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"); + throw(AST_ERR); + } + + /* TODO: Add casting */ + if(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); + /* + TODO: Instead of using self->var_name, using type name. This cant be done right now because + type can be function signature. + */ + parser_print_error(parser, ast_get_code_reference(self->lhs_expr).data, + "Can't cast data of type %.*s to type %.*s", rhs_type_name.size, rhs_type_name.data, lhs_type_name.size, lhs_type_name.data); + throw(AST_ERR); + } + + ast->resolve_data.type = self->lhs_expr->resolve_data.type; +} + static void import_resolve(Ast *ast, AstCompilerContext *context) { Import *self; assert(ast->type == AST_IMPORT); @@ -331,6 +477,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) { Parser *caller_parser; Parser *callee_parser; @@ -420,8 +567,12 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) { if(self->type == BINOP_DOT && (self->rhs->type == AST_VARIABLE || self->rhs->type == AST_FUNCTION_CALL)) { binop_resolve_dot_access(ast, context); /* Only function call has extra data that needs to be resolved (args) */ - if(self->rhs->type == AST_FUNCTION_CALL) + if(self->rhs->type == AST_FUNCTION_CALL) { + Scope *prev_scope = context->scope; + context->scope = lhsexpr_get_scope(self->lhs->resolve_data.type); ast_resolve(self->rhs, context); + context->scope = prev_scope; + } self->rhs->resolve_data.status = AST_RESOLVED; ast->resolve_data.type = self->rhs->resolve_data.type; } else { @@ -452,6 +603,28 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) { } } +static void else_if_statement_resolve(ElseIfStatement *else_if_stmt, AstCompilerContext *context) { + if(else_if_stmt->condition) + ast_resolve(else_if_stmt->condition, context); + + scope_resolve(&else_if_stmt->body, context); + if(else_if_stmt->next_else_if_stmt) + else_if_statement_resolve(else_if_stmt->next_else_if_stmt, context); +} + +static void if_statement_resolve(IfStatement *if_stmt, AstCompilerContext *context) { + assert(if_stmt->condition); + ast_resolve(if_stmt->condition, context); + scope_resolve(&if_stmt->body, context); + if(if_stmt->else_if_stmt) + else_if_statement_resolve(if_stmt->else_if_stmt, context); +} + +static void while_statement_resolve(WhileStatement *while_stmt, AstCompilerContext *context) { + ast_resolve(while_stmt->condition, context); + scope_resolve(&while_stmt->body, context); +} + void ast_resolve(Ast *self, AstCompilerContext *context) { assert(self); /* @@ -515,6 +688,9 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { case AST_LHS: lhsexpr_resolve(self, context); break; + case AST_ASSIGN: + assignmentexpr_resolve(self, context); + break; case AST_IMPORT: /* TODO: When @import(...).data syntax is added, implement the resolve for it */ import_resolve(self, context); @@ -529,6 +705,12 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { case AST_BINOP: binop_resolve(self, context); break; + case AST_IF_STATEMENT: + if_statement_resolve(self->value.if_stmt, context); + break; + case AST_WHILE_STATEMENT: + while_statement_resolve(self->value.while_stmt, context); + break; } /* TODO: See comment at the top of this function */ self->resolve_data.status = AST_RESOLVED; |