diff options
author | Bad Diode <bd@badd10de.dev> | 2021-10-30 08:36:14 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-10-30 08:36:14 +0200 |
commit | f17b11003fe384b49a7bf844824f23167b6095e0 (patch) | |
tree | 7129ee8267bf8327d608c1d3a927295929b24631 | |
parent | 4ebcd99d1fadac72ea58ea46012a86c5319ef7e7 (diff) | |
download | bdl-f17b11003fe384b49a7bf844824f23167b6095e0.tar.gz bdl-f17b11003fe384b49a7bf844824f23167b6095e0.zip |
Add parsing of if expressions
-rwxr-xr-x | README.md | 2 | ||||
-rwxr-xr-x | src/lexer.c | 2 | ||||
-rwxr-xr-x | src/lexer.h | 1 | ||||
-rw-r--r-- | src/parser.c | 91 | ||||
-rwxr-xr-x | src/parser.h | 8 |
5 files changed, 95 insertions, 9 deletions
@@ -46,7 +46,7 @@ program : <statement>* EOF | |||
46 | <statement> : <definition> | <expression> | 46 | <statement> : <definition> | <expression> |
47 | 47 | ||
48 | <definition> : ( def <symbol> <expression> ) | 48 | <definition> : ( def <symbol> <expression> ) |
49 | | ( fun ( <symbol>* ) <body> ) | 49 | | ( fun <symbol> ( <symbol>* ) <body> ) |
50 | ; | 50 | ; |
51 | 51 | ||
52 | <expression> : <constant> | 52 | <expression> : <constant> |
diff --git a/src/lexer.c b/src/lexer.c index f272901..cbcc175 100755 --- a/src/lexer.c +++ b/src/lexer.c | |||
@@ -12,6 +12,7 @@ static const char* token_str[] = { | |||
12 | [TOKEN_TRUE] = "TOKEN_TRUE", | 12 | [TOKEN_TRUE] = "TOKEN_TRUE", |
13 | [TOKEN_FALSE] = "TOKEN_FALSE", | 13 | [TOKEN_FALSE] = "TOKEN_FALSE", |
14 | [TOKEN_LAMBDA] = "TOKEN_LAMBDA", | 14 | [TOKEN_LAMBDA] = "TOKEN_LAMBDA", |
15 | [TOKEN_IF] = "TOKEN_IF", | ||
15 | [TOKEN_EOF] = "TOKEN_EOF", | 16 | [TOKEN_EOF] = "TOKEN_EOF", |
16 | }; | 17 | }; |
17 | 18 | ||
@@ -126,6 +127,7 @@ find_primitive_type(const StringView value) { | |||
126 | if (TOKEN_IS_KEYWORD(value, "true")) { return TOKEN_TRUE; } | 127 | if (TOKEN_IS_KEYWORD(value, "true")) { return TOKEN_TRUE; } |
127 | if (TOKEN_IS_KEYWORD(value, "false")) { return TOKEN_FALSE; } | 128 | if (TOKEN_IS_KEYWORD(value, "false")) { return TOKEN_FALSE; } |
128 | if (TOKEN_IS_KEYWORD(value, "lambda")) { return TOKEN_LAMBDA; } | 129 | if (TOKEN_IS_KEYWORD(value, "lambda")) { return TOKEN_LAMBDA; } |
130 | if (TOKEN_IS_KEYWORD(value, "if")) { return TOKEN_IF; } | ||
129 | 131 | ||
130 | return TOKEN_SYMBOL; | 132 | return TOKEN_SYMBOL; |
131 | } | 133 | } |
diff --git a/src/lexer.h b/src/lexer.h index 4fa4db5..4798a2b 100755 --- a/src/lexer.h +++ b/src/lexer.h | |||
@@ -20,6 +20,7 @@ typedef enum TokenType { | |||
20 | 20 | ||
21 | // Keywords. | 21 | // Keywords. |
22 | TOKEN_LAMBDA, | 22 | TOKEN_LAMBDA, |
23 | TOKEN_IF, | ||
23 | 24 | ||
24 | // End of file. | 25 | // End of file. |
25 | TOKEN_EOF, | 26 | TOKEN_EOF, |
diff --git a/src/parser.c b/src/parser.c index 8a6c4ce..5551dd2 100644 --- a/src/parser.c +++ b/src/parser.c | |||
@@ -103,6 +103,7 @@ parse_lambda(Parser *parser, Errors *errors) { | |||
103 | .line = tok.line, | 103 | .line = tok.line, |
104 | .col = tok.col, | 104 | .col = tok.col, |
105 | }); | 105 | }); |
106 | return NULL; | ||
106 | } | 107 | } |
107 | 108 | ||
108 | // Parse body. | 109 | // Parse body. |
@@ -119,23 +120,81 @@ parse_lambda(Parser *parser, Errors *errors) { | |||
119 | } | 120 | } |
120 | 121 | ||
121 | Object * | 122 | Object * |
122 | parse_list(Parser *parser, Errors *errors) { | 123 | parse_if(Parser *parser, Errors *errors) { |
123 | if (errors->n != 0) { | 124 | Token start = next_token(parser); |
125 | Object *obj_if = object_alloc(start, OBJ_TYPE_IF); | ||
126 | |||
127 | Token tok = peek_token(parser); | ||
128 | if (tok.type == TOKEN_RPAREN) { | ||
129 | error_push(errors, (Error){ | ||
130 | .type = ERR_TYPE_PARSER, | ||
131 | .value = ERR_NOT_ENOUGH_ARGS, | ||
132 | .line = tok.line, | ||
133 | .col = tok.col, | ||
134 | }); | ||
124 | return NULL; | 135 | return NULL; |
125 | } | 136 | } |
137 | obj_if->condition = parse_tree(parser, errors); | ||
126 | 138 | ||
127 | Token tok = peek_token(parser); | 139 | tok = peek_token(parser); |
128 | if (tok.type == TOKEN_RPAREN) { | 140 | if (tok.type == TOKEN_RPAREN) { |
129 | error_push(errors, (Error){ | 141 | error_push(errors, (Error){ |
130 | .type = ERR_TYPE_PARSER, | 142 | .type = ERR_TYPE_PARSER, |
131 | .value = ERR_UNBALANCED_PAREN, | 143 | .value = ERR_NOT_ENOUGH_ARGS, |
132 | .line = tok.line, | 144 | .line = tok.line, |
133 | .col = tok.col, | 145 | .col = tok.col, |
134 | }); | 146 | }); |
135 | return NULL; | 147 | return NULL; |
136 | } | 148 | } |
137 | if (tok.type == TOKEN_LAMBDA) { | 149 | obj_if->expr_true = parse_tree(parser, errors); |
138 | return parse_lambda(parser, errors); | 150 | |
151 | // Optional else expression. | ||
152 | tok = peek_token(parser); | ||
153 | if (tok.type == TOKEN_RPAREN) { | ||
154 | next_token(parser); | ||
155 | obj_if->expr_false = NULL; | ||
156 | return obj_if; | ||
157 | } | ||
158 | obj_if->expr_false = parse_tree(parser, errors); | ||
159 | |||
160 | tok = peek_token(parser); | ||
161 | if (tok.type != TOKEN_RPAREN) { | ||
162 | error_push(errors, (Error){ | ||
163 | .type = ERR_TYPE_PARSER, | ||
164 | .value = ERR_TOO_MANY_ARGS, | ||
165 | .line = tok.line, | ||
166 | .col = tok.col, | ||
167 | }); | ||
168 | return NULL; | ||
169 | } | ||
170 | next_token(parser); | ||
171 | return obj_if; | ||
172 | } | ||
173 | |||
174 | Object * | ||
175 | parse_list(Parser *parser, Errors *errors) { | ||
176 | if (errors->n != 0) { | ||
177 | return NULL; | ||
178 | } | ||
179 | |||
180 | Token tok = peek_token(parser); | ||
181 | switch (tok.type) { | ||
182 | case TOKEN_RPAREN: { | ||
183 | error_push(errors, (Error){ | ||
184 | .type = ERR_TYPE_PARSER, | ||
185 | .value = ERR_UNBALANCED_PAREN, | ||
186 | .line = tok.line, | ||
187 | .col = tok.col, | ||
188 | }); | ||
189 | return NULL; | ||
190 | } break; | ||
191 | case TOKEN_LAMBDA: { | ||
192 | return parse_lambda(parser, errors); | ||
193 | } break; | ||
194 | case TOKEN_IF: { | ||
195 | return parse_if(parser, errors); | ||
196 | } break; | ||
197 | default: break; | ||
139 | } | 198 | } |
140 | 199 | ||
141 | Token start = previous_token(parser); | 200 | Token start = previous_token(parser); |
@@ -327,13 +386,29 @@ object_display(Object *obj) { | |||
327 | printf(")"); | 386 | printf(")"); |
328 | } break; | 387 | } break; |
329 | case OBJ_TYPE_LAMBDA: { | 388 | case OBJ_TYPE_LAMBDA: { |
330 | printf("#{lambda( "); | 389 | printf("#{ lambda( "); |
331 | for (size_t i = 0; i < array_size(obj->params); i++) { | 390 | for (size_t i = 0; i < array_size(obj->params); i++) { |
332 | object_display(obj->params[i]); | 391 | object_display(obj->params[i]); |
333 | printf(" "); | 392 | printf(" "); |
334 | } | 393 | } |
335 | printf(")}"); | 394 | printf(") "); |
395 | for (size_t i = 0; i < array_size(obj->body); i++) { | ||
396 | object_display(obj->body[i]); | ||
397 | printf(" "); | ||
398 | } | ||
399 | printf("}"); | ||
336 | } break; | 400 | } break; |
401 | case OBJ_TYPE_IF: { | ||
402 | printf("#{ if "); | ||
403 | object_display(obj->condition); | ||
404 | printf(" "); | ||
405 | object_display(obj->expr_true); | ||
406 | if (obj->expr_false != NULL) { | ||
407 | printf(" "); | ||
408 | object_display(obj->expr_false); | ||
409 | } | ||
410 | printf(" }"); | ||
411 | }; | ||
337 | } | 412 | } |
338 | return; | 413 | return; |
339 | } | 414 | } |
diff --git a/src/parser.h b/src/parser.h index 17bd6d6..b2b07c8 100755 --- a/src/parser.h +++ b/src/parser.h | |||
@@ -12,6 +12,7 @@ typedef enum ObjectType { | |||
12 | OBJ_TYPE_STRING, | 12 | OBJ_TYPE_STRING, |
13 | OBJ_TYPE_PAIR, | 13 | OBJ_TYPE_PAIR, |
14 | OBJ_TYPE_LAMBDA, | 14 | OBJ_TYPE_LAMBDA, |
15 | OBJ_TYPE_IF, | ||
15 | } ObjectType; | 16 | } ObjectType; |
16 | 17 | ||
17 | typedef struct Object { | 18 | typedef struct Object { |
@@ -35,6 +36,13 @@ typedef struct Object { | |||
35 | struct Object **params; | 36 | struct Object **params; |
36 | struct Object **body; | 37 | struct Object **body; |
37 | }; | 38 | }; |
39 | |||
40 | // OBJ_TYPE_IF | ||
41 | struct { | ||
42 | struct Object *condition; | ||
43 | struct Object *expr_true; | ||
44 | struct Object *expr_false; | ||
45 | }; | ||
38 | }; | 46 | }; |
39 | 47 | ||
40 | size_t line; | 48 | size_t line; |