aboutsummaryrefslogtreecommitdiffstats
path: root/src/parser.c
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-31 14:25:44 +0100
committerBad Diode <bd@badd10de.dev>2021-10-31 14:25:44 +0100
commitef0cbf240782010a4b71d32546e022dfd4f0b6bf (patch)
treeea4e86bb0ebf206313b99fc0f7d3078f9fd5dd1e /src/parser.c
parent3ed3aa338296f82046de2061e717b49328c8b057 (diff)
downloadbdl-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.c83
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
407bool 409Object *
408symbol_in_env(Environment *env, Object *symbol) { 410symbol_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
419void 421void
@@ -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
510void
511check_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
508Root * 558Root *
509parse(Token *tokens, Errors *errors) { 559parse(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}