diff options
Diffstat (limited to 'src/ast.c')
-rw-r--r-- | src/ast.c | 164 |
1 files changed, 123 insertions, 41 deletions
@@ -1,5 +1,6 @@ #include "../include/ast.h" #include "../include/parser.h" +#include "../include/compiler.h" #include "../include/std/log.h" #include "../include/std/hash.h" #include <assert.h> @@ -40,10 +41,12 @@ BufferView ast_get_name(Ast *self) { case AST_STRUCT_DECL: case AST_IMPORT: case AST_STRING: - case AST_NUMBER: case AST_BINOP: name = create_buffer_view_null(); break; + case AST_NUMBER: + name = self->value.number->code_ref; + break; case AST_LHS: name = self->value.lhs_expr->var_name; break; @@ -89,10 +92,7 @@ int lhsexpr_init(LhsExpr *self, bool is_pub, bool is_const, BufferView var_name, variable_init(&self->type, create_buffer_view_null()); self->var_name = var_name; self->rhs_expr = NULL; - if(is_pub && allocator) - return_if_error(scoped_allocator_create_mutex(allocator, &self->mutex)); - else - self->mutex = NULL; + return_if_error(scoped_allocator_create_mutex(allocator, &self->mutex)); return 0; } @@ -107,9 +107,10 @@ int string_init(String *self, BufferView str) { return 0; } -void number_init(Number *self, i64 value, bool is_integer) { +void number_init(Number *self, i64 value, bool is_integer, BufferView code_ref) { self->value.integer = value; self->is_integer = is_integer; + self->code_ref = code_ref; } void variable_init(Variable *self, BufferView name) { @@ -133,7 +134,7 @@ int scope_init(Scope *self, Scope *parent, ScopedAllocator *allocator) { int file_scope_reference_init(FileScopeReference *self, BufferView canonical_path, ScopedAllocator *allocator) { char null_terminator; null_terminator = '\0'; - self->scope = NULL; + self->parser = NULL; return_if_error(buffer_init(&self->canonical_path, allocator)); return_if_error(buffer_append(&self->canonical_path, canonical_path.data, canonical_path.size)); @@ -151,6 +152,7 @@ int scope_add_child(Scope *self, Ast *child) { if(child->type == AST_LHS) { BufferView var_name; var_name = child->value.lhs_expr->var_name; + assert(var_name.data); child_already_exists = hash_map_get(&self->named_objects, var_name, &existing_child); if(child_already_exists) return AST_ERR_DEF_DUP; @@ -177,7 +179,7 @@ void scope_resolve(Scope *self, AstCompilerContext *context) { context->scope = self->parent; } -static LhsExpr* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) { +static Ast* scope_get_resolved_variable(Scope *self, AstCompilerContext *context, BufferView name) { Ast *result; bool exists; Scope *prev_scope; @@ -205,12 +207,12 @@ static LhsExpr* scope_get_resolved_variable(Scope *self, AstCompilerContext *con context->scope = prev_scope; assert(result->type == AST_LHS); - return result->value.lhs_expr; + return result; } 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 = scope_get_resolved_variable(context->scope, context, self->name)->resolve_data.type; } static LhsExpr* lhsexpr_resolve_rhs(Ast *ast, AstCompilerContext *context, LhsExpr *lhs_expr) { @@ -260,32 +262,32 @@ static void lhsexpr_resolve(Ast *ast, AstCompilerContext *context) { ast->resolve_data.type = rhs_resolve_type; } +static void import_resolve(Ast *ast, AstCompilerContext *context) { + Import *self; + 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); +} + /* LhsExpr has to be resolved before this is called */ -#if 0 static Scope* lhsexpr_get_scope(LhsExpr *self) { + AstValue value; + value = self->rhs_expr->value; switch(self->rhs_expr->type) { case AST_FUNCTION_DECL: - return &self->rhs_expr->value.func_decl->body; + return &value.func_decl->body; case AST_STRUCT_DECL: - return &self->rhs_expr->value.struct_decl->body; + return &value.struct_decl->body; case AST_IMPORT: - return self->rhs_expr->value.import->file_scope->scope; + 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 and struct decl"); + assert(bool_false && "Expected lhsexpr_get_scope to only be called for function decl, struct decl and import"); return NULL; } -#endif - -static void import_resolve(Ast *self, AstCompilerContext *context) { - Import *import; - import = self->value.import; - (void)import; - (void)self; - (void)context; - /* TODO: Convert all scopes to structs and set import->resolved_type to import->file_scope->scope; */ -} static void funcdecl_resolve(FunctionDecl *self, AstCompilerContext *context) { /* TODO: Implement parameters and return types */ @@ -320,45 +322,97 @@ static void structfield_resolve(Ast *self, AstCompilerContext *context) { variable_resolve(&struct_field->type, context, &self->resolve_data); } +static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { + Binop *self; + Scope *lhs_scope; + Parser *callee_parser; + BufferView caller_code_ref; + + assert(ast->type == AST_BINOP); + self = ast->value.binop; + + if(self->lhs->type != AST_VARIABLE) { + /* TODO: Allow field access for numbers and string as well */ + BufferView code_ref; + code_ref = ast_get_code_reference(self->lhs); + tokenizer_print_error(&context->parser->tokenizer, + tokenizer_get_code_reference_index(&context->parser->tokenizer, code_ref.data), + "Accessing fields is only applicable for variables"); + 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; + self->rhs->resolve_data.status = AST_RESOLVED; + + /* + const io = @import("std.io"); + io.write ^ + ^-from this, to-' + */ + if(self->lhs->resolve_data.type->rhs_expr->type == AST_IMPORT) + callee_parser = self->lhs->resolve_data.type->rhs_expr->value.import->file_scope->parser; + + caller_code_ref = ast_get_code_reference(self->rhs); + callee_parser = context->parser; + + if(self->rhs->resolve_data.type->rhs_expr->type != AST_STRUCT_DECL) { + /* TODO: Add note where the referenced data was declared */ + tokenizer_print_error(&context->parser->tokenizer, + tokenizer_get_code_reference_index(&context->parser->tokenizer, caller_code_ref.data), + "Can only access field of struct's"); + throw(AST_ERR); + } + + if(!self->rhs->resolve_data.type->is_pub) { + tokenizer_print_error(&context->parser->tokenizer, + tokenizer_get_code_reference_index(&context->parser->tokenizer, 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 */ + tokenizer_print_error(&context->parser->tokenizer, + tokenizer_get_code_reference_index(&callee_parser->tokenizer, caller_code_ref.data), + "Type was declared non-public here"); + throw(AST_ERR); + } +} + 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); + binop_resolve_dot_access(ast, context); self->rhs->resolve_data.status = AST_RESOLVED; ast->resolve_data.type = self->rhs->resolve_data.type; } else { ast_resolve(self->rhs, context); /* TODO: Convert types that can be safely converted */ - if(self->lhs->resolve_data.type != self->rhs->resolve_data.type) { + assert(self->lhs->resolve_data.type); + assert(self->rhs->resolve_data.type); + if(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. */ 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_get_code_reference_index(&context->parser->tokenizer, 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); 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); + self->lhs->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); + self->rhs->resolve_data.type->var_name.size, self->rhs->resolve_data.type->var_name.data); throw(AST_ERR); } + ast->resolve_data.type = self->lhs->resolve_data.type; } - #else - ast_resolve(self->rhs, context); - #endif } void ast_resolve(Ast *self, AstCompilerContext *context) { @@ -370,6 +424,10 @@ 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. */ + /* + 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) { @@ -379,11 +437,32 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { throw(AST_ERR); } + if(self->type == AST_LHS) { + throw_if_error(amal_mutex_lock(self->value.lhs_expr->mutex, "ast_resolve")); + if(self->resolve_data.status == AST_RESOLVED) { + amal_mutex_tryunlock(self->value.lhs_expr->mutex); + return; + } else if(self->resolve_data.status == AST_RESOLVING) { + amal_mutex_tryunlock(self->value.lhs_expr->mutex); + 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_data.status = AST_RESOLVING; switch(self->type) { - case AST_NUMBER: - /* Nothing to resolve for numbers */ + case AST_NUMBER: { + Number *number; + number = self->value.number; + /* TODO: Support other number types */ + if(number->is_integer) + self->resolve_data.type = context->compiler->default_types.i64; + else + self->resolve_data.type = context->compiler->default_types.f64; break; + } case AST_FUNCTION_DECL: funcdecl_resolve(self->value.func_decl, context); break; @@ -405,6 +484,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; break; case AST_VARIABLE: variable_resolve(self->value.variable, context, &self->resolve_data); @@ -415,4 +495,6 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { } /* TODO: See comment at the top of this function */ self->resolve_data.status = AST_RESOLVED; + if(self->type == AST_LHS) + amal_mutex_tryunlock(self->value.lhs_expr->mutex); } |