diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | src/main.c | 21 | ||||
-rw-r--r-- | tests/loops.bad | 18 |
3 files changed, 43 insertions, 3 deletions
@@ -7,7 +7,7 @@ BUILD_DIR := build | |||
7 | TESTS_DIR := tests | 7 | TESTS_DIR := tests |
8 | TEST_FILES := $(wildcard $(TESTS_DIR)/*.bad) | 8 | TEST_FILES := $(wildcard $(TESTS_DIR)/*.bad) |
9 | SRC_MAIN := $(SRC_DIR)/main.c | 9 | SRC_MAIN := $(SRC_DIR)/main.c |
10 | SRC_RUN := tests/conditionals.bad | 10 | SRC_RUN := tests/loops.bad |
11 | WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h") | 11 | WATCH_SRC := $(shell find $(SRC_DIR) -name "*.c" -or -name "*.s" -or -name "*.h") |
12 | INC_DIRS := $(shell find $(SRC_DIR) -type d) | 12 | INC_DIRS := $(shell find $(SRC_DIR) -type d) |
13 | INC_FLAGS := $(addprefix -I,$(INC_DIRS)) | 13 | INC_FLAGS := $(addprefix -I,$(INC_DIRS)) |
@@ -74,8 +74,11 @@ graph-symbols: $(BIN) | |||
74 | 74 | ||
75 | tests: $(BIN) | 75 | tests: $(BIN) |
76 | @for name in $(TEST_FILES); do\ | 76 | @for name in $(TEST_FILES); do\ |
77 | line=" OK";\ | ||
77 | printf "$${name}\r" ;\ | 78 | printf "$${name}\r" ;\ |
78 | $(BIN) $${name} && printf "$${name}\tOK!\n";\ | 79 | $(BIN) $${name} \ |
80 | && printf "$$line\r" \ | ||
81 | && printf "$${name}\n";\ | ||
79 | done | 82 | done |
80 | 83 | ||
81 | # Remove build directory. | 84 | # Remove build directory. |
@@ -82,6 +82,7 @@ typedef enum NodeKind { | |||
82 | NODE_ENUM, | 82 | NODE_ENUM, |
83 | NODE_BREAK, | 83 | NODE_BREAK, |
84 | NODE_CONTINUE, | 84 | NODE_CONTINUE, |
85 | NODE_WHILE, | ||
85 | // Helpers. | 86 | // Helpers. |
86 | NODE_SYMBOL_IDX, | 87 | NODE_SYMBOL_IDX, |
87 | NODE_TYPE, | 88 | NODE_TYPE, |
@@ -135,6 +136,7 @@ Str node_str[] = { | |||
135 | [NODE_ENUM] = cstr("ENUM"), | 136 | [NODE_ENUM] = cstr("ENUM"), |
136 | [NODE_BREAK] = cstr("BREAK"), | 137 | [NODE_BREAK] = cstr("BREAK"), |
137 | [NODE_CONTINUE] = cstr("CONTINUE"), | 138 | [NODE_CONTINUE] = cstr("CONTINUE"), |
139 | [NODE_WHILE] = cstr("WHILE"), | ||
138 | // Helpers. | 140 | // Helpers. |
139 | [NODE_TYPE] = cstr("TYPE"), | 141 | [NODE_TYPE] = cstr("TYPE"), |
140 | [NODE_ARR_TYPE] = cstr("TYPE (ARR)"), | 142 | [NODE_ARR_TYPE] = cstr("TYPE (ARR)"), |
@@ -172,6 +174,10 @@ typedef struct Node { | |||
172 | struct Node *var_val; | 174 | struct Node *var_val; |
173 | }; | 175 | }; |
174 | struct { | 176 | struct { |
177 | struct Node *while_cond; | ||
178 | struct Node *while_expr; | ||
179 | }; | ||
180 | struct { | ||
175 | struct Node *cond_if; | 181 | struct Node *cond_if; |
176 | struct Node *cond_expr; | 182 | struct Node *cond_expr; |
177 | struct Node *cond_else; | 183 | struct Node *cond_else; |
@@ -209,6 +215,7 @@ typedef struct Parser { | |||
209 | // Error handling. | 215 | // Error handling. |
210 | bool err; | 216 | bool err; |
211 | bool panic; | 217 | bool panic; |
218 | Str file_name; | ||
212 | 219 | ||
213 | // Storage. | 220 | // Storage. |
214 | Node **nodes; | 221 | Node **nodes; |
@@ -328,7 +335,8 @@ parse_emit_err(Parser *parser, Token token, Str msg) { | |||
328 | if (parser->panic) return; | 335 | if (parser->panic) return; |
329 | parser->panic = true; | 336 | parser->panic = true; |
330 | parser->err = true; | 337 | parser->err = true; |
331 | eprint("%d:%d: error: %s", token.line, token.col, msg); | 338 | eprint("%s:%d:%d: error: %s", parser->file_name, token.line, token.col, |
339 | msg); | ||
332 | 340 | ||
333 | if (token.kind == TOK_EOF) { | 341 | if (token.kind == TOK_EOF) { |
334 | eprintln(" at end of the file"); | 342 | eprintln(" at end of the file"); |
@@ -675,6 +683,16 @@ parse_keyword(Parser *parser) { | |||
675 | node = node_alloc(parser, NODE_CONTINUE, prev); | 683 | node = node_alloc(parser, NODE_CONTINUE, prev); |
676 | if (!node) return; | 684 | if (!node) return; |
677 | } break; | 685 | } break; |
686 | case TOK_WHILE: { | ||
687 | node = node_alloc(parser, NODE_WHILE, prev); | ||
688 | if (!node) return; | ||
689 | parse_expr(parser, PREC_LOW); | ||
690 | node->while_cond = array_pop(parser->nodes); | ||
691 | parse_consume(parser, TOK_ASSIGN, | ||
692 | cstr("malformed while expression")); | ||
693 | parse_expr(parser, PREC_LOW); | ||
694 | node->while_expr = array_pop(parser->nodes); | ||
695 | } break; | ||
678 | default: return; // Unreachable. | 696 | default: return; // Unreachable. |
679 | } | 697 | } |
680 | array_push(parser->nodes, node, parser->storage); | 698 | array_push(parser->nodes, node, parser->storage); |
@@ -1009,6 +1027,7 @@ process_file(Str path) { | |||
1009 | Parser parser = { | 1027 | Parser parser = { |
1010 | .tokens = tokens, | 1028 | .tokens = tokens, |
1011 | .storage = &lexer_arena, | 1029 | .storage = &lexer_arena, |
1030 | .file_name = path, | ||
1012 | }; | 1031 | }; |
1013 | array_init(parser.nodes, 256, parser.storage); | 1032 | array_init(parser.nodes, 256, parser.storage); |
1014 | parse_advance(&parser); | 1033 | parse_advance(&parser); |
diff --git a/tests/loops.bad b/tests/loops.bad new file mode 100644 index 0000000..5221844 --- /dev/null +++ b/tests/loops.bad | |||
@@ -0,0 +1,18 @@ | |||
1 | ; The most basic loop is the while loop. | ||
2 | while abc = "heelo" | ||
3 | |||
4 | while 1 + 2 == 3 = { | ||
5 | "hello" | ||
6 | } | ||
7 | |||
8 | while symbol = { | ||
9 | "hello" | ||
10 | } | ||
11 | |||
12 | |||
13 | ; We could use some sugar for this. | ||
14 | let i = 0 | ||
15 | while i < 10 = { | ||
16 | "hello" | ||
17 | set i = i + 1 | ||
18 | } | ||