aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/src/parser.c b/src/parser.c
index 6ee273b..fcc29be 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -69,7 +69,8 @@ int parser_init(Parser *self, amal_compiler *compiler, ScopedAllocator *allocato
/*
BODY_LOOP = BODY* @end_token
*/
-static THROWABLE parser_parse_body_loop(Parser *self, Buffer *body_list, Token end_token) {
+static THROWABLE parser_parse_body_loop(Parser *self, Scope *scope, Token end_token) {
+ int result;
for(;;) {
Ast body_obj;
bool is_end_token;
@@ -78,7 +79,21 @@ static THROWABLE parser_parse_body_loop(Parser *self, Buffer *body_list, Token e
break;
try(parser_parse_body(self, &body_obj));
- throw_if_error(buffer_append(body_list, &body_obj, sizeof(body_obj)));
+ result = scope_add_child(scope, &body_obj);
+ 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),
+ "A variable with the name %.*s was declared twice in the same scope", obj_name.size, obj_name.data);
+ self->error_context = ERROR_CONTEXT_NONE;
+ throw(result);
+ } else {
+ throw(result);
+ }
}
return PARSER_OK;
}
@@ -130,11 +145,15 @@ static THROWABLE parser_parse_lhs(Parser *self, LhsExpr **result, bool *assignme
*assignment = bool_false;
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_SEMICOLON, &match));
if(match && is_const) {
- self->error = tokenizer_create_error(&self->tokenizer, "const variable declaration requires assignment (expected '=', got ';')");
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "const variable declaration requires assignment (expected '=', got ';')");
throw(PARSER_UNEXPECTED_TOKEN);
}
if(!match) {
- self->error = tokenizer_create_error(&self->tokenizer, "Expected '=' or ';'");
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "Expected '=' or ';'");
throw(PARSER_UNEXPECTED_TOKEN);
}
return PARSER_OK;
@@ -282,7 +301,9 @@ static THROWABLE parser_parse_rhs_single_expr(Parser *self, Ast *rhs_expr) {
if(rhs_expr->type != AST_NONE)
return PARSER_OK;
- self->error = tokenizer_create_error(&self->tokenizer, "Expected string, variable or function call");
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "Expected string, variable or function call");
throw(PARSER_UNEXPECTED_TOKEN);
}
@@ -374,6 +395,7 @@ int parser_parse_rhs_start(Parser *self, Ast *rhs_expr) {
self->error_context = ERROR_CONTEXT_RHS_START;
try(parser_parse_rhs(self, rhs_expr));
+ self->error_context = ERROR_CONTEXT_NONE;
return PARSER_OK;
}
@@ -388,7 +410,9 @@ static THROWABLE parser_parse_body_semicolon(Parser *self, Ast *expr) {
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_SEMICOLON, &match));
if(!match) {
/* TODO: Specify all the binop characters instead of "binop" which doesn't make sense for the user */
- self->error = tokenizer_create_error(&self->tokenizer, "Expected ';' or binop");
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "Expected ';' or binop");
throw(PARSER_UNEXPECTED_TOKEN);
}
return PARSER_OK;
@@ -437,10 +461,10 @@ ROOT = BODY_LOOP
*/
int parser_parse_buffer(Parser *self, BufferView code_buffer, BufferView buffer_name) {
int result;
- throw_if_error(tokenizer_init(&self->tokenizer, code_buffer, buffer_name));
+ throw_if_error(tokenizer_init(&self->tokenizer, self->allocator, code_buffer, buffer_name));
result = setjmp(self->parse_env);
if(result == 0)
- try(parser_parse_body_loop(self, &self->scope.ast_objects, TOK_END_OF_FILE));
+ try(parser_parse_body_loop(self, &self->scope, TOK_END_OF_FILE));
else if(self->error.str != NULL) {
switch(self->error_context) {
case ERROR_CONTEXT_NONE: