From 16aaaa19a3ef4220726007d3e644ced0c9e06513 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 9 Sep 2019 01:08:34 +0200 Subject: Allow referencing code in imported file (right now for function calls, allow calling a function in another file) --- src/parser.c | 91 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 25 deletions(-) (limited to 'src/parser.c') diff --git a/src/parser.c b/src/parser.c index df326f0..01c1d9f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -6,6 +6,7 @@ #include "../include/std/mem.h" #include "../include/std/log.h" #include "../include/std/alloc.h" +#include "../include/std/hash.h" #include #include @@ -21,14 +22,16 @@ do { \ } while(0) #define VAR_MAX_LEN UINT8_MAX +#define FUNC_MAX_PARAMS 128 +#define FUNC_MAX_RETURN_TYPES 128 static CHECK_RESULT Ast* parser_parse_rhs(Parser *self); static CHECK_RESULT Ast* parser_parse_body(Parser *self); -static CHECK_RESULT Ast* parser_parse_struct_body(Parser *self); +static CHECK_RESULT StructField* parser_parse_struct_body(Parser *self); static CHECK_RESULT Ast* parser_parse_rhs_binop(Parser *self); static void parser_parse_var_type(Parser *self, VariableType *result); static void parser_parse_var_type_def(Parser *self, VariableType *result); -static void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_scope); +static void parser_queue_file(Parser *self, BufferView path, ParserFileScopeReference **parser_file_scope); int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator) { self->allocator = allocator; @@ -38,12 +41,15 @@ int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator self->error.index = 0; self->error.str = NULL; self->error_context = ERROR_CONTEXT_NONE; + self->index = 0; return_if_error(structdecl_init(&self->struct_decl, &compiler->root_scope, allocator)); lhsexpr_init(&self->file_decl, DECL_FLAG_EXTERN | DECL_FLAG_PUB | DECL_FLAG_CONST, create_buffer_view_null()); return_if_error(ast_create(self->allocator, &self->struct_decl, AST_STRUCT_DECL, &self->file_decl.rhs_expr)); + return_if_error(buffer_init(&self->imports, allocator)); + return_if_error(hash_map_init(&self->imports_by_name, allocator, sizeof(usize), hash_map_compare_string, amal_hash_string)); self->current_scope = &self->struct_decl.body; self->has_func_parent = bool_false; - am_memset(&self->bytecode, 0, sizeof(self->bytecode)); + self->bytecode = NULL; return PARSER_OK; } @@ -85,27 +91,24 @@ static void parser_parse_body_loop(Parser *self, Scope *scope, Token end_token) /* STRUCT_BODY_LOOP = '{' STRUCT_BODY* '}' */ -static void parser_parse_struct_body_loop(Parser *self, Scope *scope) { +static void parser_parse_struct_body_loop(Parser *self, StructDecl *struct_decl) { int result; throw_if_error(tokenizer_accept(&self->tokenizer, TOK_OPEN_BRACE)); for(;;) { - Ast *body_obj; + StructField *struct_field; bool is_end_token; throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_CLOSING_BRACE, &is_end_token)); if(is_end_token) break; - body_obj = parser_parse_struct_body(self); - result = scope_add_child(scope, body_obj); + struct_field = parser_parse_struct_body(self); + result = structdecl_add_field(struct_decl, struct_field, self->allocator); if(result == 0) { continue; } else if(result == AST_ERR_DEF_DUP) { - /* TODO: Convert ast type to string for error message */ - BufferView obj_name; - obj_name = ast_get_name(body_obj); - self->error = tokenizer_create_error(&self->tokenizer, - tokenizer_get_code_reference_index(&self->tokenizer, obj_name.data), - "Variable with the name %.*s was declared twice in the struct", obj_name.size, obj_name.data); + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_code_reference_index(&self->tokenizer, struct_field->name.data), + "Variable with the name %.*s was declared twice in the struct", struct_field->name.size, struct_field->name.data); self->error_context = ERROR_CONTEXT_NONE; throw(result); } else { @@ -183,18 +186,32 @@ static void parser_parse_function_return_types(Parser *self, FunctionSignature * if(var_type.type == VARIABLE_TYPE_NONE) { /* If function has no return types */ if(return_type_index == 0) - return; + break; self->error = tokenizer_create_error(&self->tokenizer, - tokenizer_get_error_index(&self->tokenizer), - "Expected type or closure signature"); + tokenizer_get_error_index(&self->tokenizer), + "Expected type or closure signature"); throw(PARSER_UNEXPECTED_TOKEN); } throw_if_error(function_signature_add_return_type(func_sig, &var_type)); throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COMMA, &match)); if(!match) - return; + break; ++return_type_index; } + + if (buffer_get_size(&func_sig->parameters, FunctionParameter) > FUNC_MAX_PARAMS) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_error_index(&self->tokenizer), + "A closure can't have more than %d parameters", FUNC_MAX_PARAMS); + throw(PARSER_ERR); + } + + if (buffer_get_size(&func_sig->return_types, FunctionReturnType) > FUNC_MAX_RETURN_TYPES) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_error_index(&self->tokenizer), + "A closure can't have more than %d return values", FUNC_MAX_RETURN_TYPES); + throw(PARSER_ERR); + } } /* @@ -399,7 +416,7 @@ static CHECK_RESULT StructDecl* parser_parse_struct_decl(Parser *self) { throw_if_error(structdecl_init(result, self->current_scope, self->allocator)); self->current_scope = &result->body; - parser_parse_struct_body_loop(self, self->current_scope); + parser_parse_struct_body_loop(self, result); self->current_scope = result->body.parent; return result; } @@ -896,8 +913,7 @@ Ast* parser_parse_body(Parser *self) { /* STRUCT_BODY = TOK_IDENTIFIER VAR_TYPE_DEF ';' */ -Ast* parser_parse_struct_body(Parser *self) { - Ast *result; +StructField* parser_parse_struct_body(Parser *self) { BufferView var_name; VariableType var_type; StructField *struct_field; @@ -912,10 +928,9 @@ Ast* parser_parse_struct_body(Parser *self) { throw(PARSER_UNEXPECTED_TOKEN); } throw_if_error(tokenizer_accept(&self->tokenizer, TOK_SEMICOLON)); - throw_if_error(arena_allocator_alloc(self->allocator, sizeof(LhsExpr), (void**)&struct_field)); + throw_if_error(arena_allocator_alloc(self->allocator, sizeof(StructField), (void**)&struct_field)); structfield_init(struct_field, var_name, &var_type); - throw_if_error(ast_create(self->allocator, struct_field, AST_STRUCT_FIELD, &result)); - return result; + return struct_field; } /* @@ -974,8 +989,9 @@ static CHECK_RESULT int file_path_join(BufferView directory, BufferView file, ch Path can be path to included library path (or system library path) in which case the path separator is a dot, otherwise the path separator is forward slash '/' */ -void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_scope) { +void parser_queue_file(Parser *self, BufferView path, ParserFileScopeReference **parser_file_scope) { /* TODO: Parse special path (to include library path with dots) */ + FileScopeReference *file_scope; BufferView file_directory; char *path_relative; int result; @@ -983,7 +999,7 @@ void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_ file_directory = file_get_parent_directory(self->tokenizer.code_name); throw_if_error(file_path_join(file_directory, path, &path_relative)); /* We want buffer to be null-terminated but null character should not be included for the size */ - result = amal_compiler_internal_load_file(self->compiler, path_relative, file_scope); + result = amal_compiler_internal_load_file(self->compiler, path_relative, &file_scope); if(result != 0) { self->error = tokenizer_create_error(&self->tokenizer, tokenizer_get_code_reference_index(&self->tokenizer, path.data), @@ -992,4 +1008,29 @@ void parser_queue_file(Parser *self, BufferView path, FileScopeReference **file_ throw(result); } am_free(path_relative); + + { + usize parser_file_scope_index; + int num_imports; + BufferView import_path_canonical = create_buffer_view(file_scope->canonical_path.data, file_scope->canonical_path.size); + + if(hash_map_get(&self->imports_by_name, import_path_canonical, &parser_file_scope_index)) { + *parser_file_scope = buffer_get(&self->imports, parser_file_scope_index, sizeof(ParserFileScopeReference*)); + return; + } + + num_imports = buffer_get_size(&self->imports, ParserFileScopeReference*); + if(num_imports == 254) { + self->error = tokenizer_create_error(&self->tokenizer, + tokenizer_get_error_index(&self->tokenizer), + "One file can't have more than 255 imports"); + throw(PARSER_ERR); + } + + throw_if_error(arena_allocator_alloc(self->allocator, sizeof(ParserFileScopeReference*), (void**)parser_file_scope)); + (*parser_file_scope)->file_scope_ref = file_scope; + (*parser_file_scope)->import_index = num_imports; + throw_if_error(buffer_append(&self->imports, parser_file_scope, sizeof(ParserFileScopeReference*))); + throw_if_error(hash_map_insert(&self->imports_by_name, import_path_canonical, &parser_file_scope_index)); + } } -- cgit v1.2.3