kit

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

expr.c (64055B)


      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 /* ============================================================
     17  * Expression parsing
     18  * ============================================================ */
     19 
     20 KitCgTypeId toy_parse_expr(ToyParser* p);
     21 KitCgMemAccess toy_mem_access(ToyParser* p, KitCgTypeId type);
     22 KitCgTypeId toy_emit_var_lvalue(ToyParser* p, KitSym name);
     23 
     24 static void toy_note_cg_result_type(ToyParser* p, KitCgTypeId ty) {
     25   p->last_type = toy_type_from_cg(p, ty);
     26 }
     27 
     28 static void toy_note_builtin_result_type(ToyParser* p, KitCgTypeId ty) {
     29   KitCgTypeId last_cg = toy_type_resolved_cg(p, p->last_type);
     30   if (last_cg != ty) toy_note_cg_result_type(p, ty);
     31 }
     32 
     33 static int toy_reject_tail_call_operand(ToyParser* p) {
     34   if (!p->tail_call_expr) return 0;
     35   toy_error(p, p->cur.loc, "tail @call must be returned directly");
     36   return 1;
     37 }
     38 
     39 KitCgTypeId toy_push_named_rvalue(ToyParser* p, KitSym name) {
     40   ToyVar* v = toy_find_var(p, name);
     41   if (v) {
     42     if (kit_cg_type_kind(p->c, v->type) == KIT_CG_TYPE_RECORD) {
     43       /* Record: leave the address (pointer VALUE) for the caller's copy. */
     44       toy_push_var_lvalue(p, v);
     45     } else if (v->is_static) {
     46       /* Static scalar: its address is a pointer; deref to a place, then load.
     47        */
     48       kit_cg_push_symbol_addr(p->cg, v->static_sym, 0);
     49       kit_cg_deref(p->cg, 0);
     50       kit_cg_load(p->cg, toy_mem_access(p, v->type));
     51     } else {
     52       /* Local scalar: the local's PLACE loads directly (no address round-trip,
     53        * which keeps small accessors inlinable). */
     54       kit_cg_push_local(p->cg, v->local);
     55       kit_cg_load(p->cg, toy_mem_access(p, v->type));
     56     }
     57     p->last_type = v->toy_type;
     58     return v->type;
     59   }
     60   {
     61     ToyGlobal* g = toy_find_global(p, name);
     62     if (g) {
     63       kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
     64       if (kit_cg_type_kind(p->c, g->type) != KIT_CG_TYPE_RECORD) {
     65         kit_cg_deref(p->cg, 0);
     66         kit_cg_load(p->cg, toy_mem_access(p, g->type));
     67       }
     68       p->last_type = g->toy_type;
     69       return g->type;
     70     }
     71   }
     72   {
     73     ToyFn* fn = toy_find_fn(p, name);
     74     if (fn) {
     75       KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, fn->type, 0);
     76       kit_cg_push_symbol_addr(p->cg, toy_fn_cur_sym(p, fn), 0);
     77       p->last_type = toy_type_register_ptr(p, ptr_ty, fn->toy_type, 0);
     78       return ptr_ty;
     79     }
     80   }
     81   return KIT_CG_TYPE_NONE;
     82 }
     83 
     84 int toy_parse_call_args(ToyParser* p, ToyToken call_tok, KitCgTypeId fn_ty,
     85                         const ToyTypeId* toy_params, size_t toy_nparams,
     86                         size_t* out_nargs) {
     87   uint32_t nparams = kit_cg_type_func_nparams(p->c, fn_ty);
     88   int variadic = kit_cg_type_func_is_variadic(p->c, fn_ty);
     89   size_t nargs = 0;
     90   if (p->cur.kind != TOK_RPAREN) {
     91     for (;;) {
     92       KitCgTypeId arg_ty;
     93       if (nargs < nparams && p->cur.kind == TOK_DOT) {
     94         KitCgFuncParam param =
     95             kit_cg_type_func_param(p->c, fn_ty, (uint32_t)nargs);
     96         ToyNamedType* named = toy_find_named_type_by_type(p, param.type);
     97         KitSym value_name;
     98         size_t i;
     99         int found = 0;
    100         int64_t value = 0;
    101         toy_parser_advance(p); /* . */
    102         if (p->cur.kind != TOK_IDENT) {
    103           toy_error(p, p->cur.loc, "expected enum value");
    104           return 0;
    105         }
    106         value_name = toy_tok_sym(p, p->cur);
    107         toy_parser_advance(p);
    108         if (!named || named->kind != TOY_NAMED_ENUM) {
    109           toy_error(p, p->cur.loc, "dot argument requires enum parameter");
    110           return 0;
    111         }
    112         for (i = 0; i < named->nenum_values; ++i) {
    113           if (named->enum_values[i].name == value_name) {
    114             found = 1;
    115             value = named->enum_values[i].value;
    116             break;
    117           }
    118         }
    119         if (!found) {
    120           toy_error(p, p->cur.loc, "unknown enum value");
    121           return 0;
    122         }
    123         kit_cg_push_int(p->cg, (uint64_t)value, param.type);
    124         arg_ty = param.type;
    125         p->last_type = (toy_params && nargs < toy_nparams)
    126                            ? toy_params[nargs]
    127                            : toy_type_from_cg(p, arg_ty);
    128       } else {
    129         arg_ty = toy_parse_expr(p);
    130       }
    131       if (arg_ty == KIT_CG_TYPE_NONE) return 0;
    132       if (toy_reject_tail_call_operand(p)) return 0;
    133       if (nargs < nparams) {
    134         KitCgFuncParam param =
    135             kit_cg_type_func_param(p->c, fn_ty, (uint32_t)nargs);
    136         ToyTypeId expected = (toy_params && nargs < toy_nparams)
    137                                  ? toy_params[nargs]
    138                                  : TOY_TYPE_NONE;
    139         ToyTypeId actual = p->last_type;
    140         if (expected != TOY_TYPE_NONE &&
    141             !toy_type_accepts_type(p, expected, actual)) {
    142           toy_error(p, call_tok.loc, "function argument type mismatch");
    143           return 0;
    144         }
    145         if (expected == TOY_TYPE_NONE &&
    146             !toy_type_can_implicitly_cast(p, arg_ty, param.type)) {
    147           toy_error(p, call_tok.loc, "function argument type mismatch");
    148           return 0;
    149         }
    150         if (arg_ty != param.type) {
    151           if (expected != TOY_TYPE_NONE) {
    152             if (!toy_emit_checked_cast(p, arg_ty, param.type)) return 0;
    153           } else if (!toy_emit_implicit_cast(p, arg_ty, param.type)) {
    154             return 0;
    155           }
    156         }
    157       } else if (!variadic) {
    158         toy_error(p, call_tok.loc, "too many arguments");
    159         return 0;
    160       }
    161       nargs++;
    162       if (!toy_parser_match(p, TOK_COMMA)) break;
    163     }
    164   }
    165   if (!toy_parser_expect(p, TOK_RPAREN)) {
    166     toy_error(p, p->cur.loc, "expected ')' after arguments");
    167     return 0;
    168   }
    169   if (nargs < nparams) {
    170     toy_error(p, call_tok.loc, "too few arguments");
    171     return 0;
    172   }
    173   *out_nargs = nargs;
    174   return 1;
    175 }
    176 
    177 KitCgMemAccess toy_mem_access(ToyParser* p, KitCgTypeId type) {
    178   KitCgMemAccess access;
    179   (void)p;
    180   memset(&access, 0, sizeof access);
    181   access.type = type;
    182   return access;
    183 }
    184 
    185 static int toy_type_is_promotable_int(ToyParser* p, KitCgTypeId ty) {
    186   return kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_INT;
    187 }
    188 
    189 static KitCgTypeId toy_int_literal_type(ToyParser* p, int64_t value) {
    190   if (value <= INT8_MAX) return toy_builtin_type(p, KIT_CG_BUILTIN_I8);
    191   if (value <= INT16_MAX) return toy_builtin_type(p, KIT_CG_BUILTIN_I16);
    192   if (value <= INT32_MAX) return toy_builtin_type(p, KIT_CG_BUILTIN_I32);
    193   return toy_builtin_type(p, KIT_CG_BUILTIN_I64);
    194 }
    195 
    196 int toy_type_can_implicitly_cast(ToyParser* p, KitCgTypeId src,
    197                                  KitCgTypeId dst) {
    198   KitCgTypeKind sk, dk;
    199   if (src == dst) return 1;
    200   sk = kit_cg_type_kind(p->c, src);
    201   dk = kit_cg_type_kind(p->c, dst);
    202   if (sk == KIT_CG_TYPE_INT && dk == KIT_CG_TYPE_INT)
    203     return toy_type_int_width(p, src) <= toy_type_int_width(p, dst);
    204   if (sk == KIT_CG_TYPE_FLOAT && dk == KIT_CG_TYPE_FLOAT)
    205     return kit_cg_type_float_width(p->c, src) <=
    206            kit_cg_type_float_width(p->c, dst);
    207   return 0;
    208 }
    209 
    210 int toy_emit_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst) {
    211   KitCgTypeKind sk, dk;
    212   if (src == dst) return 1;
    213   sk = kit_cg_type_kind(p->c, src);
    214   dk = kit_cg_type_kind(p->c, dst);
    215 
    216   if (dk == KIT_CG_TYPE_BOOL && toy_type_is_intlike(p, src)) {
    217     kit_cg_push_int(p->cg, 0, src);
    218     kit_cg_int_cmp(p->cg, KIT_CG_INT_NE);
    219     return 1;
    220   }
    221   if (toy_type_is_intlike(p, src) && toy_type_is_intlike(p, dst)) {
    222     uint32_t sw = toy_type_int_width(p, src);
    223     uint32_t dw = toy_type_int_width(p, dst);
    224     if (dw > sw && sk == KIT_CG_TYPE_BOOL)
    225       kit_cg_zext(p->cg, dst);
    226     else if (dw > sw)
    227       kit_cg_sext(p->cg, dst);
    228     else if (dw < sw)
    229       kit_cg_trunc(p->cg, dst);
    230     return 1;
    231   }
    232   if (toy_type_is_intlike(p, src) && dk == KIT_CG_TYPE_FLOAT) {
    233     kit_cg_sint_to_float(p->cg, dst, KIT_CG_ROUND_DEFAULT);
    234     return 1;
    235   }
    236   if (sk == KIT_CG_TYPE_FLOAT && toy_type_is_intlike(p, dst)) {
    237     kit_cg_float_to_sint(p->cg, dst, KIT_CG_ROUND_TOWARD_ZERO);
    238     return 1;
    239   }
    240   if (sk == KIT_CG_TYPE_FLOAT && dk == KIT_CG_TYPE_FLOAT) {
    241     uint32_t sw = kit_cg_type_float_width(p->c, src);
    242     uint32_t dw = kit_cg_type_float_width(p->c, dst);
    243     if (dw > sw)
    244       kit_cg_fpext(p->cg, dst);
    245     else if (dw < sw)
    246       kit_cg_fptrunc(p->cg, dst);
    247     return 1;
    248   }
    249   if (sk == KIT_CG_TYPE_PTR && toy_type_is_intlike(p, dst)) {
    250     kit_cg_ptr_to_int(p->cg, dst);
    251     return 1;
    252   }
    253   if (toy_type_is_intlike(p, src) && dk == KIT_CG_TYPE_PTR) {
    254     kit_cg_int_to_ptr(p->cg, dst);
    255     return 1;
    256   }
    257   if (sk == KIT_CG_TYPE_PTR && dk == KIT_CG_TYPE_PTR) {
    258     kit_cg_bitcast(p->cg, dst);
    259     return 1;
    260   }
    261   toy_error(p, p->cur.loc, "unsupported cast");
    262   return 0;
    263 }
    264 
    265 int toy_emit_implicit_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst) {
    266   if (src == dst) return 1;
    267   if (!toy_type_can_implicitly_cast(p, src, dst)) {
    268     toy_error(p, p->cur.loc, "implicit conversion would lose information");
    269     return 0;
    270   }
    271   return toy_emit_cast(p, src, dst);
    272 }
    273 
    274 int toy_emit_checked_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst) {
    275   KitCgTypeKind sk, dk;
    276   if (src == dst) return 1;
    277   if (toy_type_can_implicitly_cast(p, src, dst))
    278     return toy_emit_cast(p, src, dst);
    279   sk = kit_cg_type_kind(p->c, src);
    280   dk = kit_cg_type_kind(p->c, dst);
    281   if (sk == KIT_CG_TYPE_PTR && dk == KIT_CG_TYPE_PTR) {
    282     kit_cg_bitcast(p->cg, dst);
    283     return 1;
    284   }
    285   toy_error(p, p->cur.loc, "unsupported checked conversion");
    286   return 0;
    287 }
    288 
    289 static int toy_promote_right_operand(ToyParser* p, KitCgTypeId src,
    290                                      KitCgTypeId dst) {
    291   return toy_emit_implicit_cast(p, src, dst);
    292 }
    293 
    294 static int toy_promote_left_operand(ToyParser* p, KitCgTypeId src,
    295                                     KitCgTypeId dst) {
    296   kit_cg_swap(p->cg);
    297   if (!toy_emit_implicit_cast(p, src, dst)) return 0;
    298   kit_cg_swap(p->cg);
    299   return 1;
    300 }
    301 
    302 static int toy_promote_binary_int_operands(ToyParser* p, KitCgTypeId* left,
    303                                            KitCgTypeId* right) {
    304   uint32_t lw, rw;
    305   if (*left == *right) return 1;
    306   if (!toy_type_is_promotable_int(p, *left) ||
    307       !toy_type_is_promotable_int(p, *right))
    308     return 0;
    309   lw = toy_type_int_width(p, *left);
    310   rw = toy_type_int_width(p, *right);
    311   if (lw < rw) {
    312     if (!toy_promote_left_operand(p, *left, *right)) return 0;
    313     *left = *right;
    314   } else if (rw < lw) {
    315     if (!toy_promote_right_operand(p, *right, *left)) return 0;
    316     *right = *left;
    317   } else {
    318     return 0;
    319   }
    320   return 1;
    321 }
    322 
    323 KitCgLocalAttrs toy_slot_attrs(KitSym name) {
    324   KitCgLocalAttrs attrs;
    325   memset(&attrs, 0, sizeof attrs);
    326   attrs.name = name;
    327   return attrs;
    328 }
    329 
    330 KitSym toy_c_linkage_name(ToyParser* p, KitSym source_name) {
    331   KitSym linkage_name = kit_cg_c_linkage_name(p->c, source_name);
    332   if (!linkage_name) {
    333     toy_error(p, p->cur.loc, "failed to create linkage name");
    334   }
    335   return linkage_name;
    336 }
    337 
    338 void toy_inline_asm(ToyParser* p, KitSym tmpl, const KitCgAsmOperand* outputs,
    339                     uint32_t noutputs, const KitCgAsmOperand* inputs,
    340                     uint32_t ninputs, const KitSym* clobbers,
    341                     uint32_t nclobbers, uint32_t flags,
    342                     uint32_t clobber_abi_sets) {
    343   KitCgInlineAsm asm_block;
    344   memset(&asm_block, 0, sizeof asm_block);
    345   asm_block.tmpl = tmpl;
    346   asm_block.outputs = outputs;
    347   asm_block.noutputs = noutputs;
    348   asm_block.inputs = inputs;
    349   asm_block.ninputs = ninputs;
    350   asm_block.clobbers = clobbers;
    351   asm_block.nclobbers = nclobbers;
    352   asm_block.flags = flags;
    353   asm_block.clobber_abi_sets = clobber_abi_sets;
    354   kit_cg_inline_asm(p->cg, asm_block);
    355 }
    356 
    357 int toy_emit_truthy(ToyParser* p, KitCgTypeId type) {
    358   if (type == toy_builtin_type(p, KIT_CG_BUILTIN_BOOL)) return 1;
    359   if (toy_type_is_intlike(p, type)) {
    360     kit_cg_push_int(p->cg, 0, type);
    361     kit_cg_int_cmp(p->cg, KIT_CG_INT_NE);
    362     return 1;
    363   }
    364   toy_error(p, p->cur.loc, "condition must be int or bool");
    365   return 0;
    366 }
    367 
    368 static int toy_note_expr_island(ToyParser* p, ToyExprIsland island) {
    369   uint32_t prior = p->expr_island_mask;
    370   if (prior && prior != (uint32_t)island) {
    371     toy_error(p, p->cur.loc, "mixed precedence islands require parentheses");
    372     return 0;
    373   }
    374   p->expr_island_mask |= (uint32_t)island;
    375   return 1;
    376 }
    377 
    378 int toy_expect_comma(ToyParser* p) {
    379   if (!toy_parser_expect(p, TOK_COMMA)) {
    380     toy_error(p, p->cur.loc, "expected ','");
    381     return 0;
    382   }
    383   return 1;
    384 }
    385 
    386 static int toy_parse_dot_constant_value(ToyParser* p, int64_t* out) {
    387   KitSym name;
    388   if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) {
    389     toy_error(p, p->cur.loc, "expected dot constant");
    390     return 0;
    391   }
    392   name = toy_tok_sym(p, p->cur);
    393   toy_parser_advance(p);
    394   if (toy_sym_is(p, name, "arm64"))
    395     *out = 1;
    396   else if (toy_sym_is(p, name, "x64"))
    397     *out = 2;
    398   else if (toy_sym_is(p, name, "rv64"))
    399     *out = 3;
    400   else if (toy_sym_is(p, name, "x86"))
    401     *out = 4;
    402   else if (toy_sym_is(p, name, "arm32"))
    403     *out = 5;
    404   else if (toy_sym_is(p, name, "rv32"))
    405     *out = 6;
    406   else if (toy_sym_is(p, name, "wasm"))
    407     *out = 7;
    408   else {
    409     toy_error(p, p->cur.loc, "unknown dot constant");
    410     return 0;
    411   }
    412   return 1;
    413 }
    414 
    415 int toy_parse_switch_label_value(ToyParser* p, KitCgTypeId selector_ty,
    416                                  int64_t* out) {
    417   ToyNamedType* named;
    418   KitSym value_name;
    419   size_t i;
    420   if (p->cur.kind != TOK_DOT) return toy_parse_number_arg(p, out);
    421   named = toy_find_named_type_by_type(p, selector_ty);
    422   if (!named || named->kind != TOY_NAMED_ENUM)
    423     return toy_parse_dot_constant_value(p, out);
    424   toy_parser_advance(p); /* . */
    425   if (p->cur.kind != TOK_IDENT) {
    426     toy_error(p, p->cur.loc, "expected enum value");
    427     return 0;
    428   }
    429   value_name = toy_tok_sym(p, p->cur);
    430   toy_parser_advance(p);
    431   for (i = 0; i < named->nenum_values; ++i) {
    432     if (named->enum_values[i].name == value_name) {
    433       *out = named->enum_values[i].value;
    434       return 1;
    435     }
    436   }
    437   toy_error(p, p->cur.loc, "unknown enum value");
    438   return 0;
    439 }
    440 
    441 int toy_parse_symbol_feature_const(ToyParser* p, KitCgSymbolFeature* out) {
    442   static const ToyConstRow rows[] = {
    443       {"weak", KIT_CG_SYMFEAT_WEAK},
    444       {"protected_visibility", KIT_CG_SYMFEAT_PROTECTED_VISIBILITY},
    445       {"dllimport", KIT_CG_SYMFEAT_DLLIMPORT},
    446       {"dllexport", KIT_CG_SYMFEAT_DLLEXPORT},
    447       {"comdat", KIT_CG_SYMFEAT_COMDAT},
    448       {"common", KIT_CG_SYMFEAT_COMMON},
    449       {"merge_sections", KIT_CG_SYMFEAT_MERGE_SECTIONS},
    450       {"constructor_priority", KIT_CG_SYMFEAT_CONSTRUCTOR_PRIORITY},
    451       {"tls_local_exec", KIT_CG_SYMFEAT_TLS_LOCAL_EXEC},
    452       {"tls_initial_exec", KIT_CG_SYMFEAT_TLS_INITIAL_EXEC},
    453       {"tls_local_dynamic", KIT_CG_SYMFEAT_TLS_LOCAL_DYNAMIC},
    454       {"tls_general_dynamic", KIT_CG_SYMFEAT_TLS_GENERAL_DYNAMIC},
    455   };
    456   uint64_t v;
    457   if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1,
    458                            "symbol feature", "symbol feature", &v))
    459     return 0;
    460   *out = (KitCgSymbolFeature)v;
    461   return 1;
    462 }
    463 
    464 int toy_parse_backend_feature_const(ToyParser* p, uint64_t* out) {
    465   static const ToyConstRow rows[] = {
    466       {"unaligned_memory", KIT_CG_BACKEND_UNALIGNED_MEMORY},
    467       {"strict_alignment", KIT_CG_BACKEND_STRICT_ALIGNMENT},
    468       {"red_zone", KIT_CG_BACKEND_RED_ZONE},
    469       {"simd", KIT_CG_BACKEND_SIMD},
    470       {"pointer_auth", KIT_CG_BACKEND_POINTER_AUTH},
    471       {"branch_protection", KIT_CG_BACKEND_BRANCH_PROTECTION},
    472   };
    473   return toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1,
    474                              "backend feature", "backend feature", out);
    475 }
    476 
    477 int toy_parse_intrinsic_const(ToyParser* p, KitCgIntrinsic* out) {
    478   static const ToyConstRow rows[] = {
    479       {"cpu_nop", KIT_CG_INTRIN_CPU_NOP},
    480       {"cpu_yield", KIT_CG_INTRIN_CPU_YIELD},
    481       {"wfi", KIT_CG_INTRIN_WFI},
    482       {"wfe", KIT_CG_INTRIN_WFE},
    483       {"sev", KIT_CG_INTRIN_SEV},
    484       {"isb", KIT_CG_INTRIN_ISB},
    485       {"dmb", KIT_CG_INTRIN_DMB},
    486       {"dsb", KIT_CG_INTRIN_DSB},
    487       {"irq_save", KIT_CG_INTRIN_IRQ_SAVE},
    488       {"irq_restore", KIT_CG_INTRIN_IRQ_RESTORE},
    489       {"irq_enable", KIT_CG_INTRIN_IRQ_ENABLE},
    490       {"irq_disable", KIT_CG_INTRIN_IRQ_DISABLE},
    491       {"syscall", KIT_CG_INTRIN_SYSCALL},
    492       {"coro_switch", KIT_CG_INTRIN_CORO_SWITCH},
    493   };
    494   uint64_t v;
    495   if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1,
    496                            "intrinsic name", "intrinsic", &v))
    497     return 0;
    498   *out = (KitCgIntrinsic)v;
    499   return 1;
    500 }
    501 
    502 int toy_parse_rounding_const(ToyParser* p, KitCgRounding* out) {
    503   static const ToyConstRow rows[] = {
    504       {"default", KIT_CG_ROUND_DEFAULT},
    505       {"nearest_even", KIT_CG_ROUND_NEAREST_EVEN},
    506       {"toward_zero", KIT_CG_ROUND_TOWARD_ZERO},
    507       {"down", KIT_CG_ROUND_DOWN},
    508       {"up", KIT_CG_ROUND_UP},
    509   };
    510   uint64_t v;
    511   if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 0, NULL,
    512                            "rounding mode", &v))
    513     return 0;
    514   *out = (KitCgRounding)v;
    515   return 1;
    516 }
    517 
    518 int toy_validate_bit_range(ToyParser* p, KitCgTypeId ty, int64_t lo,
    519                            int64_t width, int allow_full_width) {
    520   uint32_t type_width;
    521   if (!toy_type_is_intlike(p, ty) || lo < 0 || width <= 0) return 0;
    522   type_width = toy_type_int_width(p, ty);
    523   if (width > (int64_t)type_width) return 0;
    524   if (!allow_full_width && width >= 64) return 0;
    525   if (lo > (int64_t)type_width || width > (int64_t)type_width - lo) return 0;
    526   return 1;
    527 }
    528 
    529 int toy_target_code(ToyParser* p) {
    530   switch (p->target.arch) {
    531     case KIT_ARCH_ARM_64:
    532       return 1;
    533     case KIT_ARCH_X86_64:
    534       return 2;
    535     case KIT_ARCH_RV64:
    536       return 3;
    537     case KIT_ARCH_RV32:
    538       return 6;
    539     case KIT_ARCH_WASM:
    540       return 7;
    541     default:
    542       return 0;
    543   }
    544 }
    545 
    546 int toy_parse_arch_string(ToyParser* p, KitSym* out, size_t* len_out) {
    547   if (p->cur.kind == TOK_STRING) return toy_parse_string_sym(p, out, len_out);
    548 
    549   toy_error(p, p->cur.loc, "expected asm template");
    550   return 0;
    551 }
    552 
    553 static int toy_emit_var_addr(ToyParser* p, KitSym name) {
    554   ToyVar* v = toy_find_var(p, name);
    555   if (v) {
    556     toy_push_var_addr(p, v);
    557     return 1;
    558   }
    559   {
    560     ToyGlobal* g = toy_find_global(p, name);
    561     if (g) {
    562       kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
    563       return 1;
    564     }
    565   }
    566   return 0;
    567 }
    568 
    569 KitCgTypeId toy_emit_var_lvalue(ToyParser* p, KitSym name) {
    570   ToyVar* v = toy_find_var(p, name);
    571   if (v) {
    572     toy_push_var_lvalue(p, v);
    573     return v->type;
    574   }
    575   {
    576     ToyGlobal* g = toy_find_global(p, name);
    577     if (g) {
    578       kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
    579       return g->type;
    580     }
    581   }
    582   return KIT_CG_TYPE_NONE;
    583 }
    584 
    585 static KitCgTypeId toy_type_id_cg_or_none(ToyParser* p, ToyTypeId id) {
    586   KitCgTypeId ty = toy_type_resolved_cg(p, id);
    587   return ty != KIT_CG_TYPE_NONE ? ty : toy_type_cg(p, id);
    588 }
    589 
    590 static void toy_store_tos_to_local(ToyParser* p, KitCgLocal local,
    591                                    KitCgTypeId ty) {
    592   kit_cg_push_local(p->cg, local);
    593   kit_cg_swap(p->cg);
    594   kit_cg_store(p->cg, toy_mem_access(p, ty));
    595 }
    596 
    597 /* Consumes [slice_base, idx] where slice_base is a pointer to the slice
    598  * record. Produces [elem_ptr] -- a pointer-rvalue to the element. */
    599 KitCgTypeId toy_emit_slice_index_lvalue(ToyParser* p, KitCgTypeId slice_ty,
    600                                         ToyTypeId slice_toy_type,
    601                                         ToyTypeId* elem_toy_out) {
    602   ToyTypeId elem_toy = toy_type_slice_elem(p, slice_toy_type);
    603   KitCgTypeId elem_ty = toy_type_id_cg_or_none(p, elem_toy);
    604   KitCgField ptr_field;
    605   KitCgLocal idx_slot;
    606   uint64_t ptr_field_off = 0;
    607   if (elem_ty == KIT_CG_TYPE_NONE ||
    608       kit_cg_type_kind(p->c, slice_ty) != KIT_CG_TYPE_RECORD ||
    609       kit_cg_type_record_field(p->c, slice_ty, 0, &ptr_field, &ptr_field_off) !=
    610           0) {
    611     toy_error(p, p->cur.loc, "cannot index non-array/non-pointer");
    612     return KIT_CG_TYPE_NONE;
    613   }
    614   /* Stash the index, then load the slice's ptr field, then re-push idx
    615    * and compute element pointer. */
    616   idx_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
    617   toy_store_tos_to_local(p, idx_slot, p->size_type);
    618   kit_cg_deref(p->cg, (int64_t)ptr_field_off);
    619   kit_cg_load(p->cg, toy_mem_access(p, ptr_field.type));
    620   kit_cg_push_local(p->cg, idx_slot);
    621   kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
    622   toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
    623                  kit_cg_type_ptr(p->c, elem_ty, 0));
    624   if (elem_toy_out) *elem_toy_out = elem_toy;
    625   return elem_ty;
    626 }
    627 
    628 KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty,
    629                                  ToyTypeId base_toy_type, KitCgTypeId start_ty,
    630                                  KitCgTypeId end_ty, ToyTypeId* slice_toy_out) {
    631   ToyTypeId elem_toy = TOY_TYPE_NONE;
    632   KitCgTypeId elem_ty = KIT_CG_TYPE_NONE;
    633   ToyTypeId slice_toy;
    634   KitCgTypeId slice_ty;
    635   KitCgField ptr_field;
    636   KitCgLocal start_slot;
    637   KitCgLocal end_slot;
    638   KitCgLocal result_slot;
    639 
    640   if (start_ty != p->size_type || end_ty != p->size_type) {
    641     toy_error(p, p->cur.loc, "slice bounds must be isize");
    642     return KIT_CG_TYPE_NONE;
    643   }
    644 
    645   if (kit_cg_type_kind(p->c, base_ty) == KIT_CG_TYPE_ARRAY) {
    646     elem_ty = kit_cg_type_array_elem(p->c, base_ty);
    647     elem_toy = toy_type_array_elem(p, base_toy_type);
    648   } else if (toy_type_is_slice(p, base_toy_type)) {
    649     elem_toy = toy_type_slice_elem(p, base_toy_type);
    650     elem_ty = toy_type_id_cg_or_none(p, elem_toy);
    651   }
    652   if (elem_toy == TOY_TYPE_NONE && elem_ty != KIT_CG_TYPE_NONE)
    653     elem_toy = toy_type_from_cg(p, elem_ty);
    654   if (elem_ty == KIT_CG_TYPE_NONE || elem_toy == TOY_TYPE_NONE) {
    655     toy_error(p, p->cur.loc, "cannot slice non-array/non-slice");
    656     return KIT_CG_TYPE_NONE;
    657   }
    658 
    659   slice_toy = toy_type_register_slice(p, elem_ty, elem_toy);
    660   slice_ty = toy_type_cg(p, slice_toy);
    661   {
    662     uint64_t ptr_off = 0;
    663     uint64_t len_off = 0;
    664     KitCgField len_field;
    665     (void)len_field;
    666     if (slice_ty == KIT_CG_TYPE_NONE ||
    667         kit_cg_type_record_field(p->c, slice_ty, 0, &ptr_field, &ptr_off) !=
    668             0 ||
    669         kit_cg_type_record_field(p->c, slice_ty, 1, &len_field, &len_off) !=
    670             0) {
    671       toy_error(p, p->cur.loc, "failed to create slice type");
    672       return KIT_CG_TYPE_NONE;
    673     }
    674 
    675     end_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
    676     toy_store_tos_to_local(p, end_slot, p->size_type);
    677     start_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
    678     toy_store_tos_to_local(p, start_slot, p->size_type);
    679 
    680     result_slot = kit_cg_local(p->cg, slice_ty, toy_slot_attrs(0));
    681     /* TOS = [base] (slice lvalue/pointer or array lvalue/pointer). */
    682     if (toy_type_is_slice(p, base_toy_type)) {
    683       /* Replace slice base with its data pointer (a pointer-rvalue). */
    684       kit_cg_deref(p->cg, (int64_t)ptr_off);
    685       kit_cg_load(p->cg, toy_mem_access(p, ptr_field.type));
    686     } else {
    687       /* Array base: TOS is a pointer-rvalue (callers always project
    688        * to a pointer for array/slice bases now). Bitcast to *elem. */
    689       kit_cg_bitcast(p->cg, kit_cg_type_ptr(p->c, elem_ty, 0));
    690     }
    691     /* Compute (base + start * sizeof(elem)) as a pointer to the slice's
    692      * first element. */
    693     kit_cg_push_local(p->cg, start_slot);
    694     kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
    695     toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
    696                    kit_cg_type_ptr(p->c, elem_ty, 0));
    697     /* Store the data pointer into result_slot.ptr. */
    698     kit_cg_push_local(p->cg, result_slot);
    699     kit_cg_addr(p->cg);
    700     kit_cg_deref(p->cg, (int64_t)ptr_off);
    701     kit_cg_swap(p->cg);
    702     kit_cg_store(p->cg, toy_mem_access(p, ptr_field.type));
    703 
    704     /* len = end - start; store into result_slot.len. */
    705     kit_cg_push_local(p->cg, result_slot);
    706     kit_cg_addr(p->cg);
    707     kit_cg_deref(p->cg, (int64_t)len_off);
    708     kit_cg_push_local(p->cg, end_slot);
    709     kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
    710     kit_cg_push_local(p->cg, start_slot);
    711     kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
    712     kit_cg_int_binop(p->cg, KIT_CG_INT_SUB, 0);
    713     kit_cg_store(p->cg, toy_mem_access(p, p->size_type));
    714   }
    715 
    716   /* Hand back the slice record as a pointer VALUE (its address), matching the
    717    * "records/slices are pointer VALUEs" shape the downstream record-copy and
    718    * slice-index paths consume. */
    719   kit_cg_push_local_addr(p->cg, result_slot);
    720   if (slice_toy_out) *slice_toy_out = slice_toy;
    721   p->last_type = slice_toy;
    722   return slice_ty;
    723 }
    724 
    725 int toy_parse_va_list_addr_arg(ToyParser* p) {
    726   KitSym name;
    727   ToyVar* v;
    728   if (p->cur.kind != TOK_IDENT) {
    729     toy_error(p, p->cur.loc, "expected va_list identifier");
    730     return 0;
    731   }
    732   name = toy_tok_sym(p, p->cur);
    733   v = toy_find_var(p, name);
    734   if (!v || v->type != p->va_list_type) {
    735     toy_error(p, p->cur.loc, "expected va_list local");
    736     return 0;
    737   }
    738   toy_parser_advance(p);
    739   return toy_emit_var_addr(p, name);
    740 }
    741 
    742 static KitCgTypeId toy_parse_expr_primary(ToyParser* p) {
    743   toy_set_loc(p);
    744   if (p->cur.kind == TOK_AT) {
    745     KitSym name;
    746     ToyToken at_tok = p->cur;
    747     toy_parser_advance(p);
    748     if (p->cur.kind != TOK_IDENT) {
    749       toy_error(p, p->cur.loc, "expected builtin name after '@'");
    750       return KIT_CG_TYPE_NONE;
    751     }
    752     name = toy_tok_sym(p, p->cur);
    753     toy_parser_advance(p);
    754 
    755     if (p->cur.kind == TOK_LT) {
    756       int recognized = 0;
    757       KitCgTypeId builtin_ty = toy_parse_generic_builtin(p, name, &recognized);
    758       if (recognized) {
    759         if (builtin_ty != KIT_CG_TYPE_NONE)
    760           toy_note_builtin_result_type(p, builtin_ty);
    761         return builtin_ty;
    762       }
    763     }
    764 
    765     if (p->cur.kind == TOK_LPAREN) {
    766       int recognized = 0;
    767       KitCgTypeId builtin_ty = toy_parse_builtin_call(p, name, &recognized);
    768       if (recognized) {
    769         if (builtin_ty != KIT_CG_TYPE_NONE)
    770           toy_note_builtin_result_type(p, builtin_ty);
    771         return builtin_ty;
    772       }
    773     }
    774 
    775     toy_error(p, at_tok.loc, "unknown builtin");
    776     return KIT_CG_TYPE_NONE;
    777   }
    778 
    779   if (p->cur.kind == TOK_NUMBER) {
    780     if (p->cur.is_float) {
    781       kit_cg_push_float(p->cg, p->cur.float_value,
    782                         toy_builtin_type(p, KIT_CG_BUILTIN_F64));
    783       toy_parser_advance(p);
    784       p->last_type =
    785           toy_type_from_cg(p, toy_builtin_type(p, KIT_CG_BUILTIN_F64));
    786       return toy_builtin_type(p, KIT_CG_BUILTIN_F64);
    787     }
    788     {
    789       KitCgTypeId lit_ty = toy_int_literal_type(p, p->cur.int_value);
    790       kit_cg_push_int(p->cg, (uint64_t)p->cur.int_value, lit_ty);
    791       toy_parser_advance(p);
    792       p->last_type = toy_type_from_cg(p, lit_ty);
    793       return lit_ty;
    794     }
    795   }
    796 
    797   if (p->cur.kind == TOK_IDENT) {
    798     KitSym name = toy_tok_sym(p, p->cur);
    799     ToyToken ident_tok = p->cur;
    800     toy_parser_advance(p);
    801 
    802     if (toy_sym_is(p, name, "true") || toy_sym_is(p, name, "false")) {
    803       kit_cg_push_int(p->cg, toy_sym_is(p, name, "true") ? 1u : 0u,
    804                       toy_builtin_type(p, KIT_CG_BUILTIN_BOOL));
    805       p->last_type =
    806           toy_type_from_cg(p, toy_builtin_type(p, KIT_CG_BUILTIN_BOOL));
    807       return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL);
    808     }
    809 
    810     if (toy_sym_is(p, name, "NULL")) {
    811       kit_cg_push_int(p->cg, 0, p->int_type);
    812       p->last_type = TOY_TYPE_NONE;
    813       return p->int_type;
    814     }
    815 
    816     if (p->cur.kind == TOK_LT) {
    817       int recognized = 0;
    818       KitCgTypeId builtin_ty = toy_parse_generic_builtin(p, name, &recognized);
    819       if (recognized) return builtin_ty;
    820     }
    821 
    822     if (p->cur.kind == TOK_LPAREN) {
    823       /* Function call */
    824       int recognized = 0;
    825       KitCgTypeId builtin_ty = toy_parse_builtin_call(p, name, &recognized);
    826       if (recognized) return builtin_ty;
    827 
    828       ToyFn* fn = toy_find_fn(p, name);
    829       toy_parser_advance(p); /* ( */
    830 
    831       size_t nargs = 0;
    832       if (fn) {
    833         if (!toy_parse_call_args(p, ident_tok, fn->type, fn->toy_params,
    834                                  fn->nparams, &nargs))
    835           return KIT_CG_TYPE_NONE;
    836         {
    837           KitCgCallAttrs attrs;
    838           memset(&attrs, 0, sizeof attrs);
    839           attrs.inline_policy = fn->func_attrs.inline_policy;
    840           kit_cg_call_symbol(p->cg, toy_fn_cur_sym(p, fn), (uint32_t)nargs,
    841                              attrs);
    842         }
    843         /* An aggregate return is a PLACE; project it to a pointer VALUE so it
    844          * matches the records-are-pointers invariant used downstream. */
    845         if (kit_cg_type_kind(p->c, fn->ret) == KIT_CG_TYPE_RECORD)
    846           kit_cg_addr(p->cg);
    847         p->last_type = fn->toy_ret;
    848         return fn->ret;
    849       }
    850 
    851       KitCgTypeId callee_ty = toy_push_named_rvalue(p, name);
    852       ToyTypeId callee_toy_type = p->last_type;
    853       const ToyType* source_fn_type = NULL;
    854       if (callee_ty == KIT_CG_TYPE_NONE) {
    855         toy_error(p, ident_tok.loc, "undefined function '%.*s'",
    856                   (int)ident_tok.text_len, (const char*)ident_tok.text);
    857         return KIT_CG_TYPE_NONE;
    858       }
    859       KitCgTypeId fn_ty = toy_ptr_pointee_func_type(p, callee_ty);
    860       if (fn_ty == KIT_CG_TYPE_NONE) {
    861         toy_error(p, ident_tok.loc, "callee is not a function pointer");
    862         return KIT_CG_TYPE_NONE;
    863       }
    864       source_fn_type = toy_type_get(p, toy_type_pointee(p, callee_toy_type));
    865       if (source_fn_type && source_fn_type->kind != TOY_TYPE_FUNC)
    866         source_fn_type = NULL;
    867       if (!toy_parse_call_args(p, ident_tok, fn_ty,
    868                                source_fn_type ? source_fn_type->params : NULL,
    869                                source_fn_type ? source_fn_type->nparams : 0,
    870                                &nargs))
    871         return KIT_CG_TYPE_NONE;
    872       kit_cg_call_default(p->cg, (uint32_t)nargs, fn_ty);
    873       if (kit_cg_type_kind(p->c, toy_cg_func_ret(p, fn_ty)) ==
    874           KIT_CG_TYPE_RECORD)
    875         kit_cg_addr(p->cg);
    876       p->last_type = source_fn_type
    877                          ? source_fn_type->ret
    878                          : toy_type_from_cg(p, toy_cg_func_ret(p, fn_ty));
    879       return toy_cg_func_ret(p, fn_ty);
    880     }
    881 
    882     if (p->cur.kind == TOK_LBRACKET || p->cur.kind == TOK_DOT) {
    883       ToyVar* v = toy_find_var(p, name);
    884       if (v && (kit_cg_type_kind(p->c, v->type) == KIT_CG_TYPE_ARRAY ||
    885                 kit_cg_type_kind(p->c, v->type) == KIT_CG_TYPE_RECORD)) {
    886         if (kit_cg_type_kind(p->c, v->type) == KIT_CG_TYPE_ARRAY) {
    887           /* Array slicing/indexing wants a pointer root for address math. */
    888           toy_push_var_addr(p, v);
    889         } else {
    890           toy_push_var_lvalue(p, v);
    891         }
    892         p->last_type = v->toy_type;
    893         return v->type;
    894       }
    895       {
    896         ToyGlobal* g = toy_find_global(p, name);
    897         if (g && (kit_cg_type_kind(p->c, g->type) == KIT_CG_TYPE_ARRAY ||
    898                   kit_cg_type_kind(p->c, g->type) == KIT_CG_TYPE_RECORD)) {
    899           kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
    900           p->last_type = g->toy_type;
    901           return g->type;
    902         }
    903       }
    904     }
    905 
    906     {
    907       ToyVar* v = toy_find_var(p, name);
    908       if (v && toy_type_is_slice(p, v->toy_type)) {
    909         toy_push_var_lvalue(p, v);
    910         p->last_type = v->toy_type;
    911         return v->type;
    912       }
    913       {
    914         ToyGlobal* g = toy_find_global(p, name);
    915         if (g && toy_type_is_slice(p, g->toy_type)) {
    916           kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
    917           p->last_type = g->toy_type;
    918           return g->type;
    919         }
    920       }
    921     }
    922 
    923     {
    924       KitCgTypeId ty = toy_push_named_rvalue(p, name);
    925       if (ty != KIT_CG_TYPE_NONE) return ty;
    926     }
    927     toy_error(p, ident_tok.loc, "undefined variable '%.*s'",
    928               (int)ident_tok.text_len, (const char*)ident_tok.text);
    929     return KIT_CG_TYPE_NONE;
    930   }
    931 
    932   if (p->cur.kind == TOK_LPAREN) {
    933     toy_parser_advance(p);
    934     KitCgTypeId ty = toy_parse_expr(p);
    935     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    936     if (!toy_parser_expect(p, TOK_RPAREN)) {
    937       toy_error(p, p->cur.loc, "expected ')'");
    938       return KIT_CG_TYPE_NONE;
    939     }
    940     return ty;
    941   }
    942 
    943   toy_error(p, p->cur.loc, "expected expression");
    944   return KIT_CG_TYPE_NONE;
    945 }
    946 
    947 static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) {
    948   KitCgTypeId ty = toy_parse_expr_primary(p);
    949   ToyTypeId toy_ty = p->last_type;
    950   if (p->tail_call_expr) return ty;
    951   while (ty != KIT_CG_TYPE_NONE) {
    952     if (toy_parser_match(p, TOK_DOTSTAR)) {
    953       if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_PTR) {
    954         toy_error(p, p->cur.loc, "cannot dereference non-pointer");
    955         return KIT_CG_TYPE_NONE;
    956       }
    957       ty = kit_cg_type_ptr_pointee(p->c, ty);
    958       toy_ty = toy_type_pointee(p, toy_ty);
    959       /* TOS is a pointer VALUE; deref it to a PLACE, then load. */
    960       kit_cg_deref(p->cg, 0);
    961       kit_cg_load(p->cg, toy_mem_access(p, ty));
    962       p->last_type = toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty);
    963       continue;
    964     }
    965 
    966     if (toy_parser_match(p, TOK_LBRACKET)) {
    967       KitCgTypeId idx_ty = toy_parse_expr(p);
    968       if (idx_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    969       if (!toy_type_can_implicitly_cast(p, idx_ty, p->size_type)) {
    970         toy_error(p, p->cur.loc, "index must be isize");
    971         return KIT_CG_TYPE_NONE;
    972       }
    973       if (!toy_emit_implicit_cast(p, idx_ty, p->size_type))
    974         return KIT_CG_TYPE_NONE;
    975       idx_ty = p->size_type;
    976       if (toy_parser_match(p, TOK_COLON)) {
    977         KitCgTypeId end_ty = toy_parse_expr(p);
    978         ToyTypeId slice_toy_type = TOY_TYPE_NONE;
    979         if (end_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    980         if (!toy_type_can_implicitly_cast(p, end_ty, p->size_type)) {
    981           toy_error(p, p->cur.loc, "slice bounds must be isize");
    982           return KIT_CG_TYPE_NONE;
    983         }
    984         if (!toy_emit_implicit_cast(p, end_ty, p->size_type))
    985           return KIT_CG_TYPE_NONE;
    986         end_ty = p->size_type;
    987         if (!toy_parser_expect(p, TOK_RBRACKET)) {
    988           toy_error(p, p->cur.loc, "expected ']' after slice");
    989           return KIT_CG_TYPE_NONE;
    990         }
    991         ty = toy_emit_slice_value(p, ty, toy_ty, idx_ty, end_ty,
    992                                   &slice_toy_type);
    993         if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    994         toy_ty = slice_toy_type;
    995         p->last_type = toy_ty;
    996         continue;
    997       }
    998       if (!toy_parser_expect(p, TOK_RBRACKET)) {
    999         toy_error(p, p->cur.loc, "expected ']' after index");
   1000         return KIT_CG_TYPE_NONE;
   1001       }
   1002       if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR) {
   1003         KitCgTypeId pointee = kit_cg_type_ptr_pointee(p->c, ty);
   1004         ToyTypeId source_pointee = toy_type_pointee(p, toy_ty);
   1005         if (kit_cg_type_kind(p->c, pointee) == KIT_CG_TYPE_ARRAY) {
   1006           /* TOS = [ptr-to-array, idx]. Cast pointer to *elem so the load
   1007            * can apply the array's elem-scale on the next memop. */
   1008           KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, pointee);
   1009           kit_cg_swap(p->cg);
   1010           kit_cg_bitcast(p->cg, kit_cg_type_ptr(p->c, elem_ty, 0));
   1011           kit_cg_swap(p->cg);
   1012           ty = elem_ty;
   1013           toy_ty = toy_type_array_elem(p, source_pointee);
   1014         } else {
   1015           ty = pointee;
   1016           toy_ty = source_pointee;
   1017         }
   1018       } else if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ARRAY) {
   1019         /* TOS = [ptr-to-array, idx]. Decay the base to *elem so kit_cg_elem
   1020          * scales by the element size, not the whole array. */
   1021         KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, ty);
   1022         kit_cg_swap(p->cg);
   1023         kit_cg_bitcast(p->cg, kit_cg_type_ptr(p->c, elem_ty, 0));
   1024         kit_cg_swap(p->cg);
   1025         ty = elem_ty;
   1026         toy_ty = toy_type_array_elem(p, toy_ty);
   1027       } else if (toy_type_is_slice(p, toy_ty)) {
   1028         ty = toy_emit_slice_index_lvalue(p, ty, toy_ty, &toy_ty);
   1029         if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1030         /* toy_emit_slice_index_lvalue returns an element pointer VALUE. */
   1031         kit_cg_deref(p->cg, 0);
   1032         kit_cg_load(p->cg, toy_mem_access(p, ty));
   1033         p->last_type =
   1034             toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty);
   1035         continue;
   1036       } else {
   1037         toy_error(p, p->cur.loc, "cannot index non-array/non-pointer");
   1038         return KIT_CG_TYPE_NONE;
   1039       }
   1040       /* TOS = [base, idx]; elem yields the element PLACE, then load. */
   1041       kit_cg_elem(p->cg, 0);
   1042       kit_cg_load(p->cg, toy_mem_access(p, ty));
   1043       p->last_type = toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty);
   1044       continue;
   1045     }
   1046 
   1047     if (toy_parser_match(p, TOK_DOT)) {
   1048       KitSym field_name;
   1049       uint32_t i, nfields;
   1050       int found = 0;
   1051       KitCgField found_field;
   1052       uint64_t found_off = 0;
   1053       ToyNamedType* named;
   1054       ToyTypeId field_toy_type = TOY_TYPE_NONE;
   1055       if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR &&
   1056           kit_cg_type_kind(p->c, kit_cg_type_ptr_pointee(p->c, ty)) ==
   1057               KIT_CG_TYPE_RECORD) {
   1058         /* TOS is a pointer to the record; the memop accepts it directly,
   1059          * so no intermediate op is needed -- we just update `ty`. */
   1060         ty = kit_cg_type_ptr_pointee(p->c, ty);
   1061         toy_ty = toy_type_pointee(p, toy_ty);
   1062       }
   1063       named = toy_find_named_type_by_type(p, ty);
   1064       if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) {
   1065         uint32_t field_index;
   1066         if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_RECORD ||
   1067             p->cur.int_value < 0 ||
   1068             p->cur.int_value >= (int64_t)kit_cg_type_record_nfields(p->c, ty)) {
   1069           toy_error(p, p->cur.loc, "invalid tuple field");
   1070           return KIT_CG_TYPE_NONE;
   1071         }
   1072         field_index = (uint32_t)p->cur.int_value;
   1073         toy_parser_advance(p);
   1074         if (kit_cg_type_record_field(p->c, ty, field_index, &found_field,
   1075                                      &found_off) != 0) {
   1076           return KIT_CG_TYPE_NONE;
   1077         }
   1078         if (named && field_index < named->nfields)
   1079           field_toy_type = named->fields[field_index].toy_type;
   1080         ty = found_field.type;
   1081         kit_cg_deref(p->cg, (int64_t)found_off);
   1082         kit_cg_load(p->cg, toy_mem_access(p, ty));
   1083         if (field_toy_type != TOY_TYPE_NONE) {
   1084           KitCgTypeId resolved = toy_type_resolved_cg(p, field_toy_type);
   1085           p->last_type = field_toy_type;
   1086           toy_ty = field_toy_type;
   1087           if (resolved != KIT_CG_TYPE_NONE && resolved != ty) {
   1088             if (!toy_emit_checked_cast(p, ty, resolved))
   1089               return KIT_CG_TYPE_NONE;
   1090             ty = resolved;
   1091           }
   1092         } else {
   1093           p->last_type = toy_type_from_cg(p, ty);
   1094           toy_ty = p->last_type;
   1095         }
   1096         continue;
   1097       }
   1098       if (p->cur.kind != TOK_IDENT) {
   1099         toy_error(p, p->cur.loc, "expected field name");
   1100         return KIT_CG_TYPE_NONE;
   1101       }
   1102       field_name = toy_tok_sym(p, p->cur);
   1103       toy_parser_advance(p);
   1104       if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_RECORD) {
   1105         toy_error(p, p->cur.loc, "field access on non-record");
   1106         return KIT_CG_TYPE_NONE;
   1107       }
   1108       nfields = kit_cg_type_record_nfields(p->c, ty);
   1109       memset(&found_field, 0, sizeof found_field);
   1110       for (i = 0; i < nfields; ++i) {
   1111         KitCgField field;
   1112         uint64_t off = 0;
   1113         if (kit_cg_type_record_field(p->c, ty, i, &field, &off) == 0 &&
   1114             field.name == field_name) {
   1115           found = 1;
   1116           found_field = field;
   1117           found_off = off;
   1118           if (named && i < named->nfields)
   1119             field_toy_type = named->fields[i].toy_type;
   1120           break;
   1121         }
   1122       }
   1123       if (!found) {
   1124         toy_error(p, p->cur.loc, "unknown record field");
   1125         return KIT_CG_TYPE_NONE;
   1126       }
   1127       ty = found_field.type;
   1128       kit_cg_deref(p->cg, (int64_t)found_off);
   1129       kit_cg_load(p->cg, toy_mem_access(p, ty));
   1130       if (field_toy_type != TOY_TYPE_NONE) {
   1131         KitCgTypeId resolved = toy_type_resolved_cg(p, field_toy_type);
   1132         p->last_type = field_toy_type;
   1133         toy_ty = field_toy_type;
   1134         if (resolved != KIT_CG_TYPE_NONE && resolved != ty) {
   1135           if (!toy_emit_checked_cast(p, ty, resolved))
   1136             return KIT_CG_TYPE_NONE;
   1137           ty = resolved;
   1138         }
   1139       } else {
   1140         p->last_type = toy_type_from_cg(p, ty);
   1141         toy_ty = p->last_type;
   1142       }
   1143       continue;
   1144     }
   1145 
   1146     break;
   1147   }
   1148   return ty;
   1149 }
   1150 
   1151 static KitCgTypeId toy_parse_expr_unary(ToyParser* p) {
   1152   toy_set_loc(p);
   1153   if (toy_parser_match(p, TOK_MINUS)) {
   1154     KitCgTypeId ty = toy_parse_expr_unary(p);
   1155     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1156     if (p->tail_call_expr) {
   1157       toy_error(p, p->cur.loc, "tail @call must be returned directly");
   1158       return KIT_CG_TYPE_NONE;
   1159     }
   1160     if (toy_type_is_float(p, ty)) {
   1161       kit_cg_fp_unop(p->cg, KIT_CG_FP_NEG, 0);
   1162       return ty;
   1163     }
   1164     if (!toy_type_is_intlike(p, ty)) {
   1165       toy_error(p, p->cur.loc, "invalid operand for unary '-'");
   1166       return KIT_CG_TYPE_NONE;
   1167     }
   1168     kit_cg_int_unop(p->cg, KIT_CG_INT_NEG, 0);
   1169     return ty;
   1170   }
   1171 
   1172   if (toy_parser_match(p, TOK_BANG)) {
   1173     KitCgTypeId ty = toy_parse_expr_unary(p);
   1174     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1175     if (p->tail_call_expr) {
   1176       toy_error(p, p->cur.loc, "tail @call must be returned directly");
   1177       return KIT_CG_TYPE_NONE;
   1178     }
   1179     if (!toy_type_is_intlike(p, ty)) {
   1180       toy_error(p, p->cur.loc, "invalid operand for '!'");
   1181       return KIT_CG_TYPE_NONE;
   1182     }
   1183     kit_cg_int_unop(p->cg, KIT_CG_INT_NOT, 0);
   1184     return ty;
   1185   }
   1186 
   1187   if (toy_parser_match(p, TOK_TILDE)) {
   1188     KitCgTypeId ty = toy_parse_expr_unary(p);
   1189     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1190     if (p->tail_call_expr) {
   1191       toy_error(p, p->cur.loc, "tail @call must be returned directly");
   1192       return KIT_CG_TYPE_NONE;
   1193     }
   1194     if (!toy_type_is_intlike(p, ty)) {
   1195       toy_error(p, p->cur.loc, "invalid operand for '~'");
   1196       return KIT_CG_TYPE_NONE;
   1197     }
   1198     kit_cg_int_unop(p->cg, KIT_CG_INT_BNOT, 0);
   1199     return ty;
   1200   }
   1201 
   1202   if (toy_parser_match(p, TOK_AMPERSAND)) {
   1203     KitSym name;
   1204     KitCgTypeId ty;
   1205     if (p->cur.kind != TOK_IDENT) {
   1206       toy_error(p, p->cur.loc, "expected identifier after '&'");
   1207       return KIT_CG_TYPE_NONE;
   1208     }
   1209     name = toy_tok_sym(p, p->cur);
   1210     toy_parser_advance(p);
   1211 
   1212     if (p->cur.kind == TOK_LBRACKET || p->cur.kind == TOK_DOTSTAR ||
   1213         p->cur.kind == TOK_DOT) {
   1214       /* `&expr` chain. Maintain the invariant that TOS holds a
   1215        * pointer-rvalue of type *ty. The chain returns a pointer-rvalue
   1216        * directly (no trailing kit_cg_addr needed). */
   1217       ToyTypeId ty_toy = TOY_TYPE_NONE;
   1218       {
   1219         ToyVar* v = toy_find_var(p, name);
   1220         ToyGlobal* g = toy_find_global(p, name);
   1221         if (v) {
   1222           toy_push_var_addr(p, v);
   1223           ty = v->type;
   1224           ty_toy = v->toy_type;
   1225         } else if (g) {
   1226           kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
   1227           ty = g->type;
   1228           ty_toy = g->toy_type;
   1229         } else {
   1230           ty = KIT_CG_TYPE_NONE;
   1231         }
   1232       }
   1233       if (ty == KIT_CG_TYPE_NONE) {
   1234         toy_error(p, p->cur.loc, "undefined variable");
   1235         return KIT_CG_TYPE_NONE;
   1236       }
   1237       for (;;) {
   1238         if (toy_parser_match(p, TOK_LBRACKET)) {
   1239           KitCgTypeId idx_ty = toy_parse_expr(p);
   1240           if (idx_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1241           if (!toy_type_can_implicitly_cast(p, idx_ty, p->size_type)) {
   1242             toy_error(p, p->cur.loc, "index must be isize");
   1243             return KIT_CG_TYPE_NONE;
   1244           }
   1245           if (!toy_emit_implicit_cast(p, idx_ty, p->size_type))
   1246             return KIT_CG_TYPE_NONE;
   1247           idx_ty = p->size_type;
   1248           if (!toy_parser_expect(p, TOK_RBRACKET)) {
   1249             toy_error(p, p->cur.loc, "expected ']' after index");
   1250             return KIT_CG_TYPE_NONE;
   1251           }
   1252           if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR) {
   1253             KitCgTypeId pointee = kit_cg_type_ptr_pointee(p->c, ty);
   1254             /* TOS holds **T_chain; load the inner pointer first. */
   1255             {
   1256               KitCgLocal idx_slot =
   1257                   kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
   1258               kit_cg_push_local(p->cg, idx_slot);
   1259               kit_cg_swap(p->cg);
   1260               kit_cg_store(p->cg, toy_mem_access(p, p->size_type));
   1261               /* TOS is the chain pointer VALUE (**T); deref to a PLACE and
   1262                * load the inner pointer it addresses. */
   1263               kit_cg_deref(p->cg, 0);
   1264               kit_cg_load(p->cg, toy_mem_access(p, ty));
   1265               kit_cg_push_local(p->cg, idx_slot);
   1266               kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
   1267             }
   1268             if (kit_cg_type_kind(p->c, pointee) == KIT_CG_TYPE_ARRAY) {
   1269               KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, pointee);
   1270               ty = elem_ty;
   1271               ty_toy = toy_type_array_elem(p, toy_type_pointee(p, ty_toy));
   1272               toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
   1273                              kit_cg_type_ptr(p->c, elem_ty, 0));
   1274             } else {
   1275               ty = pointee;
   1276               ty_toy = toy_type_pointee(p, ty_toy);
   1277               toy_addr_index(p, kit_cg_type_size(p->c, ty),
   1278                              kit_cg_type_ptr(p->c, ty, 0));
   1279             }
   1280           } else if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ARRAY) {
   1281             KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, ty);
   1282             ty = elem_ty;
   1283             ty_toy = toy_type_array_elem(p, ty_toy);
   1284             toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
   1285                            kit_cg_type_ptr(p->c, elem_ty, 0));
   1286           } else if (toy_type_is_slice(p, ty_toy)) {
   1287             ToyTypeId elem_toy = TOY_TYPE_NONE;
   1288             ty = toy_emit_slice_index_lvalue(p, ty, ty_toy, &elem_toy);
   1289             if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1290             ty_toy = elem_toy;
   1291           } else {
   1292             toy_error(p, p->cur.loc, "cannot index non-array/non-pointer");
   1293             return KIT_CG_TYPE_NONE;
   1294           }
   1295           continue;
   1296         }
   1297         if (toy_parser_match(p, TOK_DOTSTAR)) {
   1298           if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_PTR) {
   1299             toy_error(p, p->cur.loc, "cannot dereference non-pointer");
   1300             return KIT_CG_TYPE_NONE;
   1301           }
   1302           /* TOS = **T (pointer VALUE); deref to PLACE and load to TOS = *T. */
   1303           kit_cg_deref(p->cg, 0);
   1304           kit_cg_load(p->cg, toy_mem_access(p, ty));
   1305           ty = kit_cg_type_ptr_pointee(p->c, ty);
   1306           ty_toy = toy_type_pointee(p, ty_toy);
   1307           continue;
   1308         }
   1309         if (toy_parser_match(p, TOK_DOT)) {
   1310           KitCgField field;
   1311           uint32_t field_index = 0;
   1312           uint64_t foff = 0;
   1313           ToyNamedType* named;
   1314           if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR &&
   1315               kit_cg_type_kind(p->c, kit_cg_type_ptr_pointee(p->c, ty)) ==
   1316                   KIT_CG_TYPE_RECORD) {
   1317             /* TOS = **Rec (pointer VALUE); deref to PLACE and load to *Rec. */
   1318             kit_cg_deref(p->cg, 0);
   1319             kit_cg_load(p->cg, toy_mem_access(p, ty));
   1320             ty = kit_cg_type_ptr_pointee(p->c, ty);
   1321             ty_toy = toy_type_pointee(p, ty_toy);
   1322           }
   1323           if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_RECORD) {
   1324             toy_error(p, p->cur.loc, "field access on non-record");
   1325             return KIT_CG_TYPE_NONE;
   1326           }
   1327           named = toy_find_named_type_by_type(p, ty);
   1328           if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) {
   1329             if (p->cur.int_value < 0 ||
   1330                 p->cur.int_value >=
   1331                     (int64_t)kit_cg_type_record_nfields(p->c, ty)) {
   1332               toy_error(p, p->cur.loc, "invalid tuple field");
   1333               return KIT_CG_TYPE_NONE;
   1334             }
   1335             field_index = (uint32_t)p->cur.int_value;
   1336             toy_parser_advance(p);
   1337             if (kit_cg_type_record_field(p->c, ty, field_index, &field,
   1338                                          &foff) != 0)
   1339               return KIT_CG_TYPE_NONE;
   1340           } else {
   1341             KitSym field_name;
   1342             if (p->cur.kind != TOK_IDENT) {
   1343               toy_error(p, p->cur.loc, "expected field name");
   1344               return KIT_CG_TYPE_NONE;
   1345             }
   1346             field_name = toy_tok_sym(p, p->cur);
   1347             toy_parser_advance(p);
   1348             if (!toy_record_field_index(p, ty, field_name, &field_index,
   1349                                         &field)) {
   1350               toy_error(p, p->cur.loc, "unknown record field");
   1351               return KIT_CG_TYPE_NONE;
   1352             }
   1353             if (kit_cg_type_record_field(p->c, ty, field_index, NULL, &foff) !=
   1354                 0)
   1355               return KIT_CG_TYPE_NONE;
   1356           }
   1357           ty = field.type;
   1358           ty_toy = (named && field_index < named->nfields)
   1359                        ? named->fields[field_index].toy_type
   1360                        : toy_type_from_cg(p, ty);
   1361           toy_addr_offset(p, (int64_t)foff, kit_cg_type_ptr(p->c, ty, 0));
   1362           continue;
   1363         }
   1364         break;
   1365       }
   1366       /* TOS already holds a pointer-rvalue of type *ty. */
   1367       {
   1368         KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, ty, 0);
   1369         p->last_type = toy_type_register_ptr(
   1370             p, ptr_ty,
   1371             ty_toy != TOY_TYPE_NONE ? ty_toy : toy_type_from_cg(p, ty), 0);
   1372         return ptr_ty;
   1373       }
   1374     }
   1375 
   1376     {
   1377       ToyVar* v = toy_find_var(p, name);
   1378       if (v) {
   1379         KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, v->type, 0);
   1380         toy_push_var_addr(p, v);
   1381         p->last_type = toy_type_register_ptr(p, ptr_ty, v->toy_type, 0);
   1382         return ptr_ty;
   1383       } else {
   1384         ToyGlobal* g = toy_find_global(p, name);
   1385         if (g) {
   1386           KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, g->type, 0);
   1387           kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
   1388           p->last_type = toy_type_register_ptr(p, ptr_ty, g->toy_type, 0);
   1389           return ptr_ty;
   1390         } else {
   1391           ToyFn* fn = toy_find_fn(p, name);
   1392           if (fn) {
   1393             KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, fn->type, 0);
   1394             kit_cg_push_symbol_addr(p->cg, toy_fn_cur_sym(p, fn), 0);
   1395             p->last_type = toy_type_register_ptr(p, ptr_ty, fn->toy_type, 0);
   1396             return ptr_ty;
   1397           }
   1398         }
   1399         toy_error(p, p->cur.loc, "undefined variable");
   1400         return KIT_CG_TYPE_NONE;
   1401       }
   1402     }
   1403   }
   1404 
   1405   return toy_parse_expr_postfix(p);
   1406 }
   1407 
   1408 static KitCgTypeId toy_parse_expr_cast(ToyParser* p) {
   1409   KitCgTypeId ty = toy_parse_expr_unary(p);
   1410   while (ty != KIT_CG_TYPE_NONE && !p->tail_call_expr &&
   1411          toy_parser_match(p, TOK_AS)) {
   1412     KitCgTypeId dst = toy_parse_type(p);
   1413     if (dst == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1414     if (!toy_emit_cast(p, ty, dst)) return KIT_CG_TYPE_NONE;
   1415     ty = dst;
   1416   }
   1417   return ty;
   1418 }
   1419 
   1420 static KitCgTypeId toy_parse_expr_mul(ToyParser* p) {
   1421   KitCgTypeId ty = toy_parse_expr_cast(p);
   1422   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1423   while (p->cur.kind == TOK_STAR || p->cur.kind == TOK_SLASH ||
   1424          p->cur.kind == TOK_PERCENT) {
   1425     if (p->tail_call_expr) break;
   1426     ToyTokenKind op = p->cur.kind;
   1427     KitCgIntBinOp binop;
   1428     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_ARITH))
   1429       return KIT_CG_TYPE_NONE;
   1430     toy_parser_advance(p);
   1431     KitCgTypeId ty2 = toy_parse_expr_cast(p);
   1432     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1433     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1434     if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) {
   1435       if (!toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1436         toy_error(p, p->cur.loc,
   1437                   "arithmetic operands must have same numeric type");
   1438         return KIT_CG_TYPE_NONE;
   1439       }
   1440     } else if (ty != ty2 || !toy_type_is_float(p, ty)) {
   1441       toy_error(p, p->cur.loc,
   1442                 "arithmetic operands must have same numeric type");
   1443       return KIT_CG_TYPE_NONE;
   1444     }
   1445     if (toy_type_is_float(p, ty)) {
   1446       KitCgFpBinOp fp_op;
   1447       if (op == TOK_PERCENT) {
   1448         toy_error(p, p->cur.loc, "floating-point remainder is unsupported");
   1449         return KIT_CG_TYPE_NONE;
   1450       }
   1451       switch (op) {
   1452         case TOK_STAR:
   1453           fp_op = KIT_CG_FP_MUL;
   1454           break;
   1455         case TOK_SLASH:
   1456           fp_op = KIT_CG_FP_DIV;
   1457           break;
   1458         default:
   1459           return KIT_CG_TYPE_NONE;
   1460       }
   1461       kit_cg_fp_binop(p->cg, fp_op, 0);
   1462     } else {
   1463       switch (op) {
   1464         case TOK_STAR:
   1465           binop = KIT_CG_INT_MUL;
   1466           break;
   1467         case TOK_SLASH:
   1468           binop = KIT_CG_INT_SDIV;
   1469           break;
   1470         case TOK_PERCENT:
   1471           binop = KIT_CG_INT_SREM;
   1472           break;
   1473         default:
   1474           return KIT_CG_TYPE_NONE;
   1475       }
   1476       kit_cg_int_binop(p->cg, binop, 0);
   1477     }
   1478     toy_note_cg_result_type(p, ty);
   1479   }
   1480   return ty;
   1481 }
   1482 
   1483 static KitCgTypeId toy_parse_expr_add(ToyParser* p) {
   1484   KitCgTypeId ty = toy_parse_expr_mul(p);
   1485   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1486   while (p->cur.kind == TOK_PLUS || p->cur.kind == TOK_MINUS) {
   1487     if (p->tail_call_expr) break;
   1488     ToyTokenKind op = p->cur.kind;
   1489     KitCgIntBinOp binop = (op == TOK_PLUS) ? KIT_CG_INT_ADD : KIT_CG_INT_SUB;
   1490     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_ARITH))
   1491       return KIT_CG_TYPE_NONE;
   1492     toy_parser_advance(p);
   1493     KitCgTypeId ty2 = toy_parse_expr_mul(p);
   1494     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1495     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1496     if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) {
   1497       if (!toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1498         toy_error(p, p->cur.loc,
   1499                   "arithmetic operands must have same numeric type");
   1500         return KIT_CG_TYPE_NONE;
   1501       }
   1502     } else if (ty != ty2 || !toy_type_is_float(p, ty)) {
   1503       toy_error(p, p->cur.loc,
   1504                 "arithmetic operands must have same numeric type");
   1505       return KIT_CG_TYPE_NONE;
   1506     }
   1507     if (toy_type_is_float(p, ty)) {
   1508       kit_cg_fp_binop(p->cg, op == TOK_PLUS ? KIT_CG_FP_ADD : KIT_CG_FP_SUB, 0);
   1509     } else {
   1510       kit_cg_int_binop(p->cg, binop, 0);
   1511     }
   1512     toy_note_cg_result_type(p, ty);
   1513   }
   1514   return ty;
   1515 }
   1516 
   1517 static KitCgTypeId toy_parse_expr_cmp(ToyParser* p) {
   1518   KitCgTypeId ty = toy_parse_expr_add(p);
   1519   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1520   if (!p->tail_call_expr && (p->cur.kind == TOK_EQEQ || p->cur.kind == TOK_NE ||
   1521                              p->cur.kind == TOK_LT || p->cur.kind == TOK_GT ||
   1522                              p->cur.kind == TOK_LE || p->cur.kind == TOK_GE)) {
   1523     ToyTokenKind op = p->cur.kind;
   1524     KitCgIntCmpOp cmp;
   1525     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_CMP)) return KIT_CG_TYPE_NONE;
   1526     toy_parser_advance(p);
   1527     KitCgTypeId ty2 = toy_parse_expr_add(p);
   1528     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1529     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1530     if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) {
   1531       if (!toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1532         toy_error(p, p->cur.loc, "comparison operands must have same type");
   1533         return KIT_CG_TYPE_NONE;
   1534       }
   1535     } else if (ty != ty2) {
   1536       toy_error(p, p->cur.loc, "comparison operands must have same type");
   1537       return KIT_CG_TYPE_NONE;
   1538     }
   1539     if (toy_type_is_float(p, ty)) {
   1540       KitCgFpCmpOp fp_cmp;
   1541       switch (op) {
   1542         case TOK_EQEQ:
   1543           fp_cmp = KIT_CG_FP_OEQ;
   1544           break;
   1545         case TOK_NE:
   1546           /* `!=` on floats is unordered not-equal (true on NaN), not ONE. */
   1547           fp_cmp = KIT_CG_FP_UNE;
   1548           break;
   1549         case TOK_LT:
   1550           fp_cmp = KIT_CG_FP_OLT;
   1551           break;
   1552         case TOK_GT:
   1553           fp_cmp = KIT_CG_FP_OGT;
   1554           break;
   1555         case TOK_LE:
   1556           fp_cmp = KIT_CG_FP_OLE;
   1557           break;
   1558         case TOK_GE:
   1559           fp_cmp = KIT_CG_FP_OGE;
   1560           break;
   1561         default:
   1562           return KIT_CG_TYPE_NONE;
   1563       }
   1564       kit_cg_fp_cmp(p->cg, fp_cmp);
   1565     } else if (toy_type_is_intlike(p, ty) || toy_type_is_ptr(p, ty)) {
   1566       switch (op) {
   1567         case TOK_EQEQ:
   1568           cmp = KIT_CG_INT_EQ;
   1569           break;
   1570         case TOK_NE:
   1571           cmp = KIT_CG_INT_NE;
   1572           break;
   1573         case TOK_LT:
   1574           cmp = KIT_CG_INT_LT_S;
   1575           break;
   1576         case TOK_GT:
   1577           cmp = KIT_CG_INT_GT_S;
   1578           break;
   1579         case TOK_LE:
   1580           cmp = KIT_CG_INT_LE_S;
   1581           break;
   1582         case TOK_GE:
   1583           cmp = KIT_CG_INT_GE_S;
   1584           break;
   1585         default:
   1586           return KIT_CG_TYPE_NONE;
   1587       }
   1588       kit_cg_int_cmp(p->cg, cmp);
   1589     } else {
   1590       toy_error(p, p->cur.loc, "comparison operands must be scalar");
   1591       return KIT_CG_TYPE_NONE;
   1592     }
   1593     kit_cg_zext(p->cg, p->int_type);
   1594     ty = p->int_type;
   1595     toy_note_cg_result_type(p, ty);
   1596   }
   1597   return ty;
   1598 }
   1599 
   1600 static KitCgTypeId toy_parse_expr_shift(ToyParser* p) {
   1601   KitCgTypeId ty = toy_parse_expr_cmp(p);
   1602   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1603   while (p->cur.kind == TOK_SHL || p->cur.kind == TOK_SHR) {
   1604     if (p->tail_call_expr) break;
   1605     ToyTokenKind op = p->cur.kind;
   1606     KitCgIntBinOp binop = (op == TOK_SHL) ? KIT_CG_INT_SHL : KIT_CG_INT_ASHR;
   1607     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_SHIFT))
   1608       return KIT_CG_TYPE_NONE;
   1609     toy_parser_advance(p);
   1610     KitCgTypeId ty2 = toy_parse_expr_cmp(p);
   1611     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1612     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1613     if (!toy_type_is_promotable_int(p, ty) ||
   1614         !toy_type_is_promotable_int(p, ty2) ||
   1615         !toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1616       toy_error(p, p->cur.loc, "shift operands must be int");
   1617       return KIT_CG_TYPE_NONE;
   1618     }
   1619     kit_cg_int_binop(p->cg, binop, 0);
   1620     toy_note_cg_result_type(p, ty);
   1621   }
   1622   return ty;
   1623 }
   1624 
   1625 static KitCgTypeId toy_parse_expr_band(ToyParser* p) {
   1626   KitCgTypeId ty = toy_parse_expr_shift(p);
   1627   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1628   while (p->cur.kind == TOK_AMPERSAND) {
   1629     if (p->tail_call_expr) break;
   1630     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_BIT_AND))
   1631       return KIT_CG_TYPE_NONE;
   1632     toy_parser_advance(p);
   1633     KitCgTypeId ty2 = toy_parse_expr_shift(p);
   1634     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1635     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1636     if (!toy_type_is_promotable_int(p, ty) ||
   1637         !toy_type_is_promotable_int(p, ty2) ||
   1638         !toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1639       toy_error(p, p->cur.loc, "bitwise operands must be int");
   1640       return KIT_CG_TYPE_NONE;
   1641     }
   1642     kit_cg_int_binop(p->cg, KIT_CG_INT_AND, 0);
   1643     toy_note_cg_result_type(p, ty);
   1644   }
   1645   return ty;
   1646 }
   1647 
   1648 static KitCgTypeId toy_parse_expr_bxor(ToyParser* p) {
   1649   KitCgTypeId ty = toy_parse_expr_band(p);
   1650   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1651   while (p->cur.kind == TOK_CARET) {
   1652     if (p->tail_call_expr) break;
   1653     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_BIT_XOR))
   1654       return KIT_CG_TYPE_NONE;
   1655     toy_parser_advance(p);
   1656     KitCgTypeId ty2 = toy_parse_expr_band(p);
   1657     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1658     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1659     if (!toy_type_is_promotable_int(p, ty) ||
   1660         !toy_type_is_promotable_int(p, ty2) ||
   1661         !toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1662       toy_error(p, p->cur.loc, "bitwise operands must be int");
   1663       return KIT_CG_TYPE_NONE;
   1664     }
   1665     kit_cg_int_binop(p->cg, KIT_CG_INT_XOR, 0);
   1666     toy_note_cg_result_type(p, ty);
   1667   }
   1668   return ty;
   1669 }
   1670 
   1671 static KitCgTypeId toy_parse_expr_bor(ToyParser* p) {
   1672   KitCgTypeId ty = toy_parse_expr_bxor(p);
   1673   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1674   while (p->cur.kind == TOK_PIPE) {
   1675     if (p->tail_call_expr) break;
   1676     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_BIT_OR))
   1677       return KIT_CG_TYPE_NONE;
   1678     toy_parser_advance(p);
   1679     KitCgTypeId ty2 = toy_parse_expr_bxor(p);
   1680     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1681     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1682     if (!toy_type_is_promotable_int(p, ty) ||
   1683         !toy_type_is_promotable_int(p, ty2) ||
   1684         !toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1685       toy_error(p, p->cur.loc, "bitwise operands must be int");
   1686       return KIT_CG_TYPE_NONE;
   1687     }
   1688     kit_cg_int_binop(p->cg, KIT_CG_INT_OR, 0);
   1689     toy_note_cg_result_type(p, ty);
   1690   }
   1691   return ty;
   1692 }
   1693 
   1694 static KitCgTypeId toy_parse_expr_and(ToyParser* p) {
   1695   KitCgTypeId ty = toy_parse_expr_bor(p);
   1696   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1697   while (p->cur.kind == TOK_AND) {
   1698     if (p->tail_call_expr) break;
   1699     KitCgTypeId bool_ty = toy_builtin_type(p, KIT_CG_BUILTIN_BOOL);
   1700     KitCgLabel false_label;
   1701     KitCgLabel end_label;
   1702     KitCgLocal result_slot;
   1703     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_LOGIC_AND))
   1704       return KIT_CG_TYPE_NONE;
   1705     toy_parser_advance(p);
   1706     false_label = kit_cg_label_new(p->cg);
   1707     end_label = kit_cg_label_new(p->cg);
   1708     result_slot = kit_cg_local(p->cg, bool_ty, toy_slot_attrs(0));
   1709     if (!toy_emit_truthy(p, ty)) return KIT_CG_TYPE_NONE;
   1710     kit_cg_branch_false(p->cg, false_label);
   1711     ty = toy_parse_expr_bor(p);
   1712     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1713     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1714     if (!toy_emit_truthy(p, ty)) return KIT_CG_TYPE_NONE;
   1715     kit_cg_branch_false(p->cg, false_label);
   1716     kit_cg_push_local(p->cg, result_slot);
   1717     kit_cg_push_int(p->cg, 1, bool_ty);
   1718     kit_cg_store(p->cg, toy_mem_access(p, bool_ty));
   1719     kit_cg_jump(p->cg, end_label);
   1720     kit_cg_label_place(p->cg, false_label);
   1721     kit_cg_push_local(p->cg, result_slot);
   1722     kit_cg_push_int(p->cg, 0, bool_ty);
   1723     kit_cg_store(p->cg, toy_mem_access(p, bool_ty));
   1724     kit_cg_label_place(p->cg, end_label);
   1725     kit_cg_push_local(p->cg, result_slot);
   1726     kit_cg_load(p->cg, toy_mem_access(p, bool_ty));
   1727     ty = bool_ty;
   1728     toy_note_cg_result_type(p, ty);
   1729   }
   1730   return ty;
   1731 }
   1732 
   1733 static KitCgTypeId toy_parse_expr_or(ToyParser* p) {
   1734   KitCgTypeId ty = toy_parse_expr_and(p);
   1735   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1736   while (p->cur.kind == TOK_OR) {
   1737     if (p->tail_call_expr) break;
   1738     KitCgTypeId bool_ty = toy_builtin_type(p, KIT_CG_BUILTIN_BOOL);
   1739     KitCgLabel true_label;
   1740     KitCgLabel end_label;
   1741     KitCgLocal result_slot;
   1742     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_LOGIC_OR))
   1743       return KIT_CG_TYPE_NONE;
   1744     toy_parser_advance(p);
   1745     true_label = kit_cg_label_new(p->cg);
   1746     end_label = kit_cg_label_new(p->cg);
   1747     result_slot = kit_cg_local(p->cg, bool_ty, toy_slot_attrs(0));
   1748     if (!toy_emit_truthy(p, ty)) return KIT_CG_TYPE_NONE;
   1749     kit_cg_branch_true(p->cg, true_label);
   1750     ty = toy_parse_expr_and(p);
   1751     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1752     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1753     if (!toy_emit_truthy(p, ty)) return KIT_CG_TYPE_NONE;
   1754     kit_cg_branch_true(p->cg, true_label);
   1755     kit_cg_push_local(p->cg, result_slot);
   1756     kit_cg_push_int(p->cg, 0, bool_ty);
   1757     kit_cg_store(p->cg, toy_mem_access(p, bool_ty));
   1758     kit_cg_jump(p->cg, end_label);
   1759     kit_cg_label_place(p->cg, true_label);
   1760     kit_cg_push_local(p->cg, result_slot);
   1761     kit_cg_push_int(p->cg, 1, bool_ty);
   1762     kit_cg_store(p->cg, toy_mem_access(p, bool_ty));
   1763     kit_cg_label_place(p->cg, end_label);
   1764     kit_cg_push_local(p->cg, result_slot);
   1765     kit_cg_load(p->cg, toy_mem_access(p, bool_ty));
   1766     ty = bool_ty;
   1767     toy_note_cg_result_type(p, ty);
   1768   }
   1769   return ty;
   1770 }
   1771 
   1772 KitCgTypeId toy_parse_expr(ToyParser* p) {
   1773   uint32_t saved_island_mask = p->expr_island_mask;
   1774   KitCgTypeId ty;
   1775   p->expr_island_mask = 0;
   1776   ty = toy_parse_expr_or(p);
   1777   if (ty != KIT_CG_TYPE_NONE &&
   1778       (p->cur.kind == TOK_ANDAND || p->cur.kind == TOK_PIPEPIPE)) {
   1779     toy_error(p, p->cur.loc,
   1780               "legacy logical operator is unsupported; use 'and' or 'or'");
   1781     ty = KIT_CG_TYPE_NONE;
   1782   }
   1783   p->expr_island_mask = saved_island_mask;
   1784   return ty;
   1785 }