kit

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

expr.c (64036B)


      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_ARM_32:
    540       return 5; /* matches the `.arm32` dot-constant selector */
    541     case KIT_ARCH_WASM:
    542       return 7;
    543     default:
    544       return 0;
    545   }
    546 }
    547 
    548 int toy_parse_arch_string(ToyParser* p, KitSym* out, size_t* len_out) {
    549   if (p->cur.kind == TOK_STRING) return toy_parse_string_sym(p, out, len_out);
    550 
    551   toy_error(p, p->cur.loc, "expected asm template");
    552   return 0;
    553 }
    554 
    555 static int toy_emit_var_addr(ToyParser* p, KitSym name) {
    556   ToyVar* v = toy_find_var(p, name);
    557   if (v) {
    558     toy_push_var_addr(p, v);
    559     return 1;
    560   }
    561   {
    562     ToyGlobal* g = toy_find_global(p, name);
    563     if (g) {
    564       kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
    565       return 1;
    566     }
    567   }
    568   return 0;
    569 }
    570 
    571 KitCgTypeId toy_emit_var_lvalue(ToyParser* p, KitSym name) {
    572   ToyVar* v = toy_find_var(p, name);
    573   if (v) {
    574     toy_push_var_lvalue(p, v);
    575     return v->type;
    576   }
    577   {
    578     ToyGlobal* g = toy_find_global(p, name);
    579     if (g) {
    580       kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
    581       return g->type;
    582     }
    583   }
    584   return KIT_CG_TYPE_NONE;
    585 }
    586 
    587 static KitCgTypeId toy_type_id_cg_or_none(ToyParser* p, ToyTypeId id) {
    588   KitCgTypeId ty = toy_type_resolved_cg(p, id);
    589   return ty != KIT_CG_TYPE_NONE ? ty : toy_type_cg(p, id);
    590 }
    591 
    592 static void toy_store_tos_to_local(ToyParser* p, KitCgLocal local,
    593                                    KitCgTypeId ty) {
    594   kit_cg_push_local(p->cg, local);
    595   kit_cg_swap(p->cg);
    596   kit_cg_store(p->cg, toy_mem_access(p, ty));
    597 }
    598 
    599 /* Consumes [slice_base, idx] where slice_base is a pointer to the slice
    600  * record. Produces [elem_ptr] -- a pointer-rvalue to the element. */
    601 KitCgTypeId toy_emit_slice_index_lvalue(ToyParser* p, KitCgTypeId slice_ty,
    602                                         ToyTypeId slice_toy_type,
    603                                         ToyTypeId* elem_toy_out) {
    604   ToyTypeId elem_toy = toy_type_slice_elem(p, slice_toy_type);
    605   KitCgTypeId elem_ty = toy_type_id_cg_or_none(p, elem_toy);
    606   const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, slice_ty);
    607   KitCgLocal idx_slot;
    608   uint64_t ptr_field_off;
    609   KitCgTypeId ptr_field_type;
    610   if (elem_ty == KIT_CG_TYPE_NONE ||
    611       kit_cg_type_kind(p->c, slice_ty) != KIT_CG_TYPE_RECORD || !L ||
    612       L->nfields < 1) {
    613     toy_error(p, p->cur.loc, "cannot index non-array/non-pointer");
    614     return KIT_CG_TYPE_NONE;
    615   }
    616   ptr_field_off = L->fields[0].offset;
    617   ptr_field_type = L->fields[0].type;
    618   /* Stash the index, then load the slice's ptr field, then re-push idx
    619    * and compute element pointer. */
    620   idx_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
    621   toy_store_tos_to_local(p, idx_slot, p->size_type);
    622   kit_cg_deref(p->cg, (int64_t)ptr_field_off);
    623   kit_cg_load(p->cg, toy_mem_access(p, ptr_field_type));
    624   kit_cg_push_local(p->cg, idx_slot);
    625   kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
    626   toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
    627                  kit_cg_type_ptr(p->c, elem_ty, 0));
    628   if (elem_toy_out) *elem_toy_out = elem_toy;
    629   return elem_ty;
    630 }
    631 
    632 KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty,
    633                                  ToyTypeId base_toy_type, KitCgTypeId start_ty,
    634                                  KitCgTypeId end_ty, ToyTypeId* slice_toy_out) {
    635   ToyTypeId elem_toy = TOY_TYPE_NONE;
    636   KitCgTypeId elem_ty = KIT_CG_TYPE_NONE;
    637   ToyTypeId slice_toy;
    638   KitCgTypeId slice_ty;
    639   KitCgTypeId ptr_field_type = KIT_CG_TYPE_NONE;
    640   KitCgLocal start_slot;
    641   KitCgLocal end_slot;
    642   KitCgLocal result_slot;
    643 
    644   if (start_ty != p->size_type || end_ty != p->size_type) {
    645     toy_error(p, p->cur.loc, "slice bounds must be isize");
    646     return KIT_CG_TYPE_NONE;
    647   }
    648 
    649   if (kit_cg_type_kind(p->c, base_ty) == KIT_CG_TYPE_ARRAY) {
    650     elem_ty = kit_cg_type_array_elem(p->c, base_ty);
    651     elem_toy = toy_type_array_elem(p, base_toy_type);
    652   } else if (toy_type_is_slice(p, base_toy_type)) {
    653     elem_toy = toy_type_slice_elem(p, base_toy_type);
    654     elem_ty = toy_type_id_cg_or_none(p, elem_toy);
    655   }
    656   if (elem_toy == TOY_TYPE_NONE && elem_ty != KIT_CG_TYPE_NONE)
    657     elem_toy = toy_type_from_cg(p, elem_ty);
    658   if (elem_ty == KIT_CG_TYPE_NONE || elem_toy == TOY_TYPE_NONE) {
    659     toy_error(p, p->cur.loc, "cannot slice non-array/non-slice");
    660     return KIT_CG_TYPE_NONE;
    661   }
    662 
    663   slice_toy = toy_type_register_slice(p, elem_ty, elem_toy);
    664   slice_ty = toy_type_cg(p, slice_toy);
    665   {
    666     uint64_t ptr_off = 0;
    667     uint64_t len_off = 0;
    668     const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, slice_ty);
    669     if (slice_ty == KIT_CG_TYPE_NONE || !L || L->nfields < 2) {
    670       toy_error(p, p->cur.loc, "failed to create slice type");
    671       return KIT_CG_TYPE_NONE;
    672     }
    673     ptr_off = L->fields[0].offset;
    674     ptr_field_type = L->fields[0].type;
    675     len_off = L->fields[1].offset;
    676 
    677     end_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
    678     toy_store_tos_to_local(p, end_slot, p->size_type);
    679     start_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
    680     toy_store_tos_to_local(p, start_slot, p->size_type);
    681 
    682     result_slot = kit_cg_local(p->cg, slice_ty, toy_slot_attrs(0));
    683     /* TOS = [base] (slice lvalue/pointer or array lvalue/pointer). */
    684     if (toy_type_is_slice(p, base_toy_type)) {
    685       /* Replace slice base with its data pointer (a pointer-rvalue). */
    686       kit_cg_deref(p->cg, (int64_t)ptr_off);
    687       kit_cg_load(p->cg, toy_mem_access(p, ptr_field_type));
    688     } else {
    689       /* Array base: TOS is a pointer-rvalue (callers always project
    690        * to a pointer for array/slice bases now). Bitcast to *elem. */
    691       kit_cg_bitcast(p->cg, kit_cg_type_ptr(p->c, elem_ty, 0));
    692     }
    693     /* Compute (base + start * sizeof(elem)) as a pointer to the slice's
    694      * first element. */
    695     kit_cg_push_local(p->cg, start_slot);
    696     kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
    697     toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
    698                    kit_cg_type_ptr(p->c, elem_ty, 0));
    699     /* Store the data pointer into result_slot.ptr. */
    700     kit_cg_push_local(p->cg, result_slot);
    701     kit_cg_addr(p->cg);
    702     kit_cg_deref(p->cg, (int64_t)ptr_off);
    703     kit_cg_swap(p->cg);
    704     kit_cg_store(p->cg, toy_mem_access(p, ptr_field_type));
    705 
    706     /* len = end - start; store into result_slot.len. */
    707     kit_cg_push_local(p->cg, result_slot);
    708     kit_cg_addr(p->cg);
    709     kit_cg_deref(p->cg, (int64_t)len_off);
    710     kit_cg_push_local(p->cg, end_slot);
    711     kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
    712     kit_cg_push_local(p->cg, start_slot);
    713     kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
    714     kit_cg_int_binop(p->cg, KIT_CG_INT_SUB, 0);
    715     kit_cg_store(p->cg, toy_mem_access(p, p->size_type));
    716   }
    717 
    718   /* Hand back the slice record as a pointer VALUE (its address), matching the
    719    * "records/slices are pointer VALUEs" shape the downstream record-copy and
    720    * slice-index paths consume. */
    721   kit_cg_push_local_addr(p->cg, result_slot);
    722   if (slice_toy_out) *slice_toy_out = slice_toy;
    723   p->last_type = slice_toy;
    724   return slice_ty;
    725 }
    726 
    727 int toy_parse_va_list_addr_arg(ToyParser* p) {
    728   KitSym name;
    729   ToyVar* v;
    730   if (p->cur.kind != TOK_IDENT) {
    731     toy_error(p, p->cur.loc, "expected va_list identifier");
    732     return 0;
    733   }
    734   name = toy_tok_sym(p, p->cur);
    735   v = toy_find_var(p, name);
    736   if (!v || v->type != p->va_list_type) {
    737     toy_error(p, p->cur.loc, "expected va_list local");
    738     return 0;
    739   }
    740   toy_parser_advance(p);
    741   return toy_emit_var_addr(p, name);
    742 }
    743 
    744 static KitCgTypeId toy_parse_expr_primary(ToyParser* p) {
    745   toy_set_loc(p);
    746   if (p->cur.kind == TOK_AT) {
    747     KitSym name;
    748     ToyToken at_tok = p->cur;
    749     toy_parser_advance(p);
    750     if (p->cur.kind != TOK_IDENT) {
    751       toy_error(p, p->cur.loc, "expected builtin name after '@'");
    752       return KIT_CG_TYPE_NONE;
    753     }
    754     name = toy_tok_sym(p, p->cur);
    755     toy_parser_advance(p);
    756 
    757     if (p->cur.kind == TOK_LT) {
    758       int recognized = 0;
    759       KitCgTypeId builtin_ty = toy_parse_generic_builtin(p, name, &recognized);
    760       if (recognized) {
    761         if (builtin_ty != KIT_CG_TYPE_NONE)
    762           toy_note_builtin_result_type(p, builtin_ty);
    763         return builtin_ty;
    764       }
    765     }
    766 
    767     if (p->cur.kind == TOK_LPAREN) {
    768       int recognized = 0;
    769       KitCgTypeId builtin_ty = toy_parse_builtin_call(p, name, &recognized);
    770       if (recognized) {
    771         if (builtin_ty != KIT_CG_TYPE_NONE)
    772           toy_note_builtin_result_type(p, builtin_ty);
    773         return builtin_ty;
    774       }
    775     }
    776 
    777     toy_error(p, at_tok.loc, "unknown builtin");
    778     return KIT_CG_TYPE_NONE;
    779   }
    780 
    781   if (p->cur.kind == TOK_NUMBER) {
    782     if (p->cur.is_float) {
    783       kit_cg_push_float(p->cg, p->cur.float_value,
    784                         toy_builtin_type(p, KIT_CG_BUILTIN_F64));
    785       toy_parser_advance(p);
    786       p->last_type =
    787           toy_type_from_cg(p, toy_builtin_type(p, KIT_CG_BUILTIN_F64));
    788       return toy_builtin_type(p, KIT_CG_BUILTIN_F64);
    789     }
    790     {
    791       KitCgTypeId lit_ty = toy_int_literal_type(p, p->cur.int_value);
    792       kit_cg_push_int(p->cg, (uint64_t)p->cur.int_value, lit_ty);
    793       toy_parser_advance(p);
    794       p->last_type = toy_type_from_cg(p, lit_ty);
    795       return lit_ty;
    796     }
    797   }
    798 
    799   if (p->cur.kind == TOK_IDENT) {
    800     KitSym name = toy_tok_sym(p, p->cur);
    801     ToyToken ident_tok = p->cur;
    802     toy_parser_advance(p);
    803 
    804     if (toy_sym_is(p, name, "true") || toy_sym_is(p, name, "false")) {
    805       kit_cg_push_int(p->cg, toy_sym_is(p, name, "true") ? 1u : 0u,
    806                       toy_builtin_type(p, KIT_CG_BUILTIN_BOOL));
    807       p->last_type =
    808           toy_type_from_cg(p, toy_builtin_type(p, KIT_CG_BUILTIN_BOOL));
    809       return toy_builtin_type(p, KIT_CG_BUILTIN_BOOL);
    810     }
    811 
    812     if (toy_sym_is(p, name, "NULL")) {
    813       kit_cg_push_int(p->cg, 0, p->int_type);
    814       p->last_type = TOY_TYPE_NONE;
    815       return p->int_type;
    816     }
    817 
    818     if (p->cur.kind == TOK_LT) {
    819       int recognized = 0;
    820       KitCgTypeId builtin_ty = toy_parse_generic_builtin(p, name, &recognized);
    821       if (recognized) return builtin_ty;
    822     }
    823 
    824     if (p->cur.kind == TOK_LPAREN) {
    825       /* Function call */
    826       int recognized = 0;
    827       KitCgTypeId builtin_ty = toy_parse_builtin_call(p, name, &recognized);
    828       if (recognized) return builtin_ty;
    829 
    830       ToyFn* fn = toy_find_fn(p, name);
    831       toy_parser_advance(p); /* ( */
    832 
    833       size_t nargs = 0;
    834       if (fn) {
    835         if (!toy_parse_call_args(p, ident_tok, fn->type, fn->toy_params,
    836                                  fn->nparams, &nargs))
    837           return KIT_CG_TYPE_NONE;
    838         {
    839           KitCgCallAttrs attrs;
    840           memset(&attrs, 0, sizeof attrs);
    841           attrs.inline_policy = fn->func_attrs.inline_policy;
    842           kit_cg_call_symbol(p->cg, toy_fn_cur_sym(p, fn), (uint32_t)nargs,
    843                              attrs);
    844         }
    845         /* An aggregate return is a PLACE; project it to a pointer VALUE so it
    846          * matches the records-are-pointers invariant used downstream. */
    847         if (kit_cg_type_kind(p->c, fn->ret) == KIT_CG_TYPE_RECORD)
    848           kit_cg_addr(p->cg);
    849         p->last_type = fn->toy_ret;
    850         return fn->ret;
    851       }
    852 
    853       KitCgTypeId callee_ty = toy_push_named_rvalue(p, name);
    854       ToyTypeId callee_toy_type = p->last_type;
    855       const ToyType* source_fn_type = NULL;
    856       if (callee_ty == KIT_CG_TYPE_NONE) {
    857         toy_error(p, ident_tok.loc, "undefined function '%.*s'",
    858                   (int)ident_tok.text_len, (const char*)ident_tok.text);
    859         return KIT_CG_TYPE_NONE;
    860       }
    861       KitCgTypeId fn_ty = toy_ptr_pointee_func_type(p, callee_ty);
    862       if (fn_ty == KIT_CG_TYPE_NONE) {
    863         toy_error(p, ident_tok.loc, "callee is not a function pointer");
    864         return KIT_CG_TYPE_NONE;
    865       }
    866       source_fn_type = toy_type_get(p, toy_type_pointee(p, callee_toy_type));
    867       if (source_fn_type && source_fn_type->kind != TOY_TYPE_FUNC)
    868         source_fn_type = NULL;
    869       if (!toy_parse_call_args(p, ident_tok, fn_ty,
    870                                source_fn_type ? source_fn_type->params : NULL,
    871                                source_fn_type ? source_fn_type->nparams : 0,
    872                                &nargs))
    873         return KIT_CG_TYPE_NONE;
    874       kit_cg_call_default(p->cg, (uint32_t)nargs, fn_ty);
    875       if (kit_cg_type_kind(p->c, toy_cg_func_ret(p, fn_ty)) ==
    876           KIT_CG_TYPE_RECORD)
    877         kit_cg_addr(p->cg);
    878       p->last_type = source_fn_type
    879                          ? source_fn_type->ret
    880                          : toy_type_from_cg(p, toy_cg_func_ret(p, fn_ty));
    881       return toy_cg_func_ret(p, fn_ty);
    882     }
    883 
    884     if (p->cur.kind == TOK_LBRACKET || p->cur.kind == TOK_DOT) {
    885       ToyVar* v = toy_find_var(p, name);
    886       if (v && (kit_cg_type_kind(p->c, v->type) == KIT_CG_TYPE_ARRAY ||
    887                 kit_cg_type_kind(p->c, v->type) == KIT_CG_TYPE_RECORD)) {
    888         if (kit_cg_type_kind(p->c, v->type) == KIT_CG_TYPE_ARRAY) {
    889           /* Array slicing/indexing wants a pointer root for address math. */
    890           toy_push_var_addr(p, v);
    891         } else {
    892           toy_push_var_lvalue(p, v);
    893         }
    894         p->last_type = v->toy_type;
    895         return v->type;
    896       }
    897       {
    898         ToyGlobal* g = toy_find_global(p, name);
    899         if (g && (kit_cg_type_kind(p->c, g->type) == KIT_CG_TYPE_ARRAY ||
    900                   kit_cg_type_kind(p->c, g->type) == KIT_CG_TYPE_RECORD)) {
    901           kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
    902           p->last_type = g->toy_type;
    903           return g->type;
    904         }
    905       }
    906     }
    907 
    908     {
    909       ToyVar* v = toy_find_var(p, name);
    910       if (v && toy_type_is_slice(p, v->toy_type)) {
    911         toy_push_var_lvalue(p, v);
    912         p->last_type = v->toy_type;
    913         return v->type;
    914       }
    915       {
    916         ToyGlobal* g = toy_find_global(p, name);
    917         if (g && toy_type_is_slice(p, g->toy_type)) {
    918           kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
    919           p->last_type = g->toy_type;
    920           return g->type;
    921         }
    922       }
    923     }
    924 
    925     {
    926       KitCgTypeId ty = toy_push_named_rvalue(p, name);
    927       if (ty != KIT_CG_TYPE_NONE) return ty;
    928     }
    929     toy_error(p, ident_tok.loc, "undefined variable '%.*s'",
    930               (int)ident_tok.text_len, (const char*)ident_tok.text);
    931     return KIT_CG_TYPE_NONE;
    932   }
    933 
    934   if (p->cur.kind == TOK_LPAREN) {
    935     toy_parser_advance(p);
    936     KitCgTypeId ty = toy_parse_expr(p);
    937     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    938     if (!toy_parser_expect(p, TOK_RPAREN)) {
    939       toy_error(p, p->cur.loc, "expected ')'");
    940       return KIT_CG_TYPE_NONE;
    941     }
    942     return ty;
    943   }
    944 
    945   toy_error(p, p->cur.loc, "expected expression");
    946   return KIT_CG_TYPE_NONE;
    947 }
    948 
    949 static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) {
    950   KitCgTypeId ty = toy_parse_expr_primary(p);
    951   ToyTypeId toy_ty = p->last_type;
    952   if (p->tail_call_expr) return ty;
    953   while (ty != KIT_CG_TYPE_NONE) {
    954     if (toy_parser_match(p, TOK_DOTSTAR)) {
    955       if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_PTR) {
    956         toy_error(p, p->cur.loc, "cannot dereference non-pointer");
    957         return KIT_CG_TYPE_NONE;
    958       }
    959       ty = kit_cg_type_ptr_pointee(p->c, ty);
    960       toy_ty = toy_type_pointee(p, toy_ty);
    961       /* TOS is a pointer VALUE; deref it to a PLACE, then load. */
    962       kit_cg_deref(p->cg, 0);
    963       kit_cg_load(p->cg, toy_mem_access(p, ty));
    964       p->last_type = toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty);
    965       continue;
    966     }
    967 
    968     if (toy_parser_match(p, TOK_LBRACKET)) {
    969       KitCgTypeId idx_ty = toy_parse_expr(p);
    970       if (idx_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    971       if (!toy_type_can_implicitly_cast(p, idx_ty, p->size_type)) {
    972         toy_error(p, p->cur.loc, "index must be isize");
    973         return KIT_CG_TYPE_NONE;
    974       }
    975       if (!toy_emit_implicit_cast(p, idx_ty, p->size_type))
    976         return KIT_CG_TYPE_NONE;
    977       idx_ty = p->size_type;
    978       if (toy_parser_match(p, TOK_COLON)) {
    979         KitCgTypeId end_ty = toy_parse_expr(p);
    980         ToyTypeId slice_toy_type = TOY_TYPE_NONE;
    981         if (end_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    982         if (!toy_type_can_implicitly_cast(p, end_ty, p->size_type)) {
    983           toy_error(p, p->cur.loc, "slice bounds must be isize");
    984           return KIT_CG_TYPE_NONE;
    985         }
    986         if (!toy_emit_implicit_cast(p, end_ty, p->size_type))
    987           return KIT_CG_TYPE_NONE;
    988         end_ty = p->size_type;
    989         if (!toy_parser_expect(p, TOK_RBRACKET)) {
    990           toy_error(p, p->cur.loc, "expected ']' after slice");
    991           return KIT_CG_TYPE_NONE;
    992         }
    993         ty = toy_emit_slice_value(p, ty, toy_ty, idx_ty, end_ty,
    994                                   &slice_toy_type);
    995         if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
    996         toy_ty = slice_toy_type;
    997         p->last_type = toy_ty;
    998         continue;
    999       }
   1000       if (!toy_parser_expect(p, TOK_RBRACKET)) {
   1001         toy_error(p, p->cur.loc, "expected ']' after index");
   1002         return KIT_CG_TYPE_NONE;
   1003       }
   1004       if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR) {
   1005         KitCgTypeId pointee = kit_cg_type_ptr_pointee(p->c, ty);
   1006         ToyTypeId source_pointee = toy_type_pointee(p, toy_ty);
   1007         if (kit_cg_type_kind(p->c, pointee) == KIT_CG_TYPE_ARRAY) {
   1008           /* TOS = [ptr-to-array, idx]. Cast pointer to *elem so the load
   1009            * can apply the array's elem-scale on the next memop. */
   1010           KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, pointee);
   1011           kit_cg_swap(p->cg);
   1012           kit_cg_bitcast(p->cg, kit_cg_type_ptr(p->c, elem_ty, 0));
   1013           kit_cg_swap(p->cg);
   1014           ty = elem_ty;
   1015           toy_ty = toy_type_array_elem(p, source_pointee);
   1016         } else {
   1017           ty = pointee;
   1018           toy_ty = source_pointee;
   1019         }
   1020       } else if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ARRAY) {
   1021         /* TOS = [ptr-to-array, idx]. Decay the base to *elem so kit_cg_elem
   1022          * scales by the element size, not the whole array. */
   1023         KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, ty);
   1024         kit_cg_swap(p->cg);
   1025         kit_cg_bitcast(p->cg, kit_cg_type_ptr(p->c, elem_ty, 0));
   1026         kit_cg_swap(p->cg);
   1027         ty = elem_ty;
   1028         toy_ty = toy_type_array_elem(p, toy_ty);
   1029       } else if (toy_type_is_slice(p, toy_ty)) {
   1030         ty = toy_emit_slice_index_lvalue(p, ty, toy_ty, &toy_ty);
   1031         if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1032         /* toy_emit_slice_index_lvalue returns an element pointer VALUE. */
   1033         kit_cg_deref(p->cg, 0);
   1034         kit_cg_load(p->cg, toy_mem_access(p, ty));
   1035         p->last_type =
   1036             toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty);
   1037         continue;
   1038       } else {
   1039         toy_error(p, p->cur.loc, "cannot index non-array/non-pointer");
   1040         return KIT_CG_TYPE_NONE;
   1041       }
   1042       /* TOS = [base, idx]; elem yields the element PLACE, then load. */
   1043       kit_cg_elem(p->cg, 0);
   1044       kit_cg_load(p->cg, toy_mem_access(p, ty));
   1045       p->last_type = toy_ty != TOY_TYPE_NONE ? toy_ty : toy_type_from_cg(p, ty);
   1046       continue;
   1047     }
   1048 
   1049     if (toy_parser_match(p, TOK_DOT)) {
   1050       KitSym field_name;
   1051       uint32_t i, nfields;
   1052       int found = 0;
   1053       KitCgFieldLayout found_field;
   1054       uint64_t found_off = 0;
   1055       ToyNamedType* named;
   1056       ToyTypeId field_toy_type = TOY_TYPE_NONE;
   1057       if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR &&
   1058           kit_cg_type_kind(p->c, kit_cg_type_ptr_pointee(p->c, ty)) ==
   1059               KIT_CG_TYPE_RECORD) {
   1060         /* TOS is a pointer to the record; the memop accepts it directly,
   1061          * so no intermediate op is needed -- we just update `ty`. */
   1062         ty = kit_cg_type_ptr_pointee(p->c, ty);
   1063         toy_ty = toy_type_pointee(p, toy_ty);
   1064       }
   1065       named = toy_find_named_type_by_type(p, ty);
   1066       if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) {
   1067         uint32_t field_index;
   1068         const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, ty);
   1069         if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_RECORD || !L ||
   1070             p->cur.int_value < 0 || p->cur.int_value >= (int64_t)L->nfields) {
   1071           toy_error(p, p->cur.loc, "invalid tuple field");
   1072           return KIT_CG_TYPE_NONE;
   1073         }
   1074         field_index = (uint32_t)p->cur.int_value;
   1075         toy_parser_advance(p);
   1076         found_field = L->fields[field_index];
   1077         found_off = found_field.offset;
   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       {
   1109         const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, ty);
   1110         nfields = L ? L->nfields : 0;
   1111         memset(&found_field, 0, sizeof found_field);
   1112         for (i = 0; L && i < nfields; ++i) {
   1113           if (L->fields[i].name == field_name) {
   1114             found = 1;
   1115             found_field = L->fields[i];
   1116             found_off = found_field.offset;
   1117             if (named && i < named->nfields)
   1118               field_toy_type = named->fields[i].toy_type;
   1119             break;
   1120           }
   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)) return KIT_CG_TYPE_NONE;
   1136           ty = resolved;
   1137         }
   1138       } else {
   1139         p->last_type = toy_type_from_cg(p, ty);
   1140         toy_ty = p->last_type;
   1141       }
   1142       continue;
   1143     }
   1144 
   1145     break;
   1146   }
   1147   return ty;
   1148 }
   1149 
   1150 static KitCgTypeId toy_parse_expr_unary(ToyParser* p) {
   1151   toy_set_loc(p);
   1152   if (toy_parser_match(p, TOK_MINUS)) {
   1153     KitCgTypeId ty = toy_parse_expr_unary(p);
   1154     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1155     if (p->tail_call_expr) {
   1156       toy_error(p, p->cur.loc, "tail @call must be returned directly");
   1157       return KIT_CG_TYPE_NONE;
   1158     }
   1159     if (toy_type_is_float(p, ty)) {
   1160       kit_cg_fp_unop(p->cg, KIT_CG_FP_NEG, 0);
   1161       return ty;
   1162     }
   1163     if (!toy_type_is_intlike(p, ty)) {
   1164       toy_error(p, p->cur.loc, "invalid operand for unary '-'");
   1165       return KIT_CG_TYPE_NONE;
   1166     }
   1167     kit_cg_int_unop(p->cg, KIT_CG_INT_NEG, 0);
   1168     return ty;
   1169   }
   1170 
   1171   if (toy_parser_match(p, TOK_BANG)) {
   1172     KitCgTypeId ty = toy_parse_expr_unary(p);
   1173     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1174     if (p->tail_call_expr) {
   1175       toy_error(p, p->cur.loc, "tail @call must be returned directly");
   1176       return KIT_CG_TYPE_NONE;
   1177     }
   1178     if (!toy_type_is_intlike(p, ty)) {
   1179       toy_error(p, p->cur.loc, "invalid operand for '!'");
   1180       return KIT_CG_TYPE_NONE;
   1181     }
   1182     kit_cg_int_unop(p->cg, KIT_CG_INT_NOT, 0);
   1183     return ty;
   1184   }
   1185 
   1186   if (toy_parser_match(p, TOK_TILDE)) {
   1187     KitCgTypeId ty = toy_parse_expr_unary(p);
   1188     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1189     if (p->tail_call_expr) {
   1190       toy_error(p, p->cur.loc, "tail @call must be returned directly");
   1191       return KIT_CG_TYPE_NONE;
   1192     }
   1193     if (!toy_type_is_intlike(p, ty)) {
   1194       toy_error(p, p->cur.loc, "invalid operand for '~'");
   1195       return KIT_CG_TYPE_NONE;
   1196     }
   1197     kit_cg_int_unop(p->cg, KIT_CG_INT_BNOT, 0);
   1198     return ty;
   1199   }
   1200 
   1201   if (toy_parser_match(p, TOK_AMPERSAND)) {
   1202     KitSym name;
   1203     KitCgTypeId ty;
   1204     if (p->cur.kind != TOK_IDENT) {
   1205       toy_error(p, p->cur.loc, "expected identifier after '&'");
   1206       return KIT_CG_TYPE_NONE;
   1207     }
   1208     name = toy_tok_sym(p, p->cur);
   1209     toy_parser_advance(p);
   1210 
   1211     if (p->cur.kind == TOK_LBRACKET || p->cur.kind == TOK_DOTSTAR ||
   1212         p->cur.kind == TOK_DOT) {
   1213       /* `&expr` chain. Maintain the invariant that TOS holds a
   1214        * pointer-rvalue of type *ty. The chain returns a pointer-rvalue
   1215        * directly (no trailing kit_cg_addr needed). */
   1216       ToyTypeId ty_toy = TOY_TYPE_NONE;
   1217       {
   1218         ToyVar* v = toy_find_var(p, name);
   1219         ToyGlobal* g = toy_find_global(p, name);
   1220         if (v) {
   1221           toy_push_var_addr(p, v);
   1222           ty = v->type;
   1223           ty_toy = v->toy_type;
   1224         } else if (g) {
   1225           kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
   1226           ty = g->type;
   1227           ty_toy = g->toy_type;
   1228         } else {
   1229           ty = KIT_CG_TYPE_NONE;
   1230         }
   1231       }
   1232       if (ty == KIT_CG_TYPE_NONE) {
   1233         toy_error(p, p->cur.loc, "undefined variable");
   1234         return KIT_CG_TYPE_NONE;
   1235       }
   1236       for (;;) {
   1237         if (toy_parser_match(p, TOK_LBRACKET)) {
   1238           KitCgTypeId idx_ty = toy_parse_expr(p);
   1239           if (idx_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1240           if (!toy_type_can_implicitly_cast(p, idx_ty, p->size_type)) {
   1241             toy_error(p, p->cur.loc, "index must be isize");
   1242             return KIT_CG_TYPE_NONE;
   1243           }
   1244           if (!toy_emit_implicit_cast(p, idx_ty, p->size_type))
   1245             return KIT_CG_TYPE_NONE;
   1246           idx_ty = p->size_type;
   1247           if (!toy_parser_expect(p, TOK_RBRACKET)) {
   1248             toy_error(p, p->cur.loc, "expected ']' after index");
   1249             return KIT_CG_TYPE_NONE;
   1250           }
   1251           if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR) {
   1252             KitCgTypeId pointee = kit_cg_type_ptr_pointee(p->c, ty);
   1253             /* TOS holds **T_chain; load the inner pointer first. */
   1254             {
   1255               KitCgLocal idx_slot =
   1256                   kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0));
   1257               kit_cg_push_local(p->cg, idx_slot);
   1258               kit_cg_swap(p->cg);
   1259               kit_cg_store(p->cg, toy_mem_access(p, p->size_type));
   1260               /* TOS is the chain pointer VALUE (**T); deref to a PLACE and
   1261                * load the inner pointer it addresses. */
   1262               kit_cg_deref(p->cg, 0);
   1263               kit_cg_load(p->cg, toy_mem_access(p, ty));
   1264               kit_cg_push_local(p->cg, idx_slot);
   1265               kit_cg_load(p->cg, toy_mem_access(p, p->size_type));
   1266             }
   1267             if (kit_cg_type_kind(p->c, pointee) == KIT_CG_TYPE_ARRAY) {
   1268               KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, pointee);
   1269               ty = elem_ty;
   1270               ty_toy = toy_type_array_elem(p, toy_type_pointee(p, ty_toy));
   1271               toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
   1272                              kit_cg_type_ptr(p->c, elem_ty, 0));
   1273             } else {
   1274               ty = pointee;
   1275               ty_toy = toy_type_pointee(p, ty_toy);
   1276               toy_addr_index(p, kit_cg_type_size(p->c, ty),
   1277                              kit_cg_type_ptr(p->c, ty, 0));
   1278             }
   1279           } else if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_ARRAY) {
   1280             KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, ty);
   1281             ty = elem_ty;
   1282             ty_toy = toy_type_array_elem(p, ty_toy);
   1283             toy_addr_index(p, kit_cg_type_size(p->c, elem_ty),
   1284                            kit_cg_type_ptr(p->c, elem_ty, 0));
   1285           } else if (toy_type_is_slice(p, ty_toy)) {
   1286             ToyTypeId elem_toy = TOY_TYPE_NONE;
   1287             ty = toy_emit_slice_index_lvalue(p, ty, ty_toy, &elem_toy);
   1288             if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1289             ty_toy = elem_toy;
   1290           } else {
   1291             toy_error(p, p->cur.loc, "cannot index non-array/non-pointer");
   1292             return KIT_CG_TYPE_NONE;
   1293           }
   1294           continue;
   1295         }
   1296         if (toy_parser_match(p, TOK_DOTSTAR)) {
   1297           if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_PTR) {
   1298             toy_error(p, p->cur.loc, "cannot dereference non-pointer");
   1299             return KIT_CG_TYPE_NONE;
   1300           }
   1301           /* TOS = **T (pointer VALUE); deref to PLACE and load to TOS = *T. */
   1302           kit_cg_deref(p->cg, 0);
   1303           kit_cg_load(p->cg, toy_mem_access(p, ty));
   1304           ty = kit_cg_type_ptr_pointee(p->c, ty);
   1305           ty_toy = toy_type_pointee(p, ty_toy);
   1306           continue;
   1307         }
   1308         if (toy_parser_match(p, TOK_DOT)) {
   1309           KitCgFieldLayout field;
   1310           uint32_t field_index = 0;
   1311           uint64_t foff = 0;
   1312           ToyNamedType* named;
   1313           if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR &&
   1314               kit_cg_type_kind(p->c, kit_cg_type_ptr_pointee(p->c, ty)) ==
   1315                   KIT_CG_TYPE_RECORD) {
   1316             /* TOS = **Rec (pointer VALUE); deref to PLACE and load to *Rec. */
   1317             kit_cg_deref(p->cg, 0);
   1318             kit_cg_load(p->cg, toy_mem_access(p, ty));
   1319             ty = kit_cg_type_ptr_pointee(p->c, ty);
   1320             ty_toy = toy_type_pointee(p, ty_toy);
   1321           }
   1322           if (kit_cg_type_kind(p->c, ty) != KIT_CG_TYPE_RECORD) {
   1323             toy_error(p, p->cur.loc, "field access on non-record");
   1324             return KIT_CG_TYPE_NONE;
   1325           }
   1326           named = toy_find_named_type_by_type(p, ty);
   1327           if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) {
   1328             const KitCgRecordLayout* L = kit_cg_type_record_layout(p->c, ty);
   1329             if (!L || p->cur.int_value < 0 ||
   1330                 p->cur.int_value >= (int64_t)L->nfields) {
   1331               toy_error(p, p->cur.loc, "invalid tuple field");
   1332               return KIT_CG_TYPE_NONE;
   1333             }
   1334             field_index = (uint32_t)p->cur.int_value;
   1335             toy_parser_advance(p);
   1336             field = L->fields[field_index];
   1337             foff = field.offset;
   1338           } else {
   1339             KitSym field_name;
   1340             if (p->cur.kind != TOK_IDENT) {
   1341               toy_error(p, p->cur.loc, "expected field name");
   1342               return KIT_CG_TYPE_NONE;
   1343             }
   1344             field_name = toy_tok_sym(p, p->cur);
   1345             toy_parser_advance(p);
   1346             if (!toy_record_field_index(p, ty, field_name, &field_index,
   1347                                         &field)) {
   1348               toy_error(p, p->cur.loc, "unknown record field");
   1349               return KIT_CG_TYPE_NONE;
   1350             }
   1351             foff = field.offset;
   1352           }
   1353           ty = field.type;
   1354           ty_toy = (named && field_index < named->nfields)
   1355                        ? named->fields[field_index].toy_type
   1356                        : toy_type_from_cg(p, ty);
   1357           toy_addr_offset(p, (int64_t)foff, kit_cg_type_ptr(p->c, ty, 0));
   1358           continue;
   1359         }
   1360         break;
   1361       }
   1362       /* TOS already holds a pointer-rvalue of type *ty. */
   1363       {
   1364         KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, ty, 0);
   1365         p->last_type = toy_type_register_ptr(
   1366             p, ptr_ty,
   1367             ty_toy != TOY_TYPE_NONE ? ty_toy : toy_type_from_cg(p, ty), 0);
   1368         return ptr_ty;
   1369       }
   1370     }
   1371 
   1372     {
   1373       ToyVar* v = toy_find_var(p, name);
   1374       if (v) {
   1375         KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, v->type, 0);
   1376         toy_push_var_addr(p, v);
   1377         p->last_type = toy_type_register_ptr(p, ptr_ty, v->toy_type, 0);
   1378         return ptr_ty;
   1379       } else {
   1380         ToyGlobal* g = toy_find_global(p, name);
   1381         if (g) {
   1382           KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, g->type, 0);
   1383           kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0);
   1384           p->last_type = toy_type_register_ptr(p, ptr_ty, g->toy_type, 0);
   1385           return ptr_ty;
   1386         } else {
   1387           ToyFn* fn = toy_find_fn(p, name);
   1388           if (fn) {
   1389             KitCgTypeId ptr_ty = kit_cg_type_ptr(p->c, fn->type, 0);
   1390             kit_cg_push_symbol_addr(p->cg, toy_fn_cur_sym(p, fn), 0);
   1391             p->last_type = toy_type_register_ptr(p, ptr_ty, fn->toy_type, 0);
   1392             return ptr_ty;
   1393           }
   1394         }
   1395         toy_error(p, p->cur.loc, "undefined variable");
   1396         return KIT_CG_TYPE_NONE;
   1397       }
   1398     }
   1399   }
   1400 
   1401   return toy_parse_expr_postfix(p);
   1402 }
   1403 
   1404 static KitCgTypeId toy_parse_expr_cast(ToyParser* p) {
   1405   KitCgTypeId ty = toy_parse_expr_unary(p);
   1406   while (ty != KIT_CG_TYPE_NONE && !p->tail_call_expr &&
   1407          toy_parser_match(p, TOK_AS)) {
   1408     KitCgTypeId dst = toy_parse_type(p);
   1409     if (dst == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1410     if (!toy_emit_cast(p, ty, dst)) return KIT_CG_TYPE_NONE;
   1411     ty = dst;
   1412   }
   1413   return ty;
   1414 }
   1415 
   1416 static KitCgTypeId toy_parse_expr_mul(ToyParser* p) {
   1417   KitCgTypeId ty = toy_parse_expr_cast(p);
   1418   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1419   while (p->cur.kind == TOK_STAR || p->cur.kind == TOK_SLASH ||
   1420          p->cur.kind == TOK_PERCENT) {
   1421     if (p->tail_call_expr) break;
   1422     ToyTokenKind op = p->cur.kind;
   1423     KitCgIntBinOp binop;
   1424     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_ARITH))
   1425       return KIT_CG_TYPE_NONE;
   1426     toy_parser_advance(p);
   1427     KitCgTypeId ty2 = toy_parse_expr_cast(p);
   1428     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1429     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1430     if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) {
   1431       if (!toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1432         toy_error(p, p->cur.loc,
   1433                   "arithmetic operands must have same numeric type");
   1434         return KIT_CG_TYPE_NONE;
   1435       }
   1436     } else if (ty != ty2 || !toy_type_is_float(p, ty)) {
   1437       toy_error(p, p->cur.loc,
   1438                 "arithmetic operands must have same numeric type");
   1439       return KIT_CG_TYPE_NONE;
   1440     }
   1441     if (toy_type_is_float(p, ty)) {
   1442       KitCgFpBinOp fp_op;
   1443       if (op == TOK_PERCENT) {
   1444         toy_error(p, p->cur.loc, "floating-point remainder is unsupported");
   1445         return KIT_CG_TYPE_NONE;
   1446       }
   1447       switch (op) {
   1448         case TOK_STAR:
   1449           fp_op = KIT_CG_FP_MUL;
   1450           break;
   1451         case TOK_SLASH:
   1452           fp_op = KIT_CG_FP_DIV;
   1453           break;
   1454         default:
   1455           return KIT_CG_TYPE_NONE;
   1456       }
   1457       kit_cg_fp_binop(p->cg, fp_op, 0);
   1458     } else {
   1459       switch (op) {
   1460         case TOK_STAR:
   1461           binop = KIT_CG_INT_MUL;
   1462           break;
   1463         case TOK_SLASH:
   1464           binop = KIT_CG_INT_SDIV;
   1465           break;
   1466         case TOK_PERCENT:
   1467           binop = KIT_CG_INT_SREM;
   1468           break;
   1469         default:
   1470           return KIT_CG_TYPE_NONE;
   1471       }
   1472       kit_cg_int_binop(p->cg, binop, 0);
   1473     }
   1474     toy_note_cg_result_type(p, ty);
   1475   }
   1476   return ty;
   1477 }
   1478 
   1479 static KitCgTypeId toy_parse_expr_add(ToyParser* p) {
   1480   KitCgTypeId ty = toy_parse_expr_mul(p);
   1481   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1482   while (p->cur.kind == TOK_PLUS || p->cur.kind == TOK_MINUS) {
   1483     if (p->tail_call_expr) break;
   1484     ToyTokenKind op = p->cur.kind;
   1485     KitCgIntBinOp binop = (op == TOK_PLUS) ? KIT_CG_INT_ADD : KIT_CG_INT_SUB;
   1486     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_ARITH))
   1487       return KIT_CG_TYPE_NONE;
   1488     toy_parser_advance(p);
   1489     KitCgTypeId ty2 = toy_parse_expr_mul(p);
   1490     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1491     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1492     if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) {
   1493       if (!toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1494         toy_error(p, p->cur.loc,
   1495                   "arithmetic operands must have same numeric type");
   1496         return KIT_CG_TYPE_NONE;
   1497       }
   1498     } else if (ty != ty2 || !toy_type_is_float(p, ty)) {
   1499       toy_error(p, p->cur.loc,
   1500                 "arithmetic operands must have same numeric type");
   1501       return KIT_CG_TYPE_NONE;
   1502     }
   1503     if (toy_type_is_float(p, ty)) {
   1504       kit_cg_fp_binop(p->cg, op == TOK_PLUS ? KIT_CG_FP_ADD : KIT_CG_FP_SUB, 0);
   1505     } else {
   1506       kit_cg_int_binop(p->cg, binop, 0);
   1507     }
   1508     toy_note_cg_result_type(p, ty);
   1509   }
   1510   return ty;
   1511 }
   1512 
   1513 static KitCgTypeId toy_parse_expr_cmp(ToyParser* p) {
   1514   KitCgTypeId ty = toy_parse_expr_add(p);
   1515   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1516   if (!p->tail_call_expr && (p->cur.kind == TOK_EQEQ || p->cur.kind == TOK_NE ||
   1517                              p->cur.kind == TOK_LT || p->cur.kind == TOK_GT ||
   1518                              p->cur.kind == TOK_LE || p->cur.kind == TOK_GE)) {
   1519     ToyTokenKind op = p->cur.kind;
   1520     KitCgIntCmpOp cmp;
   1521     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_CMP)) return KIT_CG_TYPE_NONE;
   1522     toy_parser_advance(p);
   1523     KitCgTypeId ty2 = toy_parse_expr_add(p);
   1524     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1525     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1526     if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) {
   1527       if (!toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1528         toy_error(p, p->cur.loc, "comparison operands must have same type");
   1529         return KIT_CG_TYPE_NONE;
   1530       }
   1531     } else if (ty != ty2) {
   1532       toy_error(p, p->cur.loc, "comparison operands must have same type");
   1533       return KIT_CG_TYPE_NONE;
   1534     }
   1535     if (toy_type_is_float(p, ty)) {
   1536       KitCgFpCmpOp fp_cmp;
   1537       switch (op) {
   1538         case TOK_EQEQ:
   1539           fp_cmp = KIT_CG_FP_OEQ;
   1540           break;
   1541         case TOK_NE:
   1542           /* `!=` on floats is unordered not-equal (true on NaN), not ONE. */
   1543           fp_cmp = KIT_CG_FP_UNE;
   1544           break;
   1545         case TOK_LT:
   1546           fp_cmp = KIT_CG_FP_OLT;
   1547           break;
   1548         case TOK_GT:
   1549           fp_cmp = KIT_CG_FP_OGT;
   1550           break;
   1551         case TOK_LE:
   1552           fp_cmp = KIT_CG_FP_OLE;
   1553           break;
   1554         case TOK_GE:
   1555           fp_cmp = KIT_CG_FP_OGE;
   1556           break;
   1557         default:
   1558           return KIT_CG_TYPE_NONE;
   1559       }
   1560       kit_cg_fp_cmp(p->cg, fp_cmp);
   1561     } else if (toy_type_is_intlike(p, ty) || toy_type_is_ptr(p, ty)) {
   1562       switch (op) {
   1563         case TOK_EQEQ:
   1564           cmp = KIT_CG_INT_EQ;
   1565           break;
   1566         case TOK_NE:
   1567           cmp = KIT_CG_INT_NE;
   1568           break;
   1569         case TOK_LT:
   1570           cmp = KIT_CG_INT_LT_S;
   1571           break;
   1572         case TOK_GT:
   1573           cmp = KIT_CG_INT_GT_S;
   1574           break;
   1575         case TOK_LE:
   1576           cmp = KIT_CG_INT_LE_S;
   1577           break;
   1578         case TOK_GE:
   1579           cmp = KIT_CG_INT_GE_S;
   1580           break;
   1581         default:
   1582           return KIT_CG_TYPE_NONE;
   1583       }
   1584       kit_cg_int_cmp(p->cg, cmp);
   1585     } else {
   1586       toy_error(p, p->cur.loc, "comparison operands must be scalar");
   1587       return KIT_CG_TYPE_NONE;
   1588     }
   1589     kit_cg_zext(p->cg, p->int_type);
   1590     ty = p->int_type;
   1591     toy_note_cg_result_type(p, ty);
   1592   }
   1593   return ty;
   1594 }
   1595 
   1596 static KitCgTypeId toy_parse_expr_shift(ToyParser* p) {
   1597   KitCgTypeId ty = toy_parse_expr_cmp(p);
   1598   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1599   while (p->cur.kind == TOK_SHL || p->cur.kind == TOK_SHR) {
   1600     if (p->tail_call_expr) break;
   1601     ToyTokenKind op = p->cur.kind;
   1602     KitCgIntBinOp binop = (op == TOK_SHL) ? KIT_CG_INT_SHL : KIT_CG_INT_ASHR;
   1603     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_SHIFT))
   1604       return KIT_CG_TYPE_NONE;
   1605     toy_parser_advance(p);
   1606     KitCgTypeId ty2 = toy_parse_expr_cmp(p);
   1607     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1608     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1609     if (!toy_type_is_promotable_int(p, ty) ||
   1610         !toy_type_is_promotable_int(p, ty2) ||
   1611         !toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1612       toy_error(p, p->cur.loc, "shift operands must be int");
   1613       return KIT_CG_TYPE_NONE;
   1614     }
   1615     kit_cg_int_binop(p->cg, binop, 0);
   1616     toy_note_cg_result_type(p, ty);
   1617   }
   1618   return ty;
   1619 }
   1620 
   1621 static KitCgTypeId toy_parse_expr_band(ToyParser* p) {
   1622   KitCgTypeId ty = toy_parse_expr_shift(p);
   1623   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1624   while (p->cur.kind == TOK_AMPERSAND) {
   1625     if (p->tail_call_expr) break;
   1626     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_BIT_AND))
   1627       return KIT_CG_TYPE_NONE;
   1628     toy_parser_advance(p);
   1629     KitCgTypeId ty2 = toy_parse_expr_shift(p);
   1630     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1631     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1632     if (!toy_type_is_promotable_int(p, ty) ||
   1633         !toy_type_is_promotable_int(p, ty2) ||
   1634         !toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1635       toy_error(p, p->cur.loc, "bitwise operands must be int");
   1636       return KIT_CG_TYPE_NONE;
   1637     }
   1638     kit_cg_int_binop(p->cg, KIT_CG_INT_AND, 0);
   1639     toy_note_cg_result_type(p, ty);
   1640   }
   1641   return ty;
   1642 }
   1643 
   1644 static KitCgTypeId toy_parse_expr_bxor(ToyParser* p) {
   1645   KitCgTypeId ty = toy_parse_expr_band(p);
   1646   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1647   while (p->cur.kind == TOK_CARET) {
   1648     if (p->tail_call_expr) break;
   1649     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_BIT_XOR))
   1650       return KIT_CG_TYPE_NONE;
   1651     toy_parser_advance(p);
   1652     KitCgTypeId ty2 = toy_parse_expr_band(p);
   1653     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1654     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1655     if (!toy_type_is_promotable_int(p, ty) ||
   1656         !toy_type_is_promotable_int(p, ty2) ||
   1657         !toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1658       toy_error(p, p->cur.loc, "bitwise operands must be int");
   1659       return KIT_CG_TYPE_NONE;
   1660     }
   1661     kit_cg_int_binop(p->cg, KIT_CG_INT_XOR, 0);
   1662     toy_note_cg_result_type(p, ty);
   1663   }
   1664   return ty;
   1665 }
   1666 
   1667 static KitCgTypeId toy_parse_expr_bor(ToyParser* p) {
   1668   KitCgTypeId ty = toy_parse_expr_bxor(p);
   1669   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1670   while (p->cur.kind == TOK_PIPE) {
   1671     if (p->tail_call_expr) break;
   1672     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_BIT_OR))
   1673       return KIT_CG_TYPE_NONE;
   1674     toy_parser_advance(p);
   1675     KitCgTypeId ty2 = toy_parse_expr_bxor(p);
   1676     if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1677     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1678     if (!toy_type_is_promotable_int(p, ty) ||
   1679         !toy_type_is_promotable_int(p, ty2) ||
   1680         !toy_promote_binary_int_operands(p, &ty, &ty2)) {
   1681       toy_error(p, p->cur.loc, "bitwise operands must be int");
   1682       return KIT_CG_TYPE_NONE;
   1683     }
   1684     kit_cg_int_binop(p->cg, KIT_CG_INT_OR, 0);
   1685     toy_note_cg_result_type(p, ty);
   1686   }
   1687   return ty;
   1688 }
   1689 
   1690 static KitCgTypeId toy_parse_expr_and(ToyParser* p) {
   1691   KitCgTypeId ty = toy_parse_expr_bor(p);
   1692   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1693   while (p->cur.kind == TOK_AND) {
   1694     if (p->tail_call_expr) break;
   1695     KitCgTypeId bool_ty = toy_builtin_type(p, KIT_CG_BUILTIN_BOOL);
   1696     KitCgLabel false_label;
   1697     KitCgLabel end_label;
   1698     KitCgLocal result_slot;
   1699     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_LOGIC_AND))
   1700       return KIT_CG_TYPE_NONE;
   1701     toy_parser_advance(p);
   1702     false_label = kit_cg_label_new(p->cg);
   1703     end_label = kit_cg_label_new(p->cg);
   1704     result_slot = kit_cg_local(p->cg, bool_ty, toy_slot_attrs(0));
   1705     if (!toy_emit_truthy(p, ty)) return KIT_CG_TYPE_NONE;
   1706     kit_cg_branch_false(p->cg, false_label);
   1707     ty = toy_parse_expr_bor(p);
   1708     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1709     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1710     if (!toy_emit_truthy(p, ty)) return KIT_CG_TYPE_NONE;
   1711     kit_cg_branch_false(p->cg, false_label);
   1712     kit_cg_push_local(p->cg, result_slot);
   1713     kit_cg_push_int(p->cg, 1, bool_ty);
   1714     kit_cg_store(p->cg, toy_mem_access(p, bool_ty));
   1715     kit_cg_jump(p->cg, end_label);
   1716     kit_cg_label_place(p->cg, false_label);
   1717     kit_cg_push_local(p->cg, result_slot);
   1718     kit_cg_push_int(p->cg, 0, bool_ty);
   1719     kit_cg_store(p->cg, toy_mem_access(p, bool_ty));
   1720     kit_cg_label_place(p->cg, end_label);
   1721     kit_cg_push_local(p->cg, result_slot);
   1722     kit_cg_load(p->cg, toy_mem_access(p, bool_ty));
   1723     ty = bool_ty;
   1724     toy_note_cg_result_type(p, ty);
   1725   }
   1726   return ty;
   1727 }
   1728 
   1729 static KitCgTypeId toy_parse_expr_or(ToyParser* p) {
   1730   KitCgTypeId ty = toy_parse_expr_and(p);
   1731   if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1732   while (p->cur.kind == TOK_OR) {
   1733     if (p->tail_call_expr) break;
   1734     KitCgTypeId bool_ty = toy_builtin_type(p, KIT_CG_BUILTIN_BOOL);
   1735     KitCgLabel true_label;
   1736     KitCgLabel end_label;
   1737     KitCgLocal result_slot;
   1738     if (!toy_note_expr_island(p, TOY_EXPR_ISLAND_LOGIC_OR))
   1739       return KIT_CG_TYPE_NONE;
   1740     toy_parser_advance(p);
   1741     true_label = kit_cg_label_new(p->cg);
   1742     end_label = kit_cg_label_new(p->cg);
   1743     result_slot = kit_cg_local(p->cg, bool_ty, toy_slot_attrs(0));
   1744     if (!toy_emit_truthy(p, ty)) return KIT_CG_TYPE_NONE;
   1745     kit_cg_branch_true(p->cg, true_label);
   1746     ty = toy_parse_expr_and(p);
   1747     if (ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE;
   1748     if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE;
   1749     if (!toy_emit_truthy(p, ty)) return KIT_CG_TYPE_NONE;
   1750     kit_cg_branch_true(p->cg, true_label);
   1751     kit_cg_push_local(p->cg, result_slot);
   1752     kit_cg_push_int(p->cg, 0, bool_ty);
   1753     kit_cg_store(p->cg, toy_mem_access(p, bool_ty));
   1754     kit_cg_jump(p->cg, end_label);
   1755     kit_cg_label_place(p->cg, true_label);
   1756     kit_cg_push_local(p->cg, result_slot);
   1757     kit_cg_push_int(p->cg, 1, bool_ty);
   1758     kit_cg_store(p->cg, toy_mem_access(p, bool_ty));
   1759     kit_cg_label_place(p->cg, end_label);
   1760     kit_cg_push_local(p->cg, result_slot);
   1761     kit_cg_load(p->cg, toy_mem_access(p, bool_ty));
   1762     ty = bool_ty;
   1763     toy_note_cg_result_type(p, ty);
   1764   }
   1765   return ty;
   1766 }
   1767 
   1768 KitCgTypeId toy_parse_expr(ToyParser* p) {
   1769   uint32_t saved_island_mask = p->expr_island_mask;
   1770   KitCgTypeId ty;
   1771   p->expr_island_mask = 0;
   1772   ty = toy_parse_expr_or(p);
   1773   if (ty != KIT_CG_TYPE_NONE &&
   1774       (p->cur.kind == TOK_ANDAND || p->cur.kind == TOK_PIPEPIPE)) {
   1775     toy_error(p, p->cur.loc,
   1776               "legacy logical operator is unsupported; use 'and' or 'or'");
   1777     ty = KIT_CG_TYPE_NONE;
   1778   }
   1779   p->expr_island_mask = saved_island_mask;
   1780   return ty;
   1781 }