aboutsummaryrefslogtreecommitdiffstats
path: root/src/parser.c
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-30 14:59:44 +0200
committerBad Diode <bd@badd10de.dev>2021-10-30 14:59:44 +0200
commita921acd83750a66bcb73179ce1581f3280197289 (patch)
tree0908d707a4f72c09a0d516a60ed344aa647485f8 /src/parser.c
parent995f138c293a3db430ced10c688d07f0acf8baa8 (diff)
downloadbdl-a921acd83750a66bcb73179ce1581f3280197289.tar.gz
bdl-a921acd83750a66bcb73179ce1581f3280197289.zip
Add symbol declaration error checking
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c81
1 files changed, 75 insertions, 6 deletions
diff --git a/src/parser.c b/src/parser.c
index 2429f68..3e6abc2 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -313,13 +313,28 @@ parse_list(Parser *parser, Errors *errors) {
313 root->head = NULL; 313 root->head = NULL;
314 root->tail = NULL; 314 root->tail = NULL;
315 Object *current = root; 315 Object *current = root;
316 bool first = true;
316 while (has_next_token(parser)) { 317 while (has_next_token(parser)) {
318 Token tok = peek_token(parser);
317 current->head = parse_tree(parser, errors); 319 current->head = parse_tree(parser, errors);
318 if (errors->n != 0 || current->head == NULL) { 320 if (errors->n != 0 || current->head == NULL) {
319 return NULL; 321 return NULL;
320 } 322 }
321 323
322 Token tok = peek_token(parser); 324 if (first) {
325 if (!IS_SYMBOL(current->head) && !IS_LAMBDA(current->head)) {
326 error_push(errors, (Error){
327 .type = ERR_TYPE_PARSER,
328 .value = ERR_NOT_CALLABLE,
329 .line = tok.line,
330 .col = tok.col,
331 });
332 return NULL;
333 }
334 first = false;
335 }
336
337 tok = peek_token(parser);
323 if (tok.type == TOKEN_RPAREN) { 338 if (tok.type == TOKEN_RPAREN) {
324 next_token(parser); 339 next_token(parser);
325 return root; 340 return root;
@@ -388,9 +403,60 @@ parse_tree(Parser *parser, Errors *errors) {
388 return NULL; 403 return NULL;
389} 404}
390 405
406bool
407symbol_in_env(Environment *env, Object *symbol) {
408 while (env != NULL) {
409 Object *found = ht_lookup(env->table, symbol);
410 if (found != NULL) {
411 return true;
412 }
413 env = env->parent;
414 }
415 return false;
416}
417
391void 418void
392scope_check(Environment *env) { 419check_object_scope(Environment *env, Object *obj, Errors *errors) {
393 // STUB 420 if (obj == NULL) {
421 return;
422 }
423 switch (obj->type) {
424 case OBJ_TYPE_SYMBOL: {
425 if (!symbol_in_env(env, obj)) {
426 error_push(errors, (Error){
427 .type = ERR_TYPE_PARSER,
428 .value = ERR_SYMBOL_NOT_FOUND,
429 .line = obj->line,
430 .col = obj->col,
431 });
432 }
433 } break;
434 case OBJ_TYPE_PAIR: {
435 check_object_scope(env, obj->head, errors);
436 check_object_scope(env, obj->tail, errors);
437 } break;
438 case OBJ_TYPE_DEF: {
439 ht_insert(env->table, obj->var_name, obj->var_expr);
440 check_object_scope(env, obj->var_expr, errors);
441 } break;
442 case OBJ_TYPE_SET: {
443 check_object_scope(env, obj->var_name, errors);
444 check_object_scope(env, obj->var_expr, errors);
445 } break;
446 case OBJ_TYPE_IF: {
447 check_object_scope(env, obj->condition, errors);
448 check_object_scope(env, obj->expr_true, errors);
449 check_object_scope(env, obj->expr_false, errors);
450 } break;
451 case OBJ_TYPE_LAMBDA: {
452 Environment *new_env = env_alloc(env);
453 for (size_t i = 0; i < array_size(obj->body); i++) {
454 Object *expr = obj->body[i];
455 check_object_scope(new_env, expr, errors);
456 }
457 } break;
458 default: break;
459 }
394} 460}
395 461
396Root * 462Root *
@@ -428,9 +494,12 @@ parse(Token *tokens, Errors *errors) {
428 ht_insert(global_env->table, symbol, symbol); 494 ht_insert(global_env->table, symbol, symbol);
429 } 495 }
430 496
431 // Perform semantic analysis. 497 // Check that symbols are defined before usage.
432 scope_check(global_env); 498 for (size_t i = 0; i < array_size(roots); i++) {
433 // TODO: Check that symbols are defined before usage. 499 Object *root = roots[i];
500 check_object_scope(global_env, root, errors);
501 }
502
434 // TODO: Remove unnecessary statements. 503 // TODO: Remove unnecessary statements.
435 return roots; 504 return roots;
436} 505}