aboutsummaryrefslogtreecommitdiff
path: root/src/ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast.c')
-rw-r--r--src/ast.c494
1 files changed, 368 insertions, 126 deletions
diff --git a/src/ast.c b/src/ast.c
index 0aa19d4..413f77e 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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, &param->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;
}