diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-24 15:38:29 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-24 15:38:29 +0200 |
commit | ec7faebe81c6d4aad7f2927962fae5c9f414eb66 (patch) | |
tree | 7a382c8ddf815f1623a9bade35e68b63dbdf7797 | |
parent | 5d3bd237db051902161a919a2efb6ca25de449d9 (diff) | |
download | bdl-ec7faebe81c6d4aad7f2927962fae5c9f414eb66.tar.gz bdl-ec7faebe81c6d4aad7f2927962fae5c9f414eb66.zip |
Add funcall typechecking
-rw-r--r-- | src/main.c | 61 | ||||
-rw-r--r-- | tests/semantics.bad | 60 |
2 files changed, 79 insertions, 42 deletions
@@ -143,6 +143,18 @@ find_type(TypeScope *scope, Str type) { | |||
143 | return NULL; | 143 | return NULL; |
144 | } | 144 | } |
145 | 145 | ||
146 | FunMap * | ||
147 | find_fun(TypeScope *scope, Str type) { | ||
148 | while (scope != NULL) { | ||
149 | FunMap *val = funmap_lookup(&scope->funcs, type); | ||
150 | if (val != NULL) { | ||
151 | return val; | ||
152 | } | ||
153 | scope = scope->parent; | ||
154 | } | ||
155 | return NULL; | ||
156 | } | ||
157 | |||
146 | void | 158 | void |
147 | graph_scope(Scope *scope, Arena a) { | 159 | graph_scope(Scope *scope, Arena a) { |
148 | if (!scope->symbols) { | 160 | if (!scope->symbols) { |
@@ -302,7 +314,7 @@ graph_symbols(Scope **scopes, Arena a) { | |||
302 | void | 314 | void |
303 | graph_types(TypeScope **scopes, Arena a) { | 315 | graph_types(TypeScope **scopes, Arena a) { |
304 | if (scopes == NULL) return; | 316 | if (scopes == NULL) return; |
305 | println("digraph symbols {"); | 317 | println("digraph types {"); |
306 | println("rankdir=LR;"); | 318 | println("rankdir=LR;"); |
307 | println("ranksep=\"0.95 equally\";"); | 319 | println("ranksep=\"0.95 equally\";"); |
308 | println("nodesep=\"0.5 equally\";"); | 320 | println("nodesep=\"0.5 equally\";"); |
@@ -664,19 +676,38 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
664 | return node->type; | 676 | return node->type; |
665 | } break; | 677 | } break; |
666 | case NODE_FUNCALL: { | 678 | case NODE_FUNCALL: { |
667 | // TODO: ... | 679 | Str symbol = node->value.str; |
668 | // Str symbol = node->value.str; | 680 | FunMap *fun = find_fun(scope, symbol); |
669 | // if (find_symbol(scope, symbol) == NULL) { | 681 | if (!fun) { |
670 | // eprintln( | 682 | eprintln( |
671 | // "%s:%d:%d: error: symbol '%s' doesn't exists in current " | 683 | "%s:%d:%d: error: function '%s' doesn't exist in current " |
672 | // " scope ", | 684 | " scope ", |
673 | // a->file_name, node->line, node->col, symbol); | 685 | a->file_name, node->line, node->col, symbol); |
674 | // return; | 686 | return cstr(""); |
675 | // } | 687 | } |
676 | // for (sz i = 0; i < array_size(node->elements); i++) { | 688 | // Check that actual parameters typecheck |
677 | // Node *expr = node->elements[i]; | 689 | Type args = cstr(""); |
678 | // analyzer_symbols(a, expr, scope); | 690 | for (sz i = 0; i < array_size(node->elements); i++) { |
679 | // } | 691 | Node *expr = node->elements[i]; |
692 | Type type = type_inference(a, expr, scope); | ||
693 | args = str_concat(args, type, a->storage); | ||
694 | if (i != array_size(node->elements) - 1) { | ||
695 | args = str_concat(args, cstr(","), a->storage); | ||
696 | } | ||
697 | } | ||
698 | if (!args.size) { | ||
699 | args = cstr("nil"); | ||
700 | } | ||
701 | Str expected = fun->val.param_type; | ||
702 | bool err = !str_eq(args, expected); | ||
703 | if (err) { | ||
704 | eprintln( | ||
705 | "%s:%d:%d: error: mismatched parameter types: %s expected " | ||
706 | "%s", | ||
707 | a->file_name, node->line, node->col, args, expected); | ||
708 | } | ||
709 | node->type = fun->val.return_type; | ||
710 | return node->type; | ||
680 | } break; | 711 | } break; |
681 | case NODE_BLOCK: { | 712 | case NODE_BLOCK: { |
682 | scope = typescope_alloc(a, scope); | 713 | scope = typescope_alloc(a, scope); |
@@ -794,8 +825,6 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
794 | typecheck_returns(a, node->func_body, ret_type); | 825 | typecheck_returns(a, node->func_body, ret_type); |
795 | 826 | ||
796 | // TODO: should return statements be allowed on let blocks? | 827 | // TODO: should return statements be allowed on let blocks? |
797 | // TODO: insert this into a functions map in the current scope? need | ||
798 | // the arity and return parameters for funcalls. | ||
799 | return node->type; | 828 | return node->type; |
800 | } break; | 829 | } break; |
801 | default: { | 830 | default: { |
diff --git a/tests/semantics.bad b/tests/semantics.bad index 3305222..3479915 100644 --- a/tests/semantics.bad +++ b/tests/semantics.bad | |||
@@ -1,23 +1,31 @@ | |||
1 | ; let a:f32 = (1.0 + 2.0 * 2.0) / 2.0 | 1 | fun add10(a: int, b: str): int { |
2 | 2 | a + 10 | |
3 | let annotated:int = (1 + 2 * 2) / 2 | ||
4 | let numbers = 1 | ||
5 | let symbols = numbers | ||
6 | let arith = 1 + 2 * 4 | ||
7 | let cmp = 1 <= 2 | ||
8 | let logic = !true && false || (1 <= 2) | ||
9 | let bits = 0xff & 0b00001111 | ||
10 | let block = { | ||
11 | let a = 1 + 2 | ||
12 | a + 3 | ||
13 | } | 3 | } |
14 | 4 | ||
15 | let maybe = if (1 == 2) { | 5 | fun foo(): int { |
16 | 32 | 6 | add10(1, "hello") |
17 | } else { | ||
18 | 44 | ||
19 | } | 7 | } |
20 | 8 | ||
9 | ; let a:f32 = (1.0 + 2.0 * 2.0) / 2.0 | ||
10 | |||
11 | ; let annotated:int = (1 + 2 * 2) / 2 | ||
12 | ; let numbers = 1 | ||
13 | ; let symbols = numbers | ||
14 | ; let arith = 1 + 2 * 4 | ||
15 | ; let cmp = 1 <= 2 | ||
16 | ; let logic = !true && false || (1 <= 2) | ||
17 | ; let bits = 0xff & 0b00001111 | ||
18 | ; let block = { | ||
19 | ; let a = 1 + 2 | ||
20 | ; a + 3 | ||
21 | ; } | ||
22 | |||
23 | ; let maybe = if (1 == 2) { | ||
24 | ; 32 | ||
25 | ; } else { | ||
26 | ; 44 | ||
27 | ; } | ||
28 | |||
21 | ; let single = if (true) { | 29 | ; let single = if (true) { |
22 | ; 123 | 30 | ; 123 |
23 | ; } | 31 | ; } |
@@ -112,16 +120,16 @@ fun nested(): int { | |||
112 | ; let c = 1 | 120 | ; let c = 1 |
113 | ; 1 + 1 + c | 121 | ; 1 + 1 + c |
114 | ; } | 122 | ; } |
115 | fun foo(a: int b: str): (f64, f64) { | 123 | ; fun foo(a: int b: str): (f64, f64) { |
116 | fun bar(): nil { | 124 | ; fun bar(): nil { |
117 | println("ding") | 125 | ; println("ding") |
118 | } | 126 | ; } |
119 | if (a == 1) { | 127 | ; if (a == 1) { |
120 | ; return("test", b) | 128 | ; ; return("test", b) |
121 | return(3.0, 4.0) | 129 | ; return (3.0, 4.0) |
122 | } | 130 | ; } |
123 | return(1.0, 2.0) | 131 | ; return (1.0, 2.0) |
124 | } | 132 | ; } |
125 | 133 | ||
126 | ; let b = a | 134 | ; let b = a |
127 | ; let a = a | 135 | ; let a = a |