parser.c 68.3 KiB raw
1
#include <stdarg.h>
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <string.h>
5
6
#include "ast.h"
7
#include "io.h"
8
#include "limits.h"
9
#include "parser.h"
10
#include "scanner.h"
11
#include "strings.h"
12
13
#define error(...) __error(__VA_ARGS__, NULL)
14
15
static node_t *parse_expr(parser_t *p);
16
static node_t *parse_stmt_or_block(parser_t *p);
17
static node_t *parse_cond(parser_t *p);
18
static node_t *parse_if(parser_t *p);
19
static node_t *parse_if_let(parser_t *p);
20
static node_t *parse_if_case(parser_t *p);
21
static node_t *parse_block(parser_t *p);
22
static node_t *parse_stmt(parser_t *p);
23
static node_t *parse_type(parser_t *p);
24
static node_t *parse_union(parser_t *p, node_t *attrs);
25
static node_t *parse_record(parser_t *p, node_t *attrs);
26
static node_t *parse_record_type(parser_t *p);
27
static node_t *parse_record_lit(parser_t *p, node_t *type_name);
28
static node_t *parse_postfix(parser_t *p, node_t *expr);
29
static node_t *parse_as_cast(parser_t *p, node_t *expr);
30
static node_t *parse_name_type_value(parser_t *p, nodeclass_t cls);
31
static node_t *parse_static(parser_t *p);
32
static node_t *parse_ident(parser_t *p, const char *error);
33
static node_t *parse_ident_or_placeholder(parser_t *p, const char *error);
34
static node_t *parse_scope_segment(parser_t *p, const char *error);
35
static node_t *parse_label(parser_t *p, const char *error);
36
static node_t *parse_assignment(parser_t *p, node_t *lval);
37
static node_t *parse_fn_call_arg(parser_t *p);
38
static node_t *parse_match(parser_t *p);
39
static node_t *parse_match_case(parser_t *p);
40
static node_t *parse_builtin(parser_t *p);
41
static node_t *parse_throw(parser_t *p);
42
static node_t *parse_try(parser_t *p, bool panic, bool optional);
43
static node_t *parse_panic(parser_t *p);
44
static bool    token_is_stmt_terminator(tokenclass_t cls);
45
static bool    stmt_requires_semicolon(const node_t *stmt);
46
static bool    consume_statement_separator(
47
       parser_t *p, node_t *stmt, bool require
48
   );
49
50
/* Initialize parser. */
51
void parser_init(parser_t *p) {
52
    p->root    = NULL;
53
    p->errors  = 0;
54
    p->nnodes  = 0;
55
    p->nptrs   = 0;
56
    p->context = PARSE_CTX_NORMAL;
57
}
58
59
/* Report an error with optional format string. */
60
static void __error(parser_t *p, const char *fmt, ...) {
61
    va_list ap;
62
    va_start(ap, fmt);
63
64
    location_t loc = scanner_get_location(&p->scanner, p->current.position);
65
    fprintf(stderr, "%s:%u:%u: error: ", loc.file, loc.line, loc.col);
66
    vfprintf(stderr, fmt, ap);
67
    fprintf(stderr, "\n");
68
    va_end(ap);
69
70
    p->errors++;
71
}
72
73
/* Check that the current token is equal to the given type. */
74
static bool check(parser_t *p, tokenclass_t cls) {
75
    return p->current.cls == cls;
76
}
77
78
/* Advance the parser by one token. */
79
static void advance(parser_t *p) {
80
    p->previous = p->current;
81
    p->current  = scanner_next(&p->scanner);
82
}
83
84
/* Like `check`, but also advances the parser if it matches. */
85
static bool consume(parser_t *p, tokenclass_t cls) {
86
    if (check(p, cls)) {
87
        advance(p);
88
        return true;
89
    }
90
    return false;
91
}
92
93
/* Like `consume`, but report an error if it doesn't match. */
94
__nodiscard static bool expect(
95
    parser_t *p, tokenclass_t cls, const char *message
96
) {
97
    if (consume(p, cls)) {
98
        return true;
99
    }
100
    error(p, message);
101
102
    return false;
103
}
104
105
/* Allocate a new AST node. */
106
static node_t *node(parser_t *p, nodeclass_t cls) {
107
    if (p->nnodes >= MAX_NODES) {
108
        abort();
109
    }
110
    node_t *n = &p->nodes[p->nnodes++];
111
    n->cls    = cls;
112
    n->type   = NULL;
113
    n->sym    = NULL;
114
    n->offset = p->current.position;
115
    n->length = p->current.length;
116
    n->file   = p->scanner.file;
117
118
    return n;
119
}
120
121
/* Parse a type annotation.
122
 * Eg. `i32` or `[i32; 12]` */
