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