aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c91
1 files changed, 66 insertions, 25 deletions
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 <stdio.h>
#include <stdlib.h>
@@ -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));
+ }
}