123
static node_t *parse_type(parser_t *p) {
124
    /* Parse optional types. */
125
    if (p->current.cls == T_QUESTION) {
126
        node_t *opt = node(p, NODE_TYPE);
127
        advance(p); /* Consume `?`. */
128
129
        node_t *elem_type = parse_type(p);
130
        if (!elem_type)
131
            return NULL;
132
133
        opt->val.type.tclass    = TYPE_OPT;
134
        opt->val.type.elem_type = elem_type;
135
136
        return opt;
137
    }
138
139
    /* Parse pointer types and slice types. */
140
    if (p->current.cls == T_STAR) {
141
        advance(p); /* Consume `*`. */
142
143
        /* Consume `mut` */
144
        bool mut = consume(p, T_MUT);
145
146
        /* Parse slice types like `*[i32]` or `*mut [i32]` */
147
        if (p->current.cls == T_LBRACKET) {
148
            node_t *slice = node(p, NODE_TYPE);
149
            advance(p); /* Consume `[`. */
150
151
            node_t *elem_type = parse_type(p);
152
            if (!elem_type)
153
                return NULL;
154
155
            if (!expect(p, T_RBRACKET, "expected `]` after slice element type"))
156
                return NULL;
157
158
            slice->val.type.tclass         = TYPE_SLICE;
159
            slice->val.type.elem_type      = elem_type;
160
            slice->val.type.info.slice.mut = mut;
161
162
            return slice;
163
        }
164
165
        /* Otherwise it's a pointer type like `*i32` or `*mut i32` */
166
        node_t *ptr       = node(p, NODE_TYPE);
167
        node_t *elem_type = parse_type(p);
168
        if (!elem_type)
169
            return NULL;
170
171
        ptr->val.type.tclass       = TYPE_PTR;
172
        ptr->val.type.elem_type    = elem_type;
173
        ptr->val.type.info.ptr.mut = mut;
174
175
        return ptr;
176
    }
177
178
    /* Parse array types. */
179
    if (p->current.cls == T_LBRACKET) {
180
        advance(p); /* Consume `[`. */
181
182
        /* Get the element type. */
183
        node_t *elem_type = parse_type(p);
184
        if (!elem_type)
185
            return NULL;
186
187
        /* Expect a semicolon separator. */
188
        if (!expect(p, T_SEMICOLON, "expected `;` in array type"))
189
            return NULL;
190
191
        /* Parse the array length. */
192
        node_t *length = parse_expr(p);
193
        if (!length) {
194
            error(p, "expected array size expression");
195
            return NULL;
196
        }
197
        /* Expect the closing bracket */
198
        if (!expect(p, T_RBRACKET, "expected `]` after array size"))
199
            return NULL;
200
201
        node_t *ary                     = node(p, NODE_TYPE);
202
        ary->val.type.tclass            = TYPE_ARRAY;
203
        ary->val.type.elem_type         = elem_type;
204
        ary->val.type.info.array.length = length;
205
206
        return ary;
207
    }
208
209
    /* Type identifiers are treated differently, as a concrete type cannot
210
     * yet be assigned. */
211
    if (p->current.cls == T_IDENT || p->current.cls == T_SUPER) {
212
        node_t *path =
213
            parse_scope_segment(p, "expected type identifier or `super`");
214
        if (!path)
215
            return NULL;
216
217
        while (consume(p, T_COLON_COLON)) {
218
            node_t *next =
219
                parse_scope_segment(p, "expected identifier name after `::`");
220
            if (!next)
221
                return NULL;
222
223
            node_t *scope          = node(p, NODE_SCOPE);
224
            scope->val.access.lval = path;
225
            scope->val.access.rval = next;
226
            path                   = scope;
227
        }
228
        return path;
229
    }
230
    node_t *n = node(p, NODE_TYPE);
231
232
    switch (p->current.cls) {
233
    case T_I8:
234
        advance(p);
235
        n->val.type.tclass = TYPE_I8;
236
        return n;
237
    case T_I16:
238
        advance(p);
239
        n->val.type.tclass = TYPE_I16;
240
        return n;
241
    case T_I32:
242
        advance(p);
243
        n->val.type.tclass = TYPE_I32;
244
        return n;
245
    case T_U8:
246
        advance(p);
247
        n->val.type.tclass = TYPE_U8;
248
        return n;
249
    case T_U16:
250
        advance(p);
251
        n->val.type.tclass = TYPE_U16;
252
        return n;
253
    case T_U32:
254
        advance(p);
255
        n->val.type.tclass = TYPE_U32;
256
        return n;
257
    case T_BOOL:
258
        advance(p);
259
        n->val.type.tclass = TYPE_BOOL;
260
        return n;
261
    case T_VOID:
262
        advance(p);
263
        n->val.type.tclass = TYPE_VOID;
264
        return n;
265
    case T_OPAQUE:
266
        advance(p);
267
        n->val.type.tclass = TYPE_OPAQUE;
268
        return n;
269
    case T_FN: {
270
        advance(p); /* consume `fn` */
271
272
        if (!expect(p, T_LPAREN, "expected `(` after `fn`"))
273
            return NULL;
274
275
        n->val.type.tclass         = TYPE_FN;
276
        n->val.type.info.fn.params = nodespan_alloc(p, MAX_FN_PARAMS);
277
        n->val.type.info.fn.ret    = NULL;
278
        n->val.type.info.fn.throws = nodespan_alloc(p, MAX_FN_THROWS);
279
280
        /* Parse parameter types */
281
        if (!check(p, T_RPAREN)) {
282
            node_t *param = NULL;
283
284
            do {
285
                if (n->val.type.info.fn.params.len >= MAX_FN_PARAMS) {
286
                    error(p, "too many function pointer parameters");
287
                    return NULL;
288
                }
289
                if (!(param = parse_type(p))) {
290
                    return NULL;
291
                }
292
                nodespan_push(p, &n->val.type.info.fn.params, param);
293
            } while (consume(p, T_COMMA));
294
        }
295
        if (!expect(
296
                p, T_RPAREN, "expected `)` after function pointer parameters"
297
            ))
298
            return NULL;
299
300
        /* Parse return type */
301
        if (consume(p, T_ARROW)) {
302
            if (!(n->val.type.info.fn.ret = parse_type(p))) {
303
                return NULL;
304
            }
305
        }
306
307
        if (consume(p, T_THROWS)) {
308
            if (!expect(p, T_LPAREN, "expected `(` after `throws`"))
309
                return NULL;
310
311
            if (!check(p, T_RPAREN)) {
312
                do {
313
                    if (n->val.type.info.fn.throws.len >= MAX_FN_THROWS) {
314
                        error(p, "maximum number of thrown types exceeded");
315
                        return NULL;
316
                    }
317
318
                    node_t *thrown = parse_type(p);
319
                    if (!thrown)
320
                        return NULL;
321
322
                    nodespan_push(p, &n->val.type.info.fn.throws, thrown);
323
                } while (consume(p, T_COMMA));
324
            }
325
326
            if (!expect(p, T_RPAREN, "expected `)` after throws clause"))
327
                return NULL;
328
        }
329
        return n;
330
    }
331
    default:
332
        error(p, "expected type annotation, eg. `i32`, `bool`, etc.");
333
        return NULL;
334
    }
335
}
336
337
/* Parse primary expressions. */
338
static node_t *parse_array_literal(parser_t *p) {
339
    node_t *n = NULL;
340
341
    if (check(p, T_RBRACKET)) { /* Empty array `[]` */
342
        n                      = node(p, NODE_ARRAY_LIT);
343
        n->val.array_lit.elems = (nodespan_t){ 0 };
344
    } else {
345
        node_t *expr = parse_expr(p);
346
        if (!expr)
347
            return NULL;
348
349
        /* Check if this is a repeat array [value; count] */
350
        if (consume(p, T_SEMICOLON)) {
351
            n                             = node(p, NODE_ARRAY_REPEAT_LIT);
352
            n->val.array_repeat_lit.value = expr;
353
            n->val.array_repeat_lit.count = parse_expr(p);
354
355
            if (!n->val.array_repeat_lit.count)
356
                return NULL;
357
        } else {
358
            /* Regular array literal [a, b, ...] */
359
            n                      = node(p, NODE_ARRAY_LIT);
360
            n->val.array_lit.elems = (nodespan_t){ 0 };
361
            nodespan_push(p, &n->val.array_lit.elems, expr);
362
363
            /* Continue parsing remaining elements */
364
            while (consume(p, T_COMMA) && !check(p, T_RBRACKET)) {
365
                node_t *elem = parse_expr(p);
366
                if (!elem)
367
                    return NULL;
368
369
                nodespan_push(p, &n->val.array_lit.elems, elem);
370
            }
371
        }
372
    }
373
    if (!expect(p, T_RBRACKET, "expected `]` after array elements"))
374
        return NULL;
375
376
    return n;
377
}
378
379
static node_t *parse_builtin(parser_t *p) {
380
    node_t *n = node(p, NODE_BUILTIN);
381
382
    /* Token is @identifier, skip the '@' to get the name. */
383
    const char *name   = p->current.start + 1;
384
    usize       length = p->current.length - 1;
385
386
    advance(p); /* consume `@identifier` */
387
388
    builtin_kind_t kind;
389
390
    if (!strncmp(name, "sizeOf", 6)) {
391
        kind = BUILTIN_SIZE_OF;
392
    } else if (!strncmp(name, "alignOf", 7)) {
393
        kind = BUILTIN_ALIGN_OF;
394
    } else if (!strncmp(name, "sliceOf", 7)) {
395
        kind = BUILTIN_SLICE_OF;
396
    } else {
397
        error(p, "unknown builtin `@%.*s`", (int)length, name);
398
        return NULL;
399
    }
400
    if (!expect(p, T_LPAREN, "expected `(` after builtin name"))
401
        return NULL;
402
403
    n->val.builtin.kind = kind;
404
    n->val.builtin.args = (nodespan_t){ 0 };
405
406
    /* @sliceOf takes two expression arguments: @sliceOf(ptr, len) */
407
    if (kind == BUILTIN_SLICE_OF) {
408
        parse_ctx_t prev = p->context;
409
        p->context       = PARSE_CTX_NORMAL;
410
411
        node_t *ptr_expr = parse_expr(p);
412
        if (!ptr_expr)
413
            return NULL;
414
        nodespan_push(p, &n->val.builtin.args, ptr_expr);
415
416
        if (!expect(
417
                p, T_COMMA, "expected `,` after first argument to @sliceOf"
418
            ))
419
            return NULL;
420
421
        node_t *len_expr = parse_expr(p);
422
        if (!len_expr)
423
            return NULL;
424
        nodespan_push(p, &n->val.builtin.args, len_expr);
425
426
        p->context = prev;
427
    } else {
428
        /* @sizeOf and @alignOf take type arguments only. */
429
        node_t *type_arg = parse_type(p);
430
        if (!type_arg)
431
            return NULL;
432
        nodespan_push(p, &n->val.builtin.args, type_arg);
433
    }
434
435
    if (!expect(p, T_RPAREN, "expected `)` after builtin argument"))
436
        return NULL;
437
438
    return n;
439
}
440
441
static node_t *parse_primary(parser_t *p) {
442
    node_t *n;
443
444
    switch (p->current.cls) {
445
    case T_LBRACKET: /* Array literal [a, b, c] */
446
        advance(p);
447
        return parse_array_literal(p);
448
449
    case T_NOT: /* Unary not operator */
450
        n              = node(p, NODE_UNOP);
451
        n->val.unop.op = OP_NOT;
452
        advance(p);
453
454
        if (!(n->val.unop.expr = parse_primary(p)))
455
            return NULL;
456
457
        return n;
458
459
    case T_RECORD: {
460
        advance(p); /* consume `record` */
461
462
        node_t *rtype = parse_record_type(p);
463
        if (!rtype)
464
            return NULL;
465
466
        if (p->context == PARSE_CTX_NORMAL && consume(p, T_LBRACE)) {
467
            return parse_record_lit(p, rtype);
468
        }
469
        if (p->context == PARSE_CTX_NORMAL) {
470
            error(p, "expected `{` after anonymous record type");
471
            return NULL;
472
        }
473
        return rtype;
474
    }
475
476
    case T_LBRACE:
477
        if (p->context == PARSE_CTX_CONDITION) {
478
            error(p, "unexpected `{` in this context");
479
            return NULL;
480
        }
481
        advance(p); /* consume `{` */
482
483
        return parse_record_lit(p, NULL);
484
485
    case T_MINUS: /* Unary negation operator */
486
        n              = node(p, NODE_UNOP);
487
        n->val.unop.op = OP_NEG;
488
        advance(p);
489
490
        if (!(n->val.unop.expr = parse_primary(p)))
491
            return NULL;
492
493
        return n;
494
495
    case T_TILDE: /* Bitwise NOT operator */
496
        n              = node(p, NODE_UNOP);
497
        n->val.unop.op = OP_BNOT;
498
        advance(p);
499
500
        if (!(n->val.unop.expr = parse_primary(p)))
501
            return NULL;
502
503
        return n;
504
505
    case T_AMP:
506
        n = node(p, NODE_REF);
507
        advance(p);
508
509
        n->val.ref.mut = consume(p, T_MUT);
510
511
        if (!(n->val.ref.target = parse_primary(p)))
512
            return NULL;
513
514
        return n;
515
516
    case T_STAR:
517
        n = node(p, NODE_UNOP);
518
        advance(p);
519
520
        n->val.unop.op = OP_DEREF;
521
        if (!(n->val.unop.expr = parse_primary(p)))
522
            return NULL;
523
524
        return n;
525
526
    case T_NUMBER:
527
        n = node(p, NODE_NUMBER);
528
        advance(p);
529
530
        n->val.number.text     = p->previous.start;
531
        n->val.number.text_len = p->previous.length;
532
533
        if (check(p, T_DOT_DOT)) {
534
            return parse_postfix(p, n);
535
        }
536
        return n;
537
538
    case T_CHAR:
539
        n = node(p, NODE_CHAR);
540
        advance(p);
541
542
        if (p->previous.start[1] == '\\') {
543
            switch (p->previous.start[2]) {
544
            case 'n':
545
                n->val.char_lit = '\n';
546
                break;
547
            case 't':
548
                n->val.char_lit = '\t';
549
                break;
550
            case 'r':
551
                n->val.char_lit = '\r';
552
                break;
553
            case '\'':
554
                n->val.char_lit = '\'';
555
                break;
556
            case '\\':
557
                n->val.char_lit = '\\';
558
                break;
559
            default:
560
                abort();
561
            }
562
        } else {
563
            n->val.char_lit = p->previous.start[1];
564
        }
565
        if (check(p, T_DOT_DOT)) {
566
            return parse_postfix(p, n);
567
        }
568
        return n;
569
570
    case T_STRING: {
571
        n = node(p, NODE_STRING);
572
        advance(p);
573
574
        /* Account for quotes. */
575
        const char *data = p->previous.start + 1;
576
        usize       len  = p->previous.length - 2;
577
578
        /* Intern string. This escapes the string properly and
579
         * NULL-terminates it. */
580
        n->val.string_lit.data   = strings_alloc_len(data, len);
581
        n->val.string_lit.length = strlen(n->val.string_lit.data);
582
583
        return n;
584
    }
585
586
    case T_AT_IDENT:
587
        return parse_builtin(p);
588
589
    case T_SUPER:
590
        n = node(p, NODE_SUPER);
591
        advance(p);
592
593
        if (check(p, T_COLON_COLON)) {
594
            return parse_postfix(p, n);
595
        }
596
        return n;
597
598
    case T_IDENT:
599
        n                   = node(p, NODE_IDENT);
600
        n->val.ident.name   = p->current.start;
601
        n->val.ident.length = p->current.length;
602
603
        advance(p);
604
605
        /* Check for record initializer, eg. `{ x: 1, y: 2 }` */
606
        if (p->context == PARSE_CTX_NORMAL && consume(p, T_LBRACE)) {
607
            return parse_record_lit(p, n);
608
        }
609
610
        /* Check for field access or array indexing. */
611
        if (check(p, T_DOT) || check(p, T_LBRACKET) ||
612
            check(p, T_COLON_COLON) || check(p, T_LPAREN) ||
613
            check(p, T_DOT_DOT)) {
614
            return parse_postfix(p, n);
615
        }
616
        return n;
617
618
    case T_LPAREN:
619
        advance(p);
620
621
        /* Inside parentheses, we are in a normal parsing context */
622
        parse_ctx_t prev = p->context;
623
        p->context       = PARSE_CTX_NORMAL;
624
        n                = parse_expr(p);
625
        p->context       = prev;
626
627
        if (!expect(p, T_RPAREN, "expected closing `)` after expression"))
628
            return NULL;
629
630
        /* Check for field access or array indexing. */
631
        if (check(p, T_DOT) || check(p, T_LBRACKET) || check(p, T_DOT_DOT)) {
632
            return parse_postfix(p, n);
633
        }
634
        return n;
635
636
    case T_TRUE:
637
        n               = node(p, NODE_BOOL);
638
        n->val.bool_lit = true;
639
        advance(p);
640
641
        return n;
642
643
    case T_FALSE:
644
        n               = node(p, NODE_BOOL);
645
        n->val.bool_lit = false;
646
        advance(p);
647
648
        return n;
649
650
    case T_NIL:
651
        n = node(p, NODE_NIL);
652
        advance(p);
653
654
        return n;
655
656
    case T_UNDEF:
657
        n = node(p, NODE_UNDEF);
658
        advance(p);
659
660
        return n;
661
662
    case T_UNDERSCORE:
663
        n = node(p, NODE_PLACEHOLDER);
664
        advance(p);
665
666
        return n;
667
668
    case T_TRY: {
669
        advance(p);
670
671
        bool panic    = consume(p, T_BANG);
672
        bool optional = consume(p, T_QUESTION);
673
674
        node_t *expr = parse_try(p, panic, optional);
675
        if (!expr)
676
            return NULL;
677
678
        if (check(p, T_DOT) || check(p, T_LBRACKET) ||
679
            check(p, T_COLON_COLON) || check(p, T_LPAREN) ||
680
            check(p, T_DOT_DOT)) {
681
            return parse_postfix(p, expr);
682
        }
683
        return expr;
684
    }
685
686
    default:
687
        error(
688
            p,
689
            "expected expression, got `%.*s`",
690
            p->current.length,
691
            p->current.start
692
        );
693
        return NULL;
694
    }
695
}
696
697
/* Parse binary expressions with precedence climbing. */
698
static node_t *parse_binary(parser_t *p, node_t *left, int precedence) {
699
    /* Operator precedence table. */
700
    static const struct {
701
        tokenclass_t tok;
702
        binop_t      op;
703
        int          prec;
704
    } ops[] = {
705
        /* Arithmetic operators (higher precedence). */
706
        { T_PLUS, OP_ADD, 6 },
707
        { T_MINUS, OP_SUB, 6 },
708
        { T_STAR, OP_MUL, 7 },
709
        { T_SLASH, OP_DIV, 7 },
710
        { T_PERCENT, OP_MOD, 7 },
711
        /* Shift operators. */
712
        { T_LSHIFT, OP_SHL, 5 },
713
        { T_RSHIFT, OP_SHR, 5 },
714
        /* Bitwise operators. */
715
        { T_AMP, OP_BAND, 4 },
716
        { T_CARET, OP_XOR, 3 },
717
        { T_PIPE, OP_BOR, 2 },
718
        /* Comparison operators. */
719
        { T_EQ_EQ, OP_EQ, 1 },
720
        { T_BANG_EQ, OP_NE, 1 },
721
        { T_LT, OP_LT, 1 },
722
        { T_GT, OP_GT, 1 },
723
        { T_LT_EQ, OP_LE, 1 },
724
        { T_GT_EQ, OP_GE, 1 },
725
        /* Logical operators (lowest precedence). */
726
        { T_AND, OP_AND, 0 },
727
        { T_OR, OP_OR, 0 },
728
    };
729
730
    for (;;) {
731
        int     next = -1;
732
        binop_t op;
733
734
        /* Find matching operator and its precedence. */
735
        for (usize i = 0; i < sizeof(ops) / sizeof(ops[0]); i++) {
736
            if (check(p, ops[i].tok) && ops[i].prec > precedence) {
737
                if (next == -1 || ops[i].prec < next) {
738
                    next = ops[i].prec;
739
                    op   = ops[i].op;
740
                }
741
            }
742
        }
743
        if (next == -1)
744
            break;
745
746
        /* Consume the operator token. */
747
        advance(p);
748
749
        /* Parse the right operand. */
750
        node_t *right = parse_primary(p);
751
752
        if (!right)
753
            return NULL;
754
755
        /* Handle `as` casts on the right operand */
756
        while (check(p, T_AS)) {
757
            right = parse_as_cast(p, right);
758
            if (!right)
759
                return NULL;
760
        }
761
        /* Look for higher precedence operators. */
762
        for (usize i = 0; i < sizeof(ops) / sizeof(ops[0]); i++) {
763
            if (check(p, ops[i].tok) && ops[i].prec > next) {
764
                right = parse_binary(p, right, next);
765
                break;
766
            }
767
        }
768
769
        /* Build binary expression node. */
770
        node_t *binop          = node(p, NODE_BINOP);
771
        binop->offset          = left->offset;
772
        binop->length          = right->offset + right->length - left->offset;
773
        binop->val.binop.op    = op;
774
        binop->val.binop.left  = left;
775
        binop->val.binop.right = right;
776
        left                   = binop;
777
    }
778
    return left;
779
}
780
781
/* Parse an `if let` statement.
782
 * Syntax: if let x in (expr) { ... } else { ... }
783
 */
