aboutsummaryrefslogtreecommitdiff
path: root/src/ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast.c')
-rw-r--r--src/ast.c210
1 files changed, 196 insertions, 14 deletions
diff --git a/src/ast.c b/src/ast.c
index 983b3a4..4194737 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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;