kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

parser.c (65677B)


      1 #include <stddef.h>
      2 #include <stdint.h>
      3 #include <stdio.h>
      4 #include <string.h>
      5 
      6 #include "internal.h"
      7 
      8 /* Public CG API coverage goals for this frontend are tracked in
      9  * doc/toy-todo.md. Keep this file aligned with include/kit/cg.h rather than
     10  * private CG implementation details. */
     11 
     12 /* ============================================================
     13  * Parser (single-pass parse -> codegen)
     14  * ============================================================ */
     15 
     16 static int toy_parse_stmt(ToyParser* p);
     17 
     18 int toy_parse_block(ToyParser* p) {
     19   size_t saved_nvars = p->nvars;
     20   if (!toy_parser_expect(p, TOK_LBRACE)) {
     21     toy_error(p, p->cur.loc, "expected '{'");
     22     return 0;
     23   }
     24   while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) {
     25     if (!toy_parse_stmt(p)) return 0;
     26   }
     27   if (!toy_parser_expect(p, TOK_RBRACE)) {
     28     toy_error(p, p->cur.loc, "expected '}'");
     29     return 0;
     30   }
     31   p->nvars = saved_nvars;
     32   return 1;
     33 }
     34 
     35 /* Pushes [base_ptr, index] for kit_cg_elem: the array local is decayed to a
     36  * pointer to its element type (its address, bitcast to *elem), then the index
     37  * value is pushed on top. The following kit_cg_elem(0) yields the element
     38  * PLACE. */
     39 static void toy_push_local_indexed(ToyParser* p, KitCgLocal slot,
     40                                    KitCgTypeId elem_ty, uint64_t index) {
     41   kit_cg_push_local(p->cg, slot);
     42   kit_cg_addr(p->cg);
     43   kit_cg_bitcast(p->cg, kit_cg_type_ptr(p->c, elem_ty, 0));
     44   kit_cg_push_int(p->cg, index, p->size_type);
     45 }
     46 
     47 static int toy_check_source_value(ToyParser* p, KitCgTypeId expected_cg,
     48                                   ToyTypeId expected_toy, KitCgTypeId actual_cg,
     49                                   ToyTypeId actual_toy, const char* message) {
     50   if (expected_toy != TOY_TYPE_NONE) {
     51     if (!toy_type_accepts_type(p, expected_toy, actual_toy)) {
     52       toy_error(p, p->cur.loc, message);
     53       return 0;
     54     }
     55     return 1;
     56   }
     57   if (!toy_type_can_implicitly_cast(p, actual_cg, expected_cg)) {
     58     toy_error(p, p->cur.loc, message);
     59     return 0;
     60   }
     61   return 1;
     62 }
     63 
     64 static int toy_records_have_matching_storage(ToyParser* p, KitCgTypeId expected,
     65                                              KitCgTypeId actual) {
     66   uint32_t i;
     67   const KitCgRecordLayout* el;
     68   const KitCgRecordLayout* al;
     69   if (kit_cg_type_kind(p->c, expected) != KIT_CG_TYPE_RECORD ||
     70       kit_cg_type_kind(p->c, actual) != KIT_CG_TYPE_RECORD) {
     71     return 0;
     72   }
     73   el = kit_cg_type_record_layout(p->c, expected);
     74   al = kit_cg_type_record_layout(p->c, actual);
     75   if (!el || !al) return 0;
     76   if (el->nfields != al->nfields) return 0;
     77   for (i = 0; i < el->nfields; ++i) {
     78     if (el->fields[i].name != al->fields[i].name ||
     79         el->fields[i].type != al->fields[i].type) {
     80       return 0;
     81     }
     82   }
     83   return 1;
     84 }
     85 
     86 static int toy_copy_record_lvalue_to_local(ToyParser* p, KitCgTypeId src_ty,
     87                                            KitCgLocal dst_slot,
     88                                            KitCgTypeId dst_ty) {
     89   uint32_t i;
     90   const KitCgRecordLayout* L;
     91   if (!toy_records_have_matching_storage(p, dst_ty, src_ty)) {
     92     toy_error(p, p->cur.loc, "record storage mismatch");
     93     return 0;
     94   }
     95   L = kit_cg_type_record_layout(p->c, dst_ty);
     96   if (!L) return 0;
     97   for (i = 0; i < L->nfields; ++i) {
     98     const KitCgFieldLayout* field = &L->fields[i];
     99     uint64_t offset = field->offset;
    100     kit_cg_dup(p->cg);
    101     kit_cg_deref(p->cg, (int64_t)offset);
    102     kit_cg_load(p->cg, toy_mem_access(p, field->type));
    103     kit_cg_push_local(p->cg, dst_slot);
    104     kit_cg_addr(p->cg);
    105     kit_cg_deref(p->cg, (int64_t)offset);
    106     kit_cg_swap(p->cg);
    107     kit_cg_store(p->cg, toy_mem_access(p, field->type));
    108   }
    109   kit_cg_drop(p->cg);
    110   return 1;
    111 }
    112 
    113 static int toy_copy_record_lvalue_to_var(ToyParser* p, KitCgTypeId src_ty,
    114                                          const ToyVar* dst_var,
    115                                          const ToyGlobal* dst_global) {
    116   KitCgTypeId dst_ty = dst_var ? dst_var->type : dst_global->type;
    117   uint32_t i;
    118   const KitCgRecordLayout* L;
    119   if (!toy_records_have_matching_storage(p, dst_ty, src_ty)) {
    120     toy_error(p, p->cur.loc, "record storage mismatch");
    121     return 0;
    122   }
    123   L = kit_cg_type_record_layout(p->c, dst_ty);
    124   if (!L) return 0;
    125   for (i = 0; i < L->nfields; ++i) {
    126     const KitCgFieldLayout* field = &L->fields[i];
    127     uint64_t offset = field->offset;
    128     kit_cg_dup(p->cg);
    129     kit_cg_deref(p->cg, (int64_t)offset);
    130     kit_cg_load(p->cg, toy_mem_access(p, field->type));
    131     if (dst_var) {
    132       toy_push_var_lvalue(p, dst_var);
    133     } else {
    134       kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, dst_global), 0);
    135     }
    136     kit_cg_deref(p->cg, (int64_t)offset);
    137     kit_cg_swap(p->cg);
    138     kit_cg_store(p->cg, toy_mem_access(p, field->type));
    139   }
    140   kit_cg_drop(p->cg);
    141   return 1;
    142 }
    143 
    144 static int toy_parse_array_initializer(ToyParser* p, KitCgLocal slot,
    145                                        KitCgTypeId arr_ty,
    146                                        ToyTypeId arr_toy_type) {
    147   KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, arr_ty);
    148   ToyTypeId elem_toy_type = toy_type_array_elem(p, arr_toy_type);
    149   uint64_t count = kit_cg_type_array_count(p->c, arr_ty);
    150   uint64_t index = 0;
    151 
    152   if (!toy_parser_expect(p, TOK_LBRACKET)) {
    153     toy_error(p, p->cur.loc, "expected array literal");
    154     return 0;
    155   }
    156   while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) {
    157     KitCgTypeId expr_ty;
    158     if (index >= count) {
    159       toy_error(p, p->cur.loc, "too many array elements");
    160       return 0;
    161     }
    162     toy_push_local_indexed(p, slot, elem_ty, index);
    163     kit_cg_elem(p->cg, 0);
    164     expr_ty = toy_parse_expr(p);
    165     if (expr_ty == KIT_CG_TYPE_NONE) return 0;
    166     if (!toy_check_source_value(p, elem_ty, elem_toy_type, expr_ty,
    167                                 p->last_type, "array element type mismatch")) {
    168       return 0;
    169     }
    170     if (expr_ty != elem_ty && !toy_emit_checked_cast(p, expr_ty, elem_ty))
    171       return 0;
    172     kit_cg_store(p->cg, toy_mem_access(p, elem_ty));
    173     index++;
    174     if (!toy_parser_match(p, TOK_COMMA)) break;
    175   }
    176   if (!toy_parser_expect(p, TOK_RBRACKET)) {
    177     toy_error(p, p->cur.loc, "expected ']' after array literal");
    178     return 0;
    179   }
    180   while (index < count) {
    181     toy_push_local_indexed(p, slot, elem_ty, index);
    182     kit_cg_elem(p->cg, 0);
    183     kit_cg_push_int(p->cg, 0, elem_ty);
    184     kit_cg_store(p->cg, toy_mem_access(p, elem_ty));
    185     index++;
    186   }
    187   return 1;
    188 }
    189 
    190 static int toy_parse_record_initializer(ToyParser* p, KitCgLocal slot,
    191                                         KitCgTypeId record_ty,
    192                                         ToyTypeId record_toy_type) {
    193   uint32_t i;
    194   const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, record_ty);
    195   uint32_t nfields = L ? L->nfields : 0;
    196   ToyNamedType* named = toy_find_named_type_by_type(p, record_ty);
    197   int positional = named && named->kind == TOY_NAMED_TUPLE;
    198   (void)record_toy_type;
    199   if (!L) return 0;
    200   if (p->cur.kind == TOK_IDENT) toy_parser_advance(p);
    201   if (!toy_parser_expect(p, TOK_LBRACE)) {
    202     toy_error(p, p->cur.loc, "expected record literal");
    203     return 0;
    204   }
    205 
    206   for (i = 0; i < nfields; ++i) {
    207     const KitCgFieldLayout* field = &L->fields[i];
    208     uint64_t foff = field->offset;
    209     kit_cg_push_local(p->cg, slot);
    210     kit_cg_addr(p->cg);
    211     kit_cg_deref(p->cg, (int64_t)foff);
    212     kit_cg_push_int(p->cg, 0, field->type);
    213     kit_cg_store(p->cg, toy_mem_access(p, field->type));
    214   }
    215 
    216   if (positional) {
    217     uint32_t field_index = 0;
    218     while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) {
    219       const KitCgFieldLayout* field;
    220       KitCgTypeId expr_ty;
    221       uint64_t foff;
    222       if (field_index >= nfields) {
    223         toy_error(p, p->cur.loc, "too many tuple fields");
    224         return 0;
    225       }
    226       field = &L->fields[field_index];
    227       foff = field->offset;
    228       kit_cg_push_local(p->cg, slot);
    229       kit_cg_addr(p->cg);
    230       kit_cg_deref(p->cg, (int64_t)foff);
    231       expr_ty = toy_parse_expr(p);
    232       if (expr_ty == KIT_CG_TYPE_NONE) return 0;
    233       {
    234         ToyTypeId expected = (named && field_index < named->nfields)
    235                                  ? named->fields[field_index].toy_type
    236                                  : TOY_TYPE_NONE;
    237         if (!toy_check_source_value(p, field->type, expected, expr_ty,
    238                                     p->last_type,
    239                                     "tuple field type mismatch")) {
    240           return 0;
    241         }
    242       }
    243       if (expr_ty != field->type &&
    244           !toy_emit_checked_cast(p, expr_ty, field->type))
    245         return 0;
    246       kit_cg_store(p->cg, toy_mem_access(p, field->type));
    247       field_index++;
    248       if (!toy_parser_match(p, TOK_COMMA)) break;
    249     }
    250     if (!toy_parser_expect(p, TOK_RBRACE)) {
    251       toy_error(p, p->cur.loc, "expected '}' after tuple literal");
    252       return 0;
    253     }
    254     return 1;
    255   }
    256 
    257   while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) {
    258     KitSym field_name;
    259     KitCgFieldLayout field;
    260     uint32_t field_index;
    261     KitCgTypeId expr_ty;
    262     uint64_t foff = 0;
    263     if (p->cur.kind != TOK_IDENT) {
    264       toy_error(p, p->cur.loc, "expected field name");
    265       return 0;
    266     }
    267     field_name = toy_tok_sym(p, p->cur);
    268     toy_parser_advance(p);
    269     if (!toy_parser_expect(p, TOK_COLON)) {
    270       toy_error(p, p->cur.loc, "expected ':' in record literal");
    271       return 0;
    272     }
    273     if (!toy_record_field_index(p, record_ty, field_name, &field_index,
    274                                 &field)) {
    275       toy_error(p, p->cur.loc, "unknown record field");
    276       return 0;
    277     }
    278     foff = field.offset;
    279     kit_cg_push_local(p->cg, slot);
    280     kit_cg_addr(p->cg);
    281     kit_cg_deref(p->cg, (int64_t)foff);
    282     expr_ty = toy_parse_expr(p);
    283     if (expr_ty == KIT_CG_TYPE_NONE) return 0;
    284     {
    285       ToyTypeId expected = (named && field_index < named->nfields)
    286                                ? named->fields[field_index].toy_type
    287                                : TOY_TYPE_NONE;
    288       if (!toy_check_source_value(p, field.type, expected, expr_ty,
    289                                   p->last_type, "record field type mismatch")) {
    290         return 0;
    291       }
    292     }
    293     if (expr_ty != field.type && !toy_emit_checked_cast(p, expr_ty, field.type))
    294       return 0;
    295     kit_cg_store(p->cg, toy_mem_access(p, field.type));
    296     if (!toy_parser_match(p, TOK_COMMA)) break;
    297   }
    298   if (!toy_parser_expect(p, TOK_RBRACE)) {
    299     toy_error(p, p->cur.loc, "expected '}' after record literal");
    300     return 0;
    301   }
    302   return 1;
    303 }
    304 
    305 static int toy_parse_value_block_body_to_local(ToyParser* p, KitCgLocal slot,
    306                                                KitCgTypeId result_ty,
    307                                                ToyTypeId result_toy_type);
    308 
    309 static int toy_parse_if_initializer(ToyParser* p, KitCgLocal slot,
    310                                     KitCgTypeId result_ty,
    311                                     ToyTypeId result_toy_type) {
    312   KitCgTypeId cond_ty;
    313   KitCgIf it;
    314   if (!toy_parser_match(p, TOK_IF)) return 0;
    315   cond_ty = toy_parse_expr(p);
    316   if (cond_ty == KIT_CG_TYPE_NONE) return 0;
    317   if (!toy_emit_truthy(p, cond_ty)) return 0;
    318   it = kit_cg_if_begin(p->cg);
    319 
    320   if (!toy_parser_expect(p, TOK_LBRACE)) {
    321     toy_error(p, p->cur.loc, "expected '{' in if expression");
    322     return 0;
    323   }
    324   if (!toy_parse_value_block_body_to_local(p, slot, result_ty, result_toy_type))
    325     return 0;
    326 
    327   kit_cg_if_else(p->cg, it);
    328 
    329   if (!toy_parser_expect(p, TOK_ELSE) || !toy_parser_expect(p, TOK_LBRACE)) {
    330     toy_error(p, p->cur.loc, "expected else block in if expression");
    331     return 0;
    332   }
    333   if (!toy_parse_value_block_body_to_local(p, slot, result_ty, result_toy_type))
    334     return 0;
    335 
    336   kit_cg_if_end(p->cg, it);
    337   return 1;
    338 }
    339 
    340 static int toy_parse_value_block_body_to_local(ToyParser* p, KitCgLocal slot,
    341                                                KitCgTypeId result_ty,
    342                                                ToyTypeId result_toy_type) {
    343   size_t saved_nvars = p->nvars;
    344   while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) {
    345     KitCgTypeId arm_ty;
    346     if (p->cur.kind == TOK_LET || p->cur.kind == TOK_VAR ||
    347         p->cur.kind == TOK_IF || p->cur.kind == TOK_WHILE ||
    348         p->cur.kind == TOK_SWITCH || p->cur.kind == TOK_LABEL ||
    349         p->cur.kind == TOK_GOTO || p->cur.kind == TOK_BREAK ||
    350         p->cur.kind == TOK_CONTINUE || p->cur.kind == TOK_RETURN ||
    351         p->cur.kind == TOK_LBRACE) {
    352       if (!toy_parse_stmt(p)) {
    353         p->nvars = saved_nvars;
    354         return 0;
    355       }
    356       continue;
    357     }
    358     arm_ty = toy_parse_expr(p);
    359     if (arm_ty == KIT_CG_TYPE_NONE) {
    360       p->nvars = saved_nvars;
    361       return 0;
    362     }
    363     if (toy_parser_match(p, TOK_SEMI)) {
    364       if (arm_ty != toy_builtin_type(p, KIT_CG_BUILTIN_VOID))
    365         kit_cg_drop(p->cg);
    366       continue;
    367     }
    368     if (!toy_check_source_value(p, result_ty, result_toy_type, arm_ty,
    369                                 p->last_type, "block value type mismatch")) {
    370       p->nvars = saved_nvars;
    371       return 0;
    372     }
    373     if (arm_ty != result_ty && !toy_emit_checked_cast(p, arm_ty, result_ty)) {
    374       p->nvars = saved_nvars;
    375       return 0;
    376     }
    377     kit_cg_push_local(p->cg, slot);
    378     kit_cg_swap(p->cg);
    379     kit_cg_store(p->cg, toy_mem_access(p, result_ty));
    380     if (!toy_parser_expect(p, TOK_RBRACE)) {
    381       toy_error(p, p->cur.loc, "expected '}' after value block");
    382       p->nvars = saved_nvars;
    383       return 0;
    384     }
    385     p->nvars = saved_nvars;
    386     return 1;
    387   }
    388   toy_error(p, p->cur.loc, "missing block value");
    389   p->nvars = saved_nvars;
    390   return 0;
    391 }
    392 
    393 static int toy_parse_value_block_to_local(ToyParser* p, KitCgLocal slot,
    394                                           KitCgTypeId result_ty,
    395                                           ToyTypeId result_toy_type) {
    396   if (!toy_parser_expect(p, TOK_LBRACE)) {
    397     toy_error(p, p->cur.loc, "expected value block");
    398     return 0;
    399   }
    400   return toy_parse_value_block_body_to_local(p, slot, result_ty,
    401                                              result_toy_type);
    402 }
    403 
    404 static int toy_parse_switch_strategy_hint(ToyParser* p,
    405                                           KitCgSwitchHint* hint_out) {
    406   *hint_out = KIT_CG_SWITCH_TARGET_DEFAULT;
    407   if (p->cur.kind != TOK_AT || toy_lexer_peek(&p->lex).kind != TOK_LBRACKET)
    408     return 1;
    409   toy_parser_advance(p);
    410   if (!toy_parser_expect(p, TOK_LBRACKET)) {
    411     toy_error(p, p->cur.loc, "expected switch strategy list");
    412     return 0;
    413   }
    414   while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) {
    415     KitSym name;
    416     if (!toy_parse_attr_dot_name(p, &name)) return 0;
    417     if (toy_sym_is(p, name, "branch_chain")) {
    418       *hint_out = KIT_CG_SWITCH_BRANCH_CHAIN;
    419     } else if (toy_sym_is(p, name, "jump_table")) {
    420       *hint_out = KIT_CG_SWITCH_JUMP_TABLE;
    421     } else {
    422       toy_error(p, p->cur.loc, "unknown switch strategy");
    423       return 0;
    424     }
    425     if (!toy_parser_match(p, TOK_COMMA)) break;
    426   }
    427   if (!toy_parser_expect(p, TOK_RBRACKET)) {
    428     toy_error(p, p->cur.loc, "expected ']' after switch strategy list");
    429     return 0;
    430   }
    431   return 1;
    432 }
    433 
    434 static int toy_parse_switch_initializer(ToyParser* p, KitCgLocal slot,
    435                                         KitCgTypeId result_ty,
    436                                         ToyTypeId result_toy_type) {
    437   KitCgTypeId selector_ty;
    438   KitCgLocal selector_slot;
    439   KitCgLabel end_label;
    440   KitCgLabel dispatch_label;
    441   KitCgLabel default_arm_label = KIT_CG_LABEL_NONE;
    442   KitCgLabel unreachable_label = KIT_CG_LABEL_NONE;
    443   ToyNamedType* selector_enum;
    444   unsigned char* enum_seen = NULL;
    445   size_t enum_seen_size = 0;
    446   int saw_default = 0;
    447   size_t enum_seen_count = 0;
    448   KitCgSwitchCase* cases = NULL;
    449   size_t ncases = 0;
    450   size_t cap_cases = 0;
    451   KitCgSwitchHint hint;
    452   KitCgSwitch sw;
    453 
    454   if (!toy_parser_match(p, TOK_SWITCH)) return 0;
    455   if (!toy_parse_switch_strategy_hint(p, &hint)) return 0;
    456   selector_ty = toy_parse_expr(p);
    457   if (selector_ty == KIT_CG_TYPE_NONE) return 0;
    458   if (!toy_type_is_intlike(p, selector_ty)) {
    459     toy_error(p, p->cur.loc, "switch selector must be integer-like");
    460     return 0;
    461   }
    462   selector_slot = kit_cg_local(p->cg, selector_ty, toy_slot_attrs(0));
    463   kit_cg_push_local(p->cg, selector_slot);
    464   kit_cg_swap(p->cg);
    465   kit_cg_store(p->cg, toy_mem_access(p, selector_ty));
    466   end_label = kit_cg_label_new(p->cg);
    467   dispatch_label = kit_cg_label_new(p->cg);
    468   /* Skip the arm bodies on entry; come back through the dispatch label. */
    469   kit_cg_jump(p->cg, dispatch_label);
    470   selector_enum = toy_find_named_type_by_type(p, selector_ty);
    471   if (!selector_enum || selector_enum->kind != TOY_NAMED_ENUM)
    472     selector_enum = NULL;
    473   if (selector_enum) {
    474     enum_seen_size =
    475         (selector_enum->nenum_values ? selector_enum->nenum_values : 1u) *
    476         sizeof *enum_seen;
    477     enum_seen = (unsigned char*)toy_parser_zalloc(
    478         p, selector_enum->nenum_values ? selector_enum->nenum_values : 1u,
    479         sizeof *enum_seen, "enum switch state");
    480     if (!enum_seen) return 0;
    481   }
    482 
    483   if (!toy_parser_expect(p, TOK_LBRACE)) {
    484     toy_error(p, p->cur.loc, "expected '{' after switch selector");
    485     toy_parser_free_mem(p, enum_seen, enum_seen_size);
    486     return 0;
    487   }
    488   while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) {
    489     KitCgLabel arm_label = kit_cg_label_new(p->cg);
    490     if (p->cur.kind == TOK_DEFAULT) {
    491       saw_default = 1;
    492       default_arm_label = arm_label;
    493       toy_parser_advance(p);
    494     } else {
    495       for (;;) {
    496         int64_t value;
    497         size_t i;
    498         if (!toy_parse_switch_label_value(p, selector_ty, &value)) {
    499           toy_parser_free_mem(p, enum_seen, enum_seen_size);
    500           toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
    501           return 0;
    502         }
    503         if (selector_enum) {
    504           for (i = 0; i < selector_enum->nenum_values; ++i) {
    505             if (selector_enum->enum_values[i].value == value) {
    506               if (!enum_seen[i]) {
    507                 enum_seen[i] = 1;
    508                 enum_seen_count++;
    509               }
    510               break;
    511             }
    512           }
    513         }
    514         if (!toy_parser_reserve(p, (void**)&cases, &cap_cases, ncases + 1u,
    515                                 sizeof *cases, "switch cases")) {
    516           toy_parser_free_mem(p, enum_seen, enum_seen_size);
    517           return 0;
    518         }
    519         cases[ncases].value = (uint64_t)value;
    520         cases[ncases].label = arm_label;
    521         ncases++;
    522         if (!toy_parser_match(p, TOK_COMMA)) break;
    523       }
    524     }
    525     kit_cg_label_place(p->cg, arm_label);
    526     if (!toy_parse_value_block_to_local(p, slot, result_ty, result_toy_type)) {
    527       toy_parser_free_mem(p, enum_seen, enum_seen_size);
    528       toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
    529       return 0;
    530     }
    531     kit_cg_jump(p->cg, end_label);
    532   }
    533   if (!toy_parser_expect(p, TOK_RBRACE)) {
    534     toy_error(p, p->cur.loc, "expected '}' after switch expression");
    535     toy_parser_free_mem(p, enum_seen, enum_seen_size);
    536     toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
    537     return 0;
    538   }
    539   if (!saw_default &&
    540       (!selector_enum || enum_seen_count != selector_enum->nenum_values)) {
    541     toy_error(p, p->cur.loc, "expression switch requires default");
    542     toy_parser_free_mem(p, enum_seen, enum_seen_size);
    543     toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
    544     return 0;
    545   }
    546   kit_cg_label_place(p->cg, dispatch_label);
    547   kit_cg_push_local(p->cg, selector_slot);
    548   kit_cg_load(p->cg, toy_mem_access(p, selector_ty));
    549   if (saw_default) {
    550     sw.default_label = default_arm_label;
    551   } else {
    552     /* Enum-exhaustive switch with no source default: any value outside the
    553      * covered set is undefined behavior — emit an unreachable landing pad. */
    554     unreachable_label = kit_cg_label_new(p->cg);
    555     sw.default_label = unreachable_label;
    556   }
    557   sw.selector_type = selector_ty;
    558   sw.cases = cases;
    559   sw.ncases = (uint32_t)ncases;
    560   sw.hint = hint;
    561   kit_cg_switch(p->cg, sw);
    562   if (unreachable_label != KIT_CG_LABEL_NONE) {
    563     kit_cg_label_place(p->cg, unreachable_label);
    564     kit_cg_unreachable(p->cg);
    565   }
    566   kit_cg_label_place(p->cg, end_label);
    567   toy_parser_free_mem(p, enum_seen, enum_seen_size);
    568   toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
    569   return 1;
    570 }
    571 
    572 static int toy_parse_while_initializer_named(ToyParser* p, KitCgLocal slot,
    573                                              KitCgTypeId result_ty,
    574                                              ToyTypeId result_toy_type,
    575                                              KitSym label_name) {
    576   KitCgTypeId explicit_ty;
    577   ToyTypeId explicit_toy_type;
    578   KitCgTypeId cond_ty;
    579   KitCgScope scope;
    580   KitCgLabel else_label;
    581 
    582   if (!toy_parser_match(p, TOK_WHILE)) return 0;
    583   if (!toy_parser_expect(p, TOK_LT)) {
    584     toy_error(p, p->cur.loc, "expected result type in while expression");
    585     return 0;
    586   }
    587   explicit_ty = toy_parse_type(p);
    588   if (explicit_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_GT))
    589     return 0;
    590   explicit_toy_type = p->last_type;
    591   if (!toy_check_source_value(p, result_ty, result_toy_type, explicit_ty,
    592                               explicit_toy_type,
    593                               "while result type mismatch")) {
    594     return 0;
    595   }
    596   if (!toy_parser_reserve(p, (void**)&p->scopes, &p->cap_scopes,
    597                           p->nscopes + 1u, sizeof *p->scopes, "scopes")) {
    598     return 0;
    599   }
    600   scope = kit_cg_scope_begin_value(p->cg, result_ty);
    601   p->scopes[p->nscopes].name = label_name;
    602   p->scopes[p->nscopes].kind = TOY_SCOPE_LOOP;
    603   p->scopes[p->nscopes].cg_scope = scope;
    604   p->scopes[p->nscopes].result_type = result_ty;
    605   p->scopes[p->nscopes].result_toy_type = result_toy_type;
    606   p->nscopes++;
    607   else_label = kit_cg_label_new(p->cg);
    608 
    609   cond_ty = toy_parse_expr(p);
    610   if (cond_ty == KIT_CG_TYPE_NONE) {
    611     p->nscopes--;
    612     return 0;
    613   }
    614   if (!toy_emit_truthy(p, cond_ty)) {
    615     p->nscopes--;
    616     return 0;
    617   }
    618   kit_cg_branch_false(p->cg, else_label);
    619   if (!toy_parse_block(p)) {
    620     p->nscopes--;
    621     return 0;
    622   }
    623   kit_cg_continue(p->cg, scope);
    624   kit_cg_label_place(p->cg, else_label);
    625   if (!toy_parser_expect(p, TOK_ELSE)) {
    626     toy_error(p, p->cur.loc, "expected else in while expression");
    627     p->nscopes--;
    628     return 0;
    629   }
    630   if (!toy_parser_expect(p, TOK_LBRACE)) {
    631     toy_error(p, p->cur.loc, "expected else block in while expression");
    632     p->nscopes--;
    633     return 0;
    634   }
    635   {
    636     KitCgTypeId else_ty = toy_parse_expr(p);
    637     if (else_ty == KIT_CG_TYPE_NONE) {
    638       p->nscopes--;
    639       return 0;
    640     }
    641     if (!toy_check_source_value(p, result_ty, result_toy_type, else_ty,
    642                                 p->last_type, "while else type mismatch")) {
    643       p->nscopes--;
    644       return 0;
    645     }
    646     if (else_ty != result_ty && !toy_emit_checked_cast(p, else_ty, result_ty)) {
    647       p->nscopes--;
    648       return 0;
    649     }
    650   }
    651   if (!toy_parser_expect(p, TOK_RBRACE)) {
    652     toy_error(p, p->cur.loc, "expected '}' after while else");
    653     p->nscopes--;
    654     return 0;
    655   }
    656   kit_cg_scope_end(p->cg, scope);
    657   p->nscopes--;
    658   kit_cg_push_local(p->cg, slot);
    659   kit_cg_swap(p->cg);
    660   kit_cg_store(p->cg, toy_mem_access(p, result_ty));
    661   return 1;
    662 }
    663 
    664 static int toy_parse_while_initializer(ToyParser* p, KitCgLocal slot,
    665                                        KitCgTypeId result_ty,
    666                                        ToyTypeId result_toy_type) {
    667   return toy_parse_while_initializer_named(p, slot, result_ty, result_toy_type,
    668                                            0);
    669 }
    670 
    671 static int toy_parse_let_stmt(ToyParser* p) {
    672   KitSym name;
    673   KitCgTypeId ty = KIT_CG_TYPE_NONE;
    674   KitCgTypeId init_ty = KIT_CG_TYPE_NONE;
    675   ToyTypeId toy_ty = TOY_TYPE_NONE;
    676   ToyTypeId init_toy_type = TOY_TYPE_NONE;
    677   KitCgLocal slot;
    678   int has_init = 0;
    679   int inferred = 0;
    680   int is_var = p->cur.kind == TOK_VAR;
    681   int is_static = 0;
    682   int copy_record_init = 0;
    683   toy_parser_advance(p); /* let/var */
    684   if (!toy_skip_attr_list_ex(p, &is_static)) return 0;
    685   if (p->cur.kind != TOK_IDENT) {
    686     toy_error(p, p->cur.loc, "expected identifier after 'let'");
    687     return 0;
    688   }
    689   name = toy_tok_sym(p, p->cur);
    690   toy_parser_advance(p);
    691 
    692   if (toy_parser_match(p, TOK_COLON)) {
    693     ty = toy_parse_type(p);
    694     if (ty == KIT_CG_TYPE_NONE) return 0;
    695     toy_ty = p->last_type;
    696   } else {
    697     inferred = 1;
    698     if (p->cur.kind != TOK_EQ) {
    699       toy_error(p, p->cur.loc, "expected ':' or initializer after identifier");
    700       return 0;
    701     }
    702   }
    703 
    704   if (is_static) {
    705     KitCgDecl decl;
    706     KitCgDataDefAttrs data_attrs;
    707     KitCgSym sym;
    708     KitSym linkage_name;
    709     char sym_name[64];
    710     uint8_t buf[1024];
    711     size_t n = (size_t)kit_cg_type_size(p->c, ty);
    712     int array_data_init = 0;
    713     if (inferred) {
    714       toy_error(p, p->cur.loc, "static local requires explicit type");
    715       return 0;
    716     }
    717     if (n > sizeof buf) {
    718       toy_error(p, p->cur.loc, "static initializer too large");
    719       return 0;
    720     }
    721     memset(buf, 0, n);
    722     if (toy_parser_match(p, TOK_EQ)) {
    723       if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) {
    724         toy_emit_int_bytes(p, (uint64_t)p->cur.int_value, buf, n);
    725         toy_parser_advance(p);
    726       } else if (p->cur.kind == TOK_STRING &&
    727                  kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ARRAY &&
    728                  kit_cg_type_array_elem(p->c, ty) ==
    729                      toy_builtin_type(p, KIT_CG_BUILTIN_I8)) {
    730         size_t len = 0;
    731         if (!toy_parse_string_bytes(p, buf, sizeof buf, &len)) return 0;
    732         if (len > n) {
    733           toy_error(p, p->cur.loc, "string initializer too large");
    734           return 0;
    735         }
    736       } else if (p->cur.kind == TOK_LBRACKET &&
    737                  kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ARRAY &&
    738                  toy_lexer_peek(&p->lex).kind == TOK_AT) {
    739         array_data_init = 1;
    740       } else {
    741         toy_error(p, p->cur.loc, "expected constant static initializer");
    742         return 0;
    743       }
    744     }
    745     snprintf(sym_name, sizeof sym_name, ".Ltoy_static_%u",
    746              p->module->static_counter++);
    747     linkage_name = kit_sym_intern(p->c, kit_slice_cstr(sym_name));
    748     memset(&decl, 0, sizeof decl);
    749     decl.kind = KIT_CG_DECL_OBJECT;
    750     decl.linkage_name = linkage_name;
    751     decl.display_name = name;
    752     decl.type = ty;
    753     decl.sym.bind = KIT_SB_LOCAL;
    754     decl.sym.visibility = KIT_CG_VIS_DEFAULT;
    755     decl.as.object.tls_model = KIT_CG_TLS_AUTO;
    756     if (!is_var) decl.as.object.flags |= KIT_CG_OBJ_READONLY;
    757     sym = kit_cg_decl(p->cg, decl);
    758     if (sym == KIT_CG_SYM_NONE) {
    759       toy_error(p, p->cur.loc, "failed to declare static local");
    760       return 0;
    761     }
    762     if (!toy_add_static_local_typed(p, name, ty, toy_ty, sym, is_var)) return 0;
    763     memset(&data_attrs, 0, sizeof data_attrs);
    764     data_attrs.flags |= KIT_CG_DATADEF_FUNCTION_LOCAL;
    765     if (!is_var) data_attrs.flags |= KIT_CG_DATADEF_READONLY;
    766     kit_cg_data_begin(p->cg, sym, data_attrs);
    767     if (array_data_init) {
    768       KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, ty);
    769       uint64_t total_size = kit_cg_type_size(p->c, ty);
    770       uint64_t pos = 0;
    771       toy_parser_advance(p); /* '[' */
    772       while (p->cur.kind != TOK_RBRACKET && p->cur.kind != TOK_EOF) {
    773         if (!toy_parse_data_array_builtin(p, elem_ty, total_size, &pos))
    774           return 0;
    775         if (!toy_parser_match(p, TOK_COMMA)) break;
    776       }
    777       if (!toy_parser_expect(p, TOK_RBRACKET)) {
    778         toy_error(p, p->cur.loc, "expected ']' after static initializer");
    779         return 0;
    780       }
    781       if (pos < total_size) kit_cg_data_zero(p->cg, total_size - pos);
    782     } else {
    783       kit_cg_data_bytes(p->cg, buf, n);
    784     }
    785     kit_cg_data_end(p->cg);
    786     if (!toy_parser_expect(p, TOK_SEMI)) {
    787       toy_error(p, p->cur.loc, "expected ';' after static local");
    788       return 0;
    789     }
    790     return 1;
    791   }
    792 
    793   if (!inferred && p->cur.kind == TOK_EQ &&
    794       ((kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ARRAY &&
    795         toy_lexer_peek(&p->lex).kind == TOK_LBRACKET) ||
    796        (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_RECORD &&
    797         !toy_type_is_slice(p, toy_ty) &&
    798         (toy_lexer_peek(&p->lex).kind == TOK_IDENT ||
    799          toy_lexer_peek(&p->lex).kind == TOK_LBRACE)))) {
    800     toy_parser_advance(p); /* = */
    801     slot = kit_cg_local(p->cg, ty, toy_slot_attrs(name));
    802     if (!toy_add_local_typed(p, name, ty, toy_ty, slot, is_var)) return 0;
    803     if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ARRAY) {
    804       if (!toy_parse_array_initializer(p, slot, ty, toy_ty)) return 0;
    805     } else {
    806       if (!toy_parse_record_initializer(p, slot, ty, toy_ty)) return 0;
    807     }
    808     if (!toy_parser_expect(p, TOK_SEMI)) {
    809       toy_error(p, p->cur.loc, "expected ';' after let");
    810       return 0;
    811     }
    812     return 1;
    813   }
    814 
    815   if (!inferred && kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ENUM &&
    816       p->cur.kind == TOK_EQ && toy_lexer_peek(&p->lex).kind == TOK_DOT) {
    817     ToyNamedType* named = toy_find_named_type_by_type(p, ty);
    818     KitSym value_name;
    819     size_t i;
    820     int found = 0;
    821     int64_t value = 0;
    822     toy_parser_advance(p); /* = */
    823     toy_parser_advance(p); /* . */
    824     if (p->cur.kind != TOK_IDENT) {
    825       toy_error(p, p->cur.loc, "expected enum value");
    826       return 0;
    827     }
    828     value_name = toy_tok_sym(p, p->cur);
    829     toy_parser_advance(p);
    830     if (!named || named->kind != TOY_NAMED_ENUM) {
    831       toy_error(p, p->cur.loc, "unknown enum type");
    832       return 0;
    833     }
    834     for (i = 0; i < named->nenum_values; ++i) {
    835       if (named->enum_values[i].name == value_name) {
    836         found = 1;
    837         value = named->enum_values[i].value;
    838         break;
    839       }
    840     }
    841     if (!found) {
    842       toy_error(p, p->cur.loc, "unknown enum value");
    843       return 0;
    844     }
    845     slot = kit_cg_local(p->cg, ty, toy_slot_attrs(name));
    846     if (!toy_add_local_typed(p, name, ty, toy_ty, slot, is_var)) return 0;
    847     kit_cg_push_local(p->cg, slot);
    848     kit_cg_push_int(p->cg, (uint64_t)value, ty);
    849     kit_cg_store(p->cg, toy_mem_access(p, ty));
    850     if (!toy_parser_expect(p, TOK_SEMI)) {
    851       toy_error(p, p->cur.loc, "expected ';' after let");
    852       return 0;
    853     }
    854     return 1;
    855   }
    856 
    857   if (!inferred && p->cur.kind == TOK_EQ &&
    858       toy_lexer_peek(&p->lex).kind == TOK_IF) {
    859     toy_parser_advance(p); /* = */
    860     slot = kit_cg_local(p->cg, ty, toy_slot_attrs(name));
    861     if (!toy_add_local_typed(p, name, ty, toy_ty, slot, is_var)) return 0;
    862     if (!toy_parse_if_initializer(p, slot, ty, toy_ty)) return 0;
    863     if (!toy_parser_expect(p, TOK_SEMI)) {
    864       toy_error(p, p->cur.loc, "expected ';' after let");
    865       return 0;
    866     }
    867     return 1;
    868   }
    869 
    870   if (!inferred && p->cur.kind == TOK_EQ &&
    871       toy_lexer_peek(&p->lex).kind == TOK_SWITCH) {
    872     toy_parser_advance(p); /* = */
    873     slot = kit_cg_local(p->cg, ty, toy_slot_attrs(name));
    874     if (!toy_add_local_typed(p, name, ty, toy_ty, slot, is_var)) return 0;
    875     if (!toy_parse_switch_initializer(p, slot, ty, toy_ty)) return 0;
    876     if (!toy_parser_expect(p, TOK_SEMI)) {
    877       toy_error(p, p->cur.loc, "expected ';' after let");
    878       return 0;
    879     }
    880     return 1;
    881   }
    882 
    883   if (!inferred && p->cur.kind == TOK_EQ &&
    884       toy_lexer_peek(&p->lex).kind == TOK_WHILE) {
    885     toy_parser_advance(p); /* = */
    886     slot = kit_cg_local(p->cg, ty, toy_slot_attrs(name));
    887     if (!toy_add_local_typed(p, name, ty, toy_ty, slot, is_var)) return 0;
    888     if (!toy_parse_while_initializer(p, slot, ty, toy_ty)) return 0;
    889     if (!toy_parser_expect(p, TOK_SEMI)) {
    890       toy_error(p, p->cur.loc, "expected ';' after let");
    891       return 0;
    892     }
    893     return 1;
    894   }
    895 
    896   if (!inferred && p->cur.kind == TOK_EQ) {
    897     ToyLexer tmp_lex = p->lex;
    898     ToyToken label_tok = toy_lexer_next(&tmp_lex);
    899     ToyToken colon_tok = toy_lexer_next(&tmp_lex);
    900     ToyToken while_tok = toy_lexer_next(&tmp_lex);
    901     if (label_tok.kind == TOK_IDENT && colon_tok.kind == TOK_COLON &&
    902         while_tok.kind == TOK_WHILE) {
    903       KitSym loop_label;
    904       toy_parser_advance(p); /* = */
    905       loop_label = toy_tok_sym(p, p->cur);
    906       toy_parser_advance(p); /* label */
    907       if (!toy_parser_expect(p, TOK_COLON)) {
    908         toy_error(p, p->cur.loc, "expected ':' after loop label");
    909         return 0;
    910       }
    911       slot = kit_cg_local(p->cg, ty, toy_slot_attrs(name));
    912       if (!toy_add_local_typed(p, name, ty, toy_ty, slot, is_var)) return 0;
    913       if (!toy_parse_while_initializer_named(p, slot, ty, toy_ty, loop_label))
    914         return 0;
    915       if (!toy_parser_expect(p, TOK_SEMI)) {
    916         toy_error(p, p->cur.loc, "expected ';' after let");
    917         return 0;
    918       }
    919       return 1;
    920     }
    921   }
    922 
    923   if (toy_parser_match(p, TOK_EQ)) {
    924     has_init = 1;
    925     if (!inferred && toy_type_is_ptr(p, ty) && p->cur.kind == TOK_IDENT &&
    926         toy_sym_is(p, toy_tok_sym(p, p->cur), "NULL") &&
    927         toy_lexer_peek(&p->lex).kind == TOK_SEMI) {
    928       toy_parser_advance(p);
    929       kit_cg_push_int(p->cg, 0, p->int_type);
    930       kit_cg_int_to_ptr(p->cg, ty);
    931       init_ty = ty;
    932       init_toy_type = toy_ty;
    933     } else {
    934       init_ty = toy_parse_expr(p);
    935       if (init_ty == KIT_CG_TYPE_NONE) return 0;
    936       init_toy_type = p->last_type;
    937     }
    938     if (inferred) {
    939       ty = init_ty;
    940       toy_ty = init_toy_type;
    941     } else {
    942       if (!toy_check_source_value(p, ty, toy_ty, init_ty, init_toy_type,
    943                                   "type mismatch in let initializer")) {
    944         return 0;
    945       }
    946       if (init_ty != ty) {
    947         if (toy_records_have_matching_storage(p, ty, init_ty)) {
    948           copy_record_init = 1;
    949         } else {
    950           if (!toy_emit_checked_cast(p, init_ty, ty)) return 0;
    951         }
    952       }
    953     }
    954   }
    955 
    956   slot = kit_cg_local(p->cg, ty, toy_slot_attrs(name));
    957   if (!toy_add_local_typed(p, name, ty, toy_ty, slot, is_var)) return 0;
    958 
    959   if (has_init) {
    960     if (toy_type_is_slice(p, init_toy_type)) {
    961       if (!toy_copy_record_lvalue_to_local(p, init_ty, slot, ty)) return 0;
    962     } else if (copy_record_init ||
    963                kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_RECORD) {
    964       if (!toy_copy_record_lvalue_to_local(p, init_ty, slot, ty)) return 0;
    965     } else {
    966       kit_cg_push_local(p->cg, slot);
    967       kit_cg_swap(p->cg);
    968       kit_cg_store(p->cg, toy_mem_access(p, ty));
    969     }
    970   }
    971   if (!toy_parser_expect(p, TOK_SEMI)) {
    972     toy_error(p, p->cur.loc, "expected ';' after let");
    973     return 0;
    974   }
    975   return 1;
    976 }
    977 
    978 static int toy_parse_if_stmt(ToyParser* p) {
    979   KitCgIf it;
    980   KitCgTypeId cond_ty;
    981   toy_parser_advance(p); /* if */
    982   cond_ty = toy_parse_expr(p);
    983   if (cond_ty == KIT_CG_TYPE_NONE) return 0;
    984   if (!toy_emit_truthy(p, cond_ty)) return 0;
    985 
    986   it = kit_cg_if_begin(p->cg);
    987 
    988   if (!toy_parse_block(p)) return 0;
    989 
    990   kit_cg_if_else(p->cg, it);
    991 
    992   if (p->cur.kind == TOK_ELSE) {
    993     toy_parser_advance(p); /* else */
    994     if (p->cur.kind == TOK_LBRACE) {
    995       if (!toy_parse_block(p)) return 0;
    996     } else {
    997       if (!toy_parse_stmt(p)) return 0;
    998     }
    999   }
   1000 
   1001   kit_cg_if_end(p->cg, it);
   1002   return 1;
   1003 }
   1004 
   1005 static int toy_parse_while_stmt_named(ToyParser* p, KitSym label_name) {
   1006   KitCgScope scope;
   1007   KitCgTypeId cond_ty;
   1008 
   1009   toy_parser_advance(p); /* while */
   1010 
   1011   if (!toy_parser_reserve(p, (void**)&p->scopes, &p->cap_scopes,
   1012                           p->nscopes + 1u, sizeof *p->scopes, "scopes")) {
   1013     return 0;
   1014   }
   1015   scope = kit_cg_scope_begin(p->cg);
   1016   p->scopes[p->nscopes].name = label_name;
   1017   p->scopes[p->nscopes].kind = TOY_SCOPE_LOOP;
   1018   p->scopes[p->nscopes].cg_scope = scope;
   1019   p->scopes[p->nscopes].result_type = KIT_CG_TYPE_NONE;
   1020   p->scopes[p->nscopes].result_toy_type = TOY_TYPE_NONE;
   1021   p->nscopes++;
   1022 
   1023   cond_ty = toy_parse_expr(p);
   1024   if (cond_ty == KIT_CG_TYPE_NONE) {
   1025     p->nscopes--;
   1026     return 0;
   1027   }
   1028   if (!toy_emit_truthy(p, cond_ty)) {
   1029     p->nscopes--;
   1030     return 0;
   1031   }
   1032   kit_cg_break_false(p->cg, scope);
   1033 
   1034   if (!toy_parse_block(p)) {
   1035     p->nscopes--;
   1036     return 0;
   1037   }
   1038 
   1039   kit_cg_continue(p->cg, scope);
   1040   kit_cg_scope_end(p->cg, scope);
   1041   p->nscopes--;
   1042   return 1;
   1043 }
   1044 
   1045 static int toy_parse_while_stmt(ToyParser* p) {
   1046   return toy_parse_while_stmt_named(p, 0);
   1047 }
   1048 
   1049 static int toy_parse_switch_stmt_named(ToyParser* p, KitSym label_name) {
   1050   KitCgTypeId selector_ty;
   1051   KitCgLocal selector_slot;
   1052   KitCgLabel end_label;
   1053   KitCgLabel dispatch_label;
   1054   KitCgLabel default_arm_label = KIT_CG_LABEL_NONE;
   1055   KitCgScope scope;
   1056   KitCgSwitchCase* cases = NULL;
   1057   size_t ncases = 0;
   1058   size_t cap_cases = 0;
   1059   KitCgSwitchHint hint;
   1060   KitCgSwitch sw;
   1061 
   1062   toy_parser_advance(p); /* switch */
   1063   if (!toy_parse_switch_strategy_hint(p, &hint)) return 0;
   1064   selector_ty = toy_parse_expr(p);
   1065   if (selector_ty == KIT_CG_TYPE_NONE) return 0;
   1066   if (!toy_type_is_intlike(p, selector_ty)) {
   1067     toy_error(p, p->cur.loc, "switch selector must be integer-like");
   1068     return 0;
   1069   }
   1070   selector_slot = kit_cg_local(p->cg, selector_ty, toy_slot_attrs(0));
   1071   kit_cg_push_local(p->cg, selector_slot);
   1072   kit_cg_swap(p->cg);
   1073   kit_cg_store(p->cg, toy_mem_access(p, selector_ty));
   1074   end_label = kit_cg_label_new(p->cg);
   1075   dispatch_label = kit_cg_label_new(p->cg);
   1076   if (!toy_parser_reserve(p, (void**)&p->scopes, &p->cap_scopes,
   1077                           p->nscopes + 1u, sizeof *p->scopes, "scopes")) {
   1078     return 0;
   1079   }
   1080   /* scope_begin must precede the jump-to-dispatch so the scope's entry
   1081    * block is reachable from the straight-line predecessor. With the
   1082    * jump before scope_begin, opt's CFG sees the scope_begin block as
   1083    * unreachable and prunes it; scope_end then can't find its handle. */
   1084   scope = kit_cg_scope_begin(p->cg);
   1085   p->scopes[p->nscopes].name = label_name;
   1086   p->scopes[p->nscopes].kind = TOY_SCOPE_SWITCH;
   1087   p->scopes[p->nscopes].cg_scope = scope;
   1088   p->scopes[p->nscopes].result_type = KIT_CG_TYPE_NONE;
   1089   p->scopes[p->nscopes].result_toy_type = TOY_TYPE_NONE;
   1090   p->nscopes++;
   1091   /* Skip the arm bodies on entry; come back through the dispatch label. */
   1092   kit_cg_jump(p->cg, dispatch_label);
   1093   if (!toy_parser_expect(p, TOK_LBRACE)) {
   1094     toy_error(p, p->cur.loc, "expected '{' after switch selector");
   1095     p->nscopes--;
   1096     return 0;
   1097   }
   1098   while (p->cur.kind != TOK_RBRACE && p->cur.kind != TOK_EOF) {
   1099     KitCgLabel arm_label = kit_cg_label_new(p->cg);
   1100     if (p->cur.kind == TOK_DEFAULT) {
   1101       default_arm_label = arm_label;
   1102       toy_parser_advance(p);
   1103     } else {
   1104       for (;;) {
   1105         int64_t value;
   1106         if (!toy_parse_switch_label_value(p, selector_ty, &value)) {
   1107           toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
   1108           p->nscopes--;
   1109           return 0;
   1110         }
   1111         if (!toy_parser_reserve(p, (void**)&cases, &cap_cases, ncases + 1u,
   1112                                 sizeof *cases, "switch cases")) {
   1113           p->nscopes--;
   1114           return 0;
   1115         }
   1116         cases[ncases].value = (uint64_t)value;
   1117         cases[ncases].label = arm_label;
   1118         ncases++;
   1119         if (!toy_parser_match(p, TOK_COMMA)) break;
   1120       }
   1121     }
   1122     kit_cg_label_place(p->cg, arm_label);
   1123     if (!toy_parse_block(p)) {
   1124       toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
   1125       p->nscopes--;
   1126       return 0;
   1127     }
   1128     kit_cg_jump(p->cg, end_label);
   1129   }
   1130   if (!toy_parser_expect(p, TOK_RBRACE)) {
   1131     toy_error(p, p->cur.loc, "expected '}' after switch");
   1132     toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
   1133     p->nscopes--;
   1134     return 0;
   1135   }
   1136   kit_cg_label_place(p->cg, dispatch_label);
   1137   kit_cg_push_local(p->cg, selector_slot);
   1138   kit_cg_load(p->cg, toy_mem_access(p, selector_ty));
   1139   sw.selector_type = selector_ty;
   1140   sw.default_label =
   1141       default_arm_label != KIT_CG_LABEL_NONE ? default_arm_label : end_label;
   1142   sw.cases = cases;
   1143   sw.ncases = (uint32_t)ncases;
   1144   sw.hint = hint;
   1145   kit_cg_switch(p->cg, sw);
   1146   kit_cg_label_place(p->cg, end_label);
   1147   kit_cg_scope_end(p->cg, scope);
   1148   p->nscopes--;
   1149   toy_parser_free_mem(p, cases, cap_cases * sizeof *cases);
   1150   return 1;
   1151 }
   1152 
   1153 static int toy_parse_switch_stmt(ToyParser* p) {
   1154   return toy_parse_switch_stmt_named(p, 0);
   1155 }
   1156 
   1157 static int toy_add_goto_target(ToyParser* p, uint32_t* ntargets,
   1158                                KitCgLabel label) {
   1159   if (!toy_parser_reserve(p, (void**)&p->goto_targets, &p->cap_goto_targets,
   1160                           (size_t)*ntargets + 1u, sizeof *p->goto_targets,
   1161                           "goto targets")) {
   1162     return 0;
   1163   }
   1164   p->goto_targets[*ntargets] = label;
   1165   (*ntargets)++;
   1166   return 1;
   1167 }
   1168 
   1169 static int toy_parse_label_decl_stmt(ToyParser* p) {
   1170   KitSym name;
   1171   toy_parser_advance(p); /* label */
   1172   if (p->cur.kind != TOK_IDENT) {
   1173     toy_error(p, p->cur.loc, "expected label name");
   1174     return 0;
   1175   }
   1176   name = toy_tok_sym(p, p->cur);
   1177   toy_parser_advance(p);
   1178   if (!toy_declare_label(p, name)) return 0;
   1179   if (!toy_parser_expect(p, TOK_SEMI)) {
   1180     toy_error(p, p->cur.loc, "expected ';' after label declaration");
   1181     return 0;
   1182   }
   1183   return 1;
   1184 }
   1185 
   1186 static int toy_parse_goto_stmt(ToyParser* p) {
   1187   KitCgTypeId target_ty;
   1188   KitCgTypeId void_ptr_ty =
   1189       kit_cg_type_ptr(p->c, toy_builtin_type(p, KIT_CG_BUILTIN_VOID), 0);
   1190   uint32_t ntargets = 0;
   1191   uint32_t i;
   1192   toy_parser_advance(p); /* goto */
   1193   if (!toy_parser_expect(p, TOK_STAR)) {
   1194     toy_error(p, p->cur.loc, "expected computed goto target");
   1195     return 0;
   1196   }
   1197   target_ty = toy_parse_expr(p);
   1198   if (target_ty == KIT_CG_TYPE_NONE) return 0;
   1199   if (target_ty != void_ptr_ty) {
   1200     toy_error(p, p->cur.loc, "computed goto target must be *void");
   1201     return 0;
   1202   }
   1203   if (toy_parser_match(p, TOK_WITHIN)) {
   1204     if (!toy_parser_expect(p, TOK_LPAREN)) {
   1205       toy_error(p, p->cur.loc, "expected target list");
   1206       return 0;
   1207     }
   1208     while (p->cur.kind != TOK_RPAREN && p->cur.kind != TOK_EOF) {
   1209       KitSym name;
   1210       ToyLabel* label;
   1211       if (p->cur.kind != TOK_IDENT) {
   1212         toy_error(p, p->cur.loc, "expected label in target list");
   1213         return 0;
   1214       }
   1215       name = toy_tok_sym(p, p->cur);
   1216       toy_parser_advance(p);
   1217       label = toy_find_label(p, name);
   1218       if (!label) {
   1219         toy_error(p, p->cur.loc, "unknown label in target list");
   1220         return 0;
   1221       }
   1222       if (!toy_add_goto_target(p, &ntargets, label->label)) return 0;
   1223       if (!toy_parser_match(p, TOK_COMMA)) break;
   1224     }
   1225     if (!toy_parser_expect(p, TOK_RPAREN)) {
   1226       toy_error(p, p->cur.loc, "expected ')' after target list");
   1227       return 0;
   1228     }
   1229   }
   1230   if (ntargets == 0) {
   1231     for (i = 0; i < p->nlabels; ++i) {
   1232       if (!toy_add_goto_target(p, &ntargets, p->labels[i].label)) return 0;
   1233     }
   1234   }
   1235   kit_cg_computed_goto(p->cg, p->goto_targets, ntargets);
   1236   if (!toy_parser_expect(p, TOK_SEMI)) {
   1237     toy_error(p, p->cur.loc, "expected ';' after goto");
   1238     return 0;
   1239   }
   1240   return 1;
   1241 }
   1242 
   1243 static int toy_parse_break_stmt(ToyParser* p) {
   1244   KitSym target_name = 0;
   1245   ToyScope* target_scope;
   1246   toy_parser_advance(p); /* break */
   1247   if (p->nscopes == 0) {
   1248     toy_error(p, p->cur.loc, "break outside loop");
   1249     return 0;
   1250   }
   1251   if (p->cur.kind == TOK_IDENT) {
   1252     KitSym maybe_target = toy_tok_sym(p, p->cur);
   1253     if (toy_find_scope(p, maybe_target)) {
   1254       target_name = maybe_target;
   1255       toy_parser_advance(p);
   1256     }
   1257   }
   1258   target_scope = toy_find_scope(p, target_name);
   1259   if (!target_scope) {
   1260     toy_error(p, p->cur.loc, "unknown break target");
   1261     return 0;
   1262   }
   1263   if (p->cur.kind != TOK_SEMI) {
   1264     KitCgTypeId expr_ty = toy_parse_expr(p);
   1265     KitCgTypeId result_ty = target_scope->result_type;
   1266     if (expr_ty == KIT_CG_TYPE_NONE) return 0;
   1267     if (result_ty == KIT_CG_TYPE_NONE) {
   1268       toy_error(p, p->cur.loc, "break value type mismatch");
   1269       return 0;
   1270     }
   1271     if (!toy_check_source_value(p, result_ty, target_scope->result_toy_type,
   1272                                 expr_ty, p->last_type,
   1273                                 "break value type mismatch"))
   1274       return 0;
   1275     if (expr_ty != result_ty && !toy_emit_checked_cast(p, expr_ty, result_ty))
   1276       return 0;
   1277     kit_cg_break(p->cg, target_scope->cg_scope);
   1278     if (!toy_parser_expect(p, TOK_SEMI)) {
   1279       toy_error(p, p->cur.loc, "expected ';' after break");
   1280       return 0;
   1281     }
   1282     return 1;
   1283   }
   1284   kit_cg_break(p->cg, target_scope->cg_scope);
   1285   if (!toy_parser_expect(p, TOK_SEMI)) {
   1286     toy_error(p, p->cur.loc, "expected ';' after break");
   1287     return 0;
   1288   }
   1289   return 1;
   1290 }
   1291 
   1292 static int toy_parse_continue_stmt(ToyParser* p) {
   1293   KitSym target_name = 0;
   1294   ToyScope* target_scope;
   1295   toy_parser_advance(p); /* continue */
   1296   if (p->nscopes == 0) {
   1297     toy_error(p, p->cur.loc, "continue outside loop");
   1298     return 0;
   1299   }
   1300   if (p->cur.kind == TOK_IDENT) {
   1301     target_name = toy_tok_sym(p, p->cur);
   1302     toy_parser_advance(p);
   1303     target_scope = toy_find_scope(p, target_name);
   1304     if (!target_scope) {
   1305       toy_error(p, p->cur.loc, "unknown continue target");
   1306       return 0;
   1307     }
   1308     if (target_scope->kind != TOY_SCOPE_LOOP) {
   1309       toy_error(p, p->cur.loc, "continue target is not a loop");
   1310       return 0;
   1311     }
   1312   } else {
   1313     target_scope = toy_find_innermost_loop_scope(p);
   1314     if (!target_scope) {
   1315       toy_error(p, p->cur.loc, "continue outside loop");
   1316       return 0;
   1317     }
   1318   }
   1319   kit_cg_continue(p->cg, target_scope->cg_scope);
   1320   if (!toy_parser_expect(p, TOK_SEMI)) {
   1321     toy_error(p, p->cur.loc, "expected ';' after continue");
   1322     return 0;
   1323   }
   1324   return 1;
   1325 }
   1326 
   1327 static int toy_parse_return_stmt(ToyParser* p) {
   1328   KitCgTypeId ty;
   1329   toy_parser_advance(p); /* return */
   1330   int is_tail = p->cur.kind == TOK_TAIL;
   1331   int is_musttail = p->cur.kind == TOK_MUSTTAIL;
   1332   if (is_tail || is_musttail) {
   1333     int must_tail = is_musttail;
   1334     KitSym name;
   1335     ToyFn* fn;
   1336     ToyToken call_tok;
   1337     KitCgTypeId fn_ty;
   1338     size_t nargs = 0;
   1339     toy_parser_advance(p); /* tail | musttail */
   1340     if (p->cur.kind != TOK_IDENT) {
   1341       toy_error(p, p->cur.loc, "expected function name after %s",
   1342                 must_tail ? "musttail" : "tail");
   1343       return 0;
   1344     }
   1345     call_tok = p->cur;
   1346     name = toy_tok_sym(p, p->cur);
   1347     fn = toy_find_fn(p, name);
   1348     toy_parser_advance(p);
   1349     if (!toy_parser_expect(p, TOK_LPAREN)) return 0;
   1350     if (fn) {
   1351       fn_ty = fn->type;
   1352     } else {
   1353       KitCgTypeId callee_ty = toy_push_named_rvalue(p, name);
   1354       if (callee_ty == KIT_CG_TYPE_NONE) {
   1355         toy_error(p, call_tok.loc, "undefined function in tail call");
   1356         return 0;
   1357       }
   1358       fn_ty = toy_ptr_pointee_func_type(p, callee_ty);
   1359       if (fn_ty == KIT_CG_TYPE_NONE) {
   1360         toy_error(p, call_tok.loc, "tail callee is not a function pointer");
   1361         return 0;
   1362       }
   1363     }
   1364     /* Variadic tail calls are not rejected here: realizability is a per-target
   1365      * decision owned by CG's precondition and the target's tail_call hook
   1366      * (e.g. native fits varargs in the caller's incoming area; wasm cannot,
   1367      * since its vararg buffer lives in the frame a sibling call tears down). */
   1368     if (!toy_parse_call_args(p, call_tok, fn_ty, fn ? fn->toy_params : NULL,
   1369                              fn ? fn->nparams : 0, &nargs))
   1370       return 0;
   1371     if (fn && !toy_type_accepts_storage(p, p->cur_fn_ret_toy, fn->toy_ret)) {
   1372       toy_error(p, p->cur.loc, "tail call signature mismatch");
   1373       return 0;
   1374     }
   1375     if (!fn && toy_cg_func_ret(p, fn_ty) != p->cur_fn_ret) {
   1376       toy_error(p, p->cur.loc, "tail call signature mismatch");
   1377       return 0;
   1378     }
   1379     if (fn) {
   1380       if (must_tail)
   1381         kit_cg_musttail_call_symbol(p->cg, toy_fn_cur_sym(p, fn),
   1382                                     (uint32_t)nargs);
   1383       else
   1384         kit_cg_tail_call_symbol(p->cg, toy_fn_cur_sym(p, fn), (uint32_t)nargs);
   1385     } else {
   1386       if (must_tail)
   1387         kit_cg_musttail_call(p->cg, (uint32_t)nargs, fn_ty);
   1388       else
   1389         kit_cg_tail_call(p->cg, (uint32_t)nargs, fn_ty);
   1390     }
   1391     if (!toy_parser_expect(p, TOK_SEMI)) return 0;
   1392     return 1;
   1393   }
   1394   if (p->cur.kind == TOK_SEMI) {
   1395     toy_parser_advance(p);
   1396     if (p->cur_fn_ret != toy_builtin_type(p, KIT_CG_BUILTIN_VOID)) {
   1397       toy_error(p, p->cur.loc, "return without value in non-void function");
   1398       return 0;
   1399     }
   1400     kit_cg_ret(p->cg);
   1401     return 1;
   1402   }
   1403   if (p->cur_fn_ret != toy_builtin_type(p, KIT_CG_BUILTIN_VOID)) {
   1404     int is_control_expr = p->cur.kind == TOK_IF || p->cur.kind == TOK_SWITCH ||
   1405                           p->cur.kind == TOK_WHILE;
   1406     KitSym loop_label = 0;
   1407     if (!is_control_expr && p->cur.kind == TOK_IDENT) {
   1408       ToyLexer tmp_lex = p->lex;
   1409       ToyToken colon_tok = toy_lexer_next(&tmp_lex);
   1410       ToyToken while_tok = toy_lexer_next(&tmp_lex);
   1411       if (colon_tok.kind == TOK_COLON && while_tok.kind == TOK_WHILE) {
   1412         is_control_expr = 1;
   1413         loop_label = toy_tok_sym(p, p->cur);
   1414       }
   1415     }
   1416     if (is_control_expr) {
   1417       KitCgLocal slot = kit_cg_local(p->cg, p->cur_fn_ret, toy_slot_attrs(0));
   1418       if (p->cur.kind == TOK_IF) {
   1419         if (!toy_parse_if_initializer(p, slot, p->cur_fn_ret,
   1420                                       p->cur_fn_ret_toy))
   1421           return 0;
   1422       } else if (p->cur.kind == TOK_SWITCH) {
   1423         if (!toy_parse_switch_initializer(p, slot, p->cur_fn_ret,
   1424                                           p->cur_fn_ret_toy))
   1425           return 0;
   1426       } else if (p->cur.kind == TOK_WHILE) {
   1427         if (!toy_parse_while_initializer(p, slot, p->cur_fn_ret,
   1428                                          p->cur_fn_ret_toy))
   1429           return 0;
   1430       } else {
   1431         toy_parser_advance(p); /* label */
   1432         if (!toy_parser_expect(p, TOK_COLON)) {
   1433           toy_error(p, p->cur.loc, "expected ':' after loop label");
   1434           return 0;
   1435         }
   1436         if (!toy_parse_while_initializer_named(p, slot, p->cur_fn_ret,
   1437                                                p->cur_fn_ret_toy, loop_label)) {
   1438           return 0;
   1439         }
   1440       }
   1441       kit_cg_push_local(p->cg, slot);
   1442       kit_cg_load(p->cg, toy_mem_access(p, p->cur_fn_ret));
   1443       kit_cg_ret(p->cg);
   1444       if (!toy_parser_expect(p, TOK_SEMI)) {
   1445         toy_error(p, p->cur.loc, "expected ';' after return");
   1446         return 0;
   1447       }
   1448       return 1;
   1449     }
   1450   }
   1451   p->allow_tail_call_expr = 1;
   1452   p->tail_call_expr = 0;
   1453   p->tail_call_ret_toy = TOY_TYPE_NONE;
   1454   ty = toy_parse_expr(p);
   1455   p->allow_tail_call_expr = 0;
   1456   if (ty == KIT_CG_TYPE_NONE) return 0;
   1457   if (p->tail_call_expr) {
   1458     ToyTypeId tail_toy = p->tail_call_ret_toy;
   1459     if (!tail_toy) tail_toy = p->last_type;
   1460     if (!toy_check_source_value(p, p->cur_fn_ret, p->cur_fn_ret_toy, ty,
   1461                                 tail_toy, "return type mismatch"))
   1462       return 0;
   1463     if (!toy_parser_expect(p, TOK_SEMI)) {
   1464       toy_error(p, p->cur.loc, "expected ';' after return");
   1465       return 0;
   1466     }
   1467     p->tail_call_expr = 0;
   1468     p->tail_call_ret_toy = TOY_TYPE_NONE;
   1469     return 1;
   1470   }
   1471   if (!toy_check_source_value(p, p->cur_fn_ret, p->cur_fn_ret_toy, ty,
   1472                               p->last_type, "return type mismatch"))
   1473     return 0;
   1474   if (ty != p->cur_fn_ret && !toy_emit_checked_cast(p, ty, p->cur_fn_ret))
   1475     return 0;
   1476   kit_cg_ret(p->cg);
   1477   if (!toy_parser_expect(p, TOK_SEMI)) {
   1478     toy_error(p, p->cur.loc, "expected ';' after return");
   1479     return 0;
   1480   }
   1481   return 1;
   1482 }
   1483 
   1484 static int toy_parse_expr_stmt(ToyParser* p) {
   1485   KitCgTypeId ty = toy_parse_expr(p);
   1486   if (ty == KIT_CG_TYPE_NONE) return 0;
   1487   if (p->tail_call_expr) {
   1488     toy_error(p, p->cur.loc, "tail @call requires return");
   1489     return 0;
   1490   }
   1491   if (!toy_parser_expect(p, TOK_SEMI)) {
   1492     toy_error(p, p->cur.loc, "expected ';' after expression");
   1493     return 0;
   1494   }
   1495   if (ty != toy_builtin_type(p, KIT_CG_BUILTIN_VOID)) kit_cg_drop(p->cg);
   1496   return 1;
   1497 }
   1498 
   1499 static int toy_parse_stmt(ToyParser* p) {
   1500   toy_set_loc(p);
   1501   if (p->cur.kind == TOK_LET || p->cur.kind == TOK_VAR)
   1502     return toy_parse_let_stmt(p);
   1503   if (p->cur.kind == TOK_IF) return toy_parse_if_stmt(p);
   1504   if (p->cur.kind == TOK_WHILE) return toy_parse_while_stmt(p);
   1505   if (p->cur.kind == TOK_SWITCH) return toy_parse_switch_stmt(p);
   1506   if (p->cur.kind == TOK_LABEL) return toy_parse_label_decl_stmt(p);
   1507   if (p->cur.kind == TOK_GOTO) return toy_parse_goto_stmt(p);
   1508   if (p->cur.kind == TOK_BREAK) return toy_parse_break_stmt(p);
   1509   if (p->cur.kind == TOK_CONTINUE) return toy_parse_continue_stmt(p);
   1510   if (p->cur.kind == TOK_RETURN) return toy_parse_return_stmt(p);
   1511   if (p->cur.kind == TOK_LBRACE) return toy_parse_block(p);
   1512 
   1513   /* Assignment or expression statement */
   1514   if (p->cur.kind == TOK_IDENT && toy_lexer_peek(&p->lex).kind == TOK_COLON) {
   1515     KitSym name = toy_tok_sym(p, p->cur);
   1516     toy_parser_advance(p); /* ident */
   1517     toy_parser_advance(p); /* : */
   1518     if (p->cur.kind == TOK_WHILE) return toy_parse_while_stmt_named(p, name);
   1519     if (p->cur.kind == TOK_SWITCH) return toy_parse_switch_stmt_named(p, name);
   1520     {
   1521       ToyLabel* label = toy_declare_label(p, name);
   1522       if (!label) return 0;
   1523       kit_cg_label_place(p->cg, label->label);
   1524     }
   1525     return 1;
   1526   }
   1527 
   1528   if (p->cur.kind == TOK_IDENT &&
   1529       (toy_lexer_peek(&p->lex).kind == TOK_LBRACKET ||
   1530        toy_lexer_peek(&p->lex).kind == TOK_DOTSTAR ||
   1531        toy_lexer_peek(&p->lex).kind == TOK_DOT)) {
   1532     KitSym name = toy_tok_sym(p, p->cur);
   1533     KitCgTypeId lhs_ty;
   1534     ToyTypeId lhs_toy_type = TOY_TYPE_NONE;
   1535     KitCgTypeId root_ty = KIT_CG_TYPE_NONE;
   1536     int root_mutable = 1;
   1537     int lhs_slice_metadata = 0;
   1538     toy_parser_advance(p);
   1539     /* Chain invariant: TOS holds a pointer-rvalue of type `*lhs_ty`.
   1540      * Intermediate field / index / dereference steps materialize the
   1541      * address via toy_addr_offset / toy_addr_index / explicit loads.
   1542      * The final store consumes the pointer with EA {0, 0}. */
   1543     {
   1544       ToyVar* v = toy_find_var(p, name);
   1545       ToyGlobal* g = toy_find_global(p, name);
   1546       if (v) {
   1547         root_ty = v->type;
   1548         lhs_toy_type = v->toy_type;
   1549         root_mutable = v->mutable;
   1550       } else if (g) {
   1551         root_ty = g->type;
   1552         lhs_toy_type = g->toy_type;
   1553         root_mutable = g->mutable;
   1554       }
   1555       if (v) {
   1556         toy_push_var_addr(p, v);
   1557         lhs_ty = v->type;
   1558       } else if (g) {
   1559         kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
   1560         lhs_ty = g->type;
   1561       } else {
   1562         lhs_ty = KIT_CG_TYPE_NONE;
   1563       }
   1564     }
   1565     if (lhs_ty == KIT_CG_TYPE_NONE) {
   1566       toy_error(p, p->cur.loc, "undefined variable in assignment");
   1567       return 0;
   1568     }
   1569 
   1570     for (;;) {
   1571       if (toy_parser_match(p, TOK_LBRACKET)) {
   1572         KitCgTypeId idx_ty = toy_parse_expr(p);
   1573         lhs_slice_metadata = 0;
   1574         if (idx_ty == KIT_CG_TYPE_NONE) return 0;
   1575         if (!toy_type_can_implicitly_cast(p, idx_ty, p->size_type)) {
   1576           toy_error(p, p->cur.loc, "index must be isize");
   1577           return 0;
   1578         }
   1579         if (!toy_emit_implicit_cast(p, idx_ty, p->size_type)) return 0;
   1580         idx_ty = p->size_type;
   1581         if (!toy_parser_expect(p, TOK_RBRACKET)) {
   1582           toy_error(p, p->cur.loc, "expected ']' after index");
   1583           return 0;
   1584         }
   1585         if (kit_cg_type_kind(p->c, lhs_ty) == KIT_CG_TYPE_PTR) {
   1586           /* TOS = **T_chain (where lhs_ty = *T_chain). Load the pointer
   1587            * value so the index applies to the pointee. */
   1588           KitCgTypeId pointee = kit_cg_type_ptr_pointee(p->c, lhs_ty);
   1589           ToyTypeId source_pointee = toy_type_pointee(p, lhs_toy_type);
   1590           /* index is currently on top; stash so we can load the pointer. */
   1591           {
   1592             KitCgLocal idx_slot =
   1593                 kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
   1594             kit_cg_push_local(p->cg, idx_slot);
   1595             kit_cg_swap(p->cg);
   1596             kit_cg_store(p->cg, toy_mem_access(p, p->size_type));
   1597             /* TOS is the chain pointer VALUE (**T); deref to a PLACE and
   1598              * load the inner pointer it addresses. */
   1599             kit_cg_deref(p->cg, 0);
   1600             kit_cg_load(p->cg, toy_mem_access(p, lhs_ty));
   1601             kit_cg_push_local(p->cg, idx_slot);
   1602             kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
   1603           }
   1604           if (kit_cg_type_kind(p->c, pointee) == KIT_CG_TYPE_ARRAY) {
   1605             KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, pointee);
   1606             lhs_ty = elem_ty;
   1607             lhs_toy_type = toy_type_array_elem(p, source_pointee);
   1608             toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
   1609                            kit_cg_type_ptr(p->c, elem_ty, 0));
   1610           } else {
   1611             lhs_ty = pointee;
   1612             lhs_toy_type = source_pointee;
   1613             toy_addr_index(p, kit_cg_type_size(p->c, lhs_ty),
   1614                            kit_cg_type_ptr(p->c, lhs_ty, 0));
   1615           }
   1616         } else if (kit_cg_type_kind(p->c, lhs_ty) == KIT_CG_TYPE_ARRAY) {
   1617           KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, lhs_ty);
   1618           lhs_ty = elem_ty;
   1619           lhs_toy_type = toy_type_array_elem(p, lhs_toy_type);
   1620           toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
   1621                          kit_cg_type_ptr(p->c, elem_ty, 0));
   1622         } else if (toy_type_is_slice(p, lhs_toy_type)) {
   1623           lhs_ty = toy_emit_slice_index_lvalue(p, lhs_ty, lhs_toy_type,
   1624                                                &lhs_toy_type);
   1625           if (lhs_ty == KIT_CG_TYPE_NONE) return 0;
   1626         } else {
   1627           toy_error(p, p->cur.loc, "cannot index non-array/non-pointer");
   1628           return 0;
   1629         }
   1630         continue;
   1631       }
   1632       if (toy_parser_match(p, TOK_DOTSTAR)) {
   1633         lhs_slice_metadata = 0;
   1634         if (kit_cg_type_kind(p->c, lhs_ty) != KIT_CG_TYPE_PTR) {
   1635           toy_error(p, p->cur.loc, "cannot dereference non-pointer");
   1636           return 0;
   1637         }
   1638         /* TOS = `**T` (pointer VALUE); deref to PLACE and load to `*T`. */
   1639         kit_cg_deref(p->cg, 0);
   1640         kit_cg_load(p->cg, toy_mem_access(p, lhs_ty));
   1641         lhs_ty = kit_cg_type_ptr_pointee(p->c, lhs_ty);
   1642         lhs_toy_type = toy_type_pointee(p, lhs_toy_type);
   1643         continue;
   1644       }
   1645       if (toy_parser_match(p, TOK_DOT)) {
   1646         KitCgFieldLayout field;
   1647         uint32_t field_index = 0;
   1648         ToyNamedType* named;
   1649         uint64_t foff = 0;
   1650         if (kit_cg_type_kind(p->c, lhs_ty) == KIT_CG_TYPE_PTR &&
   1651             kit_cg_type_kind(p->c, kit_cg_type_ptr_pointee(p->c, lhs_ty)) ==
   1652                 KIT_CG_TYPE_RECORD) {
   1653           /* `p.field`: deref to PLACE and load the pointer value that
   1654            * addresses the record. */
   1655           kit_cg_deref(p->cg, 0);
   1656           kit_cg_load(p->cg, toy_mem_access(p, lhs_ty));
   1657           lhs_ty = kit_cg_type_ptr_pointee(p->c, lhs_ty);
   1658           lhs_toy_type = toy_type_pointee(p, lhs_toy_type);
   1659         }
   1660         if (kit_cg_type_kind(p->c, lhs_ty) != KIT_CG_TYPE_RECORD) {
   1661           toy_error(p, p->cur.loc, "field assignment on non-record");
   1662           return 0;
   1663         }
   1664         named = toy_find_named_type_by_type(p, lhs_ty);
   1665         if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) {
   1666           if (p->cur.int_value < 0 ||
   1667               p->cur.int_value >=
   1668                   (int64_t)kit_cg_type_record_nfields(p->c, lhs_ty)) {
   1669             toy_error(p, p->cur.loc, "invalid tuple field");
   1670             return 0;
   1671           }
   1672           const KitCgRecordLayout* L;
   1673           field_index = (uint32_t)p->cur.int_value;
   1674           toy_parser_advance(p);
   1675           L = kit_cg_type_record_layout(p->c, lhs_ty);
   1676           if (!L || field_index >= L->nfields) return 0;
   1677           field = L->fields[field_index];
   1678           foff = field.offset;
   1679         } else {
   1680           KitSym field_name;
   1681           if (p->cur.kind != TOK_IDENT) {
   1682             toy_error(p, p->cur.loc, "expected field name");
   1683             return 0;
   1684           }
   1685           field_name = toy_tok_sym(p, p->cur);
   1686           toy_parser_advance(p);
   1687           if (!toy_record_field_index(p, lhs_ty, field_name, &field_index,
   1688                                       &field)) {
   1689             toy_error(p, p->cur.loc, "unknown record field");
   1690             return 0;
   1691           }
   1692           foff = field.offset;
   1693         }
   1694         lhs_slice_metadata = toy_type_is_slice(p, lhs_toy_type) &&
   1695                              (field_index == 0 || field_index == 1);
   1696         lhs_ty = field.type;
   1697         lhs_toy_type = (named && field_index < named->nfields)
   1698                            ? named->fields[field_index].toy_type
   1699                            : TOY_TYPE_NONE;
   1700         toy_addr_offset(p, (int64_t)foff, kit_cg_type_ptr(p->c, lhs_ty, 0));
   1701         continue;
   1702       }
   1703       break;
   1704     }
   1705 
   1706     if (!toy_parser_expect(p, TOK_EQ)) {
   1707       toy_error(p, p->cur.loc, "expected '=' in assignment");
   1708       return 0;
   1709     }
   1710     if (!root_mutable && kit_cg_type_kind(p->c, root_ty) != KIT_CG_TYPE_PTR) {
   1711       toy_error(p, p->cur.loc, "cannot assign to immutable local");
   1712       return 0;
   1713     }
   1714     if (lhs_slice_metadata) {
   1715       toy_error(p, p->cur.loc, "cannot assign to slice metadata");
   1716       return 0;
   1717     }
   1718     /* The address chain leaves a pointer VALUE (`*lhs_ty`) on the stack; turn
   1719      * it into a PLACE before pushing the rhs so store sees [place, value]. */
   1720     kit_cg_deref(p->cg, 0);
   1721     {
   1722       KitCgTypeId expr_ty = toy_parse_expr(p);
   1723       ToyTypeId expr_toy_type = p->last_type;
   1724       if (expr_ty == KIT_CG_TYPE_NONE) return 0;
   1725       if (lhs_toy_type != TOY_TYPE_NONE) {
   1726         if (!toy_type_accepts_type(p, lhs_toy_type, expr_toy_type)) {
   1727           toy_error(p, p->cur.loc, "type mismatch in assignment");
   1728           return 0;
   1729         }
   1730         if (expr_ty != lhs_ty && !toy_emit_checked_cast(p, expr_ty, lhs_ty))
   1731           return 0;
   1732       } else if (!toy_type_can_implicitly_cast(p, expr_ty, lhs_ty)) {
   1733         toy_error(p, p->cur.loc, "type mismatch in assignment");
   1734         return 0;
   1735       } else if (expr_ty != lhs_ty) {
   1736         if (!toy_emit_implicit_cast(p, expr_ty, lhs_ty)) return 0;
   1737       }
   1738       kit_cg_store(p->cg, toy_mem_access(p, lhs_ty));
   1739     }
   1740     if (!toy_parser_expect(p, TOK_SEMI)) {
   1741       toy_error(p, p->cur.loc, "expected ';' after assignment");
   1742       return 0;
   1743     }
   1744     return 1;
   1745   }
   1746 
   1747   if (p->cur.kind == TOK_IDENT && toy_lexer_peek(&p->lex).kind == TOK_EQ) {
   1748     KitSym name = toy_tok_sym(p, p->cur);
   1749     toy_parser_advance(p); /* ident */
   1750     toy_parser_advance(p); /* = */
   1751     KitCgTypeId expr_ty = toy_parse_expr(p);
   1752     ToyTypeId expr_toy_type = p->last_type;
   1753     if (expr_ty == KIT_CG_TYPE_NONE) return 0;
   1754     {
   1755       ToyVar* v = toy_find_var(p, name);
   1756       if (v) {
   1757         if (!v->mutable) {
   1758           toy_error(p, p->cur.loc, "cannot assign to immutable local");
   1759           return 0;
   1760         }
   1761         if (!toy_type_accepts_type(p, v->toy_type, expr_toy_type)) {
   1762           toy_error(p, p->cur.loc, "type mismatch in assignment");
   1763           return 0;
   1764         }
   1765         if (toy_type_is_slice(p, v->toy_type) ||
   1766             kit_cg_type_kind(p->c, v->type) == KIT_CG_TYPE_RECORD) {
   1767           if (!toy_copy_record_lvalue_to_var(p, expr_ty, v, NULL)) return 0;
   1768           if (!toy_parser_expect(p, TOK_SEMI)) {
   1769             toy_error(p, p->cur.loc, "expected ';' after assignment");
   1770             return 0;
   1771           }
   1772           return 1;
   1773         }
   1774         toy_push_var_lvalue(p, v);
   1775         kit_cg_deref(p->cg, 0); /* pointer VALUE -> PLACE for store */
   1776         kit_cg_swap(p->cg);
   1777         if (expr_ty != v->type && !toy_emit_checked_cast(p, expr_ty, v->type))
   1778           return 0;
   1779         kit_cg_store(p->cg, toy_mem_access(p, v->type));
   1780       } else {
   1781         ToyGlobal* g = toy_find_global(p, name);
   1782         if (!g) {
   1783           toy_error(p, p->cur.loc, "undefined variable in assignment");
   1784           return 0;
   1785         }
   1786         if (!g->mutable) {
   1787           toy_error(p, p->cur.loc, "cannot assign to immutable global");
   1788           return 0;
   1789         }
   1790         if (!toy_type_accepts_type(p, g->toy_type, expr_toy_type)) {
   1791           toy_error(p, p->cur.loc, "type mismatch in assignment");
   1792           return 0;
   1793         }
   1794         if (toy_type_is_slice(p, g->toy_type) ||
   1795             kit_cg_type_kind(p->c, g->type) == KIT_CG_TYPE_RECORD) {
   1796           if (!toy_copy_record_lvalue_to_var(p, expr_ty, NULL, g)) return 0;
   1797           if (!toy_parser_expect(p, TOK_SEMI)) {
   1798             toy_error(p, p->cur.loc, "expected ';' after assignment");
   1799             return 0;
   1800           }
   1801           return 1;
   1802         }
   1803         kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
   1804         kit_cg_deref(p->cg, 0); /* pointer VALUE -> PLACE for store */
   1805         kit_cg_swap(p->cg);
   1806         if (expr_ty != g->type && !toy_emit_checked_cast(p, expr_ty, g->type))
   1807           return 0;
   1808         kit_cg_store(p->cg, toy_mem_access(p, g->type));
   1809       }
   1810     }
   1811     if (!toy_parser_expect(p, TOK_SEMI)) {
   1812       toy_error(p, p->cur.loc, "expected ';' after assignment");
   1813       return 0;
   1814     }
   1815     return 1;
   1816   }
   1817 
   1818   return toy_parse_expr_stmt(p);
   1819 }
   1820 
   1821 /* ============================================================
   1822  * Program parsing
   1823  * ============================================================ */
   1824 
   1825 int toy_parse_program(ToyParser* p) {
   1826   while (p->cur.kind != TOK_EOF) {
   1827     int is_extern = 0;
   1828     int is_pub = 0;
   1829     if (toy_parser_match(p, TOK_PUB)) {
   1830       is_pub = 1;
   1831       if (p->cur.kind != TOK_FN && p->cur.kind != TOK_LET &&
   1832           p->cur.kind != TOK_VAR && p->cur.kind != TOK_ALIAS) {
   1833         toy_error(p, p->cur.loc, "expected declaration after pub");
   1834         return 0;
   1835       }
   1836     }
   1837     if (toy_parser_match(p, TOK_EXTERN)) {
   1838       is_extern = 1;
   1839       if (p->cur.kind != TOK_FN && p->cur.kind != TOK_VAR &&
   1840           p->cur.kind != TOK_LET) {
   1841         toy_error(p, p->cur.loc, "expected extern declaration");
   1842         return 0;
   1843       }
   1844     }
   1845     if (p->cur.kind == TOK_FN) {
   1846       int r = toy_parse_fn(p, is_extern, is_pub);
   1847       if (r < 0) return 0;
   1848       if (r == 0) {
   1849         toy_error(p, p->cur.loc, "expected function declaration");
   1850         return 0;
   1851       }
   1852     } else if (p->cur.kind == TOK_LET || p->cur.kind == TOK_VAR) {
   1853       if (!toy_parse_global_var(p, is_extern, is_pub)) return 0;
   1854     } else if (p->cur.kind == TOK_TYPE && !is_extern) {
   1855       if (!toy_parse_type_alias_decl(p)) return 0;
   1856     } else if (p->cur.kind == TOK_RECORD) {
   1857       if (!toy_parse_record_decl(p)) return 0;
   1858     } else if (p->cur.kind == TOK_TUPLE && !is_extern) {
   1859       if (!toy_parse_tuple_decl(p)) return 0;
   1860     } else if (p->cur.kind == TOK_ENUM && !is_extern) {
   1861       if (!toy_parse_enum_decl(p)) return 0;
   1862     } else if (p->cur.kind == TOK_ALIAS && !is_extern) {
   1863       if (!toy_parse_alias_decl(p, is_pub)) return 0;
   1864     } else {
   1865       toy_error(p, p->cur.loc, "expected function or global declaration");
   1866       return 0;
   1867     }
   1868   }
   1869   return 1;
   1870 }