784
static node_t *parse_if_let(parser_t *p) {
785
    /* Consume 'let' */
786
    if (!expect(p, T_LET, "expected 'let'"))
787
        return NULL;
788
789
    /* Check for `if let case` syntax. */
790
    if (check(p, T_CASE)) {
791
        return parse_if_case(p);
792
    }
793
    node_t *n = node(p, NODE_IF_LET);
794
795
    /* Parse identifier or placeholder */
796
    if (consume(p, T_UNDERSCORE)) {
797
        n->val.if_let_stmt.var = node(p, NODE_PLACEHOLDER);
798
    } else if (expect(p, T_IDENT, "expected identifier or '_' after 'let'")) {
799
        n->val.if_let_stmt.var                   = node(p, NODE_IDENT);
800
        n->val.if_let_stmt.var->val.ident.name   = p->previous.start;
801
        n->val.if_let_stmt.var->val.ident.length = p->previous.length;
802
    } else {
803
        return NULL;
804
    }
805
    n->val.if_let_stmt.guard = NULL;
806
807
    /* Expect '=' */
808
    if (!expect(p, T_EQ, "expected `=` after identifier"))
809
        return NULL;
810
811
    /* Parse expression yielding an optional. */
812
    n->val.if_let_stmt.expr = parse_cond(p);
813
    if (!n->val.if_let_stmt.expr)
814
        return NULL;
815
816
    /* Optional boolean guard. */
817
    if (consume(p, T_SEMICOLON)) {
818
        n->val.if_let_stmt.guard = parse_cond(p);
819
    }
820
    /* Parse the 'then' branch */
821
    n->val.if_let_stmt.lbranch = parse_block(p);
822
    if (!n->val.if_let_stmt.lbranch)
823
        return NULL;
824
825
    /* Parse optional 'else' branch */
826
    if (consume(p, T_ELSE)) {
827
        /* Check for `else if` construct. */
828
        if (check(p, T_IF)) {
829
            advance(p); /* Consume the 'if' token. */
830
831
            /* Create a block to hold the nested if statement. */
832
            node_t *block          = node(p, NODE_BLOCK);
833
            block->val.block.stmts = (nodespan_t){ 0 };
834
835
            node_t *nested_if = parse_if(p);
836
837
            if (!nested_if)
838
                return NULL;
839
840
            /* Add the nested if as a statement in the block. */
841
            nodespan_push(p, &block->val.block.stmts, nested_if);
842
            /* Set the block as the else branch. */
843
            n->val.if_let_stmt.rbranch = block;
844
        } else {
845
            /* Regular else clause. */
846
            n->val.if_let_stmt.rbranch = parse_block(p);
847
        }
848
    } else {
849
        n->val.if_let_stmt.rbranch = NULL;
850
    }
851
852
    return n;
853
}
854
855
/* Parse an `if let case` statement. Called after 'let' has been consumed. */
856
static node_t *parse_if_case(parser_t *p) {
857
    node_t *n = node(p, NODE_IF_CASE);
858
859
    if (!expect(p, T_CASE, "expected 'case'"))
860
        return NULL;
861
862
    parse_ctx_t pctx = p->context;
863
    p->context       = PARSE_CTX_NORMAL;
864
    node_t *pattern  = parse_primary(p);
865
    p->context       = pctx;
866
867
    if (!pattern)
868
        return NULL;
869
870
    n->val.if_case_stmt.pattern = pattern;
871
872
    if (!expect(p, T_EQ, "expected `=` after pattern"))
873
        return NULL;
874
875
    n->val.if_case_stmt.expr = parse_cond(p);
876
    if (!n->val.if_case_stmt.expr)
877
        return NULL;
878
879
    n->val.if_case_stmt.guard = NULL;
880
881
    if (consume(p, T_SEMICOLON)) {
882
        n->val.if_case_stmt.guard = parse_cond(p);
883
        if (!n->val.if_case_stmt.guard)
884
            return NULL;
885
    }
886
    n->val.if_case_stmt.lbranch = parse_block(p);
887
    if (!n->val.if_case_stmt.lbranch)
888
        return NULL;
889
890
    if (consume(p, T_ELSE)) {
891
        if (check(p, T_IF)) {
892
            advance(p);
893
894
            node_t *block          = node(p, NODE_BLOCK);
895
            block->val.block.stmts = (nodespan_t){ 0 };
896
897
            node_t *nested_if = parse_if(p);
898
899
            if (!nested_if)
900
                return NULL;
901
902
            nodespan_push(p, &block->val.block.stmts, nested_if);
903
            n->val.if_case_stmt.rbranch = block;
904
        } else {
905
            n->val.if_case_stmt.rbranch = parse_block(p);
906
            if (!n->val.if_case_stmt.rbranch)
907
                return NULL;
908
        }
909
    } else {
910
        n->val.if_case_stmt.rbranch = NULL;
911
    }
912
    return n;
913
}
914
915
/* Parse a `let case` statement:
916
 *   `let case PATTERN = EXPR [; GUARD] else { ... };` */
917
static node_t *parse_let_case(parser_t *p) {
918
    node_t *n     = node(p, NODE_GUARD_CASE);
919
    usize   start = p->previous.position;
920
921
    parse_ctx_t pctx = p->context;
922
    p->context       = PARSE_CTX_NORMAL;
923
    node_t *pattern  = parse_primary(p);
924
    p->context       = pctx;
925
926
    if (!pattern)
927
        return NULL;
928
929
    n->val.guard_case_stmt.pattern = pattern;
930
931
    if (!expect(p, T_EQ, "expected `=` after pattern"))
932
        return NULL;
933
    if (!(n->val.guard_case_stmt.expr = parse_cond(p)))
934
        return NULL;
935
936
    n->val.guard_case_stmt.guard = NULL;
937
938
    if (consume(p, T_IF)) {
939
        if (!(n->val.guard_case_stmt.guard = parse_cond(p)))
940
            return NULL;
941
    }
942
    if (!expect(p, T_ELSE, "expected `else` after pattern"))
943
        return NULL;
944
945
    if (!(n->val.guard_case_stmt.rbranch = parse_stmt_or_block(p)))
946
        return NULL;
947
948
    n->offset = start;
949
    n->length = p->previous.position + p->previous.length - start;
950
951
    return n;
952
}
953
954
/* Parse an `if` expression, with optional `else` or `else if` clauses.
955
 * `else if` is desugared into a nested if inside a block. */
