Coverage Report

Created: 2026-02-23 20:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}