/Users/alexjokela/projects/lattice/src/parser.c
Line | Count | Source |
1 | | #include "parser.h" |
2 | | #include <stdlib.h> |
3 | | #include <string.h> |
4 | | #include <stdio.h> |
5 | | #include <stdarg.h> |
6 | | #include <ctype.h> |
7 | | |
8 | 2.87k | Parser parser_new(LatVec *tokens) { |
9 | 2.87k | Parser p; |
10 | 2.87k | p.tokens = (Token *)tokens->data; |
11 | 2.87k | p.count = tokens->len; |
12 | 2.87k | p.pos = 0; |
13 | 2.87k | return p; |
14 | 2.87k | } |
15 | | |
16 | | /* ── Helpers ── */ |
17 | | |
18 | 4.90M | static Token *peek(Parser *p) { |
19 | 4.90M | size_t idx = p->pos < p->count ? p->pos : p->count - 1; |
20 | 4.90M | return &p->tokens[idx]; |
21 | 4.90M | } |
22 | | |
23 | 4.61M | static TokenType peek_type(Parser *p) { |
24 | 4.61M | return peek(p)->type; |
25 | 4.61M | } |
26 | | |
27 | 438 | static TokenType peek_ahead_type(Parser *p, size_t offset) { |
28 | 438 | size_t idx = p->pos + offset; |
29 | 438 | if (idx >= p->count) idx = p->count - 1; |
30 | 438 | return p->tokens[idx].type; |
31 | 438 | } |
32 | | |
33 | 434k | static Token *advance(Parser *p) { |
34 | 434k | size_t idx = p->pos < p->count ? p->pos : p->count - 1; |
35 | 434k | if (p->pos < p->count) p->pos++; |
36 | 434k | return &p->tokens[idx]; |
37 | 434k | } |
38 | | |
39 | 124k | static bool at_eof(Parser *p) { |
40 | 124k | return peek_type(p) == TOK_EOF; |
41 | 124k | } |
42 | | |
43 | 0 | static char *parser_error_fmt(Parser *p, const char *fmt, ...) { |
44 | 0 | Token *t = peek(p); |
45 | 0 | char *inner = NULL; |
46 | 0 | va_list args; |
47 | 0 | va_start(args, fmt); |
48 | 0 | (void)vasprintf(&inner, fmt, args); |
49 | 0 | va_end(args); |
50 | 0 | char *err = NULL; |
51 | 0 | (void)asprintf(&err, "%zu:%zu: parse error: %s", t->line, t->col, inner); |
52 | 0 | free(inner); |
53 | 0 | return err; |
54 | 0 | } |
55 | | |
56 | 154k | static bool expect(Parser *p, TokenType expected, char **err) { |
57 | 154k | if (peek_type(p) == expected) { |
58 | 154k | advance(p); |
59 | 154k | return true; |
60 | 154k | } |
61 | 0 | *err = parser_error_fmt(p, "expected '%s', got '%s'", |
62 | 0 | token_type_name(expected), |
63 | 0 | token_type_name(peek_type(p))); |
64 | 0 | return false; |
65 | 154k | } |
66 | | |
67 | 65.4k | static char *expect_ident(Parser *p, char **err) { |
68 | 65.4k | if (peek_type(p) == TOK_IDENT) { |
69 | 65.4k | Token *t = advance(p); |
70 | 65.4k | return strdup(t->as.str_val); |
71 | 65.4k | } |
72 | 0 | *err = parser_error_fmt(p, "expected identifier, got '%s'", |
73 | 0 | token_type_name(peek_type(p))); |
74 | 0 | return NULL; |
75 | 65.4k | } |
76 | | |
77 | 44.2k | static void eat_semicolon(Parser *p) { |
78 | 44.2k | if (peek_type(p) == TOK_SEMICOLON) advance(p); |
79 | 44.2k | } |
80 | | |
81 | | /* Forward declarations */ |
82 | | static Expr *parse_expr(Parser *p, char **err); |
83 | | static Stmt *parse_stmt(Parser *p, char **err); |
84 | | |
85 | | /* ── Block stmts ── */ |
86 | | |
87 | 20.6k | static Stmt **parse_block_stmts(Parser *p, size_t *count, char **err) { |
88 | 20.6k | size_t cap = 8; |
89 | 20.6k | size_t n = 0; |
90 | 20.6k | Stmt **stmts = malloc(cap * sizeof(Stmt *)); |
91 | | |
92 | 65.6k | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
93 | 44.9k | Stmt *s = parse_stmt(p, err); |
94 | 44.9k | if (!s) { free(stmts); return NULL; } |
95 | 44.9k | if (n >= cap) { |
96 | 192 | cap *= 2; |
97 | 192 | stmts = realloc(stmts, cap * sizeof(Stmt *)); |
98 | 192 | } |
99 | 44.9k | stmts[n++] = s; |
100 | 44.9k | } |
101 | 20.6k | *count = n; |
102 | 20.6k | return stmts; |
103 | 20.6k | } |
104 | | |
105 | | /* ── Types ── */ |
106 | | |
107 | 13.5k | static TypeExpr *parse_type_expr(Parser *p, char **err) { |
108 | 13.5k | TypeExpr *te = calloc(1, sizeof(TypeExpr)); |
109 | 13.5k | if (peek_type(p) == TOK_TILDE || peek_type(p) == TOK_FLUX) { |
110 | 33 | advance(p); te->phase = PHASE_FLUID; |
111 | 13.4k | } else if (peek_type(p) == TOK_STAR || peek_type(p) == TOK_FIX) { |
112 | 24 | advance(p); te->phase = PHASE_CRYSTAL; |
113 | 13.4k | } else { |
114 | 13.4k | te->phase = PHASE_UNSPECIFIED; |
115 | 13.4k | } |
116 | | |
117 | 13.5k | if (peek_type(p) == TOK_LBRACKET) { |
118 | 6 | advance(p); |
119 | 6 | te->kind = TYPE_ARRAY; |
120 | 6 | te->inner = parse_type_expr(p, err); |
121 | 6 | if (!te->inner) { free(te); return NULL; } |
122 | 6 | if (!expect(p, TOK_RBRACKET, err)) { |
123 | 0 | type_expr_free(te); free(te); return NULL; |
124 | 0 | } |
125 | 13.5k | } else { |
126 | 13.5k | te->kind = TYPE_NAMED; |
127 | 13.5k | te->name = expect_ident(p, err); |
128 | 13.5k | if (!te->name) { free(te); return NULL; } |
129 | 13.5k | } |
130 | 13.5k | return te; |
131 | 13.5k | } |
132 | | |
133 | | /* ── Params ── */ |
134 | | |
135 | 7.99k | static Param *parse_params(Parser *p, size_t *count, char **err) { |
136 | 7.99k | size_t cap = 4; |
137 | 7.99k | size_t n = 0; |
138 | 7.99k | Param *params = malloc(cap * sizeof(Param)); |
139 | 7.99k | bool seen_default = false; |
140 | 7.99k | bool seen_variadic = false; |
141 | | |
142 | 16.5k | while (peek_type(p) != TOK_RPAREN && !at_eof(p)) { |
143 | 8.57k | if (n >= cap) { cap *= 2; params = realloc(params, cap * sizeof(Param)); } |
144 | 8.57k | if (seen_variadic) { |
145 | 0 | *err = strdup("variadic parameter must be last"); |
146 | 0 | for (size_t i = 0; i < n; i++) { free(params[i].name); if (params[i].default_value) expr_free(params[i].default_value); } |
147 | 0 | free(params); |
148 | 0 | return NULL; |
149 | 0 | } |
150 | | /* Check for variadic: ...name */ |
151 | 8.57k | bool is_variadic = false; |
152 | 8.57k | if (peek_type(p) == TOK_DOTDOTDOT) { |
153 | 96 | advance(p); |
154 | 96 | is_variadic = true; |
155 | 96 | seen_variadic = true; |
156 | 96 | } |
157 | 8.57k | params[n].name = expect_ident(p, err); |
158 | 8.57k | if (!params[n].name) { |
159 | 0 | for (size_t i = 0; i < n; i++) { free(params[i].name); if (params[i].default_value) expr_free(params[i].default_value); } |
160 | 0 | free(params); |
161 | 0 | return NULL; |
162 | 0 | } |
163 | 8.57k | if (!expect(p, TOK_COLON, err)) { |
164 | 0 | free(params[n].name); |
165 | 0 | for (size_t i = 0; i < n; i++) { free(params[i].name); if (params[i].default_value) expr_free(params[i].default_value); } |
166 | 0 | free(params); |
167 | 0 | return NULL; |
168 | 0 | } |
169 | 8.57k | TypeExpr *te = parse_type_expr(p, err); |
170 | 8.57k | if (!te) { |
171 | 0 | free(params[n].name); |
172 | 0 | for (size_t i = 0; i < n; i++) { free(params[i].name); if (params[i].default_value) expr_free(params[i].default_value); } |
173 | 0 | free(params); |
174 | 0 | return NULL; |
175 | 0 | } |
176 | 8.57k | params[n].ty = *te; |
177 | 8.57k | free(te); |
178 | 8.57k | params[n].is_variadic = is_variadic; |
179 | 8.57k | params[n].default_value = NULL; |
180 | | /* Check for default value: = expr */ |
181 | 8.57k | if (!is_variadic && peek_type(p) == TOK_EQ) { |
182 | 96 | advance(p); |
183 | 96 | seen_default = true; |
184 | 96 | Expr *def = parse_expr(p, err); |
185 | 96 | if (!def) { |
186 | 0 | free(params[n].name); |
187 | 0 | for (size_t i = 0; i < n; i++) { free(params[i].name); if (params[i].default_value) expr_free(params[i].default_value); } |
188 | 0 | free(params); |
189 | 0 | return NULL; |
190 | 0 | } |
191 | 96 | params[n].default_value = def; |
192 | 8.47k | } else if (seen_default && !is_variadic) { |
193 | 0 | *err = strdup("required parameter cannot follow a parameter with a default value"); |
194 | 0 | free(params[n].name); |
195 | 0 | for (size_t i = 0; i < n; i++) { free(params[i].name); if (params[i].default_value) expr_free(params[i].default_value); } |
196 | 0 | free(params); |
197 | 0 | return NULL; |
198 | 0 | } |
199 | 8.57k | n++; |
200 | 8.57k | if (peek_type(p) != TOK_RPAREN) { |
201 | 3.46k | if (!expect(p, TOK_COMMA, err)) { |
202 | 0 | for (size_t i = 0; i < n; i++) { free(params[i].name); if (params[i].default_value) expr_free(params[i].default_value); } |
203 | 0 | free(params); |
204 | 0 | return NULL; |
205 | 0 | } |
206 | 3.46k | } |
207 | 8.57k | } |
208 | 7.99k | *count = n; |
209 | 7.99k | return params; |
210 | 7.99k | } |
211 | | |
212 | | /* ── Arguments ── */ |
213 | | |
214 | 36.6k | static Expr **parse_args(Parser *p, size_t *count, char **err) { |
215 | 36.6k | size_t cap = 4; |
216 | 36.6k | size_t n = 0; |
217 | 36.6k | Expr **args = malloc(cap * sizeof(Expr *)); |
218 | | |
219 | 79.9k | while (peek_type(p) != TOK_RPAREN && !at_eof(p)) { |
220 | 43.3k | Expr *e = parse_expr(p, err); |
221 | 43.3k | if (!e) { free(args); return NULL; } |
222 | 43.3k | if (n >= cap) { cap *= 2; args = realloc(args, cap * sizeof(Expr *)); } |
223 | 43.3k | args[n++] = e; |
224 | 43.3k | if (peek_type(p) != TOK_RPAREN) { |
225 | 10.6k | if (!expect(p, TOK_COMMA, err)) { |
226 | 0 | for (size_t i = 0; i < n; i++) expr_free(args[i]); |
227 | 0 | free(args); |
228 | 0 | return NULL; |
229 | 0 | } |
230 | 10.6k | } |
231 | 43.3k | } |
232 | 36.6k | *count = n; |
233 | 36.6k | return args; |
234 | 36.6k | } |
235 | | |
236 | | /* ── Expressions (precedence climbing) ── */ |
237 | | |
238 | | static Expr *parse_primary(Parser *p, char **err); |
239 | | static Expr *parse_postfix(Parser *p, char **err); |
240 | | static Expr *parse_unary(Parser *p, char **err); |
241 | | static Expr *parse_multiplication(Parser *p, char **err); |
242 | | static Expr *parse_addition(Parser *p, char **err); |
243 | | static Expr *parse_shift(Parser *p, char **err); |
244 | | static Expr *parse_range_expr(Parser *p, char **err); |
245 | | static Expr *parse_comparison(Parser *p, char **err); |
246 | | static Expr *parse_equality(Parser *p, char **err); |
247 | | static Expr *parse_bitwise_and(Parser *p, char **err); |
248 | | static Expr *parse_bitwise_xor(Parser *p, char **err); |
249 | | static Expr *parse_bitwise_or(Parser *p, char **err); |
250 | | static Expr *parse_and_expr(Parser *p, char **err); |
251 | | static Expr *parse_or(Parser *p, char **err); |
252 | | |
253 | | static Expr *parse_nil_coalesce(Parser *p, char **err); |
254 | | |
255 | 107k | static Expr *parse_expr(Parser *p, char **err) { |
256 | 107k | int line = (int)peek(p)->line; |
257 | 107k | Expr *e = parse_nil_coalesce(p, err); |
258 | 107k | if (e && e->line == 0) e->line = line; |
259 | 107k | return e; |
260 | 107k | } |
261 | | |
262 | 107k | static Expr *parse_nil_coalesce(Parser *p, char **err) { |
263 | 107k | Expr *left = parse_or(p, err); |
264 | 107k | if (!left) return NULL; |
265 | 107k | while (peek_type(p) == TOK_QUESTION_QUESTION) { |
266 | 18 | advance(p); |
267 | 18 | Expr *right = parse_or(p, err); |
268 | 18 | if (!right) { expr_free(left); return NULL; } |
269 | 18 | left = expr_binop(BINOP_NIL_COALESCE, left, right); |
270 | 18 | } |
271 | 107k | return left; |
272 | 107k | } |
273 | | |
274 | 107k | static Expr *parse_or(Parser *p, char **err) { |
275 | 107k | Expr *left = parse_and_expr(p, err); |
276 | 107k | if (!left) return NULL; |
277 | 107k | while (peek_type(p) == TOK_OR) { |
278 | 6 | advance(p); |
279 | 6 | Expr *right = parse_and_expr(p, err); |
280 | 6 | if (!right) { expr_free(left); return NULL; } |
281 | 6 | left = expr_binop(BINOP_OR, left, right); |
282 | 6 | } |
283 | 107k | return left; |
284 | 107k | } |
285 | | |
286 | 107k | static Expr *parse_and_expr(Parser *p, char **err) { |
287 | 107k | Expr *left = parse_bitwise_or(p, err); |
288 | 107k | if (!left) return NULL; |
289 | 107k | while (peek_type(p) == TOK_AND) { |
290 | 93 | advance(p); |
291 | 93 | Expr *right = parse_bitwise_or(p, err); |
292 | 93 | if (!right) { expr_free(left); return NULL; } |
293 | 93 | left = expr_binop(BINOP_AND, left, right); |
294 | 93 | } |
295 | 107k | return left; |
296 | 107k | } |
297 | | |
298 | 107k | static Expr *parse_bitwise_or(Parser *p, char **err) { |
299 | 107k | Expr *left = parse_bitwise_xor(p, err); |
300 | 107k | if (!left) return NULL; |
301 | 107k | while (peek_type(p) == TOK_PIPE) { |
302 | 9 | advance(p); |
303 | 9 | Expr *right = parse_bitwise_xor(p, err); |
304 | 9 | if (!right) { expr_free(left); return NULL; } |
305 | 9 | left = expr_binop(BINOP_BIT_OR, left, right); |
306 | 9 | } |
307 | 107k | return left; |
308 | 107k | } |
309 | | |
310 | 107k | static Expr *parse_bitwise_xor(Parser *p, char **err) { |
311 | 107k | Expr *left = parse_bitwise_and(p, err); |
312 | 107k | if (!left) return NULL; |
313 | 107k | while (peek_type(p) == TOK_CARET) { |
314 | 9 | advance(p); |
315 | 9 | Expr *right = parse_bitwise_and(p, err); |
316 | 9 | if (!right) { expr_free(left); return NULL; } |
317 | 9 | left = expr_binop(BINOP_BIT_XOR, left, right); |
318 | 9 | } |
319 | 107k | return left; |
320 | 107k | } |
321 | | |
322 | 107k | static Expr *parse_bitwise_and(Parser *p, char **err) { |
323 | 107k | Expr *left = parse_equality(p, err); |
324 | 107k | if (!left) return NULL; |
325 | 107k | while (peek_type(p) == TOK_AMPERSAND) { |
326 | 12 | advance(p); |
327 | 12 | Expr *right = parse_equality(p, err); |
328 | 12 | if (!right) { expr_free(left); return NULL; } |
329 | 12 | left = expr_binop(BINOP_BIT_AND, left, right); |
330 | 12 | } |
331 | 107k | return left; |
332 | 107k | } |
333 | | |
334 | 107k | static Expr *parse_equality(Parser *p, char **err) { |
335 | 107k | Expr *left = parse_comparison(p, err); |
336 | 107k | if (!left) return NULL; |
337 | 111k | for (;;) { |
338 | 111k | BinOpKind op; |
339 | 111k | if (peek_type(p) == TOK_EQEQ) op = BINOP_EQ; |
340 | 108k | else if (peek_type(p) == TOK_BANGEQ) op = BINOP_NEQ; |
341 | 107k | else break; |
342 | 3.58k | advance(p); |
343 | 3.58k | Expr *right = parse_comparison(p, err); |
344 | 3.58k | if (!right) { expr_free(left); return NULL; } |
345 | 3.58k | left = expr_binop(op, left, right); |
346 | 3.58k | } |
347 | 107k | return left; |
348 | 107k | } |
349 | | |
350 | 111k | static Expr *parse_comparison(Parser *p, char **err) { |
351 | 111k | Expr *left = parse_shift(p, err); |
352 | 111k | if (!left) return NULL; |
353 | 113k | for (;;) { |
354 | 113k | BinOpKind op; |
355 | 113k | if (peek_type(p) == TOK_LT) op = BINOP_LT; |
356 | 112k | else if (peek_type(p) == TOK_GT) op = BINOP_GT; |
357 | 111k | else if (peek_type(p) == TOK_LTEQ) op = BINOP_LTEQ; |
358 | 111k | else if (peek_type(p) == TOK_GTEQ) op = BINOP_GTEQ; |
359 | 111k | else break; |
360 | 1.82k | advance(p); |
361 | 1.82k | Expr *right = parse_shift(p, err); |
362 | 1.82k | if (!right) { expr_free(left); return NULL; } |
363 | 1.82k | left = expr_binop(op, left, right); |
364 | 1.82k | } |
365 | 111k | return left; |
366 | 111k | } |
367 | | |
368 | 113k | static Expr *parse_shift(Parser *p, char **err) { |
369 | 113k | Expr *left = parse_range_expr(p, err); |
370 | 113k | if (!left) return NULL; |
371 | 113k | for (;;) { |
372 | 113k | BinOpKind op; |
373 | 113k | if (peek_type(p) == TOK_LSHIFT) op = BINOP_LSHIFT; |
374 | 113k | else if (peek_type(p) == TOK_RSHIFT) op = BINOP_RSHIFT; |
375 | 113k | else break; |
376 | 9 | advance(p); |
377 | 9 | Expr *right = parse_range_expr(p, err); |
378 | 9 | if (!right) { expr_free(left); return NULL; } |
379 | 9 | left = expr_binop(op, left, right); |
380 | 9 | } |
381 | 113k | return left; |
382 | 113k | } |
383 | | |
384 | 113k | static Expr *parse_range_expr(Parser *p, char **err) { |
385 | 113k | Expr *left = parse_addition(p, err); |
386 | 113k | if (!left) return NULL; |
387 | 113k | if (peek_type(p) == TOK_DOTDOT) { |
388 | 42 | advance(p); |
389 | 42 | Expr *right = parse_addition(p, err); |
390 | 42 | if (!right) { expr_free(left); return NULL; } |
391 | 42 | return expr_range(left, right); |
392 | 42 | } |
393 | 113k | return left; |
394 | 113k | } |
395 | | |
396 | 113k | static Expr *parse_addition(Parser *p, char **err) { |
397 | 113k | Expr *left = parse_multiplication(p, err); |
398 | 113k | if (!left) return NULL; |
399 | 117k | for (;;) { |
400 | 117k | BinOpKind op; |
401 | 117k | if (peek_type(p) == TOK_PLUS) op = BINOP_ADD; |
402 | 113k | else if (peek_type(p) == TOK_MINUS) op = BINOP_SUB; |
403 | 113k | else break; |
404 | 3.85k | advance(p); |
405 | 3.85k | Expr *right = parse_multiplication(p, err); |
406 | 3.85k | if (!right) { expr_free(left); return NULL; } |
407 | 3.85k | left = expr_binop(op, left, right); |
408 | 3.85k | } |
409 | 113k | return left; |
410 | 113k | } |
411 | | |
412 | 117k | static Expr *parse_multiplication(Parser *p, char **err) { |
413 | 117k | Expr *left = parse_unary(p, err); |
414 | 117k | if (!left) return NULL; |
415 | 117k | for (;;) { |
416 | 117k | BinOpKind op; |
417 | 117k | if (peek_type(p) == TOK_STAR) op = BINOP_MUL; |
418 | 117k | else if (peek_type(p) == TOK_SLASH) op = BINOP_DIV; |
419 | 117k | else if (peek_type(p) == TOK_PERCENT) op = BINOP_MOD; |
420 | 117k | else break; |
421 | 177 | advance(p); |
422 | 177 | Expr *right = parse_unary(p, err); |
423 | 177 | if (!right) { expr_free(left); return NULL; } |
424 | 177 | left = expr_binop(op, left, right); |
425 | 177 | } |
426 | 117k | return left; |
427 | 117k | } |
428 | | |
429 | 117k | static Expr *parse_unary(Parser *p, char **err) { |
430 | 117k | if (peek_type(p) == TOK_MINUS) { |
431 | 48 | advance(p); |
432 | 48 | Expr *e = parse_unary(p, err); |
433 | 48 | if (!e) return NULL; |
434 | 48 | return expr_unaryop(UNOP_NEG, e); |
435 | 48 | } |
436 | 117k | if (peek_type(p) == TOK_BANG) { |
437 | 561 | advance(p); |
438 | 561 | Expr *e = parse_unary(p, err); |
439 | 561 | if (!e) return NULL; |
440 | 561 | return expr_unaryop(UNOP_NOT, e); |
441 | 561 | } |
442 | 117k | if (peek_type(p) == TOK_TILDE) { |
443 | 9 | advance(p); |
444 | 9 | Expr *e = parse_unary(p, err); |
445 | 9 | if (!e) return NULL; |
446 | 9 | return expr_unaryop(UNOP_BIT_NOT, e); |
447 | 9 | } |
448 | 117k | return parse_postfix(p, err); |
449 | 117k | } |
450 | | |
451 | 138 | static bool is_struct_literal_ahead(Parser *p) { |
452 | | /* After '{', if we see ident ':' it's a struct literal */ |
453 | 138 | if (peek_ahead_type(p, 1) == TOK_RBRACE) return true; /* empty struct */ |
454 | 138 | return peek_ahead_type(p, 1) == TOK_IDENT && peek_ahead_type(p, 2) == TOK_COLON; |
455 | 138 | } |
456 | | |
457 | 117k | static Expr *parse_postfix(Parser *p, char **err) { |
458 | 117k | Expr *e = parse_primary(p, err); |
459 | 117k | if (!e) return NULL; |
460 | 152k | for (;;) { |
461 | 152k | if (peek_type(p) == TOK_DOT || peek_type(p) == TOK_QUESTION_DOT) { |
462 | 15.9k | bool optional = (peek_type(p) == TOK_QUESTION_DOT); |
463 | 15.9k | advance(p); |
464 | | /* Accept identifier or integer literal for tuple field access (e.g. t.0) */ |
465 | 15.9k | char *field = NULL; |
466 | 15.9k | if (peek_type(p) == TOK_INT_LIT) { |
467 | 18 | char buf[32]; |
468 | 18 | snprintf(buf, sizeof(buf), "%lld", (long long)peek(p)->as.int_val); |
469 | 18 | field = strdup(buf); |
470 | 18 | advance(p); |
471 | 15.9k | } else { |
472 | 15.9k | field = expect_ident(p, err); |
473 | 15.9k | } |
474 | 15.9k | if (!field) { expr_free(e); return NULL; } |
475 | 15.9k | if (peek_type(p) == TOK_LPAREN) { |
476 | 15.6k | advance(p); |
477 | 15.6k | size_t arg_count; |
478 | 15.6k | Expr **args = parse_args(p, &arg_count, err); |
479 | 15.6k | if (!args && *err) { free(field); expr_free(e); return NULL; } |
480 | 15.6k | if (!expect(p, TOK_RPAREN, err)) { |
481 | 0 | free(field); expr_free(e); |
482 | 0 | for (size_t i = 0; i < arg_count; i++) expr_free(args[i]); |
483 | 0 | free(args); |
484 | 0 | return NULL; |
485 | 0 | } |
486 | 15.6k | Expr *mc = expr_method_call(e, field, args, arg_count); |
487 | 15.6k | mc->as.method_call.optional = optional; |
488 | 15.6k | e = mc; |
489 | 15.6k | } else { |
490 | 267 | Expr *fa = expr_field_access(e, field); |
491 | 267 | fa->as.field_access.optional = optional; |
492 | 267 | e = fa; |
493 | 267 | } |
494 | 136k | } else if (peek_type(p) == TOK_LBRACKET || peek_type(p) == TOK_QUESTION_LBRACKET) { |
495 | 3.04k | bool optional = (peek_type(p) == TOK_QUESTION_LBRACKET); |
496 | 3.04k | advance(p); |
497 | 3.04k | Expr *idx = parse_expr(p, err); |
498 | 3.04k | if (!idx) { expr_free(e); return NULL; } |
499 | 3.04k | if (!expect(p, TOK_RBRACKET, err)) { expr_free(e); expr_free(idx); return NULL; } |
500 | 3.04k | Expr *ix = expr_index(e, idx); |
501 | 3.04k | ix->as.index.optional = optional; |
502 | 3.04k | e = ix; |
503 | 133k | } else if (peek_type(p) == TOK_LPAREN && e->tag == EXPR_IDENT) { |
504 | 16.0k | advance(p); |
505 | 16.0k | size_t arg_count; |
506 | 16.0k | Expr **args = parse_args(p, &arg_count, err); |
507 | 16.0k | if (!args && *err) { expr_free(e); return NULL; } |
508 | 16.0k | if (!expect(p, TOK_RPAREN, err)) { |
509 | 0 | expr_free(e); |
510 | 0 | for (size_t i = 0; i < arg_count; i++) expr_free(args[i]); |
511 | 0 | free(args); |
512 | 0 | return NULL; |
513 | 0 | } |
514 | 16.0k | e = expr_call(e, args, arg_count); |
515 | 117k | } else if (peek_type(p) == TOK_QUESTION) { |
516 | | /* Result ? operator — postfix try/propagate */ |
517 | 18 | advance(p); |
518 | 18 | e = expr_try_propagate(e); |
519 | 117k | } else { |
520 | 117k | break; |
521 | 117k | } |
522 | 152k | } |
523 | 117k | return e; |
524 | 117k | } |
525 | | |
526 | 117k | static Expr *parse_primary(Parser *p, char **err) { |
527 | 117k | TokenType tt = peek_type(p); |
528 | | |
529 | 117k | if (tt == TOK_INT_LIT) { |
530 | 10.2k | Token *t = advance(p); |
531 | 10.2k | return expr_int_lit(t->as.int_val); |
532 | 10.2k | } |
533 | 107k | if (tt == TOK_FLOAT_LIT) { |
534 | 324 | Token *t = advance(p); |
535 | 324 | return expr_float_lit(t->as.float_val); |
536 | 324 | } |
537 | 106k | if (tt == TOK_STRING_LIT) { |
538 | 17.8k | Token *t = advance(p); |
539 | 17.8k | return expr_string_lit(strdup(t->as.str_val)); |
540 | 17.8k | } |
541 | 88.8k | if (tt == TOK_INTERP_START) { |
542 | | /* Interpolated string: INTERP_START expr (INTERP_MID expr)* INTERP_END */ |
543 | 48 | size_t cap = 4; |
544 | 48 | size_t count = 0; |
545 | 48 | char **parts = malloc((cap + 1) * sizeof(char *)); |
546 | 48 | Expr **exprs = malloc(cap * sizeof(Expr *)); |
547 | | |
548 | 48 | Token *t = advance(p); /* consume INTERP_START */ |
549 | 48 | parts[0] = strdup(t->as.str_val); |
550 | | |
551 | 78 | for (;;) { |
552 | | /* Parse the interpolated expression */ |
553 | 78 | Expr *e = parse_expr(p, err); |
554 | 78 | if (!e) goto interp_fail; |
555 | 78 | if (count >= cap) { |
556 | 0 | cap *= 2; |
557 | 0 | parts = realloc(parts, (cap + 1) * sizeof(char *)); |
558 | 0 | exprs = realloc(exprs, cap * sizeof(Expr *)); |
559 | 0 | } |
560 | 78 | exprs[count] = e; |
561 | 78 | count++; |
562 | | |
563 | 78 | if (peek_type(p) == TOK_INTERP_MID) { |
564 | 30 | Token *mid = advance(p); |
565 | 30 | parts[count] = strdup(mid->as.str_val); |
566 | 48 | } else if (peek_type(p) == TOK_INTERP_END) { |
567 | 48 | Token *end = advance(p); |
568 | 48 | parts[count] = strdup(end->as.str_val); |
569 | 48 | break; |
570 | 48 | } else { |
571 | 0 | *err = parser_error_fmt(p, "expected interpolation continuation or end, got '%s'", |
572 | 0 | token_type_name(peek_type(p))); |
573 | 0 | goto interp_fail; |
574 | 0 | } |
575 | 78 | } |
576 | 48 | return expr_interp_string(parts, exprs, count); |
577 | | |
578 | 0 | interp_fail: |
579 | 0 | for (size_t i = 0; i <= count; i++) free(parts[i]); |
580 | 0 | free(parts); |
581 | 0 | for (size_t i = 0; i < count; i++) expr_free(exprs[i]); |
582 | 0 | free(exprs); |
583 | 0 | return NULL; |
584 | 48 | } |
585 | 88.7k | if (tt == TOK_TRUE) { advance(p); return expr_bool_lit(true); } |
586 | 87.9k | if (tt == TOK_FALSE) { advance(p); return expr_bool_lit(false); } |
587 | 86.4k | if (tt == TOK_NIL) { advance(p); return expr_nil_lit(); } |
588 | | |
589 | 85.3k | if (tt == TOK_FREEZE) { |
590 | 264 | advance(p); |
591 | 264 | if (!expect(p, TOK_LPAREN, err)) return NULL; |
592 | 264 | Expr *e = parse_expr(p, err); |
593 | 264 | if (!e) return NULL; |
594 | 264 | if (!expect(p, TOK_RPAREN, err)) { expr_free(e); return NULL; } |
595 | | /* Optional 'where' clause: freeze(x) where |v| { ... } */ |
596 | 264 | Expr *contract = NULL; |
597 | 264 | if (peek_type(p) == TOK_IDENT) { |
598 | 72 | Token *maybe_where = peek(p); |
599 | 72 | if (maybe_where->as.str_val && strcmp(maybe_where->as.str_val, "where") == 0) { |
600 | 24 | advance(p); /* consume 'where' */ |
601 | 24 | contract = parse_expr(p, err); |
602 | 24 | if (!contract) { expr_free(e); return NULL; } |
603 | 24 | } |
604 | 72 | } |
605 | | /* Optional 'except' clause: freeze(x) except ["field1", "field2"] */ |
606 | 264 | if (peek_type(p) == TOK_IDENT) { |
607 | 48 | Token *maybe_except = peek(p); |
608 | 48 | if (maybe_except->as.str_val && strcmp(maybe_except->as.str_val, "except") == 0) { |
609 | 9 | advance(p); /* consume 'except' */ |
610 | 9 | if (!expect(p, TOK_LBRACKET, err)) { expr_free(e); if (contract) expr_free(contract); return NULL; } |
611 | 9 | size_t ecap = 4, en = 0; |
612 | 9 | Expr **except_fields = malloc(ecap * sizeof(Expr *)); |
613 | 18 | while (peek_type(p) != TOK_RBRACKET && !at_eof(p)) { |
614 | 9 | Expr *ef = parse_expr(p, err); |
615 | 9 | if (!ef) { for (size_t i = 0; i < en; i++) expr_free(except_fields[i]); free(except_fields); expr_free(e); if (contract) expr_free(contract); return NULL; } |
616 | 9 | if (en >= ecap) { ecap *= 2; except_fields = realloc(except_fields, ecap * sizeof(Expr *)); } |
617 | 9 | except_fields[en++] = ef; |
618 | 9 | if (peek_type(p) != TOK_RBRACKET) { |
619 | 0 | if (!expect(p, TOK_COMMA, err)) { for (size_t i = 0; i < en; i++) expr_free(except_fields[i]); free(except_fields); expr_free(e); if (contract) expr_free(contract); return NULL; } |
620 | 0 | } |
621 | 9 | } |
622 | 9 | if (!expect(p, TOK_RBRACKET, err)) { for (size_t i = 0; i < en; i++) expr_free(except_fields[i]); free(except_fields); expr_free(e); if (contract) expr_free(contract); return NULL; } |
623 | 9 | return expr_freeze_except(e, contract, except_fields, en); |
624 | 9 | } |
625 | 48 | } |
626 | 255 | return expr_freeze(e, contract); |
627 | 264 | } |
628 | 85.1k | if (tt == TOK_THAW) { |
629 | 57 | advance(p); |
630 | 57 | if (!expect(p, TOK_LPAREN, err)) return NULL; |
631 | 57 | Expr *e = parse_expr(p, err); |
632 | 57 | if (!e) return NULL; |
633 | 57 | if (!expect(p, TOK_RPAREN, err)) { expr_free(e); return NULL; } |
634 | 57 | return expr_thaw(e); |
635 | 57 | } |
636 | 85.0k | if (tt == TOK_CLONE) { |
637 | 9 | advance(p); |
638 | 9 | if (!expect(p, TOK_LPAREN, err)) return NULL; |
639 | 9 | Expr *e = parse_expr(p, err); |
640 | 9 | if (!e) return NULL; |
641 | 9 | if (!expect(p, TOK_RPAREN, err)) { expr_free(e); return NULL; } |
642 | 9 | return expr_clone(e); |
643 | 9 | } |
644 | 85.0k | if (tt == TOK_ANNEAL) { |
645 | 21 | advance(p); |
646 | 21 | if (!expect(p, TOK_LPAREN, err)) return NULL; |
647 | 21 | Expr *target = parse_expr(p, err); |
648 | 21 | if (!target) return NULL; |
649 | 21 | if (!expect(p, TOK_RPAREN, err)) { expr_free(target); return NULL; } |
650 | | /* Expect closure: |params| { body } */ |
651 | 21 | if (peek_type(p) != TOK_PIPE) { |
652 | 0 | *err = strdup("anneal requires a closure: anneal(val) |v| { ... }"); |
653 | 0 | expr_free(target); |
654 | 0 | return NULL; |
655 | 0 | } |
656 | 21 | Expr *closure = parse_expr(p, err); |
657 | 21 | if (!closure) { expr_free(target); return NULL; } |
658 | 21 | return expr_anneal(target, closure); |
659 | 21 | } |
660 | 85.0k | if (tt == TOK_CRYSTALLIZE) { |
661 | 12 | advance(p); |
662 | 12 | if (!expect(p, TOK_LPAREN, err)) return NULL; |
663 | 12 | Expr *e = parse_expr(p, err); |
664 | 12 | if (!e) return NULL; |
665 | 12 | if (!expect(p, TOK_RPAREN, err)) { expr_free(e); return NULL; } |
666 | 12 | if (!expect(p, TOK_LBRACE, err)) { expr_free(e); return NULL; } |
667 | 12 | size_t count; |
668 | 12 | Stmt **stmts = parse_block_stmts(p, &count, err); |
669 | 12 | if (!stmts && *err) { expr_free(e); return NULL; } |
670 | 12 | if (!expect(p, TOK_RBRACE, err)) { |
671 | 0 | expr_free(e); |
672 | 0 | for (size_t i = 0; i < count; i++) stmt_free(stmts[i]); |
673 | 0 | free(stmts); |
674 | 0 | return NULL; |
675 | 0 | } |
676 | 12 | return expr_crystallize(e, stmts, count); |
677 | 12 | } |
678 | 85.0k | if (tt == TOK_SUBLIMATE) { |
679 | 15 | advance(p); |
680 | 15 | if (!expect(p, TOK_LPAREN, err)) return NULL; |
681 | 15 | Expr *e = parse_expr(p, err); |
682 | 15 | if (!e) return NULL; |
683 | 15 | if (!expect(p, TOK_RPAREN, err)) { expr_free(e); return NULL; } |
684 | 15 | return expr_sublimate(e); |
685 | 15 | } |
686 | 85.0k | if (tt == TOK_PRINT) { |
687 | 3.27k | advance(p); |
688 | 3.27k | if (!expect(p, TOK_LPAREN, err)) return NULL; |
689 | 3.27k | size_t arg_count; |
690 | 3.27k | Expr **args = parse_args(p, &arg_count, err); |
691 | 3.27k | if (!args && *err) return NULL; |
692 | 3.27k | if (!expect(p, TOK_RPAREN, err)) { |
693 | 0 | for (size_t i = 0; i < arg_count; i++) expr_free(args[i]); |
694 | 0 | free(args); |
695 | 0 | return NULL; |
696 | 0 | } |
697 | 3.27k | return expr_print(args, arg_count); |
698 | 3.27k | } |
699 | 81.7k | if (tt == TOK_FORGE) { |
700 | 3 | advance(p); |
701 | 3 | if (!expect(p, TOK_LBRACE, err)) return NULL; |
702 | 3 | size_t count; |
703 | 3 | Stmt **stmts = parse_block_stmts(p, &count, err); |
704 | 3 | if (!stmts && *err) return NULL; |
705 | 3 | if (!expect(p, TOK_RBRACE, err)) { |
706 | 0 | for (size_t i = 0; i < count; i++) stmt_free(stmts[i]); |
707 | 0 | free(stmts); |
708 | 0 | return NULL; |
709 | 0 | } |
710 | 3 | return expr_forge(stmts, count); |
711 | 3 | } |
712 | 81.7k | if (tt == TOK_SPAWN) { |
713 | 12 | advance(p); |
714 | 12 | if (!expect(p, TOK_LBRACE, err)) return NULL; |
715 | 12 | size_t count; |
716 | 12 | Stmt **stmts = parse_block_stmts(p, &count, err); |
717 | 12 | if (!stmts && *err) return NULL; |
718 | 12 | if (!expect(p, TOK_RBRACE, err)) { |
719 | 0 | for (size_t i = 0; i < count; i++) stmt_free(stmts[i]); |
720 | 0 | free(stmts); |
721 | 0 | return NULL; |
722 | 0 | } |
723 | 12 | return expr_spawn(stmts, count); |
724 | 12 | } |
725 | 81.7k | if (tt == TOK_SCOPE) { |
726 | 9 | advance(p); |
727 | 9 | if (!expect(p, TOK_LBRACE, err)) return NULL; |
728 | 9 | size_t count; |
729 | 9 | Stmt **stmts = parse_block_stmts(p, &count, err); |
730 | 9 | if (!stmts && *err) return NULL; |
731 | 9 | if (!expect(p, TOK_RBRACE, err)) { |
732 | 0 | for (size_t i = 0; i < count; i++) stmt_free(stmts[i]); |
733 | 0 | free(stmts); |
734 | 0 | return NULL; |
735 | 0 | } |
736 | 9 | return expr_scope(stmts, count); |
737 | 9 | } |
738 | 81.7k | if (tt == TOK_TRY) { |
739 | 315 | advance(p); |
740 | 315 | if (!expect(p, TOK_LBRACE, err)) return NULL; |
741 | 315 | size_t try_count; |
742 | 315 | Stmt **try_stmts = parse_block_stmts(p, &try_count, err); |
743 | 315 | if (!try_stmts && *err) return NULL; |
744 | 315 | if (!expect(p, TOK_RBRACE, err)) { |
745 | 0 | for (size_t i = 0; i < try_count; i++) stmt_free(try_stmts[i]); |
746 | 0 | free(try_stmts); |
747 | 0 | return NULL; |
748 | 0 | } |
749 | 315 | if (!expect(p, TOK_CATCH, err)) { |
750 | 0 | for (size_t i = 0; i < try_count; i++) stmt_free(try_stmts[i]); |
751 | 0 | free(try_stmts); |
752 | 0 | return NULL; |
753 | 0 | } |
754 | 315 | char *catch_var = expect_ident(p, err); |
755 | 315 | if (!catch_var) { |
756 | 0 | for (size_t i = 0; i < try_count; i++) stmt_free(try_stmts[i]); |
757 | 0 | free(try_stmts); |
758 | 0 | return NULL; |
759 | 0 | } |
760 | 315 | if (!expect(p, TOK_LBRACE, err)) { |
761 | 0 | for (size_t i = 0; i < try_count; i++) stmt_free(try_stmts[i]); |
762 | 0 | free(try_stmts); free(catch_var); |
763 | 0 | return NULL; |
764 | 0 | } |
765 | 315 | size_t catch_count; |
766 | 315 | Stmt **catch_stmts = parse_block_stmts(p, &catch_count, err); |
767 | 315 | if (!catch_stmts && *err) { |
768 | 0 | for (size_t i = 0; i < try_count; i++) stmt_free(try_stmts[i]); |
769 | 0 | free(try_stmts); free(catch_var); |
770 | 0 | return NULL; |
771 | 0 | } |
772 | 315 | if (!expect(p, TOK_RBRACE, err)) { |
773 | 0 | for (size_t i = 0; i < try_count; i++) stmt_free(try_stmts[i]); |
774 | 0 | free(try_stmts); free(catch_var); |
775 | 0 | for (size_t i = 0; i < catch_count; i++) stmt_free(catch_stmts[i]); |
776 | 0 | free(catch_stmts); |
777 | 0 | return NULL; |
778 | 0 | } |
779 | 315 | return expr_try_catch(try_stmts, try_count, catch_var, catch_stmts, catch_count); |
780 | 315 | } |
781 | 81.4k | if (tt == TOK_IDENT && peek(p)->as.str_val && |
782 | 81.4k | strcmp(peek(p)->as.str_val, "select") == 0 && |
783 | 81.4k | p->pos + 1 < p->count && |
784 | 81.4k | p->tokens[p->pos + 1].type == TOK_LBRACE) { |
785 | 15 | advance(p); |
786 | 15 | if (!expect(p, TOK_LBRACE, err)) return NULL; |
787 | 15 | size_t cap = 4, n = 0; |
788 | 15 | SelectArm *arms = malloc(cap * sizeof(SelectArm)); |
789 | 42 | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
790 | 27 | if (n >= cap) { cap *= 2; arms = realloc(arms, cap * sizeof(SelectArm)); } |
791 | 27 | memset(&arms[n], 0, sizeof(SelectArm)); |
792 | | /* Check for 'default' arm */ |
793 | 27 | if (peek_type(p) == TOK_IDENT && peek(p)->as.str_val && |
794 | 27 | strcmp(peek(p)->as.str_val, "default") == 0) { |
795 | 9 | advance(p); |
796 | 9 | arms[n].is_default = true; |
797 | 9 | if (!expect(p, TOK_FATARROW, err)) goto select_fail; |
798 | 9 | if (!expect(p, TOK_LBRACE, err)) goto select_fail; |
799 | 9 | arms[n].body = parse_block_stmts(p, &arms[n].body_count, err); |
800 | 9 | if (!arms[n].body && *err) goto select_fail; |
801 | 9 | if (!expect(p, TOK_RBRACE, err)) goto select_fail; |
802 | 9 | n++; |
803 | 9 | if (peek_type(p) == TOK_COMMA) advance(p); |
804 | 9 | continue; |
805 | 9 | } |
806 | | /* Check for 'timeout(expr)' arm */ |
807 | 18 | if (peek_type(p) == TOK_IDENT && peek(p)->as.str_val && |
808 | 18 | strcmp(peek(p)->as.str_val, "timeout") == 0) { |
809 | 0 | advance(p); |
810 | 0 | arms[n].is_timeout = true; |
811 | 0 | if (!expect(p, TOK_LPAREN, err)) goto select_fail; |
812 | 0 | arms[n].timeout_expr = parse_expr(p, err); |
813 | 0 | if (!arms[n].timeout_expr) goto select_fail; |
814 | 0 | if (!expect(p, TOK_RPAREN, err)) goto select_fail; |
815 | 0 | if (!expect(p, TOK_FATARROW, err)) goto select_fail; |
816 | 0 | if (!expect(p, TOK_LBRACE, err)) goto select_fail; |
817 | 0 | arms[n].body = parse_block_stmts(p, &arms[n].body_count, err); |
818 | 0 | if (!arms[n].body && *err) goto select_fail; |
819 | 0 | if (!expect(p, TOK_RBRACE, err)) goto select_fail; |
820 | 0 | n++; |
821 | 0 | if (peek_type(p) == TOK_COMMA) advance(p); |
822 | 0 | continue; |
823 | 0 | } |
824 | | /* Normal arm: binding from channel_expr => { body } */ |
825 | 18 | arms[n].binding_name = expect_ident(p, err); |
826 | 18 | if (!arms[n].binding_name) goto select_fail; |
827 | 18 | if (!expect(p, TOK_FROM, err)) goto select_fail; |
828 | 18 | arms[n].channel_expr = parse_expr(p, err); |
829 | 18 | if (!arms[n].channel_expr) goto select_fail; |
830 | 18 | if (!expect(p, TOK_FATARROW, err)) goto select_fail; |
831 | 18 | if (!expect(p, TOK_LBRACE, err)) goto select_fail; |
832 | 18 | arms[n].body = parse_block_stmts(p, &arms[n].body_count, err); |
833 | 18 | if (!arms[n].body && *err) goto select_fail; |
834 | 18 | if (!expect(p, TOK_RBRACE, err)) goto select_fail; |
835 | 18 | n++; |
836 | 18 | if (peek_type(p) == TOK_COMMA) advance(p); |
837 | 18 | } |
838 | 15 | if (!expect(p, TOK_RBRACE, err)) { |
839 | 0 | select_fail: |
840 | 0 | for (size_t i = 0; i < n; i++) { |
841 | 0 | free(arms[i].binding_name); |
842 | 0 | if (arms[i].channel_expr) expr_free(arms[i].channel_expr); |
843 | 0 | if (arms[i].timeout_expr) expr_free(arms[i].timeout_expr); |
844 | 0 | for (size_t j = 0; j < arms[i].body_count; j++) stmt_free(arms[i].body[j]); |
845 | 0 | free(arms[i].body); |
846 | 0 | } |
847 | 0 | free(arms); |
848 | 0 | return NULL; |
849 | 0 | } |
850 | 15 | return expr_select(arms, n); |
851 | 15 | } |
852 | 81.3k | if (tt == TOK_MATCH) { |
853 | 45 | advance(p); |
854 | 45 | Expr *scrutinee = parse_expr(p, err); |
855 | 45 | if (!scrutinee) return NULL; |
856 | 45 | if (!expect(p, TOK_LBRACE, err)) { expr_free(scrutinee); return NULL; } |
857 | | |
858 | 45 | size_t cap = 4, n = 0; |
859 | 45 | MatchArm *arms = malloc(cap * sizeof(MatchArm)); |
860 | | |
861 | 147 | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
862 | 102 | if (n >= cap) { cap *= 2; arms = realloc(arms, cap * sizeof(MatchArm)); } |
863 | | |
864 | | /* Parse optional phase qualifier: fluid/crystal */ |
865 | 102 | AstPhase phase_qual = PHASE_UNSPECIFIED; |
866 | 102 | if (peek_type(p) == TOK_IDENT) { |
867 | 75 | Token *maybe_phase = peek(p); |
868 | 75 | if (maybe_phase->as.str_val && |
869 | 75 | (strcmp(maybe_phase->as.str_val, "fluid") == 0 || |
870 | 75 | strcmp(maybe_phase->as.str_val, "crystal") == 0)) { |
871 | 24 | TokenType next = peek_ahead_type(p, 1); |
872 | 24 | if (next == TOK_IDENT || next == TOK_INT_LIT || next == TOK_FLOAT_LIT || |
873 | 24 | next == TOK_STRING_LIT || next == TOK_TRUE || next == TOK_FALSE || |
874 | 24 | next == TOK_NIL || next == TOK_MINUS) { |
875 | 24 | phase_qual = strcmp(maybe_phase->as.str_val, "fluid") == 0 |
876 | 24 | ? PHASE_FLUID : PHASE_CRYSTAL; |
877 | 24 | advance(p); |
878 | 24 | } |
879 | 24 | } |
880 | 75 | } |
881 | | |
882 | | /* Parse pattern */ |
883 | 102 | Pattern *pat = NULL; |
884 | 102 | TokenType pt = peek_type(p); |
885 | 102 | if (pt == TOK_INT_LIT) { |
886 | 21 | Token *t = advance(p); |
887 | | /* Check for range pattern: int..int */ |
888 | 21 | if (peek_type(p) == TOK_DOTDOT) { |
889 | 6 | advance(p); |
890 | 6 | Expr *start = expr_int_lit(t->as.int_val); |
891 | 6 | Expr *end = parse_expr(p, err); |
892 | 6 | if (!end) { expr_free(start); goto match_fail; } |
893 | 6 | pat = pattern_range(start, end); |
894 | 15 | } else { |
895 | 15 | pat = pattern_literal(expr_int_lit(t->as.int_val)); |
896 | 15 | } |
897 | 81 | } else if (pt == TOK_FLOAT_LIT) { |
898 | 0 | Token *t = advance(p); |
899 | 0 | pat = pattern_literal(expr_float_lit(t->as.float_val)); |
900 | 81 | } else if (pt == TOK_STRING_LIT) { |
901 | 6 | Token *t = advance(p); |
902 | 6 | pat = pattern_literal(expr_string_lit(strdup(t->as.str_val))); |
903 | 75 | } else if (pt == TOK_TRUE) { |
904 | 0 | advance(p); |
905 | 0 | pat = pattern_literal(expr_bool_lit(true)); |
906 | 75 | } else if (pt == TOK_FALSE) { |
907 | 0 | advance(p); |
908 | 0 | pat = pattern_literal(expr_bool_lit(false)); |
909 | 75 | } else if (pt == TOK_NIL) { |
910 | 3 | advance(p); |
911 | 3 | pat = pattern_literal(expr_nil_lit()); |
912 | 72 | } else if (pt == TOK_IDENT) { |
913 | 69 | Token *t = advance(p); |
914 | 69 | if (strcmp(t->as.str_val, "_") == 0) { |
915 | 54 | pat = pattern_wildcard(); |
916 | 54 | } else { |
917 | | /* Check for range: ident..expr */ |
918 | 15 | if (peek_type(p) == TOK_DOTDOT) { |
919 | 0 | advance(p); |
920 | 0 | Expr *start = expr_ident(strdup(t->as.str_val)); |
921 | 0 | Expr *end = parse_expr(p, err); |
922 | 0 | if (!end) { expr_free(start); goto match_fail; } |
923 | 0 | pat = pattern_range(start, end); |
924 | 15 | } else { |
925 | 15 | pat = pattern_binding(strdup(t->as.str_val)); |
926 | 15 | } |
927 | 15 | } |
928 | 69 | } else if (pt == TOK_MINUS) { |
929 | | /* Negative literal: -1, -3.14 */ |
930 | 3 | advance(p); |
931 | 3 | if (peek_type(p) == TOK_INT_LIT) { |
932 | 3 | Token *t = advance(p); |
933 | 3 | pat = pattern_literal(expr_int_lit(-t->as.int_val)); |
934 | 3 | } else if (peek_type(p) == TOK_FLOAT_LIT) { |
935 | 0 | Token *t = advance(p); |
936 | 0 | pat = pattern_literal(expr_float_lit(-t->as.float_val)); |
937 | 0 | } else { |
938 | 0 | *err = strdup("expected number after '-' in pattern"); |
939 | 0 | goto match_fail; |
940 | 0 | } |
941 | 3 | } else { |
942 | 0 | *err = strdup("expected pattern in match arm"); |
943 | 0 | goto match_fail; |
944 | 0 | } |
945 | | |
946 | | /* Apply phase qualifier to pattern */ |
947 | 102 | if (pat) pat->phase_qualifier = phase_qual; |
948 | | |
949 | | /* Optional guard: if expr */ |
950 | 102 | Expr *guard = NULL; |
951 | 102 | if (peek_type(p) == TOK_IF) { |
952 | 6 | advance(p); |
953 | 6 | guard = parse_expr(p, err); |
954 | 6 | if (!guard) { pattern_free(pat); goto match_fail; } |
955 | 6 | } |
956 | | |
957 | | /* => */ |
958 | 102 | if (!expect(p, TOK_FATARROW, err)) { |
959 | 0 | pattern_free(pat); |
960 | 0 | if (guard) expr_free(guard); |
961 | 0 | goto match_fail; |
962 | 0 | } |
963 | | |
964 | | /* Arm body: either { stmts } block or single expression */ |
965 | 102 | Stmt **body = NULL; |
966 | 102 | size_t body_count = 0; |
967 | 102 | if (peek_type(p) == TOK_LBRACE) { |
968 | 3 | advance(p); |
969 | 3 | body = parse_block_stmts(p, &body_count, err); |
970 | 3 | if (!body && *err) { |
971 | 0 | pattern_free(pat); |
972 | 0 | if (guard) expr_free(guard); |
973 | 0 | goto match_fail; |
974 | 0 | } |
975 | 3 | if (!expect(p, TOK_RBRACE, err)) { |
976 | 0 | pattern_free(pat); |
977 | 0 | if (guard) expr_free(guard); |
978 | 0 | for (size_t i = 0; i < body_count; i++) stmt_free(body[i]); |
979 | 0 | free(body); |
980 | 0 | goto match_fail; |
981 | 0 | } |
982 | 99 | } else { |
983 | 99 | Expr *arm_expr = parse_expr(p, err); |
984 | 99 | if (!arm_expr) { |
985 | 0 | pattern_free(pat); |
986 | 0 | if (guard) expr_free(guard); |
987 | 0 | goto match_fail; |
988 | 0 | } |
989 | 99 | body = malloc(sizeof(Stmt *)); |
990 | 99 | body[0] = stmt_expr(arm_expr); |
991 | 99 | body_count = 1; |
992 | 99 | } |
993 | | |
994 | 102 | arms[n].pattern = pat; |
995 | 102 | arms[n].guard = guard; |
996 | 102 | arms[n].body = body; |
997 | 102 | arms[n].body_count = body_count; |
998 | 102 | n++; |
999 | | |
1000 | | /* Optional comma between arms */ |
1001 | 102 | if (peek_type(p) == TOK_COMMA) advance(p); |
1002 | 102 | } |
1003 | | |
1004 | 45 | if (!expect(p, TOK_RBRACE, err)) { |
1005 | 0 | match_fail: |
1006 | 0 | for (size_t i = 0; i < n; i++) { |
1007 | 0 | pattern_free(arms[i].pattern); |
1008 | 0 | if (arms[i].guard) expr_free(arms[i].guard); |
1009 | 0 | for (size_t j = 0; j < arms[i].body_count; j++) stmt_free(arms[i].body[j]); |
1010 | 0 | free(arms[i].body); |
1011 | 0 | } |
1012 | 0 | free(arms); |
1013 | 0 | expr_free(scrutinee); |
1014 | 0 | return NULL; |
1015 | 0 | } |
1016 | 45 | return expr_match(scrutinee, arms, n); |
1017 | 45 | } |
1018 | 81.3k | if (tt == TOK_IF) { |
1019 | 7.27k | advance(p); |
1020 | 7.27k | Expr *cond = parse_expr(p, err); |
1021 | 7.27k | if (!cond) return NULL; |
1022 | 7.27k | if (!expect(p, TOK_LBRACE, err)) { expr_free(cond); return NULL; } |
1023 | 7.27k | size_t then_count; |
1024 | 7.27k | Stmt **then_stmts = parse_block_stmts(p, &then_count, err); |
1025 | 7.27k | if (!then_stmts && *err) { expr_free(cond); return NULL; } |
1026 | 7.27k | if (!expect(p, TOK_RBRACE, err)) { |
1027 | 0 | expr_free(cond); |
1028 | 0 | for (size_t i = 0; i < then_count; i++) stmt_free(then_stmts[i]); |
1029 | 0 | free(then_stmts); |
1030 | 0 | return NULL; |
1031 | 0 | } |
1032 | 7.27k | Stmt **else_stmts = NULL; |
1033 | 7.27k | size_t else_count = 0; |
1034 | 7.27k | if (peek_type(p) == TOK_ELSE) { |
1035 | 1.29k | advance(p); |
1036 | 1.29k | if (peek_type(p) == TOK_IF) { |
1037 | | /* else if → desugar to else { if ... } */ |
1038 | 18 | Expr *inner_if = parse_primary(p, err); |
1039 | 18 | if (!inner_if) { |
1040 | 0 | expr_free(cond); |
1041 | 0 | for (size_t i = 0; i < then_count; i++) stmt_free(then_stmts[i]); |
1042 | 0 | free(then_stmts); |
1043 | 0 | return NULL; |
1044 | 0 | } |
1045 | 18 | else_stmts = malloc(sizeof(Stmt *)); |
1046 | 18 | else_stmts[0] = stmt_expr(inner_if); |
1047 | 18 | else_count = 1; |
1048 | 1.27k | } else { |
1049 | 1.27k | if (!expect(p, TOK_LBRACE, err)) { |
1050 | 0 | expr_free(cond); |
1051 | 0 | for (size_t i = 0; i < then_count; i++) stmt_free(then_stmts[i]); |
1052 | 0 | free(then_stmts); |
1053 | 0 | return NULL; |
1054 | 0 | } |
1055 | 1.27k | else_stmts = parse_block_stmts(p, &else_count, err); |
1056 | 1.27k | if (!else_stmts && *err) { |
1057 | 0 | expr_free(cond); |
1058 | 0 | for (size_t i = 0; i < then_count; i++) stmt_free(then_stmts[i]); |
1059 | 0 | free(then_stmts); |
1060 | 0 | return NULL; |
1061 | 0 | } |
1062 | 1.27k | if (!expect(p, TOK_RBRACE, err)) { |
1063 | 0 | expr_free(cond); |
1064 | 0 | for (size_t i = 0; i < then_count; i++) stmt_free(then_stmts[i]); |
1065 | 0 | free(then_stmts); |
1066 | 0 | for (size_t i = 0; i < else_count; i++) stmt_free(else_stmts[i]); |
1067 | 0 | free(else_stmts); |
1068 | 0 | return NULL; |
1069 | 0 | } |
1070 | 1.27k | } |
1071 | 1.29k | } |
1072 | 7.27k | return expr_if(cond, then_stmts, then_count, else_stmts, else_count); |
1073 | 7.27k | } |
1074 | 74.0k | if (tt == TOK_LBRACKET) { |
1075 | 1.90k | advance(p); |
1076 | 1.90k | size_t cap = 4; |
1077 | 1.90k | size_t n = 0; |
1078 | 1.90k | Expr **elems = malloc(cap * sizeof(Expr *)); |
1079 | 5.24k | while (peek_type(p) != TOK_RBRACKET && !at_eof(p)) { |
1080 | 3.33k | bool is_spread = false; |
1081 | 3.33k | if (peek_type(p) == TOK_DOTDOTDOT) { |
1082 | 27 | advance(p); |
1083 | 27 | is_spread = true; |
1084 | 27 | } |
1085 | 3.33k | Expr *e = parse_expr(p, err); |
1086 | 3.33k | if (!e) { |
1087 | 0 | for (size_t i = 0; i < n; i++) expr_free(elems[i]); |
1088 | 0 | free(elems); |
1089 | 0 | return NULL; |
1090 | 0 | } |
1091 | 3.33k | if (is_spread) e = expr_spread(e); |
1092 | 3.33k | if (n >= cap) { cap *= 2; elems = realloc(elems, cap * sizeof(Expr *)); } |
1093 | 3.33k | elems[n++] = e; |
1094 | 3.33k | if (peek_type(p) != TOK_RBRACKET) { |
1095 | 1.86k | if (!expect(p, TOK_COMMA, err)) { |
1096 | 0 | for (size_t i = 0; i < n; i++) expr_free(elems[i]); |
1097 | 0 | free(elems); |
1098 | 0 | return NULL; |
1099 | 0 | } |
1100 | 1.86k | } |
1101 | 3.33k | } |
1102 | 1.90k | if (!expect(p, TOK_RBRACKET, err)) { |
1103 | 0 | for (size_t i = 0; i < n; i++) expr_free(elems[i]); |
1104 | 0 | free(elems); |
1105 | 0 | return NULL; |
1106 | 0 | } |
1107 | 1.90k | return expr_array(elems, n); |
1108 | 1.90k | } |
1109 | 72.1k | if (tt == TOK_LPAREN) { |
1110 | 33 | advance(p); |
1111 | 33 | Expr *first = parse_expr(p, err); |
1112 | 33 | if (!first) return NULL; |
1113 | | /* Check for comma: (expr, ...) is a tuple, (expr) is grouping */ |
1114 | 33 | if (peek_type(p) == TOK_COMMA) { |
1115 | 33 | advance(p); |
1116 | 33 | size_t cap = 4, n = 1; |
1117 | 33 | Expr **elems = malloc(cap * sizeof(Expr *)); |
1118 | 33 | elems[0] = first; |
1119 | | /* (expr,) is a single-element tuple */ |
1120 | 93 | while (peek_type(p) != TOK_RPAREN && !at_eof(p)) { |
1121 | 60 | Expr *e = parse_expr(p, err); |
1122 | 60 | if (!e) { |
1123 | 0 | for (size_t i = 0; i < n; i++) expr_free(elems[i]); |
1124 | 0 | free(elems); |
1125 | 0 | return NULL; |
1126 | 0 | } |
1127 | 60 | if (n >= cap) { cap *= 2; elems = realloc(elems, cap * sizeof(Expr *)); } |
1128 | 60 | elems[n++] = e; |
1129 | 60 | if (peek_type(p) != TOK_RPAREN) { |
1130 | 30 | if (!expect(p, TOK_COMMA, err)) { |
1131 | 0 | for (size_t i = 0; i < n; i++) expr_free(elems[i]); |
1132 | 0 | free(elems); |
1133 | 0 | return NULL; |
1134 | 0 | } |
1135 | 30 | } |
1136 | 60 | } |
1137 | 33 | if (!expect(p, TOK_RPAREN, err)) { |
1138 | 0 | for (size_t i = 0; i < n; i++) expr_free(elems[i]); |
1139 | 0 | free(elems); |
1140 | 0 | return NULL; |
1141 | 0 | } |
1142 | 33 | return expr_tuple(elems, n); |
1143 | 33 | } |
1144 | 0 | if (!expect(p, TOK_RPAREN, err)) { expr_free(first); return NULL; } |
1145 | 0 | return first; |
1146 | 0 | } |
1147 | 72.1k | if (tt == TOK_LBRACE) { |
1148 | 1.85k | advance(p); |
1149 | 1.85k | size_t count; |
1150 | 1.85k | Stmt **stmts = parse_block_stmts(p, &count, err); |
1151 | 1.85k | if (!stmts && *err) return NULL; |
1152 | 1.85k | if (!expect(p, TOK_RBRACE, err)) { |
1153 | 0 | for (size_t i = 0; i < count; i++) stmt_free(stmts[i]); |
1154 | 0 | free(stmts); |
1155 | 0 | return NULL; |
1156 | 0 | } |
1157 | 1.85k | return expr_block(stmts, count); |
1158 | 1.85k | } |
1159 | 70.2k | if (tt == TOK_PIPE) { |
1160 | | /* Closure: |params| expr or |a, b = 1, ...rest| expr */ |
1161 | 1.92k | advance(p); |
1162 | 1.92k | size_t cap = 4; |
1163 | 1.92k | size_t n = 0; |
1164 | 1.92k | char **params = malloc(cap * sizeof(char *)); |
1165 | 1.92k | Expr **defaults = calloc(cap, sizeof(Expr *)); |
1166 | 1.92k | bool has_variadic = false; |
1167 | 1.92k | bool seen_default = false; |
1168 | 4.03k | while (peek_type(p) != TOK_PIPE && !at_eof(p)) { |
1169 | 2.11k | if (has_variadic) { |
1170 | 0 | *err = strdup("variadic parameter must be last"); |
1171 | 0 | for (size_t i = 0; i < n; i++) { free(params[i]); if (defaults[i]) expr_free(defaults[i]); } |
1172 | 0 | free(params); free(defaults); |
1173 | 0 | return NULL; |
1174 | 0 | } |
1175 | | /* Check for variadic: ...name */ |
1176 | 2.11k | bool is_variadic = false; |
1177 | 2.11k | if (peek_type(p) == TOK_DOTDOTDOT) { |
1178 | 276 | advance(p); |
1179 | 276 | is_variadic = true; |
1180 | 276 | has_variadic = true; |
1181 | 276 | } |
1182 | 2.11k | char *name = expect_ident(p, err); |
1183 | 2.11k | if (!name) { |
1184 | 0 | for (size_t i = 0; i < n; i++) { free(params[i]); if (defaults[i]) expr_free(defaults[i]); } |
1185 | 0 | free(params); free(defaults); |
1186 | 0 | return NULL; |
1187 | 0 | } |
1188 | 2.11k | if (n >= cap) { |
1189 | 0 | cap *= 2; |
1190 | 0 | params = realloc(params, cap * sizeof(char *)); |
1191 | 0 | defaults = realloc(defaults, cap * sizeof(Expr *)); |
1192 | 0 | for (size_t i = n; i < cap; i++) defaults[i] = NULL; |
1193 | 0 | } |
1194 | 2.11k | params[n] = name; |
1195 | 2.11k | defaults[n] = NULL; |
1196 | | /* Check for default value: = expr (not for variadic params) |
1197 | | * Use parse_bitwise_xor to avoid consuming | as bitwise OR, |
1198 | | * since | delimits closure parameters. */ |
1199 | 2.11k | if (!is_variadic && peek_type(p) == TOK_EQ) { |
1200 | 21 | advance(p); |
1201 | 21 | seen_default = true; |
1202 | 21 | Expr *def = parse_bitwise_xor(p, err); |
1203 | 21 | if (!def) { |
1204 | 0 | for (size_t i = 0; i <= n; i++) { free(params[i]); if (defaults[i]) expr_free(defaults[i]); } |
1205 | 0 | free(params); free(defaults); |
1206 | 0 | return NULL; |
1207 | 0 | } |
1208 | 21 | defaults[n] = def; |
1209 | 2.09k | } else if (seen_default && !is_variadic) { |
1210 | 0 | *err = strdup("required parameter cannot follow a parameter with a default value"); |
1211 | 0 | free(name); |
1212 | 0 | for (size_t i = 0; i < n; i++) { free(params[i]); if (defaults[i]) expr_free(defaults[i]); } |
1213 | 0 | free(params); free(defaults); |
1214 | 0 | return NULL; |
1215 | 0 | } |
1216 | 2.11k | n++; |
1217 | 2.11k | if (peek_type(p) != TOK_PIPE) { |
1218 | 192 | if (!expect(p, TOK_COMMA, err)) { |
1219 | 0 | for (size_t i = 0; i < n; i++) { free(params[i]); if (defaults[i]) expr_free(defaults[i]); } |
1220 | 0 | free(params); free(defaults); |
1221 | 0 | return NULL; |
1222 | 0 | } |
1223 | 192 | } |
1224 | 2.11k | } |
1225 | 1.92k | if (!expect(p, TOK_PIPE, err)) { |
1226 | 0 | for (size_t i = 0; i < n; i++) { free(params[i]); if (defaults[i]) expr_free(defaults[i]); } |
1227 | 0 | free(params); free(defaults); |
1228 | 0 | return NULL; |
1229 | 0 | } |
1230 | 1.92k | Expr *body = parse_expr(p, err); |
1231 | 1.92k | if (!body) { |
1232 | 0 | for (size_t i = 0; i < n; i++) { free(params[i]); if (defaults[i]) expr_free(defaults[i]); } |
1233 | 0 | free(params); free(defaults); |
1234 | 0 | return NULL; |
1235 | 0 | } |
1236 | | /* Check if any defaults were actually used */ |
1237 | 1.92k | bool any_defaults = false; |
1238 | 4.01k | for (size_t i = 0; i < n; i++) { if (defaults[i]) { any_defaults = true; break; } } |
1239 | 1.92k | if (!any_defaults && !has_variadic) { free(defaults); defaults = NULL; } |
1240 | 1.92k | return expr_closure(params, n, body, defaults, has_variadic); |
1241 | 1.92k | } |
1242 | 68.3k | if (tt == TOK_IDENT) { |
1243 | 68.3k | Token *t = advance(p); |
1244 | 68.3k | char *name = strdup(t->as.str_val); |
1245 | | /* Struct literal: Name { field: value, ... } */ |
1246 | 68.3k | if (peek_type(p) == TOK_LBRACE && isupper((unsigned char)name[0]) && is_struct_literal_ahead(p)) { |
1247 | 138 | advance(p); /* { */ |
1248 | 138 | size_t cap = 4; |
1249 | 138 | size_t n = 0; |
1250 | 138 | FieldInit *fields = malloc(cap * sizeof(FieldInit)); |
1251 | 402 | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
1252 | 264 | if (n >= cap) { cap *= 2; fields = realloc(fields, cap * sizeof(FieldInit)); } |
1253 | 264 | fields[n].name = expect_ident(p, err); |
1254 | 264 | if (!fields[n].name) { |
1255 | 0 | for (size_t i = 0; i < n; i++) { free(fields[i].name); expr_free(fields[i].value); } |
1256 | 0 | free(fields); free(name); |
1257 | 0 | return NULL; |
1258 | 0 | } |
1259 | 264 | if (!expect(p, TOK_COLON, err)) { |
1260 | 0 | free(fields[n].name); |
1261 | 0 | for (size_t i = 0; i < n; i++) { free(fields[i].name); expr_free(fields[i].value); } |
1262 | 0 | free(fields); free(name); |
1263 | 0 | return NULL; |
1264 | 0 | } |
1265 | 264 | fields[n].value = parse_expr(p, err); |
1266 | 264 | if (!fields[n].value) { |
1267 | 0 | free(fields[n].name); |
1268 | 0 | for (size_t i = 0; i < n; i++) { free(fields[i].name); expr_free(fields[i].value); } |
1269 | 0 | free(fields); free(name); |
1270 | 0 | return NULL; |
1271 | 0 | } |
1272 | 264 | n++; |
1273 | 264 | if (peek_type(p) != TOK_RBRACE) { |
1274 | 132 | if (!expect(p, TOK_COMMA, err)) { |
1275 | 0 | for (size_t i = 0; i < n; i++) { free(fields[i].name); expr_free(fields[i].value); } |
1276 | 0 | free(fields); free(name); |
1277 | 0 | return NULL; |
1278 | 0 | } |
1279 | 132 | } |
1280 | 264 | } |
1281 | 138 | if (!expect(p, TOK_RBRACE, err)) { |
1282 | 0 | for (size_t i = 0; i < n; i++) { free(fields[i].name); expr_free(fields[i].value); } |
1283 | 0 | free(fields); free(name); |
1284 | 0 | return NULL; |
1285 | 0 | } |
1286 | 138 | return expr_struct_lit(name, fields, n); |
1287 | 138 | } |
1288 | | /* Name::Variant or Name::method() */ |
1289 | 68.2k | if (peek_type(p) == TOK_COLONCOLON) { |
1290 | 1.64k | advance(p); |
1291 | | /* Accept contextual keywords (e.g. 'from' in Set::from) as identifiers */ |
1292 | 1.64k | char *rhs = NULL; |
1293 | 1.64k | if (peek_type(p) == TOK_FROM) { |
1294 | 60 | advance(p); |
1295 | 60 | rhs = strdup("from"); |
1296 | 1.58k | } else { |
1297 | 1.58k | rhs = expect_ident(p, err); |
1298 | 1.58k | } |
1299 | 1.64k | if (!rhs) { free(name); return NULL; } |
1300 | | |
1301 | 1.64k | if (peek_type(p) == TOK_LPAREN) { |
1302 | | /* Could be enum variant with args or static method call. |
1303 | | * We parse as enum variant; the evaluator falls back to |
1304 | | * static call if no enum matches. */ |
1305 | 1.61k | advance(p); |
1306 | 1.61k | size_t arg_count; |
1307 | 1.61k | Expr **args = parse_args(p, &arg_count, err); |
1308 | 1.61k | if (!args && *err) { free(name); free(rhs); return NULL; } |
1309 | 1.61k | if (!expect(p, TOK_RPAREN, err)) { |
1310 | 0 | free(name); free(rhs); |
1311 | 0 | for (size_t i = 0; i < arg_count; i++) expr_free(args[i]); |
1312 | 0 | free(args); |
1313 | 0 | return NULL; |
1314 | 0 | } |
1315 | 1.61k | return expr_enum_variant(name, rhs, args, arg_count); |
1316 | 1.61k | } |
1317 | | /* Unit variant (or identifier) */ |
1318 | 30 | return expr_enum_variant(name, rhs, NULL, 0); |
1319 | 1.64k | } |
1320 | 66.5k | return expr_ident(name); |
1321 | 68.2k | } |
1322 | | |
1323 | 0 | *err = parser_error_fmt(p, "unexpected token '%s' in expression", |
1324 | 0 | token_type_name(peek_type(p))); |
1325 | 0 | return NULL; |
1326 | 68.3k | } |
1327 | | |
1328 | | /* ── Statements ── */ |
1329 | | |
1330 | 13.4k | static Stmt *parse_binding(Parser *p, AstPhase phase, char **err) { |
1331 | 13.4k | advance(p); /* consume flux/fix/let */ |
1332 | | |
1333 | | /* Array destructuring: let [a, b, ...rest] = expr */ |
1334 | 13.4k | if (peek_type(p) == TOK_LBRACKET) { |
1335 | 18 | advance(p); |
1336 | 18 | size_t cap = 4, n = 0; |
1337 | 18 | char **names = malloc(cap * sizeof(char *)); |
1338 | 18 | char *rest_name = NULL; |
1339 | 54 | while (peek_type(p) != TOK_RBRACKET && !at_eof(p)) { |
1340 | 45 | if (n >= cap) { cap *= 2; names = realloc(names, cap * sizeof(char *)); } |
1341 | 45 | if (peek_type(p) == TOK_DOTDOTDOT) { |
1342 | 9 | advance(p); |
1343 | 9 | rest_name = expect_ident(p, err); |
1344 | 9 | if (!rest_name) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); return NULL; } |
1345 | 9 | break; |
1346 | 9 | } |
1347 | 36 | names[n] = expect_ident(p, err); |
1348 | 36 | if (!names[n]) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); return NULL; } |
1349 | 36 | n++; |
1350 | 36 | if (peek_type(p) != TOK_RBRACKET && peek_type(p) != TOK_DOTDOTDOT) { |
1351 | 27 | if (!expect(p, TOK_COMMA, err)) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); free(rest_name); return NULL; } |
1352 | 27 | } |
1353 | 36 | } |
1354 | 18 | if (!expect(p, TOK_RBRACKET, err)) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); free(rest_name); return NULL; } |
1355 | 18 | if (!expect(p, TOK_EQ, err)) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); free(rest_name); return NULL; } |
1356 | 18 | Expr *value = parse_expr(p, err); |
1357 | 18 | if (!value) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); free(rest_name); return NULL; } |
1358 | 18 | eat_semicolon(p); |
1359 | 18 | return stmt_destructure(phase, DESTRUCT_ARRAY, names, n, rest_name, value); |
1360 | 18 | } |
1361 | | |
1362 | | /* Struct destructuring: let { x, y } = expr */ |
1363 | 13.3k | if (peek_type(p) == TOK_LBRACE) { |
1364 | 6 | advance(p); |
1365 | 6 | size_t cap = 4, n = 0; |
1366 | 6 | char **names = malloc(cap * sizeof(char *)); |
1367 | 18 | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
1368 | 12 | if (n >= cap) { cap *= 2; names = realloc(names, cap * sizeof(char *)); } |
1369 | 12 | names[n] = expect_ident(p, err); |
1370 | 12 | if (!names[n]) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); return NULL; } |
1371 | 12 | n++; |
1372 | 12 | if (peek_type(p) != TOK_RBRACE) { |
1373 | 6 | if (!expect(p, TOK_COMMA, err)) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); return NULL; } |
1374 | 6 | } |
1375 | 12 | } |
1376 | 6 | if (!expect(p, TOK_RBRACE, err)) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); return NULL; } |
1377 | 6 | if (!expect(p, TOK_EQ, err)) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); return NULL; } |
1378 | 6 | Expr *value = parse_expr(p, err); |
1379 | 6 | if (!value) { for (size_t i = 0; i < n; i++) free(names[i]); free(names); return NULL; } |
1380 | 6 | eat_semicolon(p); |
1381 | 6 | return stmt_destructure(phase, DESTRUCT_STRUCT, names, n, NULL, value); |
1382 | 6 | } |
1383 | | |
1384 | | /* Normal binding: let name = expr */ |
1385 | 13.3k | char *name = expect_ident(p, err); |
1386 | 13.3k | if (!name) return NULL; |
1387 | | |
1388 | 13.3k | TypeExpr *ty = NULL; |
1389 | 13.3k | if (peek_type(p) == TOK_COLON) { |
1390 | 0 | advance(p); |
1391 | 0 | ty = parse_type_expr(p, err); |
1392 | 0 | if (!ty) { free(name); return NULL; } |
1393 | 0 | } |
1394 | | |
1395 | 13.3k | if (!expect(p, TOK_EQ, err)) { free(name); if (ty) { type_expr_free(ty); free(ty); } return NULL; } |
1396 | 13.3k | Expr *value = parse_expr(p, err); |
1397 | 13.3k | if (!value) { free(name); if (ty) { type_expr_free(ty); free(ty); } return NULL; } |
1398 | 13.3k | eat_semicolon(p); |
1399 | 13.3k | return stmt_binding(phase, name, ty, value); |
1400 | 13.3k | } |
1401 | | |
1402 | 858 | static Stmt *parse_for_stmt(Parser *p, char **err) { |
1403 | 858 | if (!expect(p, TOK_FOR, err)) return NULL; |
1404 | 858 | char *var = expect_ident(p, err); |
1405 | 858 | if (!var) return NULL; |
1406 | 858 | if (!expect(p, TOK_IN, err)) { free(var); return NULL; } |
1407 | 858 | Expr *iter = parse_expr(p, err); |
1408 | 858 | if (!iter) { free(var); return NULL; } |
1409 | 858 | if (!expect(p, TOK_LBRACE, err)) { free(var); expr_free(iter); return NULL; } |
1410 | 858 | size_t count; |
1411 | 858 | Stmt **body = parse_block_stmts(p, &count, err); |
1412 | 858 | if (!body && *err) { free(var); expr_free(iter); return NULL; } |
1413 | 858 | if (!expect(p, TOK_RBRACE, err)) { |
1414 | 0 | free(var); expr_free(iter); |
1415 | 0 | for (size_t i = 0; i < count; i++) stmt_free(body[i]); |
1416 | 0 | free(body); |
1417 | 0 | return NULL; |
1418 | 0 | } |
1419 | 858 | return stmt_for(var, iter, body, count); |
1420 | 858 | } |
1421 | | |
1422 | 366 | static Stmt *parse_while_stmt(Parser *p, char **err) { |
1423 | 366 | if (!expect(p, TOK_WHILE, err)) return NULL; |
1424 | 366 | Expr *cond = parse_expr(p, err); |
1425 | 366 | if (!cond) return NULL; |
1426 | 366 | if (!expect(p, TOK_LBRACE, err)) { expr_free(cond); return NULL; } |
1427 | 366 | size_t count; |
1428 | 366 | Stmt **body = parse_block_stmts(p, &count, err); |
1429 | 366 | if (!body && *err) { expr_free(cond); return NULL; } |
1430 | 366 | if (!expect(p, TOK_RBRACE, err)) { |
1431 | 0 | expr_free(cond); |
1432 | 0 | for (size_t i = 0; i < count; i++) stmt_free(body[i]); |
1433 | 0 | free(body); |
1434 | 0 | return NULL; |
1435 | 0 | } |
1436 | 366 | return stmt_while(cond, body, count); |
1437 | 366 | } |
1438 | | |
1439 | 348 | static Stmt *parse_loop_stmt(Parser *p, char **err) { |
1440 | 348 | if (!expect(p, TOK_LOOP, err)) return NULL; |
1441 | 348 | if (!expect(p, TOK_LBRACE, err)) return NULL; |
1442 | 348 | size_t count; |
1443 | 348 | Stmt **body = parse_block_stmts(p, &count, err); |
1444 | 348 | if (!body && *err) return NULL; |
1445 | 348 | if (!expect(p, TOK_RBRACE, err)) { |
1446 | 0 | for (size_t i = 0; i < count; i++) stmt_free(body[i]); |
1447 | 0 | free(body); |
1448 | 0 | return NULL; |
1449 | 0 | } |
1450 | 348 | return stmt_loop(body, count); |
1451 | 348 | } |
1452 | | |
1453 | | /* Parse: import "path" as name |
1454 | | * Parse: import { x, y } from "path" */ |
1455 | 282 | static Stmt *parse_import_stmt(Parser *p, char **err) { |
1456 | 282 | advance(p); /* consume 'import' */ |
1457 | | |
1458 | | /* Selective import: import { name1, name2 } from "path" */ |
1459 | 282 | if (peek_type(p) == TOK_LBRACE) { |
1460 | 51 | advance(p); |
1461 | 51 | size_t cap = 4, count = 0; |
1462 | 51 | char **names = malloc(cap * sizeof(char *)); |
1463 | | |
1464 | 111 | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
1465 | 60 | if (count >= cap) { cap *= 2; names = realloc(names, cap * sizeof(char *)); } |
1466 | 60 | names[count] = expect_ident(p, err); |
1467 | 60 | if (!names[count]) { |
1468 | 0 | for (size_t i = 0; i < count; i++) free(names[i]); |
1469 | 0 | free(names); |
1470 | 0 | return NULL; |
1471 | 0 | } |
1472 | 60 | count++; |
1473 | 60 | if (peek_type(p) == TOK_COMMA) advance(p); |
1474 | 60 | } |
1475 | | |
1476 | 51 | if (!expect(p, TOK_RBRACE, err)) { |
1477 | 0 | for (size_t i = 0; i < count; i++) free(names[i]); |
1478 | 0 | free(names); |
1479 | 0 | return NULL; |
1480 | 0 | } |
1481 | 51 | if (!expect(p, TOK_FROM, err)) { |
1482 | 0 | for (size_t i = 0; i < count; i++) free(names[i]); |
1483 | 0 | free(names); |
1484 | 0 | return NULL; |
1485 | 0 | } |
1486 | | |
1487 | 51 | if (peek_type(p) != TOK_STRING_LIT) { |
1488 | 0 | *err = parser_error_fmt(p, "expected string literal after 'from'"); |
1489 | 0 | for (size_t i = 0; i < count; i++) free(names[i]); |
1490 | 0 | free(names); |
1491 | 0 | return NULL; |
1492 | 0 | } |
1493 | 51 | char *path = strdup(advance(p)->as.str_val); |
1494 | 51 | eat_semicolon(p); |
1495 | 51 | return stmt_import(path, NULL, names, count); |
1496 | 51 | } |
1497 | | |
1498 | | /* Full import: import "path" as name */ |
1499 | 231 | if (peek_type(p) != TOK_STRING_LIT) { |
1500 | 0 | *err = parser_error_fmt(p, "expected string literal or '{' after 'import'"); |
1501 | 0 | return NULL; |
1502 | 0 | } |
1503 | 231 | char *path = strdup(advance(p)->as.str_val); |
1504 | | |
1505 | 231 | char *alias = NULL; |
1506 | 231 | if (peek_type(p) == TOK_AS) { |
1507 | 231 | advance(p); |
1508 | 231 | alias = expect_ident(p, err); |
1509 | 231 | if (!alias) { free(path); return NULL; } |
1510 | 231 | } |
1511 | | |
1512 | 231 | eat_semicolon(p); |
1513 | 231 | return stmt_import(path, alias, NULL, 0); |
1514 | 231 | } |
1515 | | |
1516 | | static Stmt *parse_stmt_inner(Parser *p, char **err); |
1517 | | |
1518 | 45.7k | static Stmt *parse_stmt(Parser *p, char **err) { |
1519 | 45.7k | int line = (int)peek(p)->line; |
1520 | 45.7k | Stmt *s = parse_stmt_inner(p, err); |
1521 | 45.7k | if (s) s->line = line; |
1522 | 45.7k | return s; |
1523 | 45.7k | } |
1524 | | |
1525 | 45.7k | static Stmt *parse_stmt_inner(Parser *p, char **err) { |
1526 | 45.7k | TokenType tt = peek_type(p); |
1527 | | |
1528 | 45.7k | if (tt == TOK_FLUX) return parse_binding(p, PHASE_FLUID, err); |
1529 | 42.4k | if (tt == TOK_FIX) return parse_binding(p, PHASE_CRYSTAL, err); |
1530 | 42.4k | if (tt == TOK_LET) return parse_binding(p, PHASE_UNSPECIFIED, err); |
1531 | | |
1532 | 32.3k | if (tt == TOK_IMPORT) return parse_import_stmt(p, err); |
1533 | | |
1534 | 32.1k | if (tt == TOK_DEFER) { |
1535 | 18 | advance(p); |
1536 | 18 | if (!expect(p, TOK_LBRACE, err)) return NULL; |
1537 | 18 | size_t count; |
1538 | 18 | Stmt **body = parse_block_stmts(p, &count, err); |
1539 | 18 | if (!body && *err) return NULL; |
1540 | 18 | if (!expect(p, TOK_RBRACE, err)) { |
1541 | 0 | for (size_t i = 0; i < count; i++) stmt_free(body[i]); |
1542 | 0 | free(body); |
1543 | 0 | return NULL; |
1544 | 0 | } |
1545 | 18 | return stmt_defer(body, count); |
1546 | 18 | } |
1547 | | |
1548 | 32.0k | if (tt == TOK_RETURN) { |
1549 | 9.08k | advance(p); |
1550 | 9.08k | if (peek_type(p) == TOK_RBRACE || peek_type(p) == TOK_SEMICOLON || at_eof(p)) { |
1551 | 3 | eat_semicolon(p); |
1552 | 3 | return stmt_return(NULL); |
1553 | 3 | } |
1554 | 9.08k | Expr *e = parse_expr(p, err); |
1555 | 9.08k | if (!e) return NULL; |
1556 | 9.08k | eat_semicolon(p); |
1557 | 9.08k | return stmt_return(e); |
1558 | 9.08k | } |
1559 | | |
1560 | 22.9k | if (tt == TOK_FOR) return parse_for_stmt(p, err); |
1561 | 22.1k | if (tt == TOK_WHILE) return parse_while_stmt(p, err); |
1562 | 21.7k | if (tt == TOK_LOOP) return parse_loop_stmt(p, err); |
1563 | 21.4k | if (tt == TOK_BREAK) { advance(p); eat_semicolon(p); return stmt_break(); } |
1564 | 21.1k | if (tt == TOK_CONTINUE) { advance(p); eat_semicolon(p); return stmt_continue(); } |
1565 | | |
1566 | | /* Expression statement or assignment */ |
1567 | 21.0k | Expr *e = parse_expr(p, err); |
1568 | 21.0k | if (!e) return NULL; |
1569 | 21.0k | if (peek_type(p) == TOK_EQ) { |
1570 | 2.67k | advance(p); |
1571 | 2.67k | Expr *value = parse_expr(p, err); |
1572 | 2.67k | if (!value) { expr_free(e); return NULL; } |
1573 | 2.67k | eat_semicolon(p); |
1574 | 2.67k | return stmt_assign(e, value); |
1575 | 2.67k | } |
1576 | | /* Compound assignment: +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= */ |
1577 | 18.3k | { |
1578 | 18.3k | BinOpKind cop; |
1579 | 18.3k | bool is_compound = true; |
1580 | 18.3k | switch (peek_type(p)) { |
1581 | 54 | case TOK_PLUS_EQ: cop = BINOP_ADD; break; |
1582 | 3 | case TOK_MINUS_EQ: cop = BINOP_SUB; break; |
1583 | 3 | case TOK_STAR_EQ: cop = BINOP_MUL; break; |
1584 | 3 | case TOK_SLASH_EQ: cop = BINOP_DIV; break; |
1585 | 3 | case TOK_PERCENT_EQ: cop = BINOP_MOD; break; |
1586 | 3 | case TOK_AMP_EQ: cop = BINOP_BIT_AND; break; |
1587 | 3 | case TOK_PIPE_EQ: cop = BINOP_BIT_OR; break; |
1588 | 3 | case TOK_CARET_EQ: cop = BINOP_BIT_XOR; break; |
1589 | 3 | case TOK_LSHIFT_EQ: cop = BINOP_LSHIFT; break; |
1590 | 3 | case TOK_RSHIFT_EQ: cop = BINOP_RSHIFT; break; |
1591 | 18.2k | default: is_compound = false; break; |
1592 | 18.3k | } |
1593 | 18.3k | if (is_compound) { |
1594 | 81 | advance(p); |
1595 | 81 | Expr *rhs = parse_expr(p, err); |
1596 | 81 | if (!rhs) { expr_free(e); return NULL; } |
1597 | | /* Desugar: target op= rhs => target = target op rhs */ |
1598 | 81 | Expr *target_clone = expr_clone_ast(e); |
1599 | 81 | if (!target_clone) { expr_free(rhs); expr_free(e); *err = strdup("invalid compound assignment target"); return NULL; } |
1600 | 81 | Expr *binop = expr_binop(cop, target_clone, rhs); |
1601 | 81 | eat_semicolon(p); |
1602 | 81 | return stmt_assign(e, binop); |
1603 | 81 | } |
1604 | 18.3k | } |
1605 | 18.2k | eat_semicolon(p); |
1606 | 18.2k | return stmt_expr(e); |
1607 | 18.3k | } |
1608 | | |
1609 | | /* ── Items ── */ |
1610 | | |
1611 | 7.97k | static bool parse_fn_decl(Parser *p, FnDecl *out, char **err) { |
1612 | 7.97k | out->next_overload = NULL; |
1613 | 7.97k | out->contracts = NULL; |
1614 | 7.97k | out->contract_count = 0; |
1615 | 7.97k | if (!expect(p, TOK_FN, err)) return false; |
1616 | 7.97k | out->name = expect_ident(p, err); |
1617 | 7.97k | if (!out->name) return false; |
1618 | 7.97k | if (!expect(p, TOK_LPAREN, err)) { free(out->name); return false; } |
1619 | 7.97k | out->params = parse_params(p, &out->param_count, err); |
1620 | 7.97k | if (!out->params && *err) { free(out->name); return false; } |
1621 | 7.97k | if (!expect(p, TOK_RPAREN, err)) { free(out->name); free(out->params); return false; } |
1622 | | |
1623 | 7.97k | out->return_type = NULL; |
1624 | 7.97k | if (peek_type(p) == TOK_ARROW) { |
1625 | 4.63k | advance(p); |
1626 | 4.63k | out->return_type = parse_type_expr(p, err); |
1627 | 4.63k | if (!out->return_type) { free(out->name); free(out->params); return false; } |
1628 | 4.63k | } |
1629 | | |
1630 | | /* Parse require/ensure contracts (contextual identifiers before '{') */ |
1631 | 7.97k | { |
1632 | 7.97k | size_t ccap = 4, cn = 0; |
1633 | 7.97k | ContractClause *contracts = NULL; |
1634 | 8.00k | while (peek_type(p) == TOK_IDENT && peek(p)->as.str_val && |
1635 | 8.00k | (strcmp(peek(p)->as.str_val, "require") == 0 || |
1636 | 24 | strcmp(peek(p)->as.str_val, "ensure") == 0)) { |
1637 | 24 | if (!contracts) contracts = malloc(ccap * sizeof(ContractClause)); |
1638 | 24 | if (cn >= ccap) { ccap *= 2; contracts = realloc(contracts, ccap * sizeof(ContractClause)); } |
1639 | 24 | bool is_ensure = (strcmp(peek(p)->as.str_val, "ensure") == 0); |
1640 | 24 | advance(p); |
1641 | 24 | Expr *cond = parse_expr(p, err); |
1642 | 24 | if (!cond) { |
1643 | 0 | for (size_t i = 0; i < cn; i++) { expr_free(contracts[i].condition); free(contracts[i].message); } |
1644 | 0 | free(contracts); |
1645 | 0 | free(out->name); free(out->params); |
1646 | 0 | if (out->return_type) { type_expr_free(out->return_type); free(out->return_type); } |
1647 | 0 | return false; |
1648 | 0 | } |
1649 | 24 | char *msg = NULL; |
1650 | 24 | if (peek_type(p) == TOK_COMMA) { |
1651 | 24 | advance(p); |
1652 | 24 | if (peek_type(p) == TOK_STRING_LIT) { |
1653 | 24 | msg = strdup(advance(p)->as.str_val); |
1654 | 24 | } |
1655 | 24 | } |
1656 | 24 | contracts[cn].condition = cond; |
1657 | 24 | contracts[cn].message = msg; |
1658 | 24 | contracts[cn].is_ensure = is_ensure; |
1659 | 24 | cn++; |
1660 | 24 | } |
1661 | 7.97k | out->contracts = contracts; |
1662 | 7.97k | out->contract_count = cn; |
1663 | 7.97k | } |
1664 | | |
1665 | 7.97k | if (!expect(p, TOK_LBRACE, err)) { |
1666 | 0 | free(out->name); free(out->params); |
1667 | 0 | if (out->return_type) { type_expr_free(out->return_type); free(out->return_type); } |
1668 | 0 | if (out->contracts) { |
1669 | 0 | for (size_t i = 0; i < out->contract_count; i++) { expr_free(out->contracts[i].condition); free(out->contracts[i].message); } |
1670 | 0 | free(out->contracts); |
1671 | 0 | } |
1672 | 0 | return false; |
1673 | 0 | } |
1674 | 7.97k | out->body = parse_block_stmts(p, &out->body_count, err); |
1675 | 7.97k | if (!out->body && *err) { |
1676 | 0 | free(out->name); free(out->params); |
1677 | 0 | if (out->return_type) { type_expr_free(out->return_type); free(out->return_type); } |
1678 | 0 | if (out->contracts) { |
1679 | 0 | for (size_t i = 0; i < out->contract_count; i++) { expr_free(out->contracts[i].condition); free(out->contracts[i].message); } |
1680 | 0 | free(out->contracts); |
1681 | 0 | } |
1682 | 0 | return false; |
1683 | 0 | } |
1684 | 7.97k | if (!expect(p, TOK_RBRACE, err)) { |
1685 | 0 | fn_decl_free(out); |
1686 | 0 | return false; |
1687 | 0 | } |
1688 | 7.97k | return true; |
1689 | 7.97k | } |
1690 | | |
1691 | 144 | static bool parse_struct_decl(Parser *p, StructDecl *out, char **err) { |
1692 | 144 | if (!expect(p, TOK_STRUCT, err)) return false; |
1693 | 144 | out->name = expect_ident(p, err); |
1694 | 144 | if (!out->name) return false; |
1695 | 144 | if (!expect(p, TOK_LBRACE, err)) { free(out->name); return false; } |
1696 | | |
1697 | 144 | size_t cap = 4; |
1698 | 144 | size_t n = 0; |
1699 | 144 | out->fields = malloc(cap * sizeof(FieldDecl)); |
1700 | | |
1701 | 417 | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
1702 | 273 | if (n >= cap) { cap *= 2; out->fields = realloc(out->fields, cap * sizeof(FieldDecl)); } |
1703 | 273 | out->fields[n].name = expect_ident(p, err); |
1704 | 273 | if (!out->fields[n].name) { free(out->name); free(out->fields); return false; } |
1705 | 273 | if (!expect(p, TOK_COLON, err)) { |
1706 | 0 | free(out->fields[n].name); free(out->name); free(out->fields); |
1707 | 0 | return false; |
1708 | 0 | } |
1709 | 273 | TypeExpr *te = parse_type_expr(p, err); |
1710 | 273 | if (!te) { free(out->fields[n].name); free(out->name); free(out->fields); return false; } |
1711 | 273 | out->fields[n].ty = *te; |
1712 | 273 | free(te); |
1713 | 273 | n++; |
1714 | 273 | if (peek_type(p) != TOK_RBRACE) { |
1715 | 138 | if (!expect(p, TOK_COMMA, err)) { free(out->name); free(out->fields); return false; } |
1716 | 138 | } |
1717 | 273 | } |
1718 | 144 | out->field_count = n; |
1719 | 144 | if (!expect(p, TOK_RBRACE, err)) { free(out->name); free(out->fields); return false; } |
1720 | 144 | return true; |
1721 | 144 | } |
1722 | | |
1723 | | /* ── Test declaration ── */ |
1724 | | |
1725 | 6 | static bool parse_test_decl(Parser *p, TestDecl *out, char **err) { |
1726 | 6 | if (!expect(p, TOK_TEST, err)) return false; |
1727 | 6 | if (peek_type(p) != TOK_STRING_LIT) { |
1728 | 0 | *err = strdup("expected string literal for test name"); |
1729 | 0 | return false; |
1730 | 0 | } |
1731 | 6 | Token *name_tok = advance(p); |
1732 | 6 | out->name = strdup(name_tok->as.str_val); |
1733 | 6 | if (!expect(p, TOK_LBRACE, err)) { free(out->name); return false; } |
1734 | 6 | out->body = parse_block_stmts(p, &out->body_count, err); |
1735 | 6 | if (!out->body && *err) { free(out->name); return false; } |
1736 | 6 | if (!expect(p, TOK_RBRACE, err)) { |
1737 | 0 | free(out->name); |
1738 | 0 | for (size_t i = 0; i < out->body_count; i++) stmt_free(out->body[i]); |
1739 | 0 | free(out->body); |
1740 | 0 | return false; |
1741 | 0 | } |
1742 | 6 | return true; |
1743 | 6 | } |
1744 | | |
1745 | | /* ── Enum declaration ── */ |
1746 | | |
1747 | 27 | static bool parse_enum_decl(Parser *p, EnumDecl *out, char **err) { |
1748 | 27 | if (!expect(p, TOK_ENUM, err)) return false; |
1749 | 27 | out->name = expect_ident(p, err); |
1750 | 27 | if (!out->name) return false; |
1751 | 27 | if (!expect(p, TOK_LBRACE, err)) { free(out->name); return false; } |
1752 | | |
1753 | 27 | size_t cap = 4; |
1754 | 27 | size_t n = 0; |
1755 | 27 | out->variants = malloc(cap * sizeof(VariantDecl)); |
1756 | | |
1757 | 99 | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
1758 | 72 | if (n >= cap) { cap *= 2; out->variants = realloc(out->variants, cap * sizeof(VariantDecl)); } |
1759 | 72 | out->variants[n].name = expect_ident(p, err); |
1760 | 72 | if (!out->variants[n].name) goto fail; |
1761 | 72 | out->variants[n].param_types = NULL; |
1762 | 72 | out->variants[n].param_count = 0; |
1763 | | |
1764 | | /* Tuple variant: Variant(Type1, Type2) */ |
1765 | 72 | if (peek_type(p) == TOK_LPAREN) { |
1766 | 12 | advance(p); |
1767 | 12 | size_t tcap = 4, tn = 0; |
1768 | 12 | TypeExpr *types = malloc(tcap * sizeof(TypeExpr)); |
1769 | 30 | while (peek_type(p) != TOK_RPAREN && !at_eof(p)) { |
1770 | 18 | if (tn >= tcap) { tcap *= 2; types = realloc(types, tcap * sizeof(TypeExpr)); } |
1771 | 18 | TypeExpr *te = parse_type_expr(p, err); |
1772 | 18 | if (!te) { free(types); free(out->variants[n].name); goto fail; } |
1773 | 18 | types[tn++] = *te; |
1774 | 18 | free(te); |
1775 | 18 | if (peek_type(p) != TOK_RPAREN) { |
1776 | 6 | if (!expect(p, TOK_COMMA, err)) { free(types); free(out->variants[n].name); goto fail; } |
1777 | 6 | } |
1778 | 18 | } |
1779 | 12 | if (!expect(p, TOK_RPAREN, err)) { free(types); free(out->variants[n].name); goto fail; } |
1780 | 12 | out->variants[n].param_types = types; |
1781 | 12 | out->variants[n].param_count = tn; |
1782 | 12 | } |
1783 | 72 | n++; |
1784 | 72 | if (peek_type(p) != TOK_RBRACE) { |
1785 | 45 | if (peek_type(p) == TOK_COMMA) advance(p); |
1786 | 45 | } |
1787 | 72 | } |
1788 | 27 | out->variant_count = n; |
1789 | 27 | if (!expect(p, TOK_RBRACE, err)) goto fail; |
1790 | 27 | return true; |
1791 | | |
1792 | 0 | fail: |
1793 | 0 | free(out->name); |
1794 | 0 | for (size_t i = 0; i < n; i++) { |
1795 | 0 | free(out->variants[i].name); |
1796 | 0 | if (out->variants[i].param_types) { |
1797 | 0 | for (size_t j = 0; j < out->variants[i].param_count; j++) |
1798 | 0 | type_expr_free(&out->variants[i].param_types[j]); |
1799 | 0 | free(out->variants[i].param_types); |
1800 | 0 | } |
1801 | 0 | } |
1802 | 0 | free(out->variants); |
1803 | 0 | return false; |
1804 | 27 | } |
1805 | | |
1806 | | /* ── Trait declaration ── */ |
1807 | | |
1808 | 12 | static bool parse_trait_decl(Parser *p, TraitDecl *out, char **err) { |
1809 | 12 | if (!expect(p, TOK_TRAIT, err)) return false; |
1810 | 12 | out->name = expect_ident(p, err); |
1811 | 12 | if (!out->name) return false; |
1812 | 12 | if (!expect(p, TOK_LBRACE, err)) { free(out->name); return false; } |
1813 | | |
1814 | 12 | size_t cap = 4; |
1815 | 12 | size_t n = 0; |
1816 | 12 | out->methods = malloc(cap * sizeof(TraitMethod)); |
1817 | | |
1818 | 27 | while (peek_type(p) != TOK_RBRACE && !at_eof(p)) { |
1819 | 15 | if (n >= cap) { cap *= 2; out->methods = realloc(out->methods, cap * sizeof(TraitMethod)); } |
1820 | | |
1821 | | /* fn name(params) -> RetType */ |
1822 | 15 | if (!expect(p, TOK_FN, err)) { |
1823 | 0 | for (size_t i = 0; i < n; i++) { |
1824 | 0 | free(out->methods[i].name); |
1825 | 0 | for (size_t j = 0; j < out->methods[i].param_count; j++) { |
1826 | 0 | free(out->methods[i].params[j].name); |
1827 | 0 | type_expr_free(&out->methods[i].params[j].ty); |
1828 | 0 | } |
1829 | 0 | free(out->methods[i].params); |
1830 | 0 | if (out->methods[i].return_type) { type_expr_free(out->methods[i].return_type); free(out->methods[i].return_type); } |
1831 | 0 | } |
1832 | 0 | free(out->methods); free(out->name); |
1833 | 0 | return false; |
1834 | 0 | } |
1835 | 15 | out->methods[n].name = expect_ident(p, err); |
1836 | 15 | if (!out->methods[n].name) { free(out->methods); free(out->name); return false; } |
1837 | 15 | if (!expect(p, TOK_LPAREN, err)) { free(out->methods[n].name); free(out->methods); free(out->name); return false; } |
1838 | 15 | out->methods[n].params = parse_params(p, &out->methods[n].param_count, err); |
1839 | 15 | if (!out->methods[n].params && *err) { free(out->methods[n].name); free(out->methods); free(out->name); return false; } |
1840 | 15 | if (!expect(p, TOK_RPAREN, err)) { free(out->methods[n].name); free(out->methods[n].params); free(out->methods); free(out->name); return false; } |
1841 | | |
1842 | 15 | out->methods[n].return_type = NULL; |
1843 | 15 | if (peek_type(p) == TOK_ARROW) { |
1844 | 15 | advance(p); |
1845 | 15 | out->methods[n].return_type = parse_type_expr(p, err); |
1846 | 15 | if (!out->methods[n].return_type) { free(out->methods[n].name); free(out->methods[n].params); free(out->methods); free(out->name); return false; } |
1847 | 15 | } |
1848 | 15 | n++; |
1849 | | /* Allow optional semicolons between methods */ |
1850 | 15 | eat_semicolon(p); |
1851 | 15 | } |
1852 | 12 | out->method_count = n; |
1853 | 12 | if (!expect(p, TOK_RBRACE, err)) { trait_decl_free(out); return false; } |
1854 | 12 | return true; |
1855 | 12 | } |
1856 | | |
1857 | | /* ── Impl block ── */ |
1858 | | |
1859 | 15 | static bool parse_impl_block(Parser *p, ImplBlock *out, char **err) { |
1860 | 15 | if (!expect(p, TOK_IMPL, err)) return false; |
1861 | 15 | out->trait_name = expect_ident(p, err); |
1862 | 15 | if (!out->trait_name) return false; |
1863 | | |
1864 | | /* "for TypeName" */ |
1865 | 15 | if (peek_type(p) != TOK_FOR) { |
1866 | 0 | *err = parser_error_fmt(p, "expected 'for' after trait name in impl block"); |
1867 | 0 | free(out->trait_name); |
1868 | 0 | return false; |
1869 | 0 | } |
1870 | 15 | advance(p); |
1871 | 15 | out->type_name = expect_ident(p, err); |
1872 | 15 | if (!out->type_name) { free(out->trait_name); return false; } |
1873 | | |
1874 | 15 | if (!expect(p, TOK_LBRACE, err)) { free(out->trait_name); free(out->type_name); return false; } |
1875 | | |
1876 | 15 | size_t cap = 4; |
1877 | 15 | size_t n = 0; |
1878 | 15 | out->methods = malloc(cap * sizeof(FnDecl)); |
1879 | | |
1880 | 33 | while (peek_type(p) == TOK_FN && !at_eof(p)) { |
1881 | 18 | if (n >= cap) { cap *= 2; out->methods = realloc(out->methods, cap * sizeof(FnDecl)); } |
1882 | 18 | if (!parse_fn_decl(p, &out->methods[n], err)) { |
1883 | 0 | for (size_t i = 0; i < n; i++) fn_decl_free(&out->methods[i]); |
1884 | 0 | free(out->methods); free(out->trait_name); free(out->type_name); |
1885 | 0 | return false; |
1886 | 0 | } |
1887 | 18 | n++; |
1888 | 18 | } |
1889 | 15 | out->method_count = n; |
1890 | 15 | if (!expect(p, TOK_RBRACE, err)) { |
1891 | 0 | for (size_t i = 0; i < n; i++) fn_decl_free(&out->methods[i]); |
1892 | 0 | free(out->methods); free(out->trait_name); free(out->type_name); |
1893 | 0 | return false; |
1894 | 0 | } |
1895 | 15 | return true; |
1896 | 15 | } |
1897 | | |
1898 | | /* ── Program ── */ |
1899 | | |
1900 | 36 | static void prog_add_export(Program *prog, const char *name) { |
1901 | 36 | if (prog->export_count >= prog->export_cap) { |
1902 | 18 | prog->export_cap = prog->export_cap ? prog->export_cap * 2 : 8; |
1903 | 18 | prog->export_names = realloc(prog->export_names, |
1904 | 18 | prog->export_cap * sizeof(char *)); |
1905 | 18 | } |
1906 | 36 | prog->export_names[prog->export_count++] = strdup(name); |
1907 | 36 | } |
1908 | | |
1909 | 2.87k | Program parser_parse(Parser *p, char **err) { |
1910 | 2.87k | Program prog; |
1911 | 2.87k | memset(&prog, 0, sizeof(prog)); |
1912 | 2.87k | *err = NULL; |
1913 | | |
1914 | | /* Mode directive */ |
1915 | 2.87k | if (peek_type(p) == TOK_MODE_DIRECTIVE) { |
1916 | 9 | Token *t = advance(p); |
1917 | 9 | if (strcmp(t->as.str_val, "strict") == 0) |
1918 | 9 | prog.mode = MODE_STRICT; |
1919 | 0 | else |
1920 | 0 | prog.mode = MODE_CASUAL; |
1921 | 2.86k | } else { |
1922 | 2.86k | prog.mode = MODE_CASUAL; |
1923 | 2.86k | } |
1924 | | |
1925 | 2.87k | size_t cap = 8; |
1926 | 2.87k | size_t n = 0; |
1927 | 2.87k | prog.items = malloc(cap * sizeof(Item)); |
1928 | | |
1929 | 11.8k | while (!at_eof(p)) { |
1930 | 8.97k | if (n >= cap) { |
1931 | 465 | cap *= 2; |
1932 | 465 | prog.items = realloc(prog.items, cap * sizeof(Item)); |
1933 | 465 | } |
1934 | | |
1935 | | /* Check for 'export' keyword */ |
1936 | 8.97k | bool is_exported = false; |
1937 | 8.97k | if (peek_type(p) == TOK_EXPORT) { |
1938 | 36 | is_exported = true; |
1939 | 36 | prog.has_exports = true; |
1940 | 36 | advance(p); |
1941 | 36 | } |
1942 | | |
1943 | 8.97k | prog.items[n].exported = is_exported; |
1944 | | |
1945 | 8.97k | if (peek_type(p) == TOK_FN) { |
1946 | 7.95k | prog.items[n].tag = ITEM_FUNCTION; |
1947 | 7.95k | if (!parse_fn_decl(p, &prog.items[n].as.fn_decl, err)) { |
1948 | 0 | prog.item_count = n; |
1949 | 0 | return prog; |
1950 | 0 | } |
1951 | 7.95k | if (is_exported) |
1952 | 18 | prog_add_export(&prog, prog.items[n].as.fn_decl.name); |
1953 | 7.95k | } else if (peek_type(p) == TOK_STRUCT) { |
1954 | 144 | prog.items[n].tag = ITEM_STRUCT; |
1955 | 144 | if (!parse_struct_decl(p, &prog.items[n].as.struct_decl, err)) { |
1956 | 0 | prog.item_count = n; |
1957 | 0 | return prog; |
1958 | 0 | } |
1959 | 144 | if (is_exported) |
1960 | 3 | prog_add_export(&prog, prog.items[n].as.struct_decl.name); |
1961 | 870 | } else if (peek_type(p) == TOK_TEST) { |
1962 | 6 | prog.items[n].tag = ITEM_TEST; |
1963 | 6 | if (!parse_test_decl(p, &prog.items[n].as.test_decl, err)) { |
1964 | 0 | prog.item_count = n; |
1965 | 0 | return prog; |
1966 | 0 | } |
1967 | 864 | } else if (peek_type(p) == TOK_ENUM) { |
1968 | 27 | prog.items[n].tag = ITEM_ENUM; |
1969 | 27 | if (!parse_enum_decl(p, &prog.items[n].as.enum_decl, err)) { |
1970 | 0 | prog.item_count = n; |
1971 | 0 | return prog; |
1972 | 0 | } |
1973 | 27 | if (is_exported) |
1974 | 0 | prog_add_export(&prog, prog.items[n].as.enum_decl.name); |
1975 | 837 | } else if (peek_type(p) == TOK_TRAIT) { |
1976 | 12 | prog.items[n].tag = ITEM_TRAIT; |
1977 | 12 | if (!parse_trait_decl(p, &prog.items[n].as.trait_decl, err)) { |
1978 | 0 | prog.item_count = n; |
1979 | 0 | return prog; |
1980 | 0 | } |
1981 | 12 | if (is_exported) |
1982 | 0 | prog_add_export(&prog, prog.items[n].as.trait_decl.name); |
1983 | 825 | } else if (peek_type(p) == TOK_IMPL) { |
1984 | 15 | prog.items[n].tag = ITEM_IMPL; |
1985 | 15 | if (!parse_impl_block(p, &prog.items[n].as.impl_block, err)) { |
1986 | 0 | prog.item_count = n; |
1987 | 0 | return prog; |
1988 | 0 | } |
1989 | 810 | } else { |
1990 | 810 | if (is_exported) { |
1991 | | /* export must precede fn, struct, enum, trait, or a binding stmt */ |
1992 | 15 | TokenType next = peek_type(p); |
1993 | 15 | if (next != TOK_LET && next != TOK_FLUX && next != TOK_FIX) { |
1994 | 0 | *err = NULL; |
1995 | 0 | Token *t = peek(p); |
1996 | 0 | (void)asprintf(err, "%zu:%zu: 'export' must precede fn, struct, enum, trait, or variable binding", |
1997 | 0 | t->line, t->col); |
1998 | 0 | prog.item_count = n; |
1999 | 0 | return prog; |
2000 | 0 | } |
2001 | 15 | } |
2002 | 810 | prog.items[n].tag = ITEM_STMT; |
2003 | 810 | prog.items[n].as.stmt = parse_stmt(p, err); |
2004 | 810 | if (!prog.items[n].as.stmt) { |
2005 | 0 | prog.item_count = n; |
2006 | 0 | return prog; |
2007 | 0 | } |
2008 | 810 | if (is_exported && prog.items[n].as.stmt->tag == STMT_BINDING) { |
2009 | 15 | prog_add_export(&prog, prog.items[n].as.stmt->as.binding.name); |
2010 | 15 | } |
2011 | 810 | } |
2012 | 8.97k | n++; |
2013 | 8.97k | } |
2014 | | |
2015 | 2.87k | prog.item_count = n; |
2016 | 2.87k | return prog; |
2017 | 2.87k | } |