956
static node_t *parse_if(parser_t *p) {
957
    /* Check for `if let` or `if let case` syntax */
958
    if (check(p, T_LET)) {
959
        return parse_if_let(p);
960
    }
961
    /* Regular if statement */
962
    node_t *n = node(p, NODE_IF);
963
964
    n->val.if_stmt.cond = parse_cond(p);
965
    if (!n->val.if_stmt.cond)
966
        return NULL;
967
968
    n->val.if_stmt.lbranch = parse_block(p);
969
    if (!n->val.if_stmt.lbranch)
970
        return NULL;
971
972
    if (consume(p, T_ELSE)) {
973
        /* Check for `else if` construct. */
974
        if (check(p, T_IF)) {
975
            advance(p); /* Consume the 'if' token. */
976
977
            /* Create a block to hold the nested if statement. */
978
            node_t *block          = node(p, NODE_BLOCK);
979
            block->val.block.stmts = (nodespan_t){ 0 };
980
981
            node_t *nested_if = parse_if(p);
982
983
            if (!nested_if)
984
                return NULL;
985
986
            /* Add the nested if as a statement in the block. */
987
            nodespan_push(p, &block->val.block.stmts, nested_if);
988
            /* Set the block as the else branch. */
989
            n->val.if_stmt.rbranch = block;
990
        } else {
991
            /* Regular else clause. */
992
            n->val.if_stmt.rbranch = parse_block(p);
993
        }
994
    } else {
995
        n->val.if_stmt.rbranch = NULL;
996
    }
997
    return n;
998
}
999
1000
/* Parse a match statement. */
1001
static node_t *parse_match(parser_t *p) {
1002
    node_t *n               = node(p, NODE_MATCH);
1003
    n->val.match_stmt.cases = (nodespan_t){ 0 };
1004
1005
    /* Parse the expression to match on */
1006
    if (!(n->val.match_stmt.expr = parse_cond(p)))
1007
        return NULL;
1008
    if (!expect(p, T_LBRACE, "expected '{' before match cases"))
1009
        return NULL;
1010
1011
    /* Parse cases until we reach the end of the match block */
1012
    while (!check(p, T_RBRACE) && !check(p, T_EOF)) {
1013
        node_t *case_node = parse_match_case(p);
1014
        if (!case_node)
1015
            return NULL;
1016
1017
        if (!nodespan_push(p, &n->val.match_stmt.cases, case_node)) {
1018
            error(p, "too many cases in match statement");
1019
            return NULL;
1020
        }
1021
1022
        /* Consume the comma separating cases if present */
1023
        bool consumed = consume(p, T_COMMA);
1024
        (void)consumed;
1025
    }
1026
    if (!expect(p, T_RBRACE, "expected '}' after match cases"))
1027
        return NULL;
1028
1029
    return n;
1030
}
1031
1032
/* Parse a single match case. */
1033
static node_t *parse_match_case(parser_t *p) {
1034
    node_t *n                  = node(p, NODE_MATCH_CASE);
1035
    n->val.match_case.patterns = (nodespan_t){ 0 };
1036
    n->val.match_case.guard    = NULL;
1037
1038
    if (check(p, T_ELSE)) {
1039
        /* For the 'else' case, we use zero patterns
1040
         * to indicate the else case */
1041
        advance(p);
1042
    } else {
1043
        if (!expect(p, T_CASE, "expected 'case' at start of match case"))
1044
            return NULL;
1045
1046
        /* Parse one or more comma-separated patterns */
1047
        do {
1048
            parse_ctx_t pctx = p->context;
1049
            p->context       = PARSE_CTX_NORMAL;
1050
            node_t *pattern  = parse_primary(p);
1051
            p->context       = pctx;
1052
1053
            if (!pattern) {
1054
                return NULL;
1055
            }
1056
            /* Add pattern to the case */
1057
            if (!nodespan_push(p, &n->val.match_case.patterns, pattern)) {
1058
                error(p, "too many patterns in case statement");
1059
                return NULL;
1060
            }
1061
        } while (consume(p, T_COMMA)); /* Continue if there's a comma */
1062
1063
        if (consume(p, T_IF)) {
1064
            if (!(n->val.match_case.guard = parse_cond(p)))
1065
                return NULL;
1066
        }
1067
    }
1068
    if (!expect(p, T_FAT_ARROW, "expected `=>` after case pattern"))
1069
        return NULL;
1070
1071
    n->val.match_case.body = parse_stmt(p);
1072
    if (!n->val.match_case.body)
1073
        return NULL;
1074
1075
    return n;
1076
}
1077
1078
/* Parse a `log` statement. */
1079
/* Parse a record declaration. */
1080
static node_t *parse_record(parser_t *p, node_t *attrs) {
1081
    node_t *n                  = node(p, NODE_RECORD);
1082
    n->val.record_decl.attribs = attrs;
1083
    n->val.record_decl.fields  = (nodespan_t){ 0 };
1084
    n->val.record_decl.tuple   = false;
1085
    n->val.record_decl.name    = parse_ident(p, "expected record name");
1086
1087
    if (!n->val.record_decl.name)
1088
        return NULL;
1089
1090
    if (consume(p, T_LPAREN)) {
1091
        n->val.record_decl.tuple = true;
1092
1093
        if (!check(p, T_RPAREN)) {
1094
            do {
1095
                node_t *field        = node(p, NODE_RECORD_FIELD);
1096
                field->val.var.ident = NULL; /* No field name for tuples */
1097
                field->val.var.type  = parse_type(p);
1098
                field->val.var.value = NULL;
1099
                field->val.var.align = NULL;
1100
1101
                if (!field->val.var.type)
1102
                    return NULL;
1103
1104
                if (!nodespan_push(p, &n->val.record_decl.fields, field)) {
1105
                    error(p, "too many record fields");
1106
                    return NULL;
1107
                }
1108
            } while (consume(p, T_COMMA) && !check(p, T_RPAREN));
1109
        }
1110
        if (!expect(p, T_RPAREN, "expected `)` after record fields"))
1111
            return NULL;
1112
1113
        /* Unlabeled records must end with semicolon */
1114
        if (!expect(p, T_SEMICOLON, "expected `;` after record declaration"))
1115
            return NULL;
1116
    } else {
1117
        /* Record with named fields */
1118
        if (!expect(p, T_LBRACE, "expected `{` before record body"))
1119
            return NULL;
1120
1121
        node_t *field;
1122
        do {
1123
            if (!(field = parse_name_type_value(p, NODE_RECORD_FIELD)))
1124
                return NULL;
1125
            if (!nodespan_push(p, &n->val.record_decl.fields, field)) {
1126
                error(p, "too many record fields");
1127
                return NULL;
1128
            }
1129
        } while (consume(p, T_COMMA) && !check(p, T_RBRACE));
1130
1131
        if (!expect(p, T_RBRACE, "expected `}`"))
1132
            return NULL;
1133
    }
1134
    return n;
1135
}
1136
1137
static node_t *parse_record_type(parser_t *p) {
1138
    node_t *n                 = node(p, NODE_RECORD_TYPE);
1139
    n->val.record_type.fields = (nodespan_t){ 0 };
1140
1141
    if (!expect(p, T_LBRACE, "expected `{` after `record`"))
1142
        return NULL;
1143
1144
    if (!check(p, T_RBRACE)) {
1145
        do {
1146
            node_t *field = parse_name_type_value(p, NODE_RECORD_FIELD);
1147
            if (!field)
1148
                return NULL;
1149
            if (field->val.var.value) {
1150
                error(p, "anonymous record fields cannot have initializers");
1151
                return NULL;
1152
            }
1153
            if (!nodespan_push(p, &n->val.record_type.fields, field)) {
1154
                error(p, "too many record fields");
1155
                return NULL;
1156
            }
1157
        } while (consume(p, T_COMMA) && !check(p, T_RBRACE));
1158
    }
1159
1160
    if (!expect(p, T_RBRACE, "expected `}` after record fields"))
1161
        return NULL;
1162
1163
    return n;
1164
}
1165
1166
/* Parse a single record literal field (labeled or shorthand). */
1167
static node_t *parse_record_lit_field(parser_t *p) {
1168
    node_t *n     = node(p, NODE_RECORD_LIT_FIELD);
1169
    usize   start = p->current.position;
1170
1171
    record_lit_field_t *field = &n->val.record_lit_field;
1172
1173
    /* Field must start with an identifier. */
1174
    node_t *name = parse_ident(p, "expected field name");
1175
    if (!name)
1176
        return NULL;
1177
1178
    if (consume(p, T_COLON)) {
1179
        /* Labeled field: `name: value` */
1180
        field->name  = name;
1181
        field->value = parse_expr(p);
1182
        if (!field->value)
1183
            return NULL;
1184
    } else {
1185
        /* Shorthand syntax: `{ x }` is equivalent to `{ x: x }` */
1186
        field->name  = name;
1187
        field->value = name;
1188
    }
1189
    n->offset = start;
1190
    n->length = p->previous.position + p->previous.length - start;
1191
1192
    return n;
1193
}
1194
1195
/* Parse a record literal expression (e.g., Point { x: 1, y: 2 })
1196
 * Also handles pattern syntax: Variant { .. } to discard all fields */
1197
static node_t *parse_record_lit(parser_t *p, node_t *type_name) {
1198
    node_t *n                = node(p, NODE_RECORD_LIT);
1199
    n->val.record_lit.type   = type_name;
1200
    n->val.record_lit.fields = (nodespan_t){ 0 };
1201
    n->val.record_lit.etc    = false;
1202
1203
    do {
1204
        /* Check for `..` to discard remaining fields. */
1205
        if (consume(p, T_DOT_DOT)) {
1206
            n->val.record_lit.etc = true;
1207
            break;
1208
        }
1209
        node_t *field = parse_record_lit_field(p);
1210
        if (!field)
1211
            return NULL;
1212
1213
        if (!nodespan_push(p, &n->val.record_lit.fields, field)) {
1214
            error(p, "too many record fields");
1215
            return NULL;
1216
        }
1217
1218
    } while (consume(p, T_COMMA) && !check(p, T_RBRACE));
1219
1220
    if (!expect(p, T_RBRACE, "expected '}' to end record literal"))
1221
        return NULL;
1222
1223
    return n;
1224
}
1225
1226
/* Parse a union declaration.
1227
 * Eg. `union Color { Red, Green, Blue = 5 }` */
