aboutsummaryrefslogtreecommitdiff
path: root/src/ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast.c')
-rw-r--r--src/ast.c164
1 files changed, 123 insertions, 41 deletions
diff --git a/src/ast.c b/src/ast.c
index 7d25401..4ee0934 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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);
}