diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-18 19:12:13 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-18 19:12:13 +0200 |
commit | a0068318895ff8dea6d3c3f0db381fbca83e3f40 (patch) | |
tree | 200a987c8ac3eb10cc1d6400328baeee986837a7 | |
parent | c80020d23599a9ea7b60f83449dbb93762ca9770 (diff) | |
download | bdl-a0068318895ff8dea6d3c3f0db381fbca83e3f40.tar.gz bdl-a0068318895ff8dea6d3c3f0db381fbca83e3f40.zip |
Add parsing for match-case statements
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | src/main.c | 59 | ||||
-rw-r--r-- | tests/conditionals.bad | 8 |
3 files changed, 66 insertions, 4 deletions
@@ -122,6 +122,9 @@ cond (10 == 1) { | |||
122 | 122 | ||
123 | ~a << b & 10 | 123 | ~a << b & 10 |
124 | 124 | ||
125 | ; How do we declare and use hashmap types? (builtin) | ||
126 | #str:u32 | ||
127 | |||
125 | } | 128 | } |
126 | ``` | 129 | ``` |
127 | 130 | ||
@@ -76,6 +76,8 @@ typedef enum NodeKind { | |||
76 | NODE_SET, | 76 | NODE_SET, |
77 | NODE_STRUCT, | 77 | NODE_STRUCT, |
78 | NODE_IF, | 78 | NODE_IF, |
79 | NODE_MATCH, | ||
80 | NODE_CASE, | ||
79 | // Helpers. | 81 | // Helpers. |
80 | NODE_SYMBOL_IDX, | 82 | NODE_SYMBOL_IDX, |
81 | NODE_TYPE, | 83 | NODE_TYPE, |
@@ -123,6 +125,8 @@ Str node_str[] = { | |||
123 | [NODE_SET] = cstr("SET"), | 125 | [NODE_SET] = cstr("SET"), |
124 | [NODE_STRUCT] = cstr("STRUCT DEF"), | 126 | [NODE_STRUCT] = cstr("STRUCT DEF"), |
125 | [NODE_IF] = cstr("IF"), | 127 | [NODE_IF] = cstr("IF"), |
128 | [NODE_MATCH] = cstr("MATCH"), | ||
129 | [NODE_CASE] = cstr("CASE"), | ||
126 | // Helpers. | 130 | // Helpers. |
127 | [NODE_TYPE] = cstr("TYPE"), | 131 | [NODE_TYPE] = cstr("TYPE"), |
128 | [NODE_ARR_TYPE] = cstr("TYPE (ARR)"), | 132 | [NODE_ARR_TYPE] = cstr("TYPE (ARR)"), |
@@ -169,6 +173,14 @@ typedef struct Node { | |||
169 | struct Node *field_type; | 173 | struct Node *field_type; |
170 | struct Node *field_val; | 174 | struct Node *field_val; |
171 | }; | 175 | }; |
176 | struct { | ||
177 | struct Node *match_expr; | ||
178 | struct Node **match_cases; | ||
179 | }; | ||
180 | struct { | ||
181 | struct Node *case_value; | ||
182 | struct Node *case_expr; | ||
183 | }; | ||
172 | struct Node **struct_field; | 184 | struct Node **struct_field; |
173 | struct Node **elements; | 185 | struct Node **elements; |
174 | struct Node **statements; | 186 | struct Node **statements; |
@@ -280,7 +292,6 @@ ParseRule parse_rules[] = { | |||
280 | [TOK_STRUCT] = {parse_keyword, NULL, PREC_NONE}, | 292 | [TOK_STRUCT] = {parse_keyword, NULL, PREC_NONE}, |
281 | [TOK_IF] = {parse_keyword, NULL, PREC_NONE}, | 293 | [TOK_IF] = {parse_keyword, NULL, PREC_NONE}, |
282 | [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, | 294 | [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, |
283 | [TOK_CASE] = {parse_keyword, NULL, PREC_NONE}, | ||
284 | [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, | 295 | [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, |
285 | [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, | 296 | [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, |
286 | [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, | 297 | [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, |
@@ -345,11 +356,11 @@ parse_consume(Parser *parser, TokenKind kind, Str msg) { | |||
345 | parse_emit_err(parser, parser->current, msg); | 356 | parse_emit_err(parser, parser->current, msg); |
346 | } | 357 | } |
347 | 358 | ||
348 | void | 359 | void |
349 | parse_block(Parser *parser) { | 360 | parse_block(Parser *parser) { |
350 | #if DEBUG == 1 | 361 | #if DEBUG == 1 |
351 | print("parsing block "); | 362 | print("parsing block "); |
352 | print_token(prev); | 363 | print_token(parser->previous); |
353 | #endif | 364 | #endif |
354 | Node *block = node_alloc(parser, NODE_BLOCK, parser->previous); | 365 | Node *block = node_alloc(parser, NODE_BLOCK, parser->previous); |
355 | if (!block) return; | 366 | if (!block) return; |
@@ -563,6 +574,34 @@ parse_keyword(Parser *parser) { | |||
563 | node->cond_else = array_pop(parser->nodes); | 574 | node->cond_else = array_pop(parser->nodes); |
564 | } | 575 | } |
565 | } break; | 576 | } break; |
577 | case TOK_MATCH: { | ||
578 | node = node_alloc(parser, NODE_MATCH, prev); | ||
579 | if (!node) return; | ||
580 | parse_expr(parser, PREC_LOW); | ||
581 | node->match_expr = array_pop(parser->nodes); | ||
582 | parse_consume(parser, TOK_LCURLY, | ||
583 | cstr("expected block of match cases")); | ||
584 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | ||
585 | parse_consume(parser, TOK_CASE, | ||
586 | cstr("expected case statement")); | ||
587 | Node *tmp = node_alloc(parser, NODE_CASE, parser->previous); | ||
588 | if (!tmp) return; | ||
589 | // Are we on the default case. | ||
590 | if (!parse_match(parser, TOK_ASSIGN)) { | ||
591 | parse_expr(parser, PREC_LOW); | ||
592 | tmp->case_value = array_pop(parser->nodes); | ||
593 | parse_consume(parser, TOK_ASSIGN, | ||
594 | cstr("malformed case statement")); | ||
595 | } | ||
596 | parse_expr(parser, PREC_LOW); | ||
597 | tmp->case_expr = array_pop(parser->nodes); | ||
598 | array_push(node->match_cases, tmp, parser->storage); | ||
599 | } | ||
600 | // TODO: Check that we only have literals on the match case, this | ||
601 | // could be done on the analysis step, but also here... | ||
602 | // TODO: Check that there are no multiple default or duplicated | ||
603 | // cases. | ||
604 | } break; | ||
566 | default: return; // Unreachable. | 605 | default: return; // Unreachable. |
567 | } | 606 | } |
568 | array_push(parser->nodes, node, parser->storage); | 607 | array_push(parser->nodes, node, parser->storage); |
@@ -770,6 +809,17 @@ graph_node(Node *node) { | |||
770 | println("\"];"); | 809 | println("\"];"); |
771 | 810 | ||
772 | switch (node->kind) { | 811 | switch (node->kind) { |
812 | case NODE_MATCH: { | ||
813 | if (node->match_expr) { | ||
814 | println("%d:e->%d:w;", node->id, node->match_expr->id); | ||
815 | graph_node(node->match_expr); | ||
816 | } | ||
817 | for (sz i = 0; i < array_size(node->match_cases); i++) { | ||
818 | Node *next = node->match_cases[i]; | ||
819 | println("%d:e->%d:w;", node->id, next->id); | ||
820 | graph_node(next); | ||
821 | } | ||
822 | } break; | ||
773 | case NODE_BLOCK: | 823 | case NODE_BLOCK: |
774 | case NODE_STRUCT_LIT: | 824 | case NODE_STRUCT_LIT: |
775 | case NODE_COMPOUND_TYPE: { | 825 | case NODE_COMPOUND_TYPE: { |
@@ -929,7 +979,8 @@ print_usage(void) { | |||
929 | printf("\n"); | 979 | printf("\n"); |
930 | printf("\t-h \t\tShow usage.\n"); | 980 | printf("\t-h \t\tShow usage.\n"); |
931 | printf( | 981 | printf( |
932 | "\t-p [l|p|s|t]\tPrint mode for [l]exing, [p]arsing, [s]emantic " | 982 | "\t-p [l|p|s|t]\tPrint mode for [l]exing, [p]arsing, " |
983 | "[s]emantic " | ||
933 | "analysis, symbol [t]ables\n"); | 984 | "analysis, symbol [t]ables\n"); |
934 | printf("\n"); | 985 | printf("\n"); |
935 | } | 986 | } |
diff --git a/tests/conditionals.bad b/tests/conditionals.bad index 45e1bd2..71d49c3 100644 --- a/tests/conditionals.bad +++ b/tests/conditionals.bad | |||
@@ -17,3 +17,11 @@ else 8 | |||
17 | if true != false { | 17 | if true != false { |
18 | let a = "yo" | 18 | let a = "yo" |
19 | } | 19 | } |
20 | |||
21 | ; Match cases should only apply to literal values, for example `case 1 + 2` | ||
22 | ; isn't allowed. | ||
23 | match 4 * 2 { | ||
24 | case 8 = "hello" | ||
25 | case 9 = "world" | ||
26 | case = "what" | ||
27 | } | ||