1228
static node_t *parse_union(parser_t *p, node_t *attrs) {
1229
    node_t *n                  = node(p, NODE_UNION);
1230
    n->val.union_decl.attribs  = attrs;
1231
    n->val.union_decl.variants = (nodespan_t){ 0 };
1232
    n->val.union_decl.name     = parse_ident(p, "expected union name");
1233
1234
    if (!n->val.union_decl.name)
1235
        return NULL;
1236
1237
    /* Parse union body with { ... } */
1238
    if (!expect(p, T_LBRACE, "expected `{` before union body"))
1239
        return NULL;
1240
1241
    /* Parse union variants. */
1242
    if (!check(p, T_RBRACE)) {
1243
        do {
1244
            /* Allow optional `case` keyword before variant name. */
1245
            consume(p, T_CASE);
1246
1247
            /* Parse variant name. */
1248
            node_t *variant_name = parse_ident(p, "expected variant name");
1249
            if (!variant_name)
1250
                return NULL;
1251
1252
            node_t          *v       = node(p, NODE_UNION_VARIANT);
1253
            union_variant_t *variant = &v->val.union_variant;
1254
1255
            variant->name       = variant_name;
1256
            variant->type       = NULL;
1257
            variant->value_expr = NULL;
1258
1259
            if (consume(p, T_LPAREN)) {
1260
                /* Tuple-like variant: Foo(Type) */
1261
                node_t *payload = parse_type(p);
1262
                if (!payload)
1263
                    return NULL;
1264
                variant->type = payload;
1265
                if (!expect(p, T_RPAREN, "expected `)` after variant type"))
1266
                    return NULL;
1267
            } else if (check(p, T_LBRACE)) {
1268
                /* Struct-like variant: Bar { x: i32, y: i32 } */
1269
                node_t *payload = parse_record_type(p);
1270
                if (!payload)
1271
                    return NULL;
1272
                variant->type = payload;
1273
            } else {
1274
                /* Check for explicit value assignment. */
1275
                if (consume(p, T_EQ)) {
1276
                    if (!expect(
1277
                            p, T_NUMBER, "expected integer literal after `=`"
1278
                        ))
1279
                        return NULL;
1280
1281
                    token_t literal_tok = p->previous;
1282
                    node_t *literal     = node(p, NODE_NUMBER);
1283
1284
                    literal->offset              = literal_tok.position;
1285
                    literal->length              = literal_tok.length;
1286
                    literal->val.number.text     = literal_tok.start;
1287
                    literal->val.number.text_len = literal_tok.length;
1288
                    literal->val.number.value    = (imm_t){ 0 };
1289
1290
                    variant->value_expr = literal;
1291
                } else {
1292
                    /* Auto-assign value. */
1293
                }
1294
            }
1295
            /* Add variant to declaration node. */
1296
            if (!nodespan_push(p, &n->val.union_decl.variants, v)) {
1297
                error(p, "too many union variants");
1298
                return NULL;
1299
            }
1300
            /* Allow trailing comma. */
1301
        } while (consume(p, T_COMMA) && !check(p, T_RBRACE));
1302
    }
1303
    if (!expect(p, T_RBRACE, "expected `}`"))
1304
        return NULL;
1305
1306
    return n;
1307
}
1308
1309
/* Parse a code block or an expression */
1310
static node_t *parse_stmt_or_block(parser_t *p) {
1311
    if (check(p, T_LBRACE)) {
1312
        return parse_block(p);
1313
    }
1314
    node_t *stmt         = parse_stmt(p);
1315
    node_t *blk          = node(p, NODE_BLOCK);
1316
    blk->val.block.stmts = (nodespan_t){ 0 };
1317
    nodespan_push(p, &blk->val.block.stmts, stmt);
1318
1319
    return blk;
1320
}
1321
1322
/* Parse a code block, enclosed by `{}`. */
1323
static node_t *parse_block(parser_t *p) {
1324
    if (!expect(p, T_LBRACE, "expected '{' before block")) {
1325
        return NULL;
1326
    }
1327
    node_t *n = node(p, NODE_BLOCK);
1328
    node_t *stmt;
1329
1330
    /* Parse statements. */
1331
    n->val.block.stmts = (nodespan_t){ 0 };
1332
    while (!check(p, T_RBRACE) && !check(p, T_EOF)) {
1333
        usize start = p->current.position;
1334
1335
        if (!(stmt = parse_stmt(p)))
1336
            return NULL;
1337
1338
        if (!consume_statement_separator(p, stmt, true))
1339
            return NULL;
1340
1341
        stmt->offset = start;
1342
        stmt->length = p->current.position - start;
1343
1344
        if (!nodespan_push(p, &n->val.block.stmts, stmt)) {
1345
            error(p, "too many statements in block");
1346
            return NULL;
1347
        }
1348
    }
1349
1350
    if (!expect(p, T_RBRACE, "expected matching '}' after block"))
1351
        return NULL;
1352
1353
    return n;
1354
}
1355
1356
/* Parse an expression. */
1357
static node_t *parse_expr(parser_t *p) {
1358
    node_t *lval;
1359
1360
    if ((lval = parse_primary(p)) == NULL)
1361
        return NULL;
1362
1363
    /* Handle `as` casts before binary operators (higher precedence than
1364
     * binary ops, lower than unary) */
1365
    while (check(p, T_AS)) {
1366
        lval = parse_as_cast(p, lval);
1367
        if (!lval)
1368
            return NULL;
1369
    }
1370
    lval = parse_binary(p, lval, -1);
1371
1372
    return lval;
1373
}
1374
1375
/* Parse an assignment statement. */
1376
static node_t *parse_assignment(parser_t *p, node_t *lval) {
1377
    /* We've already verified this is an assignment. */
1378
    if (lval->cls != NODE_IDENT && lval->cls != NODE_ACCESS &&
1379
        lval->cls != NODE_ARRAY_INDEX &&
1380
        !(lval->cls == NODE_UNOP && lval->val.unop.op == OP_DEREF)) {
1381
        error(
1382
            p,
1383
            "can't assign to `%.*s`",
1384
            lval->length,
1385
            &p->scanner.source[lval->offset]
1386
        );
1387
        return NULL;
1388
    }
1389
    node_t *rval;
1390
1391
    if (!(rval = parse_expr(p)))
1392
        return NULL;
1393
1394
    node_t *assign          = node(p, NODE_ASSIGN);
1395
    assign->val.assign.lval = lval;
1396
    assign->val.assign.rval = rval;
1397
1398
    return assign;
1399
}
1400
1401
/* Parse a condition. */
1402
static node_t *parse_cond(parser_t *p) {
1403
    parse_ctx_t prev = p->context;
1404
    p->context       = PARSE_CTX_CONDITION;
1405
1406
    node_t *cond = parse_expr(p);
1407
    if (!cond) {
1408
        p->context = prev;
1409
        return NULL;
1410
    }
1411
    p->context = prev;
1412
1413
    return cond;
1414
}
1415
1416
static bool token_is_stmt_terminator(tokenclass_t cls) {
1417
    switch (cls) {
1418
    case T_SEMICOLON:
1419
    case T_RBRACE:
1420
    case T_COMMA:
1421
    case T_CASE:
1422
    case T_ELSE:
1423
    case T_EOF:
1424
        return true;
1425
    default:
1426
        return false;
1427
    }
1428
}
1429
1430
static bool stmt_requires_semicolon(const node_t *stmt) {
1431
    switch (stmt->cls) {
1432
    case NODE_IF:
1433
    case NODE_IF_LET:
1434
    case NODE_IF_CASE:
1435
    case NODE_WHILE:
1436
    case NODE_WHILE_LET:
1437
    case NODE_LOOP:
1438
    case NODE_FOR:
1439
    case NODE_MATCH:
1440
    case NODE_BLOCK:
1441
    case NODE_FN:
1442
    case NODE_RECORD:
1443
    case NODE_UNION:
1444
        return false;
1445
    default:
1446
        return true;
1447
    }
1448
}
1449
1450
static bool consume_statement_separator(
1451
    parser_t *p, node_t *stmt, bool require
1452
) {
1453
    if (stmt_requires_semicolon(stmt)) {
1454
        return expect(p, T_SEMICOLON, "expected `;` after statement");
1455
    }
1456
    if (require)
1457
        consume(p, T_SEMICOLON);
1458
    return true;
1459
}
1460
1461
/* Parse a `return` statement. */
1462
static node_t *parse_return(parser_t *p) {
1463
    node_t *n = node(p, NODE_RETURN);
1464
1465
    if (!token_is_stmt_terminator(p->current.cls)) {
1466
        n->val.return_stmt.value = parse_expr(p);
1467
        if (!n->val.return_stmt.value)
1468
            return NULL;
1469
    } else {
1470
        n->val.return_stmt.value = NULL; /* Return void. */
1471
    }
1472
1473
    return n;
1474
}
1475
1476
static node_t *parse_throw(parser_t *p) {
1477
    node_t *n = node(p, NODE_THROW);
1478
1479
    if (!(n->val.throw_stmt.expr = parse_expr(p)))
1480
        return NULL;
1481
1482
    return n;
1483
}
1484
1485
/* Parse a `break` statement. */
1486
static node_t *parse_break(parser_t *p) {
1487
    node_t *n = node(p, NODE_BREAK);
1488
1489
    return n;
1490
}
1491
1492
/* Parse a `for` statement. */
1493
static node_t *parse_for(parser_t *p) {
1494
    node_t *n               = node(p, NODE_FOR);
1495
    n->val.for_stmt.rbranch = NULL;
1496
    n->val.for_stmt.idx     = NULL;
1497
1498
    /* Parse the loop variable name or placeholder */
1499
    if (!(n->val.for_stmt.var =
1500
              parse_ident_or_placeholder(p, "expected identifier or '_'")))
1501
        return NULL;
1502
1503
    /* Check for optional index variable: `for x, i in xs` */
1504
    if (consume(p, T_COMMA)) {
1505
        /* Parse the index variable name or placeholder */
1506
        if (!(n->val.for_stmt.idx = parse_ident_or_placeholder(
1507
                  p, "expected index identifier or '_' after comma"
1508
              )))
1509
            return NULL;
1510
    }
1511
1512
    if (!expect(p, T_IN, "expected `in`"))
1513
        return NULL;
1514
1515
    if (!(n->val.for_stmt.iter = parse_cond(p)))
1516
        return NULL;
1517
1518
    if (!(n->val.for_stmt.body = parse_block(p)))
1519
        return NULL;
1520
1521
    /* Parse optional `else` clause */
1522
    if (consume(p, T_ELSE)) {
1523
        if (!(n->val.for_stmt.rbranch = parse_block(p)))
1524
            return NULL;
1525
    }
1526
    return n;
1527
}
1528
1529
/* Parse a `while let` statement. */
1530
static node_t *parse_while_let(parser_t *p) {
1531
    if (!expect(p, T_LET, "expected `let`"))
1532
        return NULL;
1533
1534
    node_t *n = node(p, NODE_WHILE_LET);
1535
1536
    /* Parse identifier or placeholder */
1537
    if (consume(p, T_UNDERSCORE)) {
1538
        n->val.while_let_stmt.var = node(p, NODE_PLACEHOLDER);
1539
    } else if (expect(p, T_IDENT, "expected identifier or '_' after `let`")) {
1540
        n->val.while_let_stmt.var                   = node(p, NODE_IDENT);
1541
        n->val.while_let_stmt.var->val.ident.name   = p->previous.start;
1542
        n->val.while_let_stmt.var->val.ident.length = p->previous.length;
1543
    } else {
1544
        return NULL;
1545
    }
1546
    n->val.while_let_stmt.guard   = NULL;
1547
    n->val.while_let_stmt.rbranch = NULL;
1548
1549
    if (!expect(p, T_EQ, "expected `=` after identifier"))
1550
        return NULL;
1551
1552
    /* Parse expression yielding an optional. */
1553
    n->val.while_let_stmt.expr = parse_cond(p);
1554
    if (!n->val.while_let_stmt.expr)
1555
        return NULL;
1556
1557
    /* Optional guard condition after semicolon. */
1558
    if (consume(p, T_SEMICOLON)) {
1559
        if (!(n->val.while_let_stmt.guard = parse_cond(p)))
1560
            return NULL;
1561
    }
1562
1563
    /* Parse the loop body and optional 'else' branch */
1564
    if (!(n->val.while_let_stmt.body = parse_block(p)))
1565
        return NULL;
1566
    if (consume(p, T_ELSE)) {
1567
        if (!(n->val.while_let_stmt.rbranch = parse_block(p)))
1568
            return NULL;
1569
    }
1570
    return n;
1571
}
1572
1573
/* Parse a `while` statement. */
1574
static node_t *parse_while(parser_t *p) {
1575
    /* Check for `while let` syntax */
1576
    if (check(p, T_LET)) {
1577
        return parse_while_let(p);
1578
    }
1579
    node_t *n                 = node(p, NODE_WHILE);
1580
    n->val.while_stmt.rbranch = NULL;
1581
1582
    if (!(n->val.while_stmt.cond = parse_cond(p)))
1583
        return NULL;
1584
    if (!(n->val.while_stmt.body = parse_block(p)))
1585
        return NULL;
1586
1587
    /* Parse optional else clause */
1588
    if (consume(p, T_ELSE)) {
1589
        if (!(n->val.while_stmt.rbranch = parse_block(p)))
1590
            return NULL;
1591
    }
1592
    return n;
1593
}
1594
1595
/* Parse a `loop` statement. */
1596
static node_t *parse_loop(parser_t *p) {
1597
    node_t *n = node(p, NODE_LOOP);
1598
1599
    if (!(n->val.loop_stmt.body = parse_block(p)))
1600
        return NULL;
1601
1602
    return n;
1603
}
1604
1605
static node_t *parse_try(parser_t *p, bool panic, bool optional) {
1606
    node_t *n = node(p, NODE_TRY);
1607
1608
    n->val.try_expr.expr       = NULL;
1609
    n->val.try_expr.catch_expr = NULL;
1610
    n->val.try_expr.handlers   = nodespan_alloc(p, MAX_TRY_CATCHES);
1611
    n->val.try_expr.panic      = panic;
1612
    n->val.try_expr.optional   = optional;
1613
1614
    if (!(n->val.try_expr.expr = parse_primary(p)))
1615
        return NULL;
1616
1617
    /* Parse catch clause: `catch { ... }` or `catch e { ... }` */
1618
    if (consume(p, T_CATCH)) {
1619
        node_t *catch_node                   = node(p, NODE_CATCH);
1620
        catch_node->val.catch_clause.binding = NULL;
1621
        catch_node->val.catch_clause.body    = NULL;
1622
        catch_node->val.catch_clause.scope   = NULL;
1623
1624
        /* Check for error binding: `catch e { ... }` */
1625
        if (check(p, T_IDENT)) {
1626
            node_t *binding                      = node(p, NODE_IDENT);
1627
            binding->val.ident.name              = p->current.start;
1628
            binding->val.ident.length            = p->current.length;
1629
            catch_node->val.catch_clause.binding = binding;
1630
            advance(p);
1631
        }
1632
1633
        if (!check(p, T_LBRACE)) {
1634
            error(p, "expected `{` after `catch`");
1635
            return NULL;
1636
        }
1637
        if (!(catch_node->val.catch_clause.body = parse_block(p)))
1638
            return NULL;
1639
1640
        n->val.try_expr.catch_expr = catch_node;
1641
    }
1642
    return n;
1643
}
1644
1645
static node_t *parse_panic(parser_t *p) {
1646
    node_t *panic = node(p, NODE_PANIC);
1647
1648
    /* `panic { "Something's wrong!" }` */
1649
    if (consume(p, T_LBRACE)) {
1650
        node_t *expr = parse_expr(p);
1651
        if (!(panic->val.panic_stmt.message = expr))
1652
            return NULL;
1653
        if (!expect(p, T_RBRACE, "expected closing `}` after expression"))
1654
            return NULL;
1655
1656
        return panic;
1657
    }
1658
1659
    if (token_is_stmt_terminator(p->current.cls)) {
1660
        panic->val.panic_stmt.message = NULL;
1661
        return panic;
1662
    }
1663
1664
    node_t *expr = parse_expr(p);
1665
    if (!(panic->val.panic_stmt.message = expr))
1666
        return NULL;
1667
1668
    return panic;
1669
}
1670
1671
/* Parse a name, type, and optional value.
1672
 *
1673
 * Used for record field declarations, variable declarations, and record field
1674
 * initializations. */
