aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-18 16:57:24 +0200
committerBad Diode <bd@badd10de.dev>2024-06-18 16:57:24 +0200
commitc80020d23599a9ea7b60f83449dbb93762ca9770 (patch)
tree259d721f962783e4a51691b1034708f3e305eb20
parent649b378bb01a6964b9deec4d0fe57aeae1e5cb9e (diff)
downloadbdl-c80020d23599a9ea7b60f83449dbb93762ca9770.tar.gz
bdl-c80020d23599a9ea7b60f83449dbb93762ca9770.zip
Add parsing support for basic conditionals and blocks
-rw-r--r--Makefile2
-rw-r--r--src/lexer.c7
-rw-r--r--src/main.c56
-rw-r--r--tests/conditionals.bad19
4 files changed, 82 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index fabc1c7..b6419fd 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
5SRC_DIR := src 5SRC_DIR := src
6BUILD_DIR := build 6BUILD_DIR := build
7SRC_MAIN := $(SRC_DIR)/main.c 7SRC_MAIN := $(SRC_DIR)/main.c
8SRC_BAD := tests/variables.bad 8SRC_BAD := tests/conditionals.bad
9WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h") 9WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h")
10INC_DIRS := $(shell find $(SRC_DIR) -type d) 10INC_DIRS := $(shell find $(SRC_DIR) -type d)
11INC_FLAGS := $(addprefix -I,$(INC_DIRS)) 11INC_FLAGS := $(addprefix -I,$(INC_DIRS))
diff --git a/src/lexer.c b/src/lexer.c
index e5bea2e..36a5636 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -27,6 +27,7 @@ typedef enum TokenKind {
27 TOK_FALSE, // false 27 TOK_FALSE, // false
28 TOK_FUN, // fun 28 TOK_FUN, // fun
29 TOK_IF, // if 29 TOK_IF, // if
30 TOK_ELSE, // else
30 TOK_LET, // let 31 TOK_LET, // let
31 TOK_MATCH, // match 32 TOK_MATCH, // match
32 TOK_NIL, // nil 33 TOK_NIL, // nil
@@ -93,6 +94,7 @@ Str token_str[] = {
93 [TOK_BREAK] = cstr("BREAK"), 94 [TOK_BREAK] = cstr("BREAK"),
94 [TOK_CASE] = cstr("CASE"), 95 [TOK_CASE] = cstr("CASE"),
95 [TOK_CONTINUE] = cstr("CONTINUE"), 96 [TOK_CONTINUE] = cstr("CONTINUE"),
97 [TOK_ELSE] = cstr("ELSE"),
96 [TOK_FALSE] = cstr("FALSE"), 98 [TOK_FALSE] = cstr("FALSE"),
97 [TOK_FUN] = cstr("FUN"), 99 [TOK_FUN] = cstr("FUN"),
98 [TOK_IF] = cstr("IF"), 100 [TOK_IF] = cstr("IF"),
@@ -539,6 +541,11 @@ scan_token(Scanner *scanner) {
539 return emit_token(current, scanner, TOK_CONTINUE); 541 return emit_token(current, scanner, TOK_CONTINUE);
540 } 542 }
541 } break; 543 } break;
544 case 'e': {
545 if (str_has_prefix(val, cstr("else"))) {
546 return emit_token(current, scanner, TOK_ELSE);
547 }
548 } break;
542 case 'f': { 549 case 'f': {
543 if (str_has_prefix(val, cstr("false"))) { 550 if (str_has_prefix(val, cstr("false"))) {
544 return emit_token(current, scanner, TOK_FALSE); 551 return emit_token(current, scanner, TOK_FALSE);
diff --git a/src/main.c b/src/main.c
index 13bd469..0679558 100644
--- a/src/main.c
+++ b/src/main.c
@@ -75,12 +75,14 @@ typedef enum NodeKind {
75 NODE_LET, 75 NODE_LET,
76 NODE_SET, 76 NODE_SET,
77 NODE_STRUCT, 77 NODE_STRUCT,
78 NODE_IF,
78 // Helpers. 79 // Helpers.
79 NODE_SYMBOL_IDX, 80 NODE_SYMBOL_IDX,
80 NODE_TYPE, 81 NODE_TYPE,
81 NODE_ARR_TYPE, 82 NODE_ARR_TYPE,
82 NODE_COMPOUND_TYPE, 83 NODE_COMPOUND_TYPE,
83 NODE_STRUCT_FIELD, 84 NODE_STRUCT_FIELD,
85 NODE_BLOCK,
84} NodeKind; 86} NodeKind;
85 87
86Str node_str[] = { 88Str node_str[] = {
@@ -120,12 +122,14 @@ Str node_str[] = {
120 [NODE_LET] = cstr("LET"), 122 [NODE_LET] = cstr("LET"),
121 [NODE_SET] = cstr("SET"), 123 [NODE_SET] = cstr("SET"),
122 [NODE_STRUCT] = cstr("STRUCT DEF"), 124 [NODE_STRUCT] = cstr("STRUCT DEF"),
125 [NODE_IF] = cstr("IF"),
123 // Helpers. 126 // Helpers.
124 [NODE_TYPE] = cstr("TYPE"), 127 [NODE_TYPE] = cstr("TYPE"),
125 [NODE_ARR_TYPE] = cstr("TYPE (ARR)"), 128 [NODE_ARR_TYPE] = cstr("TYPE (ARR)"),
126 [NODE_SYMBOL_IDX] = cstr("SYMBOL[IDX]"), 129 [NODE_SYMBOL_IDX] = cstr("SYMBOL[IDX]"),
127 [NODE_COMPOUND_TYPE] = cstr("TYPE (COMPOUND)"), 130 [NODE_COMPOUND_TYPE] = cstr("TYPE (COMPOUND)"),
128 [NODE_STRUCT_FIELD] = cstr("FIELD"), 131 [NODE_STRUCT_FIELD] = cstr("FIELD"),
132 [NODE_BLOCK] = cstr("BLOCK"),
129}; 133};
130 134
131typedef struct Node { 135typedef struct Node {
@@ -156,12 +160,18 @@ typedef struct Node {
156 struct Node *var_val; 160 struct Node *var_val;
157 }; 161 };
158 struct { 162 struct {
163 struct Node *cond_if;
164 struct Node *cond_expr;
165 struct Node *cond_else;
166 };
167 struct {
159 struct Node *field_name; 168 struct Node *field_name;
160 struct Node *field_type; 169 struct Node *field_type;
161 struct Node *field_val; 170 struct Node *field_val;
162 }; 171 };
163 struct Node **struct_field; 172 struct Node **struct_field;
164 struct Node **elements; 173 struct Node **elements;
174 struct Node **statements;
165 }; 175 };
166 bool is_ptr; 176 bool is_ptr;
167} Node; 177} Node;
@@ -222,10 +232,11 @@ void parse_string(Parser *parser);
222void parse_symbol(Parser *parser); 232void parse_symbol(Parser *parser);
223void parse_keyword(Parser *parser); 233void parse_keyword(Parser *parser);
224void parse_type(Parser *parser); 234void parse_type(Parser *parser);
235void parse_block(Parser *parser);
225 236
226ParseRule parse_rules[] = { 237ParseRule parse_rules[] = {
227 [TOK_LPAREN] = {parse_grouping, NULL, PREC_NONE}, 238 [TOK_LPAREN] = {parse_grouping, NULL, PREC_NONE},
228 [TOK_LCURLY] = {NULL, NULL, PREC_NONE}, 239 [TOK_LCURLY] = {parse_block, NULL, PREC_NONE},
229 [TOK_AT] = {parse_symbol, NULL, PREC_NONE}, 240 [TOK_AT] = {parse_symbol, NULL, PREC_NONE},
230 241
231 // Arithmetic. 242 // Arithmetic.
@@ -334,6 +345,22 @@ parse_consume(Parser *parser, TokenKind kind, Str msg) {
334 parse_emit_err(parser, parser->current, msg); 345 parse_emit_err(parser, parser->current, msg);
335} 346}
336 347
348void
349parse_block(Parser *parser) {
350#if DEBUG == 1
351 print("parsing block ");
352 print_token(prev);
353#endif
354 Node *block = node_alloc(parser, NODE_BLOCK, parser->previous);
355 if (!block) return;
356 while (!parse_match(parser, TOK_RCURLY) && !parser->panic) {
357 parse_expr(parser, PREC_LOW);
358 Node *next = array_pop(parser->nodes);
359 array_push(block->statements, next, parser->storage);
360 }
361 array_push(parser->nodes, block, parser->storage);
362}
363
337void 364void
338parse_expr(Parser *parser, ParsePrecedence precedence) { 365parse_expr(Parser *parser, ParsePrecedence precedence) {
339 parse_advance(parser); 366 parse_advance(parser);
@@ -524,6 +551,18 @@ parse_keyword(Parser *parser) {
524 array_push(node->struct_field, field, parser->storage); 551 array_push(node->struct_field, field, parser->storage);
525 } 552 }
526 } break; 553 } break;
554 case TOK_IF: {
555 node = node_alloc(parser, NODE_IF, prev);
556 if (!node) return;
557 parse_expr(parser, PREC_LOW);
558 node->cond_if = array_pop(parser->nodes);
559 parse_expr(parser, PREC_LOW);
560 node->cond_expr = array_pop(parser->nodes);
561 if (parse_match(parser, TOK_ELSE)) {
562 parse_expr(parser, PREC_LOW);
563 node->cond_else = array_pop(parser->nodes);
564 }
565 } break;
527 default: return; // Unreachable. 566 default: return; // Unreachable.
528 } 567 }
529 array_push(parser->nodes, node, parser->storage); 568 array_push(parser->nodes, node, parser->storage);
@@ -731,6 +770,7 @@ graph_node(Node *node) {
731 println("\"];"); 770 println("\"];");
732 771
733 switch (node->kind) { 772 switch (node->kind) {
773 case NODE_BLOCK:
734 case NODE_STRUCT_LIT: 774 case NODE_STRUCT_LIT:
735 case NODE_COMPOUND_TYPE: { 775 case NODE_COMPOUND_TYPE: {
736 for (sz i = 0; i < array_size(node->elements); i++) { 776 for (sz i = 0; i < array_size(node->elements); i++) {
@@ -746,6 +786,20 @@ graph_node(Node *node) {
746 graph_node(next); 786 graph_node(next);
747 } 787 }
748 } break; 788 } break;
789 case NODE_IF: {
790 if (node->cond_if) {
791 println("%d:e->%d:w;", node->id, node->cond_if->id);
792 graph_node(node->cond_if);
793 }
794 if (node->cond_expr) {
795 println("%d:e->%d:w;", node->id, node->cond_expr->id);
796 graph_node(node->cond_expr);
797 }
798 if (node->cond_else) {
799 println("%d:e->%d:w;", node->id, node->cond_else->id);
800 graph_node(node->cond_else);
801 }
802 } break;
749 case NODE_STRUCT_FIELD: 803 case NODE_STRUCT_FIELD:
750 case NODE_SET: 804 case NODE_SET:
751 case NODE_LET: { 805 case NODE_LET: {
diff --git a/tests/conditionals.bad b/tests/conditionals.bad
new file mode 100644
index 0000000..45e1bd2
--- /dev/null
+++ b/tests/conditionals.bad
@@ -0,0 +1,19 @@
1; Basic if expressions.
2if true "hello"
3
4; These can produce values and the result bound to a name.
5let a = if (2 + 2 >= 4) 42
6
7; We support a single if expression.
8let b = if 0xff == 255 "hello" else "world"
9
10; ... but these can compound on each other
11if 1 < 2 6
12else if 1 > 2 7
13else 8
14
15; A block is an expression, and if raise the scope level regardless if a block
16; is used or not.
17if true != false {
18 let a = "yo"
19}