aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-18 19:47:39 +0200
committerBad Diode <bd@badd10de.dev>2024-06-18 19:47:39 +0200
commitf9d0fe5ad641e453724dabc2b17634a44e198ce0 (patch)
tree9d86cd3f89b36ae9053a383fd44f93f9c044b0fe
parentc9db27abbbfa80a79515e26efaae9012d3275404 (diff)
downloadbdl-f9d0fe5ad641e453724dabc2b17634a44e198ce0.tar.gz
bdl-f9d0fe5ad641e453724dabc2b17634a44e198ce0.zip
Add enum parsing
-rw-r--r--src/lexer.c12
-rw-r--r--src/main.c55
-rw-r--r--tests/conditionals.bad62
3 files changed, 99 insertions, 30 deletions
diff --git a/src/lexer.c b/src/lexer.c
index 36a5636..2d2b6fc 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -23,11 +23,13 @@ typedef enum TokenKind {
23 // Keywords. 23 // Keywords.
24 TOK_BREAK, // break 24 TOK_BREAK, // break
25 TOK_CASE, // case 25 TOK_CASE, // case
26 TOK_COND, // match
26 TOK_CONTINUE, // continue 27 TOK_CONTINUE, // continue
28 TOK_ELSE, // else
29 TOK_ENUM, // enum
27 TOK_FALSE, // false 30 TOK_FALSE, // false
28 TOK_FUN, // fun 31 TOK_FUN, // fun
29 TOK_IF, // if 32 TOK_IF, // if
30 TOK_ELSE, // else
31 TOK_LET, // let 33 TOK_LET, // let
32 TOK_MATCH, // match 34 TOK_MATCH, // match
33 TOK_NIL, // nil 35 TOK_NIL, // nil
@@ -93,8 +95,10 @@ Str token_str[] = {
93 // Keywords. 95 // Keywords.
94 [TOK_BREAK] = cstr("BREAK"), 96 [TOK_BREAK] = cstr("BREAK"),
95 [TOK_CASE] = cstr("CASE"), 97 [TOK_CASE] = cstr("CASE"),
98 [TOK_COND] = cstr("COND"),
96 [TOK_CONTINUE] = cstr("CONTINUE"), 99 [TOK_CONTINUE] = cstr("CONTINUE"),
97 [TOK_ELSE] = cstr("ELSE"), 100 [TOK_ELSE] = cstr("ELSE"),
101 [TOK_ENUM] = cstr("ENUM"),
98 [TOK_FALSE] = cstr("FALSE"), 102 [TOK_FALSE] = cstr("FALSE"),
99 [TOK_FUN] = cstr("FUN"), 103 [TOK_FUN] = cstr("FUN"),
100 [TOK_IF] = cstr("IF"), 104 [TOK_IF] = cstr("IF"),
@@ -540,11 +544,17 @@ scan_token(Scanner *scanner) {
540 if (str_has_prefix(val, cstr("continue"))) { 544 if (str_has_prefix(val, cstr("continue"))) {
541 return emit_token(current, scanner, TOK_CONTINUE); 545 return emit_token(current, scanner, TOK_CONTINUE);
542 } 546 }
547 if (str_has_prefix(val, cstr("cond"))) {
548 return emit_token(current, scanner, TOK_COND);
549 }
543 } break; 550 } break;
544 case 'e': { 551 case 'e': {
545 if (str_has_prefix(val, cstr("else"))) { 552 if (str_has_prefix(val, cstr("else"))) {
546 return emit_token(current, scanner, TOK_ELSE); 553 return emit_token(current, scanner, TOK_ELSE);
547 } 554 }
555 if (str_has_prefix(val, cstr("enum"))) {
556 return emit_token(current, scanner, TOK_ENUM);
557 }
548 } break; 558 } break;
549 case 'f': { 559 case 'f': {
550 if (str_has_prefix(val, cstr("false"))) { 560 if (str_has_prefix(val, cstr("false"))) {
diff --git a/src/main.c b/src/main.c
index ccd4877..f73c7cc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -78,12 +78,14 @@ typedef enum NodeKind {
78 NODE_IF, 78 NODE_IF,
79 NODE_MATCH, 79 NODE_MATCH,
80 NODE_CASE, 80 NODE_CASE,
81 NODE_COND,
82 NODE_ENUM,
81 // Helpers. 83 // Helpers.
82 NODE_SYMBOL_IDX, 84 NODE_SYMBOL_IDX,
83 NODE_TYPE, 85 NODE_TYPE,
84 NODE_ARR_TYPE, 86 NODE_ARR_TYPE,
85 NODE_COMPOUND_TYPE, 87 NODE_COMPOUND_TYPE,
86 NODE_STRUCT_FIELD, 88 NODE_VAL_FIELD,
87 NODE_BLOCK, 89 NODE_BLOCK,
88} NodeKind; 90} NodeKind;
89 91
@@ -127,12 +129,14 @@ Str node_str[] = {
127 [NODE_IF] = cstr("IF"), 129 [NODE_IF] = cstr("IF"),
128 [NODE_MATCH] = cstr("MATCH"), 130 [NODE_MATCH] = cstr("MATCH"),
129 [NODE_CASE] = cstr("CASE"), 131 [NODE_CASE] = cstr("CASE"),
132 [NODE_COND] = cstr("COND"),
133 [NODE_ENUM] = cstr("ENUM"),
130 // Helpers. 134 // Helpers.
131 [NODE_TYPE] = cstr("TYPE"), 135 [NODE_TYPE] = cstr("TYPE"),
132 [NODE_ARR_TYPE] = cstr("TYPE (ARR)"), 136 [NODE_ARR_TYPE] = cstr("TYPE (ARR)"),
133 [NODE_SYMBOL_IDX] = cstr("SYMBOL[IDX]"), 137 [NODE_SYMBOL_IDX] = cstr("SYMBOL[IDX]"),
134 [NODE_COMPOUND_TYPE] = cstr("TYPE (COMPOUND)"), 138 [NODE_COMPOUND_TYPE] = cstr("TYPE (COMPOUND)"),
135 [NODE_STRUCT_FIELD] = cstr("FIELD"), 139 [NODE_VAL_FIELD] = cstr("FIELD"),
136 [NODE_BLOCK] = cstr("BLOCK"), 140 [NODE_BLOCK] = cstr("BLOCK"),
137}; 141};
138 142
@@ -290,8 +294,10 @@ ParseRule parse_rules[] = {
290 [TOK_LET] = {parse_keyword, NULL, PREC_NONE}, 294 [TOK_LET] = {parse_keyword, NULL, PREC_NONE},
291 [TOK_SET] = {parse_keyword, NULL, PREC_NONE}, 295 [TOK_SET] = {parse_keyword, NULL, PREC_NONE},
292 [TOK_STRUCT] = {parse_keyword, NULL, PREC_NONE}, 296 [TOK_STRUCT] = {parse_keyword, NULL, PREC_NONE},
297 [TOK_ENUM] = {parse_keyword, NULL, PREC_NONE},
293 [TOK_IF] = {parse_keyword, NULL, PREC_NONE}, 298 [TOK_IF] = {parse_keyword, NULL, PREC_NONE},
294 [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, 299 [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE},
300 [TOK_COND] = {parse_keyword, NULL, PREC_NONE},
295 [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, 301 [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE},
296 [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, 302 [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE},
297 [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, 303 [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE},
@@ -535,14 +541,15 @@ parse_keyword(Parser *parser) {
535 541
536 while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { 542 while (!parse_match(parser, TOK_RCURLY) && !parser->panic) {
537 Node *field = 543 Node *field =
538 node_alloc(parser, NODE_STRUCT_FIELD, parser->current); 544 node_alloc(parser, NODE_VAL_FIELD, parser->current);
539 if (!field) return; 545 if (!field) return;
540 parse_consume( 546 parse_consume(
541 parser, TOK_SYMBOL, 547 parser, TOK_SYMBOL,
542 cstr("expected symbol name on struct definition")); 548 cstr("expected symbol name on struct definition"));
543 parse_symbol(parser); 549 parse_symbol(parser);
544 field->field_name = array_pop(parser->nodes); 550 field->field_name = array_pop(parser->nodes);
545 if (field->field_name->next) { 551 if (field->field_name->next ||
552 field->field_name->kind == NODE_SYMBOL_IDX) {
546 parse_emit_err(parser, prev, 553 parse_emit_err(parser, prev,
547 cstr("invalid symbol name in struct field")); 554 cstr("invalid symbol name in struct field"));
548 return; 555 return;
@@ -589,12 +596,12 @@ parse_keyword(Parser *parser) {
589 // Are we on the default case. 596 // Are we on the default case.
590 if (!parse_match(parser, TOK_ELSE)) { 597 if (!parse_match(parser, TOK_ELSE)) {
591 parse_consume(parser, TOK_CASE, 598 parse_consume(parser, TOK_CASE,
592 cstr("expected case statement")); 599 cstr("expected case statement"));
593 parse_expr(parser, PREC_LOW); 600 parse_expr(parser, PREC_LOW);
594 tmp->case_value = array_pop(parser->nodes); 601 tmp->case_value = array_pop(parser->nodes);
595 } 602 }
596 parse_consume(parser, TOK_ASSIGN, 603 parse_consume(parser, TOK_ASSIGN,
597 cstr("malformed case statement")); 604 cstr("malformed case statement"));
598 parse_expr(parser, PREC_LOW); 605 parse_expr(parser, PREC_LOW);
599 tmp->case_expr = array_pop(parser->nodes); 606 tmp->case_expr = array_pop(parser->nodes);
600 array_push(node->match_cases, tmp, parser->storage); 607 array_push(node->match_cases, tmp, parser->storage);
@@ -604,6 +611,36 @@ parse_keyword(Parser *parser) {
604 // TODO: Check that there are no multiple default or duplicated 611 // TODO: Check that there are no multiple default or duplicated
605 // cases. 612 // cases.
606 } break; 613 } break;
614 case TOK_ENUM: {
615 node = node_alloc(parser, NODE_ENUM, prev);
616 if (!node) return;
617 parse_consume(parser, TOK_SYMBOL,
618 cstr("expected symbol name on enum definition"));
619 // Just consume this to avoid conflicts with struct literals.
620 node->value.sym = parser->previous.val;
621 parse_consume(parser, TOK_LCURLY,
622 cstr("expected '{' on enum definition"));
623 while (!parse_match(parser, TOK_RCURLY) && !parser->panic) {
624 Node *field =
625 node_alloc(parser, NODE_VAL_FIELD, parser->current);
626 if (!field) return;
627 parse_consume(parser, TOK_SYMBOL,
628 cstr("expected symbol name on enum definition"));
629 parse_symbol(parser);
630 field->field_name = array_pop(parser->nodes);
631 if (field->field_name->next ||
632 field->field_name->kind == NODE_SYMBOL_IDX) {
633 parse_emit_err(parser, prev,
634 cstr("invalid symbol name in enum field"));
635 return;
636 }
637 if (parse_match(parser, TOK_ASSIGN)) {
638 parse_expr(parser, PREC_LOW);
639 field->field_val = array_pop(parser->nodes);
640 }
641 array_push(node->struct_field, field, parser->storage);
642 }
643 } break;
607 default: return; // Unreachable. 644 default: return; // Unreachable.
608 } 645 }
609 array_push(parser->nodes, node, parser->storage); 646 array_push(parser->nodes, node, parser->storage);
@@ -741,8 +778,7 @@ parse_symbol(Parser *parser) {
741 // Struct literal. 778 // Struct literal.
742 node->kind = NODE_STRUCT_LIT; 779 node->kind = NODE_STRUCT_LIT;
743 while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { 780 while (!parse_match(parser, TOK_RCURLY) && !parser->panic) {
744 Node *field = 781 Node *field = node_alloc(parser, NODE_VAL_FIELD, parser->current);
745 node_alloc(parser, NODE_STRUCT_FIELD, parser->current);
746 parse_consume(parser, TOK_SYMBOL, cstr("expected symbol name")); 782 parse_consume(parser, TOK_SYMBOL, cstr("expected symbol name"));
747 parse_symbol(parser); 783 parse_symbol(parser);
748 field->field_name = array_pop(parser->nodes); 784 field->field_name = array_pop(parser->nodes);
@@ -831,6 +867,7 @@ graph_node(Node *node) {
831 graph_node(next); 867 graph_node(next);
832 } 868 }
833 } break; 869 } break;
870 case NODE_ENUM:
834 case NODE_STRUCT: { 871 case NODE_STRUCT: {
835 for (sz i = 0; i < array_size(node->struct_field); i++) { 872 for (sz i = 0; i < array_size(node->struct_field); i++) {
836 Node *next = node->struct_field[i]; 873 Node *next = node->struct_field[i];
@@ -852,7 +889,7 @@ graph_node(Node *node) {
852 graph_node(node->cond_else); 889 graph_node(node->cond_else);
853 } 890 }
854 } break; 891 } break;
855 case NODE_STRUCT_FIELD: 892 case NODE_VAL_FIELD:
856 case NODE_SET: 893 case NODE_SET:
857 case NODE_LET: { 894 case NODE_LET: {
858 if (node->var_name) { 895 if (node->var_name) {
diff --git a/tests/conditionals.bad b/tests/conditionals.bad
index b1c6a89..44467a8 100644
--- a/tests/conditionals.bad
+++ b/tests/conditionals.bad
@@ -1,28 +1,50 @@
1; Basic if expressions. 1; ; Basic if expressions.
2if true "hello" 2; if true "hello"
3 3
4; These can produce values and the result bound to a name. 4; ; These can produce values and the result bound to a name.
5let a = if (2 + 2 >= 4) 42 5; let a = if (2 + 2 >= 4) 42
6 6
7; We support a single if expression. 7; ; We support a single if expression.
8let b = if 0xff == 255 "hello" else "world" 8; let b = if 0xff == 255 "hello" else "world"
9 9
10; ... but these can compound on each other 10; ; ... but these can compound on each other
11if 1 < 2 6 11; if 1 < 2 6
12else if 1 > 2 7 12; else if 1 > 2 7
13else 8 13; else 8
14 14
15; A block is an expression, and if raise the scope level regardless if a block 15; ; A block is an expression, and if raise the scope level regardless if a block
16; is used or not. 16; ; is used or not.
17if true != false { 17; if true != false {
18 let a = "yo" 18; let a = "yo"
19; }
20
21; ; Match cases should only apply to literal values, for example `case 1 + 2`
22; ; isn't allowed. They should generally convert to a lookup table.
23; match a = {
24; case 8 = "hello"
25; case 9 = "world"
26; else = "what"
27; }
28
29; cond {
30; case a == b = "hello"
31; case a != c = "world"
32; else = "what"
33; }
34
35; Enums are integers with values that increase automatically or that can be set
36; with a constexpr.
37enum flags {
38 node_add = 1 << 0
39 node_sub = 1 << 1
40 node_div = 1 << 2
41 node_mul
19} 42}
43let a:flags = flags.node_add
20 44
21; Match cases should only apply to literal values, for example `case 1 + 2` 45; No need to qualify enum fields inside match-case.
22; isn't allowed. They should generally convert to a lookup table.
23match a = { 46match a = {
24 case 8 = "hello" 47 case node_add = "adding something..."
25 case 9 = "world" 48 case node_add = "subbing something..."
26 else = "what" 49 else = "default case"
27} 50}
28