1675
static node_t *parse_name_type_value(parser_t *p, nodeclass_t cls) {
1676
    node_t *n        = node(p, cls);
1677
    usize   start    = p->current.position;
1678
    node_t *type     = NULL;
1679
    bool    is_typed = false;
1680
1681
    n->val.var.ident =
1682
        parse_ident_or_placeholder(p, "expected identifier or '_'");
1683
    if (!n->val.var.ident)
1684
        return NULL;
1685
1686
    if (cls == NODE_VAR) {
1687
        /* Type annotation is optional for variable declarations. */
1688
        if (consume(p, T_COLON))
1689
            is_typed = true;
1690
    } else {
1691
        if (!expect(p, T_COLON, "expected `:` after identifier"))
1692
            return NULL;
1693
        is_typed = true;
1694
    }
1695
1696
    if (is_typed) {
1697
        type = parse_type(p);
1698
        if (!type)
1699
            return NULL;
1700
1701
        if (cls == NODE_VAR) {
1702
            n->val.var.align = NULL;
1703
1704
            if (consume(p, T_ALIGN)) {
1705
                if (!expect(p, T_LPAREN, "expected `(` after `align`"))
1706
                    return NULL;
1707
1708
                n->val.var.align            = node(p, NODE_ALIGN);
1709
                n->val.var.align->val.align = parse_expr(p);
1710
1711
                if (!expect(p, T_RPAREN, "expected `)` after expression"))
1712
                    return NULL;
1713
            }
1714
        }
1715
    } else if (cls == NODE_VAR) {
1716
        n->val.var.align = NULL;
1717
    }
1718
    n->val.var.type  = type;
1719
    n->val.var.value = NULL;
1720
1721
    /* Parse the optional value. */
1722
    if (consume(p, T_EQ)) {
1723
        node_t *value = parse_expr(p);
1724
        if (!value)
1725
            return NULL;
1726
        n->val.var.value = value;
1727
    }
1728
    /* Set the node location. */
1729
    n->offset = start;
1730
    n->length = p->previous.position + p->previous.length - start;
1731
1732
    return n;
1733
}
1734
1735
/* Parse a variable declaration. */
1736
static node_t *parse_var(parser_t *p, bool mutable) {
1737
    node_t *var = parse_name_type_value(p, NODE_VAR);
1738
1739
    if (!var)
1740
        return NULL;
1741
1742
    var->val.var.mutable = mutable;
1743
1744
    /* Parse optional `else` clause. */
1745
    if (consume(p, T_ELSE)) {
1746
        if (mutable) {
1747
            error(p, "let-else bindings cannot be mutable");
1748
            return NULL;
1749
        }
1750
        if (!var->val.var.value) {
1751
            error(p, "let-else requires an initializer");
1752
            return NULL;
1753
        }
1754
        node_t *rbranch = parse_stmt_or_block(p);
1755
        if (!rbranch)
1756
            return NULL;
1757
1758
        var->cls                        = NODE_GUARD_LET;
1759
        var->val.guard_let_stmt.var     = var->val.var.ident;
1760
        var->val.guard_let_stmt.expr    = var->val.var.value;
1761
        var->val.guard_let_stmt.rbranch = rbranch;
1762
        var->length = p->previous.position + p->previous.length - var->offset;
1763
1764
        return var;
1765
    }
1766
    var->length = p->previous.position + p->previous.length - var->offset;
1767
1768
    return var;
1769
}
1770
1771
/* Parse a static variable declaration. */
1772
static node_t *parse_static(parser_t *p) {
1773
    node_t *n     = node(p, NODE_STATIC);
1774
    usize   start = p->previous.position;
1775
1776
    node_t *ident = parse_label(p, "expected identifier in static declaration");
1777
    if (!ident)
1778
        return NULL;
1779
1780
    node_t *type = parse_type(p);
1781
    if (!type)
1782
        return NULL;
1783
1784
    if (!expect(p, T_EQ, "expected `=` in static declaration"))
1785
        return NULL;
1786
1787
    node_t *value = parse_expr(p);
1788
    if (!value)
1789
        return NULL;
1790
1791
    n->val.static_decl.ident = ident;
1792
    n->val.static_decl.type  = type;
1793
    n->val.static_decl.value = value;
1794
    n->offset                = start;
1795
    n->length = p->previous.position + p->previous.length - start;
1796
1797
    return n;
1798
}
1799
1800
/* Parse a constant declaration. */
1801
static node_t *parse_const(parser_t *p) {
1802
    node_t *var = parse_name_type_value(p, NODE_CONST);
1803
1804
    if (!var)
1805
        return NULL;
1806
1807
    return var;
1808
}
1809
1810
/* Parse a module use declaration. */
1811
static node_t *parse_use(parser_t *p, node_t *attrs) {
1812
    usize start = p->current.position;
1813
1814
    /* Parse the first identifier in the path. */
1815
    node_t *path = parse_scope_segment(p, "expected module name after 'use'");
1816
    if (!path)
1817
        return NULL;
1818
1819
    /* Track if this is a wildcard import. */
1820
    bool wildcard = false;
1821
1822
    /* Continue parsing the dotted path if present. */
1823
    while (consume(p, T_COLON_COLON)) {
1824
        /* Check for wildcard import (e.g., `use foo::*`) */
1825
        if (consume(p, T_STAR)) {
1826
            wildcard = true;
1827
            break;
1828
        }
1829
1830
        node_t *n          = node(p, NODE_SCOPE);
1831
        n->val.access.lval = path;
1832
1833
        /* Parse the sub-module name. */
1834
        node_t *mod =
1835
            parse_scope_segment(p, "expected identifier or '*' after '::'");
1836
        if (!mod)
1837
            return NULL;
1838
1839
        n->val.access.rval = mod;
1840
        path               = n;
1841
    }
1842
1843
    /* Create a use node and wrap the path. */
1844
    node_t *use_node                = node(p, NODE_USE);
1845
    use_node->val.use_decl.path     = path;
1846
    use_node->val.use_decl.attribs  = attrs;
1847
    use_node->val.use_decl.wildcard = wildcard;
1848
1849
    /* Set position information. */
1850
    use_node->offset = start;
1851
    use_node->length = p->previous.position + p->previous.length - start;
1852
1853
    return use_node;
1854
}
1855
1856
/* Parse a module declaration. */
1857
static node_t *parse_mod(parser_t *p, node_t *attrs) {
1858
    usize start = p->current.position;
1859
1860
    node_t *ident = parse_ident(p, "expected module name after 'mod'");
1861
    if (!ident)
1862
        return NULL;
1863
    node_t *mod_node               = node(p, NODE_MOD);
1864
    mod_node->val.mod_decl.ident   = ident;
1865
    mod_node->val.mod_decl.attribs = attrs;
1866
1867
    mod_node->offset = start;
1868
    mod_node->length = p->previous.position + p->previous.length - start;
1869
1870
    return mod_node;
1871
}
1872
1873
/* Parse a function parameter. */
1874
static node_t *parse_fn_param(parser_t *p) {
1875
    /* Create parameter node. */
1876
    node_t *param = node(p, NODE_PARAM);
1877
    node_t *name  = parse_label(p, "expected parameter name");
1878
    if (!name)
1879
        return NULL;
1880
1881
    param->val.param.ident = name;
1882
1883
    /* Parse and store parameter type. */
1884
    if (!(param->val.param.type = parse_type(p)))
1885
        return NULL;
1886
1887
    return param;
1888
}
1889
1890
static node_t *parse_module_body(parser_t *p) {
1891
    node_t *mod          = node(p, NODE_MOD_BODY);
1892
    mod->val.block.stmts = (nodespan_t){ 0 };
1893
1894
    while (!check(p, T_EOF)) {
1895
        node_t *stmt;
1896
        usize   start = p->current.position;
1897
1898
        if (!(stmt = parse_stmt(p)))
1899
            return NULL;
1900
1901
        if (!consume_statement_separator(p, stmt, true))
1902
            return NULL;
1903
1904
        stmt->offset = start;
1905
        stmt->length = p->current.position - start;
1906
1907
        if (!nodespan_push(p, &mod->val.block.stmts, stmt)) {
1908
            error(p, "too many statements in module");
1909
            return NULL;
1910
        }
1911
    }
1912
    return mod;
1913
}
1914
1915
/* Parse a function definition. */
1916
static node_t *parse_fn(parser_t *p, node_t *attrs) {
1917
    node_t *n     = node(p, NODE_FN);
1918
    node_t *param = NULL;
1919
1920
    /* Parse the function name. */
1921
    node_t *name = parse_ident(p, "expected function name");
1922
    if (!name)
1923
        return NULL;
1924
1925
    n->val.fn_decl.ident   = name;
1926
    n->val.fn_decl.params  = nodespan_alloc(p, MAX_FN_PARAMS);
1927
    n->val.fn_decl.throws  = nodespan_alloc(p, MAX_FN_THROWS);
1928
    n->val.fn_decl.attribs = attrs;
1929
    n->val.fn_decl.body    = NULL;
1930
1931
    /* Check if it's an extern function */
1932
    bool is_extern = (attrs && attrs->val.attrib & ATTRIB_EXTERN);
1933
1934
    if (!expect(p, T_LPAREN, "expected `(` after function name"))
1935
        return NULL;
1936
1937
    /* Parse parameters with types */
1938
    if (!check(p, T_RPAREN)) {
1939
        do {
1940
            if (n->val.fn_decl.params.len >= MAX_FN_PARAMS) {
1941
                error(
1942
                    p,
1943
                    "maximum number of function parameters (%d) exceeded",
1944
                    MAX_FN_PARAMS
1945
                );
1946
                return NULL;
1947
            }
1948
            if (!(param = parse_fn_param(p))) {
1949
                return NULL;
1950
            }
1951
            node_fn_add_param(p, n, param);
1952
1953
        } while (consume(p, T_COMMA));
1954
    }
1955
    if (!expect(p, T_RPAREN, "expected matching `)` after parameters list"))
1956
        return NULL;
1957
1958
    if (consume(p, T_ARROW)) {
1959
        if (!(n->val.fn_decl.return_type = parse_type(p))) {
1960
            return NULL;
1961
        }
1962
    } else {
1963
        n->val.fn_decl.return_type = NULL;
1964
    }
1965
    if (consume(p, T_THROWS)) {
1966
        if (!expect(p, T_LPAREN, "expected `(` after `throws`"))
1967
            return NULL;
1968
1969
        if (!check(p, T_RPAREN)) {
1970
            do {
1971
                if (n->val.fn_decl.throws.len >= MAX_FN_THROWS) {
1972
                    error(p, "maximum number of thrown types exceeded");
1973
                    return NULL;
1974
                }
1975
                node_t *thrown = parse_type(p);
1976
                if (!thrown)
1977
                    return NULL;
1978
1979
                nodespan_push(p, &n->val.fn_decl.throws, thrown);
1980
            } while (consume(p, T_COMMA));
1981
        }
1982
        if (!expect(p, T_RPAREN, "expected `)` after throws clause"))
1983
            return NULL;
1984
    }
1985
1986
    /* For extern functions, expect semicolon instead of body */
1987
    if (is_extern) {
1988
        if (!expect(
1989
                p, T_SEMICOLON, "expected `;` after extern function declaration"
1990
            ))
1991
            return NULL;
1992
    } else {
1993
        if (!(n->val.fn_decl.body = parse_block(p)))
1994
            return NULL;
1995
    }
1996
    return n;
1997
}
1998
1999
/* Try to parse an annotation like `@default`.
2000
 * Returns true if a known annotation was found and consumed.
2001
 * Returns false if not an annotation (e.g. @sizeOf) - tokens not consumed. */
