diff options
-rw-r--r-- | src/main.c | 65 | ||||
-rw-r--r-- | tests/semantics.bad | 25 |
2 files changed, 78 insertions, 12 deletions
@@ -8,8 +8,8 @@ | |||
8 | #include "vm.c" | 8 | #include "vm.c" |
9 | 9 | ||
10 | // TODO: unions | 10 | // TODO: unions |
11 | // TODO: match deconstruct enums | ||
12 | // TODO: arrays and pointers | 11 | // TODO: arrays and pointers |
12 | // TODO: embed (binary file) and include (source file) | ||
13 | 13 | ||
14 | typedef enum ExecMode { | 14 | typedef enum ExecMode { |
15 | RUN_NORMAL, | 15 | RUN_NORMAL, |
@@ -600,7 +600,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
600 | &scope->symbols, field_name, | 600 | &scope->symbols, field_name, |
601 | (Symbol){.name = field_name, .kind = SYM_ENUM_FIELD}, | 601 | (Symbol){.name = field_name, .kind = SYM_ENUM_FIELD}, |
602 | a->storage); | 602 | a->storage); |
603 | field->type = cstr("int"); | 603 | field->type = symbol; |
604 | } | 604 | } |
605 | symmap_insert(&scope->symbols, symbol, | 605 | symmap_insert(&scope->symbols, symbol, |
606 | (Symbol){.name = symbol, .kind = SYM_ENUM}, | 606 | (Symbol){.name = symbol, .kind = SYM_ENUM}, |
@@ -652,11 +652,57 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
652 | node->type = cstr("nil"); | 652 | node->type = cstr("nil"); |
653 | return node->type; | 653 | return node->type; |
654 | } break; | 654 | } break; |
655 | case NODE_COND: | 655 | case NODE_COND: { |
656 | Str previous = cstr(""); | ||
657 | for (sz i = 0; i < array_size(node->match_cases); i++) { | ||
658 | Node *expr = node->match_cases[i]; | ||
659 | Str next = type_inference(a, expr, scope); | ||
660 | if (i != 0 && !str_eq(next, previous)) { | ||
661 | emit_semantic_error( | ||
662 | a, node, | ||
663 | cstr("non-matching types for cond expressions")); | ||
664 | return cstr(""); | ||
665 | } | ||
666 | previous = next; | ||
667 | } | ||
668 | node->type = previous; | ||
669 | return node->type; | ||
670 | } break; | ||
656 | case NODE_MATCH: { | 671 | case NODE_MATCH: { |
657 | // TODO: proper typecheck matchcase expressions here... | 672 | Str e = type_inference(a, node->match_expr, scope); |
658 | if (node->match_expr) { | 673 | if (str_eq(e, cstr("int"))) { |
659 | type_inference(a, node->match_expr, scope); | 674 | // Integer matching. |
675 | for (sz i = 0; i < array_size(node->match_cases); i++) { | ||
676 | Node *field = node->match_cases[i]; | ||
677 | if (field->case_value) { | ||
678 | if (field->case_value->kind != NODE_NUM_INT && | ||
679 | field->case_value->kind != NODE_NUM_UINT) { | ||
680 | emit_semantic_error( | ||
681 | a, field->case_value, | ||
682 | cstr( | ||
683 | "non-integer or enum types on match case")); | ||
684 | } | ||
685 | } | ||
686 | } | ||
687 | } else { | ||
688 | // Get enum type and de-structure the match. | ||
689 | FindEnumResult res = find_enum(scope, e); | ||
690 | Str enum_prefix = | ||
691 | str_concat(res.map->val.name, cstr("."), a->storage); | ||
692 | for (sz i = 0; i < array_size(node->match_cases); i++) { | ||
693 | Node *field = node->match_cases[i]; | ||
694 | if (field->case_value) { | ||
695 | Str field_name = str_concat( | ||
696 | enum_prefix, field->case_value->value.str, | ||
697 | a->storage); | ||
698 | if (!enummap_lookup(&res.scope->enums, field_name)) { | ||
699 | eprintln("%s:%d:%d: error: unknown enum field '%s'", | ||
700 | a->file_name, field->case_value->line, | ||
701 | field->case_value->col, field_name); | ||
702 | a->err = true; | ||
703 | } | ||
704 | } | ||
705 | } | ||
660 | } | 706 | } |
661 | Str previous = cstr(""); | 707 | Str previous = cstr(""); |
662 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 708 | for (sz i = 0; i < array_size(node->match_cases); i++) { |
@@ -665,7 +711,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
665 | if (i != 0 && !str_eq(next, previous)) { | 711 | if (i != 0 && !str_eq(next, previous)) { |
666 | emit_semantic_error( | 712 | emit_semantic_error( |
667 | a, node, | 713 | a, node, |
668 | cstr("non-matching types for case expressions")); | 714 | cstr("non-matching types for match expressions")); |
669 | return cstr(""); | 715 | return cstr(""); |
670 | } | 716 | } |
671 | previous = next; | 717 | previous = next; |
@@ -674,9 +720,6 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
674 | return node->type; | 720 | return node->type; |
675 | } break; | 721 | } break; |
676 | case NODE_CASE_MATCH: { | 722 | case NODE_CASE_MATCH: { |
677 | if (node->case_value) { | ||
678 | type_inference(a, node->case_value, scope); | ||
679 | } | ||
680 | if (node->case_expr->kind != NODE_BLOCK) { | 723 | if (node->case_expr->kind != NODE_BLOCK) { |
681 | scope = typescope_alloc(a, scope); | 724 | scope = typescope_alloc(a, scope); |
682 | } | 725 | } |
@@ -846,7 +889,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
846 | a->err = true; | 889 | a->err = true; |
847 | return cstr(""); | 890 | return cstr(""); |
848 | } | 891 | } |
849 | node->next->type = cstr("int"); | 892 | node->next->type = type->val.name; |
850 | node->type = type->val.name; | 893 | node->type = type->val.name; |
851 | return node->next->type; | 894 | return node->next->type; |
852 | } | 895 | } |
diff --git a/tests/semantics.bad b/tests/semantics.bad index 8a2818f..e5178f2 100644 --- a/tests/semantics.bad +++ b/tests/semantics.bad | |||
@@ -14,6 +14,17 @@ struct vec { | |||
14 | } | 14 | } |
15 | } | 15 | } |
16 | let a = 1 | 16 | let a = 1 |
17 | |||
18 | match a { | ||
19 | case 1 = "ha" | ||
20 | case 2 = "ho" | ||
21 | } | ||
22 | |||
23 | cond { | ||
24 | 1 == 1 = "ha" | ||
25 | 2 != 2 = "ho" | ||
26 | } | ||
27 | |||
17 | ; struct vec { | 28 | ; struct vec { |
18 | ; x: f64 | 29 | ; x: f64 |
19 | ; y: f64 | 30 | ; y: f64 |
@@ -90,9 +101,21 @@ enum weekdays { | |||
90 | sat | 101 | sat |
91 | sun | 102 | sun |
92 | } | 103 | } |
93 | ; let a = weekdays.tue | 104 | let d = weekdays.tue |
94 | ; let b = a | 105 | ; let b = a |
95 | 106 | ||
107 | match 1 { | ||
108 | case 2 = "monday" | ||
109 | case 3 = "tuesday" | ||
110 | else = "whateverday" | ||
111 | } | ||
112 | |||
113 | match d { | ||
114 | case mon = "monday" | ||
115 | case tue = "tuesday" | ||
116 | else = "whateverday" | ||
117 | } | ||
118 | |||
96 | ; struct item { | 119 | ; struct item { |
97 | ; id: int | 120 | ; id: int |
98 | ; name: str | 121 | ; name: str |