diff options
author | Bad Diode <bd@badd10de.dev> | 2021-10-31 14:25:44 +0100 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-10-31 14:25:44 +0100 |
commit | ef0cbf240782010a4b71d32546e022dfd4f0b6bf (patch) | |
tree | ea4e86bb0ebf206313b99fc0f7d3078f9fd5dd1e /src/parser.c | |
parent | 3ed3aa338296f82046de2061e717b49328c8b057 (diff) | |
download | bdl-ef0cbf240782010a4b71d32546e022dfd4f0b6bf.tar.gz bdl-ef0cbf240782010a4b71d32546e022dfd4f0b6bf.zip |
Add number of arguments check in function calls
Diffstat (limited to 'src/parser.c')
-rw-r--r-- | src/parser.c | 83 |
1 files changed, 71 insertions, 12 deletions
diff --git a/src/parser.c b/src/parser.c index 59e8075..d4deb74 100644 --- a/src/parser.c +++ b/src/parser.c | |||
@@ -313,6 +313,7 @@ parse_list(Parser *parser, Errors *errors) { | |||
313 | Object *root = object_alloc(start, OBJ_TYPE_PAIR); | 313 | Object *root = object_alloc(start, OBJ_TYPE_PAIR); |
314 | root->head = NULL; | 314 | root->head = NULL; |
315 | root->tail = NULL; | 315 | root->tail = NULL; |
316 | root->n_elems = 0; | ||
316 | Object *current = root; | 317 | Object *current = root; |
317 | bool first = true; | 318 | bool first = true; |
318 | while (has_next_token(parser)) { | 319 | while (has_next_token(parser)) { |
@@ -346,6 +347,7 @@ parse_list(Parser *parser, Errors *errors) { | |||
346 | next->tail = NULL; | 347 | next->tail = NULL; |
347 | current->tail = next; | 348 | current->tail = next; |
348 | current = current->tail; | 349 | current = current->tail; |
350 | root->n_elems++; | ||
349 | } | 351 | } |
350 | error_push(errors, (Error){ | 352 | error_push(errors, (Error){ |
351 | .type = ERR_TYPE_PARSER, | 353 | .type = ERR_TYPE_PARSER, |
@@ -404,16 +406,16 @@ parse_tree(Parser *parser, Errors *errors) { | |||
404 | return NULL; | 406 | return NULL; |
405 | } | 407 | } |
406 | 408 | ||
407 | bool | 409 | Object * |
408 | symbol_in_env(Environment *env, Object *symbol) { | 410 | symbol_in_env(Environment *env, Object *symbol) { |
409 | while (env != NULL) { | 411 | while (env != NULL) { |
410 | Object *found = ht_lookup(env->table, symbol); | 412 | Object *found = ht_lookup(env->table, symbol); |
411 | if (found != NULL) { | 413 | if (found != NULL) { |
412 | return true; | 414 | return found; |
413 | } | 415 | } |
414 | env = env->parent; | 416 | env = env->parent; |
415 | } | 417 | } |
416 | return false; | 418 | return NULL; |
417 | } | 419 | } |
418 | 420 | ||
419 | void | 421 | void |
@@ -423,7 +425,7 @@ check_object_scope(Environment *env, Object *obj, Errors *errors) { | |||
423 | } | 425 | } |
424 | switch (obj->type) { | 426 | switch (obj->type) { |
425 | case OBJ_TYPE_SYMBOL: { | 427 | case OBJ_TYPE_SYMBOL: { |
426 | if (!symbol_in_env(env, obj)) { | 428 | if (symbol_in_env(env, obj) == NULL) { |
427 | error_push(errors, (Error){ | 429 | error_push(errors, (Error){ |
428 | .type = ERR_TYPE_PARSER, | 430 | .type = ERR_TYPE_PARSER, |
429 | .value = ERR_SYMBOL_NOT_FOUND, | 431 | .value = ERR_SYMBOL_NOT_FOUND, |
@@ -505,6 +507,54 @@ remove_unused_expr(Object *obj) { | |||
505 | } | 507 | } |
506 | } | 508 | } |
507 | 509 | ||
510 | void | ||
511 | check_function_args(Environment *env, Object *obj, Errors *errors) { | ||
512 | if (obj == NULL || obj->visited) { | ||
513 | return; | ||
514 | } | ||
515 | obj->visited = true; | ||
516 | switch (obj->type) { | ||
517 | case OBJ_TYPE_SYMBOL: { | ||
518 | Object *found = symbol_in_env(env, obj); | ||
519 | check_function_args(env, found, errors); | ||
520 | } break; | ||
521 | case OBJ_TYPE_DEF: | ||
522 | case OBJ_TYPE_SET: { | ||
523 | check_function_args(env, obj->var_expr, errors); | ||
524 | } break; | ||
525 | case OBJ_TYPE_IF: { | ||
526 | check_function_args(env, obj->condition, errors); | ||
527 | check_function_args(env, obj->expr_true, errors); | ||
528 | check_function_args(env, obj->expr_false, errors); | ||
529 | } break; | ||
530 | case OBJ_TYPE_PAIR: { | ||
531 | Object *head = obj->head; | ||
532 | if (IS_SYMBOL(head)) { | ||
533 | head = symbol_in_env(env, head); | ||
534 | } | ||
535 | if (IS_LAMBDA(head)) { | ||
536 | if (obj->n_elems != array_size(head->params)) { | ||
537 | error_push(errors, (Error){ | ||
538 | .type = ERR_TYPE_PARSER, | ||
539 | .value = ERR_NOT_ENOUGH_ARGS, | ||
540 | .line = obj->line, | ||
541 | .col = obj->col | ||
542 | }); | ||
543 | } | ||
544 | } | ||
545 | check_function_args(env, head, errors); | ||
546 | check_function_args(env, obj->tail, errors); | ||
547 | } break; | ||
548 | case OBJ_TYPE_LAMBDA: { | ||
549 | for (size_t i = 0; i < array_size(obj->body); i++) { | ||
550 | Object *expr = obj->body[i]; | ||
551 | check_function_args(obj->env, expr, errors); | ||
552 | } | ||
553 | } break; | ||
554 | default: break; | ||
555 | } | ||
556 | } | ||
557 | |||
508 | Root * | 558 | Root * |
509 | parse(Token *tokens, Errors *errors) { | 559 | parse(Token *tokens, Errors *errors) { |
510 | array_init(roots, 0); | 560 | array_init(roots, 0); |
@@ -564,7 +614,6 @@ parse(Token *tokens, Errors *errors) { | |||
564 | } | 614 | } |
565 | } | 615 | } |
566 | array_push(final_roots, root); | 616 | array_push(final_roots, root); |
567 | |||
568 | remove_unused_expr(root); | 617 | remove_unused_expr(root); |
569 | if (errors->n != 0) { | 618 | if (errors->n != 0) { |
570 | return NULL; | 619 | return NULL; |
@@ -573,6 +622,19 @@ parse(Token *tokens, Errors *errors) { | |||
573 | array_free(roots); | 622 | array_free(roots); |
574 | roots = final_roots; | 623 | roots = final_roots; |
575 | 624 | ||
625 | // Check that the number of arguments in function calls match the number of | ||
626 | // formal parameters. | ||
627 | for (size_t i = 0; i < array_size(roots); i++) { | ||
628 | Object *root = roots[i]; | ||
629 | check_function_args(global_env, root, errors); | ||
630 | if (errors->n != 0) { | ||
631 | return NULL; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | // TODO: Type check basic expressions (e.g. arithmetic/numeric comparisons). | ||
636 | // We can't be sure when we have functions unless the return type is known. | ||
637 | |||
576 | return roots; | 638 | return roots; |
577 | } | 639 | } |
578 | 640 | ||
@@ -591,6 +653,7 @@ object_alloc(Token tok, ObjectType type) { | |||
591 | node->line = tok.line; | 653 | node->line = tok.line; |
592 | node->col = tok.col; | 654 | node->col = tok.col; |
593 | node->type = type; | 655 | node->type = type; |
656 | node->visited = false; | ||
594 | array_push(objects, node); | 657 | array_push(objects, node); |
595 | return node; | 658 | return node; |
596 | } | 659 | } |
@@ -739,13 +802,9 @@ object_equal(Object *a, Object *b) { | |||
739 | return false; | 802 | return false; |
740 | } | 803 | } |
741 | } | 804 | } |
805 | return true; | ||
742 | } break; | 806 | } break; |
743 | case OBJ_TYPE_LAMBDA: { | 807 | default: break; |
744 | // return a->closure == b.closure; | ||
745 | } break; | ||
746 | default: { | ||
747 | return false; | ||
748 | } break; | ||
749 | } | 808 | } |
750 | return true; | 809 | return false; |
751 | } | 810 | } |