diff options
author | Bad Diode <bd@badd10de.dev> | 2021-10-30 14:59:44 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-10-30 14:59:44 +0200 |
commit | a921acd83750a66bcb73179ce1581f3280197289 (patch) | |
tree | 0908d707a4f72c09a0d516a60ed344aa647485f8 /src/parser.c | |
parent | 995f138c293a3db430ced10c688d07f0acf8baa8 (diff) | |
download | bdl-a921acd83750a66bcb73179ce1581f3280197289.tar.gz bdl-a921acd83750a66bcb73179ce1581f3280197289.zip |
Add symbol declaration error checking
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 81 |
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 | ||
406 | bool | ||
407 | symbol_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 | |||
391 | void | 418 | void |
392 | scope_check(Environment *env) { | 419 | check_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 | ||
396 | Root * | 462 | Root * |
@@ -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 | } |