2002
static bool try_parse_annotation(parser_t *p, attrib_t *attrs) {
2003
    if (!check(p, T_AT_IDENT))
2004
        return false;
2005
2006
    /* Token is @identifier, skip the '@' to get the name. */
2007
    const char *name   = p->current.start + 1;
2008
    usize       length = p->current.length - 1;
2009
2010
    if (length == 7 && !strncmp(name, "default", 7)) {
2011
        advance(p); /* Consume `@default`. */
2012
        *attrs |= ATTRIB_DEFAULT;
2013
        return true;
2014
    }
2015
    if (length == 4 && !strncmp(name, "test", 4)) {
2016
        advance(p); /* Consume `@test`. */
2017
        *attrs |= ATTRIB_TEST;
2018
        return true;
2019
    }
2020
    if (length == 9 && !strncmp(name, "intrinsic", 9)) {
2021
        advance(p); /* Consume `@intrinsic`. */
2022
        *attrs |= ATTRIB_INTRINSIC;
2023
        return true;
2024
    }
2025
    /* Not a known annotation - leave for parse_builtin to handle. */
2026
    return false;
2027
}
2028
2029
/* Parse statement attributes. */
2030
static node_t *parse_attribs(parser_t *p) {
2031
    node_t  *n     = NULL;
2032
    attrib_t attrs = ATTRIB_NONE;
2033
2034
    for (;;) {
2035
        if (consume(p, T_PUB)) {
2036
            if (attrs & ATTRIB_PUB) {
2037
                error(p, "duplicate `pub` attribute");
2038
                return NULL;
2039
            }
2040
            attrs |= ATTRIB_PUB;
2041
        } else if (try_parse_annotation(p, &attrs)) {
2042
            /* Annotation was consumed, continue. */
2043
        } else if (consume(p, T_EXTERN)) {
2044
            if (attrs & ATTRIB_EXTERN) {
2045
                error(p, "duplicate `extern` attribute");
2046
                return NULL;
2047
            }
2048
            attrs |= ATTRIB_EXTERN;
2049
        } else {
2050
            break;
2051
        }
2052
    }
2053
2054
    if (attrs != ATTRIB_NONE) {
2055
        n             = node(p, NODE_ATTRIBUTE);
2056
        n->val.attrib = attrs;
2057
    }
2058
    return n;
2059
}
2060
2061
/* Parse a statement. */
2062
static node_t *parse_stmt(parser_t *p) {
2063
    /* Parse any attributes that come before the statement. */
2064
    node_t *attrs = parse_attribs(p);
2065
2066
    if (attrs) {
2067
        switch (p->current.cls) {
2068
        case T_FN:
2069
        case T_UNION:
2070
        case T_RECORD:
2071
        case T_MOD:
2072
        case T_CONST:
2073
        case T_USE:
2074
            break;
2075
        default:
2076
            error(p, "attributes are not allowed in this context");
2077
            return NULL;
2078
        }
2079
2080
        /* Verify extern is only used with functions */
2081
        if ((attrs->val.attrib & ATTRIB_EXTERN) && p->current.cls != T_FN) {
2082
            error(
2083
                p, "extern attribute is only allowed on function declarations"
2084
            );
2085
            return NULL;
2086
        }
2087
    }
2088
2089
    switch (p->current.cls) {
2090
    case T_LBRACE:
2091
        return parse_block(p);
2092
    case T_LET:
2093
        advance(p);
2094
        if (consume(p, T_CASE)) {
2095
            return parse_let_case(p);
2096
        }
2097
        if (consume(p, T_MUT)) {
2098
            return parse_var(p, true);
2099
        }
2100
        return parse_var(p, false);
2101
    case T_STATIC:
2102
        advance(p);
2103
        return parse_static(p);
2104
    case T_CONST:
2105
        advance(p);
2106
        return parse_const(p);
2107
    case T_USE:
2108
        advance(p);
2109
        return parse_use(p, attrs);
2110
    case T_MOD:
2111
        advance(p);
2112
        return parse_mod(p, attrs);
2113
    case T_RETURN:
2114
        advance(p);
2115
        return parse_return(p);
2116
    case T_THROW:
2117
        advance(p);
2118
        return parse_throw(p);
2119
    case T_BREAK:
2120
        advance(p);
2121
        return parse_break(p);
2122
    case T_WHILE:
2123
        advance(p);
2124
        return parse_while(p);
2125
    case T_FOR:
2126
        advance(p);
2127
        return parse_for(p);
2128
    case T_LOOP:
2129
        advance(p);
2130
        return parse_loop(p);
2131
    case T_IF:
2132
        advance(p);
2133
        return parse_if(p);
2134
    case T_MATCH:
2135
        advance(p);
2136
        return parse_match(p);
2137
    case T_FN:
2138
        advance(p);
2139
        return parse_fn(p, attrs);
2140
    case T_UNION:
2141
        advance(p);
2142
        return parse_union(p, attrs);
2143
    case T_RECORD:
2144
        advance(p);
2145
        return parse_record(p, attrs);
2146
    case T_PANIC:
2147
        advance(p);
2148
        return parse_panic(p);
2149
    default:
2150
        break;
2151
    }
2152
    /* Parse an expression as a statement or an assignment statement. */
2153
    node_t *expr;
2154
2155
    if ((expr = parse_expr(p)) == NULL)
2156
        return NULL;
2157
2158
    /* If we see an equals sign, this is an assignment statement */
2159
    if (consume(p, T_EQ)) {
2160
        return parse_assignment(p, expr);
2161
    }
2162
2163
    /* Create an expression statement node. */
2164
    node_t *stmt        = node(p, NODE_EXPR_STMT);
2165
    stmt->val.expr_stmt = expr;
2166
2167
    return stmt;
2168
}
2169
2170
/* Parse a function argument, which may have an optional label. */
2171
static node_t *parse_fn_call_arg(parser_t *p) {
2172
    usize   start = p->current.position;
2173
    node_t *arg   = node(p, NODE_CALL_ARG);
2174
2175
    /* Parse the expression first */
2176
    node_t *expr = parse_expr(p);
2177
    if (!expr)
2178
        return NULL;
2179
2180
    /* Check if this was an identifier followed by a colon
2181
     * (making it a label), or the complete expression. */
2182
    if (expr->cls == NODE_IDENT && consume(p, T_COLON)) {
2183
        /* It's a label, parse the actual value expression */
2184
        arg->val.call_arg.label = expr;
2185
2186
        if (!(arg->val.call_arg.expr = parse_expr(p))) {
2187
            return NULL;
2188
        }
2189
    } else {
2190
        arg->val.call_arg.label = NULL;
2191
        arg->val.call_arg.expr  = expr;
2192
    }
2193
    arg->offset = start;
2194
    arg->length = p->previous.position + p->previous.length - start;
2195
2196
    return arg;
2197
}
2198
2199
/* Parse an identifier. */
2200
static node_t *parse_ident(parser_t *p, const char *error) {
2201
    if (!expect(p, T_IDENT, error))
2202
        return NULL;
2203
2204
    node_t *ident = node(p, NODE_IDENT);
2205
2206
    ident->val.ident.name   = p->previous.start;
2207
    ident->val.ident.length = p->previous.length;
2208
2209
    return ident;
2210
}
2211
2212
/* Parse either an identifier or a placeholder ('_'). */
2213
static node_t *parse_ident_or_placeholder(parser_t *p, const char *error) {
2214
    if (consume(p, T_UNDERSCORE)) {
2215
        return node(p, NODE_PLACEHOLDER);
2216
    }
2217
    return parse_ident(p, error);
2218
}
2219
2220
/* Parse a label.
2221
 * Returns an identifier node. Expects IDENT followed by COLON. */
2222
static node_t *parse_label(parser_t *p, const char *error) {
2223
    if (!expect(p, T_IDENT, error))
2224
        return NULL;
2225
2226
    node_t *ident = node(p, NODE_IDENT);
2227
2228
    ident->val.ident.name   = p->previous.start;
2229
    ident->val.ident.length = p->previous.length;
2230
2231
    if (!expect(p, T_COLON, "expected ':' after identifier"))
2232
        return NULL;
2233
2234
    return ident;
2235
}
2236
2237
static node_t *parse_scope_segment(parser_t *p, const char *error) {
2238
    if (check(p, T_SUPER)) {
2239
        node_t *super_node = node(p, NODE_SUPER);
2240
        advance(p);
2241
        return super_node;
2242
    }
2243
    return parse_ident(p, error);
2244
}
2245
2246
static node_t *parse_as_cast(parser_t *p, node_t *expr) {
2247
    if (!consume(p, T_AS))
2248
        return NULL;
2249
2250
    node_t *as           = node(p, NODE_AS);
2251
    as->val.as_expr.expr = expr;
2252
2253
    /* Parse the target type */
2254
    node_t *typ = parse_type(p);
2255
    if (!typ)
2256
        return NULL;
2257
2258
    as->val.as_expr.type = typ;
2259
    as->offset           = expr->offset;
2260
    as->length           = p->current.position - as->offset;
2261
2262
    return as;
2263
}
2264
2265
/* Parse postfix expressions (field access and array indexing).
2266
 *
2267
 * This function handles both field access (expr.field) and array indexing
2268
 * (expr[index]) in a unified way, enabling arbitrarily complex nested
2269
 * expressions like `x.y.z[1].w[2][3].q`.
2270
 */
2271
static node_t *parse_postfix(parser_t *p, node_t *expr) {
2272
    node_t *result = expr;
2273
2274
    for (;;) {
2275
        if (consume(p, T_DOT)) { /* Field access. */
2276
            node_t *n          = node(p, NODE_ACCESS);
2277
            n->val.access.lval = result;
2278
2279
            node_t *field = parse_ident(p, "expected field name after `.`");
2280
            if (!field)
2281
                return NULL;
2282
2283
            field->val.ident.name   = p->previous.start;
2284
            field->val.ident.length = p->previous.length;
2285
            n->val.access.rval      = field;
2286
2287
            result = n;
2288
        } else if (consume(p, T_DOT_DOT)) {
2289
            node_t *range          = node(p, NODE_RANGE);
2290
            range->val.range.start = result;
2291
            range->val.range.end   = NULL;
2292
2293
            /* Check if there's a right-hand side for the range. */
2294
            if (!check(p, T_RBRACKET) && !check(p, T_SEMICOLON) &&
2295
                !check(p, T_COMMA) && !check(p, T_RPAREN) &&
2296
                !check(p, T_LBRACE)) {
2297
                if (!(range->val.range.end = parse_expr(p))) {
2298
                    return NULL;
2299
                }
2300
            }
2301
            result = range;
2302
        } else if (consume(p, T_COLON_COLON)) { /* Scope access */
2303
            node_t *ident =
2304
                parse_scope_segment(p, "expected identifier name after `::`");
2305
            if (!ident)
2306
                return NULL;
2307
2308
            node_t *n          = node(p, NODE_SCOPE);
2309
            n->val.access.lval = result;
2310
            n->val.access.rval = ident;
2311
2312
            result = n;
2313
        } else if (consume(p, T_LBRACKET)) { /* Array indexing or slicing. */
2314
            node_t *expr = NULL;
2315
2316
            if (consume(p, T_DOT_DOT)) {
2317
                /* Either `..` or `..n` */
2318
                /* Create range node with NULL start and end. */
2319
                expr                  = node(p, NODE_RANGE);
2320
                expr->val.range.start = NULL;
2321
                expr->val.range.end   = NULL;
2322
2323
                if (!check(p, T_RBRACKET)) {
2324
                    if (!(expr->val.range.end = parse_expr(p))) {
2325
                        return NULL;
2326
                    }
2327
                }
2328
            } else {
2329
                /* Either `n`, `n..` or `n..m` */
2330
                node_t *index = parse_expr(p);
2331
                if (!index)
2332
                    return NULL;
2333
2334
                expr = index;
2335
            }
2336
            /* Create array index node with the index expression */
2337
            node_t *n          = node(p, NODE_ARRAY_INDEX);
2338
            n->val.access.lval = result;
2339
            n->val.access.rval = expr;
2340
2341
            n->offset = result->offset;
2342
            n->length = result->length;
2343
2344
            /* Expect closing bracket */
2345
            if (!expect(p, T_RBRACKET, "expected `]` after array index"))
2346
                return NULL;
2347
2348
            result = n;
2349
        } else if (consume(p, T_LPAREN)) { /* Parse function call. */
2350
            node_t *call          = node(p, NODE_CALL);
2351
            call->val.call.callee = result;
2352
            call->val.call.args   = nodespan_alloc(p, MAX_FN_PARAMS);
2353
2354
            node_t *arg = NULL;
2355
            if (!check(p, T_RPAREN)) {
2356
                do {
2357
                    if (!(arg = parse_fn_call_arg(p))) {
2358
                        return NULL;
2359
                    }
2360
                    nodespan_push(p, &call->val.call.args, arg);
2361
                } while (consume(p, T_COMMA));
2362
            }
2363
            if (!expect(p, T_RPAREN, "expected `)` after function arguments"))
2364
                return NULL;
2365
2366
            result = call;
2367
        } else if (p->context == PARSE_CTX_NORMAL &&
2368
                   result->cls == NODE_SCOPE && check(p, T_LBRACE)) {
2369
            /* Record literal after scope access: `Union::Variant { ... }`. */
2370
            advance(p); /* consume `{` */
2371
2372
            node_t *literal = parse_record_lit(p, result);
2373
            if (!literal)
2374
                return NULL;
2375
2376
            result = literal;
2377
        } else {
2378
            /* No postfix operators to try. */
2379
            break;
2380
        }
2381
    }
2382
    return result;
2383
}
2384
2385
/* Parse a complete program, return the root of the AST, or `NULL`
2386
 * if parsing failed. */
2387
node_t *parser_parse(parser_t *p) {
2388
    p->current = scanner_next(&p->scanner);
2389
2390
    /* Create a top-level module. */
2391
    node_t *root = parse_module_body(p);
2392
    if (!root)
2393
        return NULL;
2394
2395
    if (!expect(p, T_EOF, "expected end-of-file"))
2396
        return NULL;
2397
2398
    root->length = (usize)(p->scanner.cursor - p->scanner.source);
2399
2400
    return (p->root = root);
2401
}