kit

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

wat.c (74847B)


      1 #include <kit/source.h>
      2 
      3 #include "wasm/wasm.h"
      4 #include "wasm/wasm_insn_table.h"
      5 
      6 typedef struct WasmTok {
      7   const char* p;
      8   size_t len;
      9   uint32_t line;
     10   uint32_t col;
     11   uint8_t kind;
     12 } WasmTok;
     13 
     14 enum {
     15   WT_EOF = 0,
     16   WT_LPAREN,
     17   WT_RPAREN,
     18   WT_ATOM,
     19   WT_STRING,
     20 };
     21 
     22 /* One entry in the parser's lexical label scope. A block/loop/if pushes its
     23  * optional `$name` (a borrowed slice into the source text; NULL for anonymous
     24  * blocks); the matching end/close pops it. br/br_if/br_table resolve a `$name`
     25  * operand to the relative depth (0 = innermost enclosing). */
     26 typedef struct WatLabel {
     27   const char* name; /* NULL for an anonymous (unnamed) block */
     28   size_t name_len;
     29 } WatLabel;
     30 
     31 typedef struct WatParser {
     32   KitCompiler* c;
     33   const char* name;
     34   const char* src;
     35   size_t len;
     36   size_t pos;
     37   uint32_t line;
     38   uint32_t col;
     39   WasmTok tok;
     40   KitSrcLoc field_loc;
     41   WasmModule* module;
     42   /* Heap-grown label scope stack (no fixed cap, hangs off the parser). The
     43    * top of the stack is the innermost enclosing block, i.e. branch depth 0. */
     44   WatLabel* labels;
     45   uint32_t nlabels;
     46   uint32_t cap_labels;
     47 } WatParser;
     48 
     49 static KitSrcLoc wat_loc(WatParser* p, uint32_t line, uint32_t col) {
     50   KitSrcLoc loc = wasm_loc(line, col);
     51   if (p && p->module) loc.file_id = p->module->file_id;
     52   return loc;
     53 }
     54 
     55 static KitSrcLoc wat_tok_loc(WatParser* p, WasmTok t) {
     56   return wat_loc(p, t.line, t.col);
     57 }
     58 
     59 static int tok_is(WasmTok t, const char* s) {
     60   size_t n = kit_slice_cstr(s).len;
     61   return t.kind == WT_ATOM && t.len == n && memcmp(t.p, s, n) == 0;
     62 }
     63 
     64 static int wasm_name_eq(const char* name, WasmTok t) {
     65   size_t n;
     66   if (!name || t.kind != WT_ATOM) return 0;
     67   n = kit_slice_cstr(name).len;
     68   return t.len == n && memcmp(name, t.p, n) == 0;
     69 }
     70 
     71 static int wat_hex(char ch) {
     72   if (ch >= '0' && ch <= '9') return ch - '0';
     73   if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
     74   if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10;
     75   return -1;
     76 }
     77 
     78 static char* wat_dup_string(WatParser* p, WasmTok t, size_t* len_out) {
     79   char* out;
     80   size_t i, n = 0;
     81   if (t.kind != WT_STRING)
     82     wasm_error(p->c, wasm_loc(t.line, t.col), "wasm wat: expected string");
     83   out = (char*)p->module->heap->alloc(p->module->heap, t.len + 1u, 1);
     84   if (!out) wasm_error(p->c, wasm_loc(t.line, t.col), "wasm: out of memory");
     85   for (i = 0; i < t.len; ++i) {
     86     char ch = t.p[i];
     87     if (ch != '\\') {
     88       out[n++] = ch;
     89       continue;
     90     }
     91     if (++i >= t.len)
     92       wasm_error(p->c, wasm_loc(t.line, t.col),
     93                  "wasm wat: unterminated string escape");
     94     ch = t.p[i];
     95     switch (ch) {
     96       case 'n':
     97         out[n++] = '\n';
     98         break;
     99       case 'r':
    100         out[n++] = '\r';
    101         break;
    102       case 't':
    103         out[n++] = '\t';
    104         break;
    105       case '"':
    106       case '\'':
    107       case '\\':
    108         out[n++] = ch;
    109         break;
    110       default: {
    111         int hi = wat_hex(ch);
    112         int lo = (i + 1u < t.len) ? wat_hex(t.p[i + 1u]) : -1;
    113         if (hi < 0 || lo < 0)
    114           wasm_error(p->c, wasm_loc(t.line, t.col),
    115                      "wasm wat: unsupported string escape");
    116         out[n++] = (char)((hi << 4) | lo);
    117         i++;
    118         break;
    119       }
    120     }
    121   }
    122   out[n] = '\0';
    123   if (len_out) *len_out = n;
    124   return out;
    125 }
    126 
    127 static char* wat_dup_atom(WatParser* p, WasmTok t) {
    128   char* out = wasm_strdup(p->module->heap, t.p, t.len);
    129   if (!out) wasm_error(p->c, wasm_loc(t.line, t.col), "wasm: out of memory");
    130   return out;
    131 }
    132 
    133 static void wat_next(WatParser* p) {
    134   const char* s = p->src;
    135   while (p->pos < p->len) {
    136     char ch = s[p->pos];
    137     if (ch == '\n') {
    138       p->pos++;
    139       p->line++;
    140       p->col = 1;
    141       continue;
    142     }
    143     if (ch == ' ' || ch == '\t' || ch == '\r') {
    144       p->pos++;
    145       p->col++;
    146       continue;
    147     }
    148     if (ch == ';' && p->pos + 1u < p->len && s[p->pos + 1u] == ';') {
    149       while (p->pos < p->len && s[p->pos] != '\n') {
    150         p->pos++;
    151         p->col++;
    152       }
    153       continue;
    154     }
    155     if (ch == '(' && p->pos + 1u < p->len && s[p->pos + 1u] == ';') {
    156       uint32_t depth = 1;
    157       p->pos += 2u;
    158       p->col += 2u;
    159       while (depth && p->pos < p->len) {
    160         if (s[p->pos] == '\n') {
    161           p->pos++;
    162           p->line++;
    163           p->col = 1;
    164         } else if (s[p->pos] == '(' && p->pos + 1u < p->len &&
    165                    s[p->pos + 1u] == ';') {
    166           p->pos += 2u;
    167           p->col += 2u;
    168           depth++;
    169         } else if (s[p->pos] == ';' && p->pos + 1u < p->len &&
    170                    s[p->pos + 1u] == ')') {
    171           p->pos += 2u;
    172           p->col += 2u;
    173           depth--;
    174         } else {
    175           p->pos++;
    176           p->col++;
    177         }
    178       }
    179       if (depth)
    180         wasm_error(p->c, wasm_loc(p->line, p->col),
    181                    "wasm wat: unterminated block comment");
    182       continue;
    183     }
    184     break;
    185   }
    186   p->tok.p = s + p->pos;
    187   p->tok.len = 0;
    188   p->tok.line = p->line;
    189   p->tok.col = p->col;
    190   p->tok.kind = WT_EOF;
    191   if (p->pos >= p->len) return;
    192   if (s[p->pos] == '(') {
    193     p->tok.kind = WT_LPAREN;
    194     p->tok.len = 1;
    195     p->pos++;
    196     p->col++;
    197     return;
    198   }
    199   if (s[p->pos] == ')') {
    200     p->tok.kind = WT_RPAREN;
    201     p->tok.len = 1;
    202     p->pos++;
    203     p->col++;
    204     return;
    205   }
    206   if (s[p->pos] == '"') {
    207     size_t start = ++p->pos;
    208     p->col++;
    209     p->tok.kind = WT_STRING;
    210     p->tok.p = s + start;
    211     while (p->pos < p->len && s[p->pos] != '"') {
    212       if (s[p->pos] == '\\') {
    213         p->pos++;
    214         p->col++;
    215         if (p->pos >= p->len) break;
    216       } else if ((unsigned char)s[p->pos] < 0x20) {
    217         wasm_error(p->c, wasm_loc(p->line, p->col),
    218                    "wasm wat: unsupported string escape/control character");
    219       }
    220       p->pos++;
    221       p->col++;
    222     }
    223     if (p->pos >= p->len)
    224       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    225                  "wasm wat: unterminated string");
    226     p->tok.len = (size_t)(s + p->pos - p->tok.p);
    227     p->pos++;
    228     p->col++;
    229     return;
    230   }
    231   p->tok.kind = WT_ATOM;
    232   while (p->pos < p->len) {
    233     char ch = s[p->pos];
    234     if (ch == '(' || ch == ')' || ch == ' ' || ch == '\t' || ch == '\r' ||
    235         ch == '\n')
    236       break;
    237     p->pos++;
    238     p->col++;
    239   }
    240   p->tok.len = (size_t)(s + p->pos - p->tok.p);
    241 }
    242 
    243 static void wat_expect(WatParser* p, uint8_t kind, const char* what) {
    244   if (p->tok.kind != kind)
    245     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    246                "wasm wat: expected %.*s", KIT_SLICE_ARG(kit_slice_cstr(what)));
    247   wat_next(p);
    248 }
    249 
    250 static int wat_parse_i64(WatParser* p, int64_t* out) {
    251   const char* s = p->tok.p;
    252   size_t n = p->tok.len, i = 0;
    253   uint64_t v = 0;
    254   int neg = 0;
    255   unsigned base = 10;
    256   if (p->tok.kind != WT_ATOM || n == 0) return 0;
    257   if (s[0] == '-' || s[0] == '+') {
    258     neg = s[0] == '-';
    259     i = 1;
    260   }
    261   if (i + 2u <= n && s[i] == '0' && (s[i + 1u] == 'x' || s[i + 1u] == 'X')) {
    262     base = 16;
    263     i += 2u;
    264   }
    265   if (i == n) return 0;
    266   for (; i < n; ++i) {
    267     int hd;
    268     unsigned d;
    269     if (s[i] == '_') continue;
    270     hd = wat_hex(s[i]);
    271     if (hd < 0 || (unsigned)hd >= base) return 0;
    272     d = (unsigned)hd;
    273     if (v > (UINT64_MAX - d) / base) return 0;
    274     v = v * base + d;
    275   }
    276   *out = neg ? -(int64_t)v : (int64_t)v;
    277   return 1;
    278 }
    279 
    280 static int wat_parse_f64(WatParser* p, double* out) {
    281   char buf[128];
    282   char* end = NULL;
    283   if (p->tok.kind != WT_ATOM || p->tok.len == 0 || p->tok.len >= sizeof buf)
    284     return 0;
    285   memcpy(buf, p->tok.p, p->tok.len);
    286   buf[p->tok.len] = '\0';
    287   *out = strtod(buf, &end);
    288   return end && *end == '\0';
    289 }
    290 
    291 static int wat_val_type(WasmTok t, WasmValType* out) {
    292   if (tok_is(t, "i32")) {
    293     *out = WASM_VAL_I32;
    294     return 1;
    295   }
    296   if (tok_is(t, "i64")) {
    297     *out = WASM_VAL_I64;
    298     return 1;
    299   }
    300   if (tok_is(t, "f32")) {
    301     *out = WASM_VAL_F32;
    302     return 1;
    303   }
    304   if (tok_is(t, "f64")) {
    305     *out = WASM_VAL_F64;
    306     return 1;
    307   }
    308   if (tok_is(t, "funcref")) {
    309     *out = WASM_VAL_FUNCREF;
    310     return 1;
    311   }
    312   if (tok_is(t, "externref")) {
    313     *out = WASM_VAL_EXTERNREF;
    314     return 1;
    315   }
    316   return 0;
    317 }
    318 
    319 static void wat_require_feature(WatParser* p, WasmFeatureSet feature,
    320                                 const char* feature_name, const char* what) {
    321   if (!wasm_feature_enabled(p->module, feature))
    322     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    323                "wasm wat: %.*s requires %.*s",
    324                KIT_SLICE_ARG(kit_slice_cstr(what)),
    325                KIT_SLICE_ARG(kit_slice_cstr(feature_name)));
    326 }
    327 
    328 static uint8_t wasm_export_kind_from_tok(WasmTok t) {
    329   if (tok_is(t, "func")) return 0;
    330   if (tok_is(t, "table")) return 1;
    331   if (tok_is(t, "memory")) return 2;
    332   if (tok_is(t, "global")) return 3;
    333   return 0xffu;
    334 }
    335 
    336 static void wat_skip_list(WatParser* p) {
    337   uint32_t depth = 1;
    338   while (depth && p->tok.kind != WT_EOF) {
    339     if (p->tok.kind == WT_LPAREN)
    340       depth++;
    341     else if (p->tok.kind == WT_RPAREN)
    342       depth--;
    343     wat_next(p);
    344   }
    345 }
    346 
    347 /* A handful of mnemonics have legacy spellings that map to the same kind as
    348  * their canonical WASM_INSN_TABLE name; the table carries only the canonical
    349  * spelling, so these aliases are checked separately. */
    350 static const struct {
    351   const char* mnemonic;
    352   WasmInsnKind kind;
    353 } WAT_INSN_ALIASES[] = {
    354     {"i32.atomic.wait", WASM_INSN_I32_ATOMIC_WAIT},
    355     {"i64.atomic.wait", WASM_INSN_I64_ATOMIC_WAIT},
    356     {"atomic.notify", WASM_INSN_MEMORY_ATOMIC_NOTIFY},
    357 };
    358 
    359 /* Resolve a WAT mnemonic token to its instruction kind via a linear scan over
    360  * the single WASM_INSN_TABLE map (same set, same semantics as the former
    361  * 200-arm strcmp chain), plus a tiny alias list. `has_imm` reflects whether the
    362  * grammar parses one trailing immediate token, derived from the operand
    363  * class. */
    364 static int wat_instr_kind(WasmTok t, WasmInsnKind* out, int* has_imm) {
    365   *has_imm = 0;
    366   if (t.kind != WT_ATOM) return 0;
    367   for (WasmInsnKind k = 0; k <= WASM_INSN_TABLE_FILL; ++k) {
    368     const WasmInsnInfo* info = wasm_insn_info(k);
    369     if (!info) continue;
    370     if (tok_is(t, info->mnemonic)) {
    371       *out = k;
    372       *has_imm =
    373           wasm_operand_class_has_imm((WasmOperandClass)info->operand_class);
    374       return 1;
    375     }
    376   }
    377   for (size_t i = 0; i < sizeof(WAT_INSN_ALIASES) / sizeof(WAT_INSN_ALIASES[0]);
    378        ++i) {
    379     if (tok_is(t, WAT_INSN_ALIASES[i].mnemonic)) {
    380       const WasmInsnInfo* info = wasm_insn_info(WAT_INSN_ALIASES[i].kind);
    381       *out = WAT_INSN_ALIASES[i].kind;
    382       *has_imm = info && wasm_operand_class_has_imm(
    383                              (WasmOperandClass)info->operand_class);
    384       return 1;
    385     }
    386   }
    387   return 0;
    388 }
    389 
    390 /* Push a block/loop/if onto the lexical label scope. `name`/`name_len` borrow
    391  * a `$name` slice from the source text (NULL for an anonymous block). The
    392  * stack grows on demand off the parser; it is never shrunk below 0 and is
    393  * popped in lockstep with WASM_INSN_END emission. */
    394 static void wat_label_push(WatParser* p, const char* name, size_t name_len) {
    395   KitHeap* h = p->module->heap;
    396   if (p->nlabels == p->cap_labels) {
    397     uint32_t nc = p->cap_labels ? p->cap_labels * 2u : 8u;
    398     WatLabel* nl = (WatLabel*)wasm_realloc(h, p->labels,
    399                                            sizeof(WatLabel) * p->cap_labels,
    400                                            sizeof(WatLabel) * nc);
    401     if (!nl) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: oom");
    402     p->labels = nl;
    403     p->cap_labels = nc;
    404   }
    405   p->labels[p->nlabels].name = name;
    406   p->labels[p->nlabels].name_len = name_len;
    407   p->nlabels++;
    408 }
    409 
    410 static void wat_label_pop(WatParser* p) {
    411   if (p->nlabels) p->nlabels--;
    412 }
    413 
    414 /* Resolve a branch operand to a relative depth. A `$name` token is matched
    415  * against the enclosing label scope (innermost = 0); a numeric token is taken
    416  * literally. Fatal on an unknown name or a malformed immediate. */
    417 static void wat_parse_branch_depth(WatParser* p, int64_t* out) {
    418   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
    419     uint32_t i;
    420     for (i = 0; i < p->nlabels; ++i) {
    421       const WatLabel* l = &p->labels[p->nlabels - 1u - i];
    422       if (l->name && l->name_len == p->tok.len &&
    423           memcmp(l->name, p->tok.p, p->tok.len) == 0) {
    424         *out = (int64_t)i;
    425         return;
    426       }
    427     }
    428     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    429                "wasm wat: unknown label name");
    430   }
    431   if (!wat_parse_i64(p, out) || *out < 0)
    432     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    433                "wasm wat: expected branch depth");
    434 }
    435 
    436 static void wat_parse_func_index(WatParser* p, int64_t* out) {
    437   uint32_t i;
    438   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
    439     for (i = 0; i < p->module->nfuncs; ++i) {
    440       if (wasm_name_eq(p->module->funcs[i].name, p->tok)) {
    441         *out = i;
    442         return;
    443       }
    444     }
    445     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    446                "wasm wat: unknown function name");
    447   }
    448   if (!wat_parse_i64(p, out))
    449     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    450                "wasm wat: expected instruction immediate");
    451 }
    452 
    453 static void wat_parse_type_index(WatParser* p, int64_t* out) {
    454   uint32_t i;
    455   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
    456     for (i = 0; i < p->module->ntypes; ++i) {
    457       if (wasm_name_eq(p->module->types[i].name, p->tok)) {
    458         *out = i;
    459         return;
    460       }
    461     }
    462     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    463                "wasm wat: unknown type name");
    464   }
    465   if (!wat_parse_i64(p, out))
    466     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    467                "wasm wat: expected type index");
    468 }
    469 
    470 static void wat_parse_local_index(WatParser* p, WasmFunc* f, int64_t* out) {
    471   uint32_t i, nlocals = f->nparams + f->nlocals;
    472   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
    473     for (i = 0; i < nlocals; ++i) {
    474       if (wasm_name_eq(f->local_names[i], p->tok)) {
    475         *out = i;
    476         return;
    477       }
    478     }
    479     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    480                "wasm wat: unknown local name");
    481   }
    482   if (!wat_parse_i64(p, out))
    483     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    484                "wasm wat: expected instruction immediate");
    485 }
    486 
    487 static void wat_parse_global_index(WatParser* p, int64_t* out) {
    488   uint32_t i;
    489   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
    490     for (i = 0; i < p->module->nglobals; ++i) {
    491       if (wasm_name_eq(p->module->globals[i].name, p->tok)) {
    492         *out = i;
    493         return;
    494       }
    495     }
    496     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    497                "wasm wat: unknown global name");
    498   }
    499   if (!wat_parse_i64(p, out))
    500     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    501                "wasm wat: expected global index");
    502 }
    503 
    504 static void wat_parse_instr_imm(WatParser* p, WasmFunc* f, WasmInsnKind kind,
    505                                 int64_t* out) {
    506   switch (kind) {
    507     case WASM_INSN_CALL:
    508     case WASM_INSN_RETURN_CALL:
    509       wat_parse_func_index(p, out);
    510       break;
    511     case WASM_INSN_GLOBAL_GET:
    512     case WASM_INSN_GLOBAL_SET:
    513       wat_parse_global_index(p, out);
    514       break;
    515     case WASM_INSN_LOCAL_GET:
    516     case WASM_INSN_LOCAL_SET:
    517     case WASM_INSN_LOCAL_TEE:
    518       wat_parse_local_index(p, f, out);
    519       break;
    520     case WASM_INSN_BR:
    521     case WASM_INSN_BR_IF:
    522       wat_parse_branch_depth(p, out);
    523       break;
    524     default:
    525       if (!wat_parse_i64(p, out))
    526         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    527                    "wasm wat: expected instruction immediate");
    528       break;
    529   }
    530 }
    531 
    532 static int wat_atom_prefix(WasmTok t, const char* prefix) {
    533   size_t n = kit_slice_cstr(prefix).len;
    534   return t.kind == WT_ATOM && t.len >= n && memcmp(t.p, prefix, n) == 0;
    535 }
    536 
    537 static int wat_parse_u32_atom(WasmTok t, uint32_t* out) {
    538   uint64_t v = 0;
    539   size_t i = 0;
    540   unsigned base = 10;
    541   if (t.kind != WT_ATOM || t.len == 0) return 0;
    542   if (i + 2u <= t.len && t.p[i] == '0' &&
    543       (t.p[i + 1u] == 'x' || t.p[i + 1u] == 'X')) {
    544     base = 16;
    545     i += 2u;
    546   }
    547   if (i == t.len) return 0;
    548   for (; i < t.len; ++i) {
    549     int hd;
    550     if (t.p[i] == '_') continue;
    551     hd = wat_hex(t.p[i]);
    552     if (hd < 0 || (unsigned)hd >= base) return 0;
    553     if (v > (UINT32_MAX - (uint32_t)hd) / base) return 0;
    554     v = v * base + (uint32_t)hd;
    555   }
    556   *out = (uint32_t)v;
    557   return 1;
    558 }
    559 
    560 static int wat_parse_mem_align_log2(WasmTok t, uint32_t* out) {
    561   uint32_t bytes;
    562   uint32_t lg = 0;
    563   if (!wat_parse_u32_atom(t, &bytes) || bytes == 0u) return 0;
    564   if (bytes & (bytes - 1u)) return 0;
    565   while (bytes > 1u) {
    566     bytes >>= 1u;
    567     lg++;
    568   }
    569   *out = lg;
    570   return 1;
    571 }
    572 
    573 static int wat_parse_u64_atom(WasmTok t, uint64_t* out) {
    574   uint64_t v = 0;
    575   size_t i = 0;
    576   unsigned base = 10;
    577   if (t.kind != WT_ATOM || t.len == 0) return 0;
    578   if (i + 2u <= t.len && t.p[i] == '0' &&
    579       (t.p[i + 1u] == 'x' || t.p[i + 1u] == 'X')) {
    580     base = 16;
    581     i += 2u;
    582   }
    583   if (i == t.len) return 0;
    584   for (; i < t.len; ++i) {
    585     int hd;
    586     if (t.p[i] == '_') continue;
    587     hd = wat_hex(t.p[i]);
    588     if (hd < 0 || (unsigned)hd >= base) return 0;
    589     if (v > (UINT64_MAX - (uint64_t)hd) / base) return 0;
    590     v = v * base + (uint64_t)hd;
    591   }
    592   *out = v;
    593   return 1;
    594 }
    595 
    596 static void wat_parse_memory_index(WatParser* p, uint32_t* out) {
    597   uint32_t i;
    598   int64_t idx;
    599   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
    600     for (i = 0; i < p->module->nmemories; ++i) {
    601       if (wasm_name_eq(p->module->memories[i].name, p->tok)) {
    602         *out = i;
    603         return;
    604       }
    605     }
    606     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    607                "wasm wat: unknown memory name");
    608   }
    609   if (!wat_parse_i64(p, &idx) || idx < 0 || idx > UINT32_MAX)
    610     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    611                "wasm wat: expected memory index");
    612   *out = (uint32_t)idx;
    613 }
    614 
    615 static void wat_parse_mem_attrs(WatParser* p, uint32_t* align, uint64_t* offset,
    616                                 uint32_t* memidx) {
    617   while (p->tok.kind == WT_ATOM) {
    618     WasmTok val;
    619     if (wat_atom_prefix(p->tok, "align=")) {
    620       val = p->tok;
    621       val.p += 6;
    622       val.len -= 6;
    623       if (!wat_parse_mem_align_log2(val, align))
    624         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    625                    "wasm wat: bad memory alignment");
    626       wat_next(p);
    627     } else if (wat_atom_prefix(p->tok, "offset=")) {
    628       val = p->tok;
    629       val.p += 7;
    630       val.len -= 7;
    631       if (!wat_parse_u64_atom(val, offset))
    632         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    633                    "wasm wat: bad memory offset");
    634       wat_next(p);
    635     } else if (wat_atom_prefix(p->tok, "memory=")) {
    636       val = p->tok;
    637       val.p += 7;
    638       val.len -= 7;
    639       if (!wat_parse_u32_atom(val, memidx))
    640         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    641                    "wasm wat: bad memory index");
    642       wat_next(p);
    643     } else if (wat_atom_prefix(p->tok, "mem=")) {
    644       val = p->tok;
    645       val.p += 4;
    646       val.len -= 4;
    647       if (!wat_parse_u32_atom(val, memidx))
    648         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    649                    "wasm wat: bad memory index");
    650       wat_next(p);
    651     } else {
    652       break;
    653     }
    654   }
    655 }
    656 
    657 /* Re-synthesize the current token as a '(' that was just consumed via
    658  * wat_next(), rewinding the lexer to just after it. Used when a one-token
    659  * lookahead past a '(' did not match the expected keyword and the '(' must be
    660  * handed to a nested instruction parse. Mirrors the inline idiom used
    661  * throughout this file. */
    662 static void wat_unget_to_lparen(WatParser* p, size_t lparen_pos,
    663                                 uint32_t lparen_line, uint32_t lparen_col) {
    664   p->pos = lparen_pos;
    665   p->line = lparen_line;
    666   p->col = lparen_col;
    667   p->tok.kind = WT_LPAREN;
    668   p->tok.p = p->src + p->pos - 1u;
    669   p->tok.len = 1;
    670   p->tok.line = lparen_line;
    671   p->tok.col = lparen_col - 1u;
    672 }
    673 
    674 /* Parse an optional `$label` for a block/loop/if header, pushing it onto the
    675  * label scope (anonymous push when absent). Returns nothing; the keyword has
    676  * already been consumed. */
    677 static void wat_block_push_label(WatParser* p) {
    678   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
    679     const char* nm = p->tok.p;
    680     size_t nlen = p->tok.len;
    681     wat_next(p);
    682     wat_label_push(p, nm, nlen);
    683   } else {
    684     wat_label_push(p, NULL, 0);
    685   }
    686 }
    687 
    688 /* The resolved blocktype of a block/loop/if header: either the void/single-
    689  * result shorthand (is_typeidx == 0; `result` is the value type, 0 == void) or
    690  * a function-type index (is_typeidx == 1; the multi-value form carrying block
    691  * params and/or multiple results). wat_parse_blocktype_apply stamps it onto a
    692  * freshly-added instruction. */
    693 typedef struct WatBlockType {
    694   int is_typeidx;
    695   uint32_t typeidx;
    696   WasmValType result;
    697 } WatBlockType;
    698 
    699 #define WAT_BLOCKTYPE_MAX 64u
    700 
    701 /* Parse an optional structured-control blocktype that follows a block/loop/if
    702  * header (after the label): `(type idx)? (param valtype*)* (result valtype*)*`.
    703  * The fidelity rule mirrors the binary blocktype: void or a single-`(result)`
    704  * with no params stays the scalar shorthand; any param or a second result (or
    705  * an explicit `(type idx)`) resolves to a function-type index, interned into
    706  * the type section when not named directly. `what` names the construct for
    707  * diagnostics. */
    708 static WatBlockType wat_parse_blocktype(WatParser* p, const char* what) {
    709   WatBlockType bt;
    710   WasmFunc sig;
    711   WasmValType pbuf[WAT_BLOCKTYPE_MAX];
    712   WasmValType rbuf[WAT_BLOCKTYPE_MAX];
    713   int64_t explicit_typeidx = -1;
    714   memset(&bt, 0, sizeof bt);
    715   memset(&sig, 0, sizeof sig);
    716   sig.params = pbuf;
    717   sig.cap_params = WAT_BLOCKTYPE_MAX;
    718   sig.results = rbuf;
    719   sig.cap_results = WAT_BLOCKTYPE_MAX;
    720   while (p->tok.kind == WT_LPAREN) {
    721     size_t lp = p->pos;
    722     uint32_t ll = p->line, lc = p->col;
    723     wat_next(p);
    724     if (tok_is(p->tok, "type")) {
    725       wat_next(p);
    726       wat_parse_type_index(p, &explicit_typeidx);
    727       if (explicit_typeidx < 0 ||
    728           (uint64_t)explicit_typeidx >= p->module->ntypes)
    729         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    730                    "wasm wat: %.*s blocktype type index out of range",
    731                    KIT_SLICE_ARG(kit_slice_cstr(what)));
    732       wat_next(p);
    733       wat_expect(p, WT_RPAREN, "')'");
    734     } else if (tok_is(p->tok, "param")) {
    735       wat_next(p);
    736       while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
    737         WasmValType vt;
    738         if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
    739           wat_next(p);
    740           continue;
    741         }
    742         if (!wat_val_type(p->tok, &vt) || !wasm_is_frontend_value_type(vt))
    743           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    744                      "wasm wat: unsupported %.*s param type",
    745                      KIT_SLICE_ARG(kit_slice_cstr(what)));
    746         if (sig.nparams >= WAT_BLOCKTYPE_MAX)
    747           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    748                      "wasm wat: too many %.*s blocktype params",
    749                      KIT_SLICE_ARG(kit_slice_cstr(what)));
    750         sig.params[sig.nparams++] = vt;
    751         wat_next(p);
    752       }
    753       wat_expect(p, WT_RPAREN, "')'");
    754     } else if (tok_is(p->tok, "result")) {
    755       wat_next(p);
    756       while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
    757         WasmValType vt;
    758         if (!wat_val_type(p->tok, &vt) || !wasm_is_frontend_value_type(vt))
    759           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    760                      "wasm wat: unsupported %.*s result type",
    761                      KIT_SLICE_ARG(kit_slice_cstr(what)));
    762         if (sig.nresults >= WAT_BLOCKTYPE_MAX)
    763           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    764                      "wasm wat: too many %.*s blocktype results",
    765                      KIT_SLICE_ARG(kit_slice_cstr(what)));
    766         sig.results[sig.nresults++] = vt;
    767         wat_next(p);
    768       }
    769       wat_expect(p, WT_RPAREN, "')'");
    770     } else {
    771       /* Not a blocktype clause — hand the '(' back to the body parser. */
    772       wat_unget_to_lparen(p, lp, ll, lc);
    773       break;
    774     }
    775   }
    776   if (explicit_typeidx >= 0) {
    777     const WasmFuncType* t = &p->module->types[explicit_typeidx];
    778     /* If param/result clauses also appear, they must match the named type. */
    779     if ((sig.nparams || sig.nresults) &&
    780         (sig.nparams != t->nparams || sig.nresults != t->nresults ||
    781          (sig.nparams &&
    782           memcmp(sig.params, t->params, sizeof(WasmValType) * sig.nparams)) ||
    783          (sig.nresults &&
    784           memcmp(sig.results, t->results, sizeof(WasmValType) * sig.nresults))))
    785       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    786                  "wasm wat: %.*s blocktype does not match named type",
    787                  KIT_SLICE_ARG(kit_slice_cstr(what)));
    788     bt.is_typeidx = 1;
    789     bt.typeidx = (uint32_t)explicit_typeidx;
    790     return bt;
    791   }
    792   /* Shorthand: no params and at most one result stays a scalar blocktype for
    793    * round-trip fidelity; anything richer interns a function type. */
    794   if (sig.nparams == 0 && sig.nresults <= 1) {
    795     bt.result = sig.nresults ? sig.results[0] : 0;
    796     return bt;
    797   }
    798   bt.is_typeidx = 1;
    799   bt.typeidx = wasm_intern_func_type(p->c, p->module, &sig);
    800   return bt;
    801 }
    802 
    803 /* Stamp a parsed blocktype onto the most-recently-added instruction `in`. */
    804 static void wat_parse_blocktype_apply(WasmInsn* in, WatBlockType bt) {
    805   if (bt.is_typeidx)
    806     wasm_insn_set_blocktype_typeidx(in, bt.typeidx);
    807   else
    808     in->type = (uint8_t)bt.result;
    809 }
    810 
    811 static void wat_parse_instr(WatParser* p, WasmFunc* f);
    812 
    813 static void wat_check_instr_feature(WatParser* p, WasmInsnKind kind) {
    814   if (kind == WASM_INSN_RETURN_CALL || kind == WASM_INSN_RETURN_CALL_INDIRECT ||
    815       kind == WASM_INSN_RETURN_CALL_REF)
    816     wat_require_feature(p, WASM_FEATURE_TAIL_CALLS, "tail calls",
    817                         "tail-call instruction");
    818   if (kind == WASM_INSN_REF_NULL || kind == WASM_INSN_REF_FUNC ||
    819       kind == WASM_INSN_REF_IS_NULL || kind == WASM_INSN_CALL_REF ||
    820       kind == WASM_INSN_RETURN_CALL_REF)
    821     wat_require_feature(p, WASM_FEATURE_TYPED_FUNC_REFS,
    822                         "typed function references",
    823                         "typed-reference instruction");
    824   if (kind == WASM_INSN_ATOMIC_FENCE || wasm_insn_is_atomic_mem(kind))
    825     wat_require_feature(p, WASM_FEATURE_THREADS, "threads",
    826                         "atomic instruction");
    827 }
    828 
    829 static uint32_t wat_parse_call_indirect_type(WatParser* p) {
    830   int64_t typeidx;
    831   wat_expect(p, WT_LPAREN, "'('");
    832   if (!tok_is(p->tok, "type"))
    833     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    834                "wasm wat: expected call_indirect type");
    835   wat_next(p);
    836   wat_parse_type_index(p, &typeidx);
    837   if (typeidx < 0 || (uint64_t)typeidx >= p->module->ntypes)
    838     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    839                "wasm wat: type index out of range");
    840   wat_next(p);
    841   wat_expect(p, WT_RPAREN, "')'");
    842   return (uint32_t)typeidx;
    843 }
    844 
    845 static void wat_parse_ref_null_type(WatParser* p, int64_t* out) {
    846   if (tok_is(p->tok, "func") || tok_is(p->tok, "nofunc") ||
    847       tok_is(p->tok, "funcref")) {
    848     *out = WASM_VAL_FUNCREF;
    849     return;
    850   }
    851   if (tok_is(p->tok, "extern") || tok_is(p->tok, "noextern") ||
    852       tok_is(p->tok, "externref")) {
    853     *out = WASM_VAL_EXTERNREF;
    854     return;
    855   }
    856   wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
    857              "wasm wat: expected reference type");
    858 }
    859 
    860 /* True for bulk-memory and table.* ops whose WAT form takes one or two
    861  * index immediates rather than a memarg. */
    862 static int wat_is_bulk_op(WasmInsnKind k) {
    863   switch (k) {
    864     case WASM_INSN_MEMORY_INIT:
    865     case WASM_INSN_DATA_DROP:
    866     case WASM_INSN_MEMORY_COPY:
    867     case WASM_INSN_MEMORY_FILL:
    868     case WASM_INSN_TABLE_INIT:
    869     case WASM_INSN_ELEM_DROP:
    870     case WASM_INSN_TABLE_COPY:
    871     case WASM_INSN_TABLE_GROW:
    872     case WASM_INSN_TABLE_SIZE:
    873     case WASM_INSN_TABLE_FILL:
    874       return 1;
    875     default:
    876       return 0;
    877   }
    878 }
    879 
    880 /* Optionally parse a uleb-style index immediate. Accepts:
    881  *   - a numeric literal (any base/sign accepted by wat_parse_i64)
    882  *   - a `$name` resolved against the segment lookup callback `resolver`,
    883  *     which returns 1 with the resolved index in *out on success.
    884  * Returns 0 if the token isn't a recognizable immediate. */
    885 typedef int (*WatNameResolver)(WatParser*, WasmTok name, uint32_t* out);
    886 static int wat_try_parse_uleb_imm_named(WatParser* p, WatNameResolver resolver,
    887                                         uint32_t* out) {
    888   int64_t v;
    889   WasmInsnKind next_kind;
    890   int next_has_imm;
    891   if (p->tok.kind != WT_ATOM) return 0;
    892   if (p->tok.len && p->tok.p[0] == '$') {
    893     if (!resolver) return 0;
    894     if (!resolver(p, p->tok, out)) return 0;
    895     wat_next(p);
    896     return 1;
    897   }
    898   if (wat_instr_kind(p->tok, &next_kind, &next_has_imm)) return 0;
    899   if (!wat_parse_i64(p, &v) || v < 0 || v > UINT32_MAX) return 0;
    900   *out = (uint32_t)v;
    901   wat_next(p);
    902   return 1;
    903 }
    904 
    905 static int wat_resolve_data_name(WatParser* p, WasmTok name, uint32_t* out) {
    906   for (uint32_t i = 0; i < p->module->ndata; ++i) {
    907     if (wasm_name_eq(p->module->data[i].name, name)) {
    908       *out = i;
    909       return 1;
    910     }
    911   }
    912   return 0;
    913 }
    914 
    915 static int wat_resolve_elem_name(WatParser* p, WasmTok name, uint32_t* out) {
    916   for (uint32_t i = 0; i < p->module->nelems; ++i) {
    917     if (wasm_name_eq(p->module->elems[i].name, name)) {
    918       *out = i;
    919       return 1;
    920     }
    921   }
    922   return 0;
    923 }
    924 
    925 /* Emit a bulk-memory or table op, parsing 0..2 index immediates depending on
    926  * the kind. Caller has already consumed the opcode token. Named refs of the
    927  * form `$name` resolve against the appropriate segment table (data segments
    928  * for memory.init/data.drop, elem segments for table.init/elem.drop). */
    929 static void wat_emit_bulk_op(WatParser* p, WasmFunc* f, WasmInsnKind kind) {
    930   uint32_t a = 0, b = 0;
    931   int got_a, got_b;
    932   WatNameResolver primary = NULL;
    933   switch (kind) {
    934     case WASM_INSN_MEMORY_INIT:
    935     case WASM_INSN_DATA_DROP:
    936       primary = wat_resolve_data_name;
    937       break;
    938     case WASM_INSN_TABLE_INIT:
    939     case WASM_INSN_ELEM_DROP:
    940       primary = wat_resolve_elem_name;
    941       break;
    942     default:
    943       primary = NULL;
    944       break;
    945   }
    946   got_a = wat_try_parse_uleb_imm_named(p, primary, &a);
    947   got_b = wat_try_parse_uleb_imm_named(p, primary, &b);
    948   wasm_func_add_insn(p->c, p->module, f, kind, 0);
    949   switch (kind) {
    950     case WASM_INSN_MEMORY_INIT:
    951       /* memory.init [memidx] dataidx — single arg means dataidx, two args
    952        * is (memidx dataidx). */
    953       if (got_b) {
    954         f->insns[f->ninsns - 1u].memidx = a;
    955         f->insns[f->ninsns - 1u].imm = (int64_t)b;
    956       } else {
    957         f->insns[f->ninsns - 1u].memidx = 0;
    958         f->insns[f->ninsns - 1u].imm = (int64_t)a;
    959       }
    960       break;
    961     case WASM_INSN_DATA_DROP:
    962       f->insns[f->ninsns - 1u].imm = (int64_t)a;
    963       break;
    964     case WASM_INSN_MEMORY_COPY:
    965       /* memory.copy [dst src] — both default to 0. */
    966       f->insns[f->ninsns - 1u].memidx = got_a ? a : 0;
    967       f->insns[f->ninsns - 1u].aux_idx = got_b ? b : 0;
    968       break;
    969     case WASM_INSN_MEMORY_FILL:
    970       f->insns[f->ninsns - 1u].memidx = got_a ? a : 0;
    971       break;
    972     case WASM_INSN_TABLE_INIT:
    973       /* table.init [tableidx] elemidx. */
    974       if (got_b) {
    975         f->insns[f->ninsns - 1u].aux_idx = a;
    976         f->insns[f->ninsns - 1u].imm = (int64_t)b;
    977       } else {
    978         f->insns[f->ninsns - 1u].aux_idx = 0;
    979         f->insns[f->ninsns - 1u].imm = (int64_t)a;
    980       }
    981       break;
    982     case WASM_INSN_ELEM_DROP:
    983       f->insns[f->ninsns - 1u].imm = (int64_t)a;
    984       break;
    985     case WASM_INSN_TABLE_COPY:
    986       f->insns[f->ninsns - 1u].imm = (int64_t)(got_a ? a : 0);
    987       f->insns[f->ninsns - 1u].aux_idx = got_b ? b : 0;
    988       break;
    989     case WASM_INSN_TABLE_GROW:
    990     case WASM_INSN_TABLE_SIZE:
    991     case WASM_INSN_TABLE_FILL:
    992       f->insns[f->ninsns - 1u].imm = (int64_t)(got_a ? a : 0);
    993       break;
    994     default:
    995       break;
    996   }
    997 }
    998 
    999 static void wat_parse_instr_list(WatParser* p, WasmFunc* f) {
   1000   WasmInsnKind kind;
   1001   int has_imm;
   1002   int64_t imm = 0;
   1003   WasmTok head;
   1004   wat_expect(p, WT_LPAREN, "'('");
   1005   head = p->tok;
   1006   p->module->current_loc = wat_tok_loc(p, head);
   1007   if (tok_is(head, "block") || tok_is(head, "loop")) {
   1008     WatBlockType blockty;
   1009     kind = tok_is(head, "block") ? WASM_INSN_BLOCK : WASM_INSN_LOOP;
   1010     wat_next(p);
   1011     wat_block_push_label(p);
   1012     blockty = wat_parse_blocktype(p, tok_is(head, "block") ? "block" : "loop");
   1013     wasm_func_add_insn(p->c, p->module, f, kind, 0);
   1014     wat_parse_blocktype_apply(&f->insns[f->ninsns - 1u], blockty);
   1015     while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF)
   1016       wat_parse_instr(p, f);
   1017     wasm_func_add_insn(p->c, p->module, f, WASM_INSN_END, 0);
   1018     wat_label_pop(p);
   1019     wat_expect(p, WT_RPAREN, "')'");
   1020     return;
   1021   }
   1022   if (tok_is(head, "if")) {
   1023     WatBlockType blockty;
   1024     wat_next(p);
   1025     wat_block_push_label(p);
   1026     blockty = wat_parse_blocktype(p, "if");
   1027     while (p->tok.kind == WT_LPAREN) {
   1028       WasmTok save_head;
   1029       size_t save_pos = p->pos;
   1030       uint32_t save_line = p->line, save_col = p->col;
   1031       wat_next(p);
   1032       save_head = p->tok;
   1033       wat_unget_to_lparen(p, save_pos, save_line, save_col);
   1034       if (tok_is(save_head, "then") || tok_is(save_head, "else")) break;
   1035       wat_parse_instr(p, f);
   1036     }
   1037     wasm_func_add_insn(p->c, p->module, f, WASM_INSN_IF, 0);
   1038     wat_parse_blocktype_apply(&f->insns[f->ninsns - 1u], blockty);
   1039     if (p->tok.kind == WT_LPAREN) {
   1040       wat_next(p);
   1041       if (!tok_is(p->tok, "then"))
   1042         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1043                    "wasm wat: expected then");
   1044       wat_next(p);
   1045       while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF)
   1046         wat_parse_instr(p, f);
   1047       wat_expect(p, WT_RPAREN, "')'");
   1048     }
   1049     if (p->tok.kind == WT_LPAREN) {
   1050       wat_next(p);
   1051       if (!tok_is(p->tok, "else"))
   1052         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1053                    "wasm wat: expected else");
   1054       wasm_func_add_insn(p->c, p->module, f, WASM_INSN_ELSE, 0);
   1055       wat_next(p);
   1056       while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF)
   1057         wat_parse_instr(p, f);
   1058       wat_expect(p, WT_RPAREN, "')'");
   1059     }
   1060     wasm_func_add_insn(p->c, p->module, f, WASM_INSN_END, 0);
   1061     wat_label_pop(p);
   1062     wat_expect(p, WT_RPAREN, "')'");
   1063     return;
   1064   }
   1065   if (!wat_instr_kind(head, &kind, &has_imm))
   1066     wasm_error(p->c, wasm_loc(head.line, head.col),
   1067                "wasm wat: unsupported instruction");
   1068   wat_check_instr_feature(p, kind);
   1069   wat_next(p);
   1070   if (wasm_insn_is_mem(kind)) {
   1071     uint32_t align = 0, memidx = 0;
   1072     uint64_t offset = 0;
   1073     wat_parse_mem_attrs(p, &align, &offset, &memidx);
   1074     while (p->tok.kind == WT_LPAREN) {
   1075       wat_next(p);
   1076       if (tok_is(p->tok, "memory")) {
   1077         wat_next(p);
   1078         wat_parse_memory_index(p, &memidx);
   1079         wat_next(p);
   1080         wat_expect(p, WT_RPAREN, "')'");
   1081       } else {
   1082         p->pos = (size_t)(p->tok.p - p->src);
   1083         p->line = p->tok.line;
   1084         p->col = p->tok.col;
   1085         p->tok.kind = WT_LPAREN;
   1086         p->tok.p = p->src + p->pos - 1u;
   1087         p->tok.len = 1;
   1088         p->tok.line = p->line;
   1089         p->tok.col = p->col - 1u;
   1090         wat_parse_instr(p, f);
   1091       }
   1092     }
   1093     wasm_func_add_mem_insn(p->c, p->module, f, kind, align, offset, memidx);
   1094     wat_expect(p, WT_RPAREN, "')'");
   1095     return;
   1096   }
   1097   if (kind == WASM_INSN_BR_TABLE) {
   1098     KitHeap* heap = p->module->heap;
   1099     uint32_t n = 0, cap = 8u;
   1100     uint32_t* tmp = (uint32_t*)heap->alloc(heap, sizeof(uint32_t) * cap,
   1101                                            _Alignof(uint32_t));
   1102     if (!tmp)
   1103       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: oom");
   1104     while (p->tok.kind == WT_ATOM) {
   1105       int64_t target;
   1106       wat_parse_branch_depth(p, &target);
   1107       if (target > UINT32_MAX)
   1108         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1109                    "wasm wat: bad br_table target");
   1110       if (n == cap) {
   1111         uint32_t nc = cap * 2u;
   1112         tmp =
   1113             (uint32_t*)heap->realloc(heap, tmp, sizeof(uint32_t) * cap,
   1114                                      sizeof(uint32_t) * nc, _Alignof(uint32_t));
   1115         if (!tmp)
   1116           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: oom");
   1117         cap = nc;
   1118       }
   1119       tmp[n++] = (uint32_t)target;
   1120       wat_next(p);
   1121     }
   1122     wasm_func_add_insn(p->c, p->module, f, WASM_INSN_BR_TABLE, 0);
   1123     wasm_insn_set_targets(p->c, p->module, &f->insns[f->ninsns - 1u], tmp, n);
   1124     heap->free(heap, tmp, sizeof(uint32_t) * cap);
   1125     while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f);
   1126     wat_expect(p, WT_RPAREN, "')'");
   1127     return;
   1128   }
   1129   if (kind == WASM_INSN_CALL_INDIRECT ||
   1130       kind == WASM_INSN_RETURN_CALL_INDIRECT) {
   1131     uint32_t typeidx = wat_parse_call_indirect_type(p);
   1132     while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f);
   1133     wasm_func_add_insn(p->c, p->module, f, kind, typeidx);
   1134     wat_expect(p, WT_RPAREN, "')'");
   1135     return;
   1136   }
   1137   if (kind == WASM_INSN_CALL_REF || kind == WASM_INSN_RETURN_CALL_REF) {
   1138     uint32_t typeidx = wat_parse_call_indirect_type(p);
   1139     while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f);
   1140     wasm_func_add_insn(p->c, p->module, f, kind, typeidx);
   1141     wat_expect(p, WT_RPAREN, "')'");
   1142     return;
   1143   }
   1144   if (kind == WASM_INSN_REF_NULL) {
   1145     wat_parse_ref_null_type(p, &imm);
   1146     wat_next(p);
   1147     wasm_func_add_insn(p->c, p->module, f, kind, imm);
   1148     wat_expect(p, WT_RPAREN, "')'");
   1149     return;
   1150   }
   1151   if (kind == WASM_INSN_REF_FUNC) {
   1152     wat_parse_func_index(p, &imm);
   1153     wat_next(p);
   1154     wasm_func_add_insn(p->c, p->module, f, kind, imm);
   1155     wat_expect(p, WT_RPAREN, "')'");
   1156     return;
   1157   }
   1158   if (wat_is_bulk_op(kind)) {
   1159     wat_emit_bulk_op(p, f, kind);
   1160     while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f);
   1161     wat_expect(p, WT_RPAREN, "')'");
   1162     return;
   1163   }
   1164   if (kind == WASM_INSN_MEMORY_SIZE || kind == WASM_INSN_MEMORY_GROW) {
   1165     uint32_t memidx = 0;
   1166     while (p->tok.kind == WT_LPAREN) {
   1167       wat_next(p);
   1168       if (!tok_is(p->tok, "memory")) {
   1169         p->pos = (size_t)(p->tok.p - p->src);
   1170         p->line = p->tok.line;
   1171         p->col = p->tok.col;
   1172         p->tok.kind = WT_LPAREN;
   1173         p->tok.p = p->src + p->pos - 1u;
   1174         p->tok.len = 1;
   1175         p->tok.line = p->line;
   1176         p->tok.col = p->col - 1u;
   1177         wat_parse_instr(p, f);
   1178         continue;
   1179       }
   1180       wat_next(p);
   1181       wat_parse_memory_index(p, &memidx);
   1182       wat_next(p);
   1183       wat_expect(p, WT_RPAREN, "')'");
   1184     }
   1185     {
   1186       WasmInsnKind next_kind;
   1187       int next_has_imm;
   1188       if (p->tok.kind == WT_ATOM &&
   1189           !wat_instr_kind(p->tok, &next_kind, &next_has_imm)) {
   1190         wat_parse_memory_index(p, &memidx);
   1191         wat_next(p);
   1192       }
   1193     }
   1194     wasm_func_add_insn(p->c, p->module, f,
   1195                        kind == WASM_INSN_MEMORY_GROW ? WASM_INSN_MEMORY_GROW
   1196                                                      : WASM_INSN_MEMORY_SIZE,
   1197                        0);
   1198     f->insns[f->ninsns - 1u].memidx = memidx;
   1199     wat_expect(p, WT_RPAREN, "')'");
   1200     return;
   1201   }
   1202   if (has_imm) {
   1203     if (kind == WASM_INSN_F32_CONST || kind == WASM_INSN_F64_CONST) {
   1204       double fv;
   1205       if (!wat_parse_f64(p, &fv))
   1206         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1207                    "wasm wat: expected float immediate");
   1208       wat_next(p);
   1209       while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f);
   1210       wasm_func_add_fp_insn(p->c, p->module, f, kind, fv);
   1211       wat_expect(p, WT_RPAREN, "')'");
   1212       return;
   1213     } else {
   1214       wat_parse_instr_imm(p, f, kind, &imm);
   1215       wat_next(p);
   1216     }
   1217   }
   1218   while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f);
   1219   wasm_func_add_insn(p->c, p->module, f, kind, imm);
   1220   wat_expect(p, WT_RPAREN, "')'");
   1221 }
   1222 
   1223 static void wat_parse_instr(WatParser* p, WasmFunc* f) {
   1224   WasmInsnKind kind;
   1225   int has_imm;
   1226   if (p->tok.kind == WT_LPAREN) {
   1227     wat_parse_instr_list(p, f);
   1228     return;
   1229   }
   1230   if (!wat_instr_kind(p->tok, &kind, &has_imm))
   1231     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1232                "wasm wat: unsupported instruction");
   1233   p->module->current_loc = wat_tok_loc(p, p->tok);
   1234   wat_check_instr_feature(p, kind);
   1235   wat_next(p);
   1236   if (kind == WASM_INSN_BLOCK || kind == WASM_INSN_LOOP ||
   1237       kind == WASM_INSN_IF) {
   1238     /* Flat-form structured control: `block $l (result T) ... end`. Parse the
   1239      * optional label and blocktype, push the label scope, and record the
   1240      * resolved blocktype on the instruction. */
   1241     WatBlockType blockty;
   1242     wat_block_push_label(p);
   1243     blockty = wat_parse_blocktype(
   1244         p, kind == WASM_INSN_IF ? "if" : (kind == WASM_INSN_LOOP ? "loop"
   1245                                                                  : "block"));
   1246     wasm_func_add_insn(p->c, p->module, f, kind, 0);
   1247     wat_parse_blocktype_apply(&f->insns[f->ninsns - 1u], blockty);
   1248     return;
   1249   }
   1250   if (kind == WASM_INSN_END) {
   1251     wat_label_pop(p);
   1252     wasm_func_add_insn(p->c, p->module, f, kind, 0);
   1253     return;
   1254   }
   1255   if (wasm_insn_is_mem(kind)) {
   1256     uint32_t align = 0, memidx = 0;
   1257     uint64_t offset = 0;
   1258     wat_parse_mem_attrs(p, &align, &offset, &memidx);
   1259     wasm_func_add_mem_insn(p->c, p->module, f, kind, align, offset, memidx);
   1260     return;
   1261   }
   1262   if (kind == WASM_INSN_BR_TABLE) {
   1263     KitHeap* heap = p->module->heap;
   1264     uint32_t n = 0, cap = 8u;
   1265     uint32_t* tmp = (uint32_t*)heap->alloc(heap, sizeof(uint32_t) * cap,
   1266                                            _Alignof(uint32_t));
   1267     if (!tmp)
   1268       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: oom");
   1269     wasm_func_add_insn(p->c, p->module, f, WASM_INSN_BR_TABLE, 0);
   1270     while (p->tok.kind == WT_ATOM) {
   1271       WasmInsnKind next_kind;
   1272       int next_has_imm;
   1273       int64_t target;
   1274       int is_label = p->tok.len && p->tok.p[0] == '$';
   1275       if (!is_label && wat_instr_kind(p->tok, &next_kind, &next_has_imm)) break;
   1276       wat_parse_branch_depth(p, &target);
   1277       if (target > UINT32_MAX)
   1278         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1279                    "wasm wat: bad br_table target");
   1280       if (n == cap) {
   1281         uint32_t nc = cap * 2u;
   1282         tmp =
   1283             (uint32_t*)heap->realloc(heap, tmp, sizeof(uint32_t) * cap,
   1284                                      sizeof(uint32_t) * nc, _Alignof(uint32_t));
   1285         if (!tmp)
   1286           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: oom");
   1287         cap = nc;
   1288       }
   1289       tmp[n++] = (uint32_t)target;
   1290       wat_next(p);
   1291     }
   1292     wasm_insn_set_targets(p->c, p->module, &f->insns[f->ninsns - 1u], tmp, n);
   1293     heap->free(heap, tmp, sizeof(uint32_t) * cap);
   1294     return;
   1295   }
   1296   if (kind == WASM_INSN_CALL_INDIRECT ||
   1297       kind == WASM_INSN_RETURN_CALL_INDIRECT) {
   1298     uint32_t typeidx = wat_parse_call_indirect_type(p);
   1299     wasm_func_add_insn(p->c, p->module, f, kind, typeidx);
   1300     return;
   1301   }
   1302   if (kind == WASM_INSN_CALL_REF || kind == WASM_INSN_RETURN_CALL_REF) {
   1303     uint32_t typeidx = wat_parse_call_indirect_type(p);
   1304     wasm_func_add_insn(p->c, p->module, f, kind, typeidx);
   1305     return;
   1306   }
   1307   if (kind == WASM_INSN_REF_NULL) {
   1308     int64_t imm;
   1309     wat_parse_ref_null_type(p, &imm);
   1310     wasm_func_add_insn(p->c, p->module, f, kind, imm);
   1311     wat_next(p);
   1312     return;
   1313   }
   1314   if (kind == WASM_INSN_REF_FUNC) {
   1315     int64_t imm;
   1316     wat_parse_func_index(p, &imm);
   1317     wasm_func_add_insn(p->c, p->module, f, kind, imm);
   1318     wat_next(p);
   1319     return;
   1320   }
   1321   if (kind == WASM_INSN_MEMORY_SIZE || kind == WASM_INSN_MEMORY_GROW) {
   1322     uint32_t memidx = 0;
   1323     WasmInsnKind next_kind;
   1324     int next_has_imm;
   1325     if (p->tok.kind == WT_ATOM &&
   1326         !wat_instr_kind(p->tok, &next_kind, &next_has_imm)) {
   1327       wat_parse_memory_index(p, &memidx);
   1328       wat_next(p);
   1329     }
   1330     wasm_func_add_insn(p->c, p->module, f, kind, 0);
   1331     f->insns[f->ninsns - 1u].memidx = memidx;
   1332     return;
   1333   }
   1334   if (wat_is_bulk_op(kind)) {
   1335     wat_emit_bulk_op(p, f, kind);
   1336     return;
   1337   }
   1338   if (has_imm) {
   1339     if (kind == WASM_INSN_F32_CONST || kind == WASM_INSN_F64_CONST) {
   1340       double fv;
   1341       if (!wat_parse_f64(p, &fv))
   1342         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1343                    "wasm wat: expected float immediate");
   1344       wasm_func_add_fp_insn(p->c, p->module, f, kind, fv);
   1345       wat_next(p);
   1346     } else {
   1347       int64_t imm;
   1348       wat_parse_instr_imm(p, f, kind, &imm);
   1349       wasm_func_add_insn(p->c, p->module, f, kind, imm);
   1350       wat_next(p);
   1351     }
   1352   } else {
   1353     wasm_func_add_insn(p->c, p->module, f, kind, 0);
   1354   }
   1355 }
   1356 
   1357 static void wat_parse_func(WatParser* p) {
   1358   WasmFunc* f = wasm_add_func(p->c, p->module);
   1359   uint32_t checked_params = 0;
   1360   uint32_t checked_results = 0;
   1361   /* The label scope is per-function; a well-formed body balances its pushes
   1362    * and pops, but reset defensively so a malformed prior function can't leak
   1363    * stale labels into this one. */
   1364   p->nlabels = 0;
   1365   f->loc = p->field_loc;
   1366   wat_expect(p, WT_LPAREN, "'('");
   1367   if (!tok_is(p->tok, "func"))
   1368     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1369                "wasm wat: expected func");
   1370   wat_next(p);
   1371   if (p->tok.kind == WT_ATOM && p->tok.len > 0 && p->tok.p[0] == '$') {
   1372     f->name = wat_dup_atom(p, p->tok);
   1373     wat_next(p);
   1374   }
   1375   while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1376     if (p->tok.kind == WT_LPAREN) {
   1377       wat_next(p);
   1378       if (tok_is(p->tok, "export")) {
   1379         wat_next(p);
   1380         if (p->tok.kind != WT_STRING)
   1381           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1382                      "wasm wat: expected export string");
   1383         f->export_name = wat_dup_string(p, p->tok, NULL);
   1384         {
   1385           WasmExport* ex = wasm_add_export(p->c, p->module);
   1386           ex->name = wasm_strdup(p->module->heap, f->export_name,
   1387                                  kit_slice_cstr(f->export_name).len);
   1388           if (!ex->name)
   1389             wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1390                        "wasm: out of memory");
   1391           ex->kind = 0;
   1392           ex->index = p->module->nfuncs - 1u;
   1393         }
   1394         wat_next(p);
   1395         wat_expect(p, WT_RPAREN, "')'");
   1396       } else if (tok_is(p->tok, "type")) {
   1397         int64_t typeidx;
   1398         wat_next(p);
   1399         wat_parse_type_index(p, &typeidx);
   1400         if (typeidx < 0 || (uint64_t)typeidx >= p->module->ntypes)
   1401           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1402                      "wasm wat: type index out of range");
   1403         f->typeidx = (uint32_t)typeidx;
   1404         f->has_typeidx = 1;
   1405         wasm_func_set_params(p->c, p->module, f,
   1406                              p->module->types[typeidx].params,
   1407                              p->module->types[typeidx].nparams);
   1408         wasm_func_set_results(p->c, p->module, f,
   1409                               p->module->types[typeidx].results,
   1410                               p->module->types[typeidx].nresults);
   1411         wat_next(p);
   1412         wat_expect(p, WT_RPAREN, "')'");
   1413       } else if (tok_is(p->tok, "param")) {
   1414         WasmTok pending_name;
   1415         int have_name = 0;
   1416         memset(&pending_name, 0, sizeof pending_name);
   1417         wat_next(p);
   1418         while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1419           WasmValType vt;
   1420           if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1421             pending_name = p->tok;
   1422             have_name = 1;
   1423             wat_next(p);
   1424             continue;
   1425           }
   1426           if (!wat_val_type(p->tok, &vt))
   1427             wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1428                        "wasm wat: expected parameter type");
   1429           if (!wasm_is_frontend_value_type(vt))
   1430             wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1431                        "wasm wat: unsupported parameter type");
   1432           if (f->has_typeidx) {
   1433             if (checked_params >= f->nparams || f->params[checked_params] != vt)
   1434               wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1435                          "wasm wat: parameter does not match type");
   1436             if (have_name) {
   1437               wasm_func_set_local_name(p->c, p->module, f, checked_params,
   1438                                        pending_name.p, pending_name.len);
   1439               have_name = 0;
   1440             }
   1441             checked_params++;
   1442             wat_next(p);
   1443             continue;
   1444           }
   1445           if (have_name) {
   1446             wasm_func_set_local_name(p->c, p->module, f, f->nparams,
   1447                                      pending_name.p, pending_name.len);
   1448             have_name = 0;
   1449           }
   1450           wasm_func_push_param(p->c, p->module, f, vt);
   1451           wat_next(p);
   1452         }
   1453         wat_expect(p, WT_RPAREN, "')'");
   1454       } else if (tok_is(p->tok, "result")) {
   1455         wat_next(p);
   1456         while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1457           WasmValType vt;
   1458           if (!wat_val_type(p->tok, &vt))
   1459             wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1460                        "wasm wat: expected result type");
   1461           if (!wasm_is_frontend_value_type(vt))
   1462             wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1463                        "wasm wat: unsupported result type");
   1464           if (f->has_typeidx) {
   1465             if (checked_results >= f->nresults ||
   1466                 f->results[checked_results] != vt)
   1467               wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1468                          "wasm wat: result does not match type");
   1469             checked_results++;
   1470           } else {
   1471             wasm_func_push_result(p->c, p->module, f, vt);
   1472           }
   1473           wat_next(p);
   1474         }
   1475         wat_expect(p, WT_RPAREN, "')'");
   1476       } else if (tok_is(p->tok, "local")) {
   1477         WasmTok pending_name;
   1478         int have_name = 0;
   1479         memset(&pending_name, 0, sizeof pending_name);
   1480         wat_next(p);
   1481         while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1482           WasmValType vt;
   1483           if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1484             pending_name = p->tok;
   1485             have_name = 1;
   1486             wat_next(p);
   1487             continue;
   1488           }
   1489           if (!wat_val_type(p->tok, &vt))
   1490             wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1491                        "wasm wat: expected local type");
   1492           if (have_name) {
   1493             uint32_t index = f->nparams + f->nlocals;
   1494             wasm_func_set_local_name(p->c, p->module, f, index, pending_name.p,
   1495                                      pending_name.len);
   1496             have_name = 0;
   1497           }
   1498           wasm_func_push_local(p->c, p->module, f, vt);
   1499           wat_next(p);
   1500         }
   1501         wat_expect(p, WT_RPAREN, "')'");
   1502       } else {
   1503         p->pos = (size_t)(p->tok.p - p->src);
   1504         p->line = p->tok.line;
   1505         p->col = p->tok.col;
   1506         p->tok.kind = WT_LPAREN;
   1507         p->tok.p = p->src + p->pos - 1u;
   1508         p->tok.len = 1;
   1509         p->tok.line = p->line;
   1510         p->tok.col = p->col - 1u;
   1511         wat_parse_instr(p, f);
   1512       }
   1513     } else {
   1514       wat_parse_instr(p, f);
   1515     }
   1516   }
   1517   if (!f->has_typeidx)
   1518     f->typeidx = wasm_intern_func_type(p->c, p->module, f);
   1519   else if (checked_params && checked_params != f->nparams)
   1520     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1521                "wasm wat: parameter list does not match type");
   1522   wat_expect(p, WT_RPAREN, "')'");
   1523 }
   1524 
   1525 static void wat_parse_type_field(WatParser* p) {
   1526   WasmFuncType* t = wasm_add_type(p->c, p->module);
   1527   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1528     t->name = wat_dup_atom(p, p->tok);
   1529     wat_next(p);
   1530   }
   1531   wat_expect(p, WT_LPAREN, "'('");
   1532   if (!tok_is(p->tok, "func"))
   1533     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1534                "wasm wat: expected func type");
   1535   wat_next(p);
   1536   while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1537     wat_expect(p, WT_LPAREN, "'('");
   1538     if (tok_is(p->tok, "param")) {
   1539       wat_next(p);
   1540       while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1541         WasmValType vt;
   1542         if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1543           wat_next(p);
   1544           continue;
   1545         }
   1546         if (!wat_val_type(p->tok, &vt) || !wasm_is_num_type(vt))
   1547           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1548                      "wasm wat: expected parameter type");
   1549         wasm_type_push_param(p->c, p->module, t, vt);
   1550         wat_next(p);
   1551       }
   1552     } else if (tok_is(p->tok, "result")) {
   1553       wat_next(p);
   1554       while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1555         WasmValType vt;
   1556         if (!wat_val_type(p->tok, &vt) || !wasm_is_num_type(vt))
   1557           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1558                      "wasm wat: expected result type");
   1559         wasm_type_push_result(p->c, p->module, t, vt);
   1560         wat_next(p);
   1561       }
   1562     } else {
   1563       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1564                  "wasm wat: expected type field");
   1565     }
   1566     wat_expect(p, WT_RPAREN, "')'");
   1567   }
   1568   wat_expect(p, WT_RPAREN, "')'");
   1569   wat_expect(p, WT_RPAREN, "')'");
   1570 }
   1571 
   1572 static void wat_parse_export_field(WatParser* p) {
   1573   char* name;
   1574   int64_t idx = 0;
   1575   uint8_t kind;
   1576   if (p->tok.kind != WT_STRING)
   1577     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1578                "wasm wat: expected export string");
   1579   name = wat_dup_string(p, p->tok, NULL);
   1580   wat_next(p);
   1581   wat_expect(p, WT_LPAREN, "'('");
   1582   kind = wasm_export_kind_from_tok(p->tok);
   1583   if (kind == 0xffu)
   1584     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1585                "wasm wat: expected export kind");
   1586   wat_next(p);
   1587   if (kind == 0)
   1588     wat_parse_func_index(p, &idx);
   1589   else if (!wat_parse_i64(p, &idx))
   1590     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1591                "wasm wat: expected export index");
   1592   if (idx < 0 || idx > UINT32_MAX)
   1593     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1594                "wasm wat: export index out of range");
   1595   {
   1596     WasmExport* ex = wasm_add_export(p->c, p->module);
   1597     ex->name = name;
   1598     ex->kind = kind;
   1599     ex->index = (uint32_t)idx;
   1600   }
   1601   if (kind == 0 && (uint64_t)idx < p->module->nfuncs) {
   1602     wasm_free_str(p->module->heap, &p->module->funcs[idx].export_name);
   1603     p->module->funcs[idx].export_name =
   1604         wasm_strdup(p->module->heap, name, kit_slice_cstr(name).len);
   1605   } else if (kind == 2 && (uint64_t)idx < p->module->nmemories) {
   1606     wasm_free_str(p->module->heap,
   1607                   &p->module->memories[(uint32_t)idx].export_name);
   1608     p->module->memories[(uint32_t)idx].export_name =
   1609         wasm_strdup(p->module->heap, name, kit_slice_cstr(name).len);
   1610   } else if (kind == 1 && (uint64_t)idx < p->module->ntables) {
   1611     wasm_free_str(p->module->heap, &p->module->tables[idx].export_name);
   1612     p->module->tables[idx].export_name =
   1613         wasm_strdup(p->module->heap, name, kit_slice_cstr(name).len);
   1614   } else if (kind == 3 && (uint64_t)idx < p->module->nglobals) {
   1615     wasm_free_str(p->module->heap, &p->module->globals[idx].export_name);
   1616     p->module->globals[idx].export_name =
   1617         wasm_strdup(p->module->heap, name, kit_slice_cstr(name).len);
   1618   }
   1619   wat_next(p);
   1620   wat_expect(p, WT_RPAREN, "')'");
   1621   wat_expect(p, WT_RPAREN, "')'");
   1622 }
   1623 
   1624 static void wat_parse_memory_field(WatParser* p) {
   1625   int64_t min_pages, max_pages;
   1626   WasmMemory* mem = wasm_add_memory(p->c, p->module);
   1627   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1628     mem->name = wat_dup_atom(p, p->tok);
   1629     wat_next(p);
   1630   }
   1631   while (p->tok.kind == WT_ATOM &&
   1632          (tok_is(p->tok, "i64") || tok_is(p->tok, "shared"))) {
   1633     if (tok_is(p->tok, "i64"))
   1634       mem->is64 = 1;
   1635     else
   1636       mem->shared = 1;
   1637     wat_next(p);
   1638   }
   1639   if (!wat_parse_i64(p, &min_pages) || min_pages < 0)
   1640     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1641                "wasm wat: expected memory minimum");
   1642   mem->min_pages = (uint64_t)min_pages;
   1643   wat_next(p);
   1644   while (p->tok.kind == WT_ATOM &&
   1645          (tok_is(p->tok, "i64") || tok_is(p->tok, "shared"))) {
   1646     if (tok_is(p->tok, "i64"))
   1647       mem->is64 = 1;
   1648     else
   1649       mem->shared = 1;
   1650     wat_next(p);
   1651   }
   1652   if (p->tok.kind != WT_RPAREN) {
   1653     if (!wat_parse_i64(p, &max_pages) || max_pages < min_pages)
   1654       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1655                  "wasm wat: bad memory maximum");
   1656     mem->has_max = 1;
   1657     mem->max_pages = (uint64_t)max_pages;
   1658     wat_next(p);
   1659     while (p->tok.kind == WT_ATOM &&
   1660            (tok_is(p->tok, "i64") || tok_is(p->tok, "shared"))) {
   1661       if (tok_is(p->tok, "i64"))
   1662         mem->is64 = 1;
   1663       else
   1664         mem->shared = 1;
   1665       wat_next(p);
   1666     }
   1667   }
   1668   (void)mem;
   1669   wat_expect(p, WT_RPAREN, "')'");
   1670 }
   1671 
   1672 static void wat_parse_memory_limits(WatParser* p, WasmMemory* mem) {
   1673   int64_t lo, hi;
   1674   while (p->tok.kind == WT_ATOM &&
   1675          (tok_is(p->tok, "i64") || tok_is(p->tok, "shared"))) {
   1676     if (tok_is(p->tok, "i64"))
   1677       mem->is64 = 1;
   1678     else
   1679       mem->shared = 1;
   1680     wat_next(p);
   1681   }
   1682   if (!wat_parse_i64(p, &lo) || lo < 0)
   1683     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1684                "wasm wat: expected memory minimum");
   1685   mem->min_pages = (uint64_t)lo;
   1686   wat_next(p);
   1687   while (p->tok.kind == WT_ATOM &&
   1688          (tok_is(p->tok, "i64") || tok_is(p->tok, "shared"))) {
   1689     if (tok_is(p->tok, "i64"))
   1690       mem->is64 = 1;
   1691     else
   1692       mem->shared = 1;
   1693     wat_next(p);
   1694   }
   1695   if (p->tok.kind != WT_RPAREN) {
   1696     if (!wat_parse_i64(p, &hi) || hi < lo)
   1697       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1698                  "wasm wat: bad memory maximum");
   1699     mem->has_max = 1;
   1700     mem->max_pages = (uint64_t)hi;
   1701     wat_next(p);
   1702     while (p->tok.kind == WT_ATOM &&
   1703            (tok_is(p->tok, "i64") || tok_is(p->tok, "shared"))) {
   1704       if (tok_is(p->tok, "i64"))
   1705         mem->is64 = 1;
   1706       else
   1707         mem->shared = 1;
   1708       wat_next(p);
   1709     }
   1710   }
   1711 }
   1712 
   1713 static void wat_parse_table_limits_and_type(WatParser* p, WasmTable* t) {
   1714   int64_t lo, hi;
   1715   if (!wat_parse_i64(p, &lo) || lo < 0 || lo > UINT32_MAX)
   1716     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1717                "wasm wat: expected table minimum");
   1718   t->min = (uint32_t)lo;
   1719   wat_next(p);
   1720   if (p->tok.kind == WT_ATOM) {
   1721     WasmValType maybe_type;
   1722     if (!wat_val_type(p->tok, &maybe_type)) {
   1723       if (!wat_parse_i64(p, &hi) || hi < lo || hi > UINT32_MAX)
   1724         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1725                    "wasm wat: bad table maximum");
   1726       t->has_max = 1;
   1727       t->max = (uint32_t)hi;
   1728       wat_next(p);
   1729     }
   1730   }
   1731   if (!wat_val_type(p->tok, &t->elem_type))
   1732     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1733                "wasm wat: expected table element type");
   1734   wat_next(p);
   1735 }
   1736 
   1737 static void wat_parse_import_field(WatParser* p) {
   1738   char *mod, *name;
   1739   if (p->tok.kind != WT_STRING)
   1740     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1741                "wasm wat: expected import module string");
   1742   mod = wat_dup_string(p, p->tok, NULL);
   1743   wat_next(p);
   1744   if (p->tok.kind != WT_STRING)
   1745     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1746                "wasm wat: expected import name string");
   1747   name = wat_dup_string(p, p->tok, NULL);
   1748   wat_next(p);
   1749   wat_expect(p, WT_LPAREN, "'('");
   1750   if (tok_is(p->tok, "func")) {
   1751     WasmFunc* f = wasm_add_func(p->c, p->module);
   1752     f->is_import = 1;
   1753     f->import_module = mod;
   1754     f->import_name = name;
   1755     wat_next(p);
   1756     if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1757       f->name = wat_dup_atom(p, p->tok);
   1758       wat_next(p);
   1759     }
   1760     while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1761       wat_expect(p, WT_LPAREN, "'('");
   1762       if (tok_is(p->tok, "type")) {
   1763         int64_t typeidx;
   1764         wat_next(p);
   1765         wat_parse_type_index(p, &typeidx);
   1766         if (typeidx < 0 || (uint64_t)typeidx >= p->module->ntypes)
   1767           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1768                      "wasm wat: type index out of range");
   1769         f->typeidx = (uint32_t)typeidx;
   1770         f->has_typeidx = 1;
   1771         wasm_func_set_params(p->c, p->module, f,
   1772                              p->module->types[typeidx].params,
   1773                              p->module->types[typeidx].nparams);
   1774         wasm_func_set_results(p->c, p->module, f,
   1775                               p->module->types[typeidx].results,
   1776                               p->module->types[typeidx].nresults);
   1777         wat_next(p);
   1778       } else if (tok_is(p->tok, "param")) {
   1779         wat_next(p);
   1780         while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1781           WasmValType vt;
   1782           if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1783             wat_next(p);
   1784             continue;
   1785           }
   1786           if (!wat_val_type(p->tok, &vt) || !wasm_is_frontend_value_type(vt))
   1787             wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1788                        "wasm wat: expected parameter type");
   1789           wasm_func_push_param(p->c, p->module, f, vt);
   1790           wat_next(p);
   1791         }
   1792       } else if (tok_is(p->tok, "result")) {
   1793         wat_next(p);
   1794         while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1795           WasmValType vt;
   1796           if (!wat_val_type(p->tok, &vt) || !wasm_is_frontend_value_type(vt))
   1797             wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1798                        "wasm wat: expected result type");
   1799           wasm_func_push_result(p->c, p->module, f, vt);
   1800           wat_next(p);
   1801         }
   1802       } else {
   1803         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1804                    "wasm wat: expected import func type field");
   1805       }
   1806       wat_expect(p, WT_RPAREN, "')'");
   1807     }
   1808     if (!f->has_typeidx) f->typeidx = wasm_intern_func_type(p->c, p->module, f);
   1809   } else if (tok_is(p->tok, "memory")) {
   1810     WasmMemory* mem = wasm_add_memory(p->c, p->module);
   1811     mem->is_import = 1;
   1812     mem->import_module = mod;
   1813     mem->import_name = name;
   1814     wat_next(p);
   1815     if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1816       mem->name = wat_dup_atom(p, p->tok);
   1817       wat_next(p);
   1818     }
   1819     wat_parse_memory_limits(p, mem);
   1820   } else if (tok_is(p->tok, "table")) {
   1821     WasmTable* t = wasm_add_table(p->c, p->module);
   1822     t->is_import = 1;
   1823     t->import_module = mod;
   1824     t->import_name = name;
   1825     wat_next(p);
   1826     if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1827       t->name = wat_dup_atom(p, p->tok);
   1828       wat_next(p);
   1829     }
   1830     wat_parse_table_limits_and_type(p, t);
   1831   } else if (tok_is(p->tok, "global")) {
   1832     WasmGlobal* g = wasm_add_global(p->c, p->module);
   1833     g->is_import = 1;
   1834     g->import_module = mod;
   1835     g->import_name = name;
   1836     wat_next(p);
   1837     if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1838       g->name = wat_dup_atom(p, p->tok);
   1839       wat_next(p);
   1840     }
   1841     if (p->tok.kind == WT_LPAREN) {
   1842       wat_next(p);
   1843       if (!tok_is(p->tok, "mut"))
   1844         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1845                    "wasm wat: expected mut");
   1846       g->mutable_ = 1;
   1847       wat_next(p);
   1848       if (!wat_val_type(p->tok, &g->type) || !wasm_is_num_type(g->type))
   1849         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1850                    "wasm wat: expected global type");
   1851       wat_next(p);
   1852       wat_expect(p, WT_RPAREN, "')'");
   1853     } else {
   1854       if (!wat_val_type(p->tok, &g->type) || !wasm_is_num_type(g->type))
   1855         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1856                    "wasm wat: expected global type");
   1857       wat_next(p);
   1858     }
   1859   } else {
   1860     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1861                "wasm wat: unsupported import kind");
   1862   }
   1863   wat_expect(p, WT_RPAREN, "')'");
   1864   wat_expect(p, WT_RPAREN, "')'");
   1865 }
   1866 
   1867 static void wat_parse_table_field(WatParser* p) {
   1868   WasmTable* t = wasm_add_table(p->c, p->module);
   1869   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1870     t->name = wat_dup_atom(p, p->tok);
   1871     wat_next(p);
   1872   }
   1873   wat_parse_table_limits_and_type(p, t);
   1874   wat_expect(p, WT_RPAREN, "')'");
   1875 }
   1876 
   1877 static void wat_parse_const_expr(WatParser* p, WasmInsn* out) {
   1878   WasmInsnKind kind;
   1879   int has_imm;
   1880   memset(out, 0, sizeof *out);
   1881   wat_expect(p, WT_LPAREN, "'('");
   1882   if (!wat_instr_kind(p->tok, &kind, &has_imm) ||
   1883       (kind != WASM_INSN_I32_CONST && kind != WASM_INSN_I64_CONST &&
   1884        kind != WASM_INSN_F32_CONST && kind != WASM_INSN_F64_CONST))
   1885     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1886                "wasm wat: expected constant expression");
   1887   out->kind = (uint8_t)kind;
   1888   out->loc = wat_tok_loc(p, p->tok);
   1889   wat_next(p);
   1890   if (kind == WASM_INSN_F32_CONST || kind == WASM_INSN_F64_CONST) {
   1891     if (!wat_parse_f64(p, &out->fp))
   1892       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1893                  "wasm wat: expected float immediate");
   1894   } else if (!wat_parse_i64(p, &out->imm)) {
   1895     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1896                "wasm wat: expected integer immediate");
   1897   }
   1898   wat_next(p);
   1899   wat_expect(p, WT_RPAREN, "')'");
   1900 }
   1901 
   1902 static void wat_parse_global_field(WatParser* p) {
   1903   WasmGlobal* g = wasm_add_global(p->c, p->module);
   1904   g->loc = p->field_loc;
   1905   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1906     g->name = wat_dup_atom(p, p->tok);
   1907     wat_next(p);
   1908   }
   1909   if (p->tok.kind == WT_LPAREN) {
   1910     wat_next(p);
   1911     if (tok_is(p->tok, "export")) {
   1912       wat_next(p);
   1913       if (p->tok.kind != WT_STRING)
   1914         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1915                    "wasm wat: expected export string");
   1916       g->export_name = wat_dup_string(p, p->tok, NULL);
   1917       {
   1918         WasmExport* ex = wasm_add_export(p->c, p->module);
   1919         ex->name = wasm_strdup(p->module->heap, g->export_name,
   1920                                kit_slice_cstr(g->export_name).len);
   1921         if (!ex->name)
   1922           wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1923                      "wasm: out of memory");
   1924         ex->kind = 3;
   1925         ex->index = p->module->nglobals - 1u;
   1926       }
   1927       wat_next(p);
   1928       wat_expect(p, WT_RPAREN, "')'");
   1929     } else if (tok_is(p->tok, "mut")) {
   1930       g->mutable_ = 1;
   1931       wat_next(p);
   1932       if (!wat_val_type(p->tok, &g->type) || !wasm_is_num_type(g->type))
   1933         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1934                    "wasm wat: expected global type");
   1935       wat_next(p);
   1936       wat_expect(p, WT_RPAREN, "')'");
   1937     } else {
   1938       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1939                  "wasm wat: expected global type");
   1940     }
   1941   } else {
   1942     if (!wat_val_type(p->tok, &g->type) || !wasm_is_num_type(g->type))
   1943       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1944                  "wasm wat: expected global type");
   1945     wat_next(p);
   1946   }
   1947   if (!g->type)
   1948     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1949                "wasm wat: missing global type");
   1950   wat_parse_const_expr(p, &g->init);
   1951   wat_expect(p, WT_RPAREN, "')'");
   1952 }
   1953 
   1954 static void wat_parse_elem_field(WatParser* p) {
   1955   WasmElemSegment* e = wasm_add_elem(p->c, p->module);
   1956   int has_offset = 0;
   1957   int is_declarative = 0;
   1958   e->tableidx = 0;
   1959   e->elem_type = WASM_VAL_FUNCREF;
   1960   /* Optional `$name` or "declare" keyword for declarative segments. */
   1961   if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') {
   1962     e->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len);
   1963     wat_next(p);
   1964   }
   1965   if (tok_is(p->tok, "declare")) {
   1966     is_declarative = 1;
   1967     wat_next(p);
   1968   } else if (p->tok.kind == WT_ATOM) {
   1969     int64_t tableidx;
   1970     if (wat_parse_i64(p, &tableidx)) {
   1971       if (tableidx < 0 || tableidx > UINT32_MAX)
   1972         wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1973                    "wasm wat: table index out of range");
   1974       e->tableidx = (uint32_t)tableidx;
   1975       wat_next(p);
   1976     }
   1977   }
   1978   if (!is_declarative && p->tok.kind == WT_LPAREN) {
   1979     WasmInsn off;
   1980     wat_parse_const_expr(p, &off);
   1981     if (off.kind != WASM_INSN_I32_CONST || off.imm < 0)
   1982       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1983                  "wasm wat: element offset must be i32.const");
   1984     e->offset = off.imm;
   1985     has_offset = 1;
   1986   }
   1987   if (is_declarative)
   1988     e->mode = WASM_SEG_DECLARATIVE;
   1989   else if (has_offset)
   1990     e->mode = WASM_SEG_ACTIVE;
   1991   else
   1992     e->mode = WASM_SEG_PASSIVE;
   1993   if (tok_is(p->tok, "func")) wat_next(p);
   1994   while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) {
   1995     int64_t idx;
   1996     wat_parse_func_index(p, &idx);
   1997     if (idx < 0 || idx > UINT32_MAX)
   1998       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   1999                  "wasm wat: element function index out of range");
   2000     wasm_elem_push_func(p->c, p->module, e, (uint32_t)idx);
   2001     wat_next(p);
   2002   }
   2003   wat_expect(p, WT_RPAREN, "')'");
   2004 }
   2005 
   2006 static void wat_parse_start_field(WatParser* p) {
   2007   int64_t idx;
   2008   p->module->start_field_loc = p->field_loc;
   2009   wat_parse_func_index(p, &idx);
   2010   if (idx < 0 || idx > UINT32_MAX)
   2011     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   2012                "wasm wat: start function index out of range");
   2013   p->module->has_start = 1;
   2014   p->module->start_func = (uint32_t)idx;
   2015   wat_next(p);
   2016   wat_expect(p, WT_RPAREN, "')'");
   2017 }
   2018 
   2019 static void wat_parse_custom_field(WatParser* p) {
   2020   WasmCustom* cs;
   2021   size_t n = 0;
   2022   char* bytes;
   2023   if (p->tok.kind != WT_STRING)
   2024     wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   2025                "wasm wat: expected custom section name");
   2026   cs = wasm_add_custom(p->c, p->module);
   2027   cs->name = wat_dup_string(p, p->tok, NULL);
   2028   if (kit_slice_eq_cstr(kit_slice_cstr(cs->name), "target_features") ||
   2029       kit_slice_eq_cstr(kit_slice_cstr(cs->name), "target-feature"))
   2030     p->module->has_target_features = 1;
   2031   wat_next(p);
   2032   if (p->tok.kind == WT_STRING) {
   2033     bytes = wat_dup_string(p, p->tok, &n);
   2034     cs->data = (uint8_t*)p->module->heap->alloc(p->module->heap, n ? n : 1u, 1);
   2035     if (!cs->data)
   2036       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   2037                  "wasm: out of memory");
   2038     memcpy(cs->data, bytes, n);
   2039     cs->len = (uint32_t)n;
   2040     p->module->heap->free(p->module->heap, bytes, p->tok.len + 1u);
   2041     wat_next(p);
   2042   }
   2043   wat_expect(p, WT_RPAREN, "')'");
   2044 }
   2045 
   2046 static void wat_parse_data_field(WatParser* p) {
   2047   int64_t offset = 0;
   2048   uint32_t memidx = 0;
   2049   int has_offset = 0;
   2050   char* bytes = NULL;
   2051   size_t nbytes = 0;
   2052   size_t alloc_len = 0;
   2053   char* seg_name = NULL;
   2054   WasmDataSegment* d;
   2055   if (p->tok.kind == WT_ATOM) {
   2056     WasmInsnKind next_kind;
   2057     int next_has_imm;
   2058     if (p->tok.len && p->tok.p[0] == '$') {
   2059       seg_name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len);
   2060       wat_next(p);
   2061     } else if (!wat_instr_kind(p->tok, &next_kind, &next_has_imm)) {
   2062       wat_parse_memory_index(p, &memidx);
   2063       wat_next(p);
   2064     } else {
   2065       wat_next(p);
   2066     }
   2067   }
   2068   if (p->tok.kind == WT_LPAREN) {
   2069     size_t save_pos = p->pos;
   2070     uint32_t save_line = p->line, save_col = p->col;
   2071     wat_next(p);
   2072     if (tok_is(p->tok, "memory")) {
   2073       wat_next(p);
   2074       wat_parse_memory_index(p, &memidx);
   2075       wat_next(p);
   2076       wat_expect(p, WT_RPAREN, "')'");
   2077     } else {
   2078       p->pos = save_pos;
   2079       p->line = save_line;
   2080       p->col = save_col;
   2081       p->tok.kind = WT_LPAREN;
   2082       p->tok.p = p->src + p->pos - 1u;
   2083       p->tok.len = 1;
   2084       p->tok.line = save_line;
   2085       p->tok.col = save_col - 1u;
   2086     }
   2087   }
   2088   /* The offset expression `(i32.const N)` is optional: when absent the
   2089    * segment is passive. */
   2090   if (p->tok.kind == WT_LPAREN) {
   2091     wat_next(p);
   2092     if (!tok_is(p->tok, "i32.const") && !tok_is(p->tok, "i64.const"))
   2093       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   2094                  "wasm wat: expected const data offset");
   2095     wat_next(p);
   2096     if (!wat_parse_i64(p, &offset) || offset < 0 || offset > UINT32_MAX)
   2097       wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
   2098                  "wasm wat: bad data offset");
   2099     wat_next(p);
   2100     wat_expect(p, WT_RPAREN, "')'");
   2101     has_offset = 1;
   2102   }
   2103   if (p->tok.kind == WT_STRING) {
   2104     alloc_len = p->tok.len + 1u;
   2105     bytes = wat_dup_string(p, p->tok, &nbytes);
   2106     wat_next(p);
   2107   }
   2108   d = wasm_add_data(p->c, p->module);
   2109   d->name = seg_name;
   2110   if (has_offset) {
   2111     d->mode = WASM_SEG_ACTIVE;
   2112     d->memidx = memidx;
   2113     d->offset = offset;
   2114   } else {
   2115     d->mode = WASM_SEG_PASSIVE;
   2116   }
   2117   if (nbytes)
   2118     wasm_data_set_bytes(p->c, p->module, d, (const uint8_t*)bytes, nbytes);
   2119   if (bytes) p->module->heap->free(p->module->heap, bytes, alloc_len);
   2120   wat_expect(p, WT_RPAREN, "')'");
   2121 }
   2122 
   2123 void wasm_parse_wat_body(KitCompiler* c, WasmModule* m, WasmFunc* f,
   2124                          const char* src, size_t len, KitSrcLoc loc) {
   2125   WatParser p;
   2126   memset(&p, 0, sizeof p);
   2127   p.c = c;
   2128   p.name = "<asm template>";
   2129   p.src = src;
   2130   p.len = len;
   2131   p.line = loc.line ? loc.line : 1u;
   2132   p.col = loc.col ? loc.col : 1u;
   2133   p.module = m;
   2134   p.field_loc = loc;
   2135   wat_next(&p);
   2136   while (p.tok.kind != WT_EOF) wat_parse_instr(&p, f);
   2137   if (p.labels)
   2138     m->heap->free(m->heap, p.labels, sizeof(WatLabel) * p.cap_labels);
   2139 }
   2140 
   2141 void wasm_parse_wat(KitCompiler* c, KitSlice name, const KitSlice* input,
   2142                     WasmModule* out) {
   2143   WatParser p;
   2144   memset(&p, 0, sizeof p);
   2145   if (name.s) (void)kit_source_add_memory(c, name, &out->file_id);
   2146   p.c = c;
   2147   p.name = name.s;
   2148   p.src = input->s;
   2149   p.len = input->len;
   2150   p.line = 1;
   2151   p.col = 1;
   2152   p.module = out;
   2153   wat_next(&p);
   2154   wat_expect(&p, WT_LPAREN, "'('");
   2155   if (!tok_is(p.tok, "module"))
   2156     wasm_error(c, wasm_loc(p.tok.line, p.tok.col), "wasm wat: expected module");
   2157   wat_next(&p);
   2158   while (p.tok.kind != WT_RPAREN && p.tok.kind != WT_EOF) {
   2159     if (p.tok.kind != WT_LPAREN)
   2160       wasm_error(c, wasm_loc(p.tok.line, p.tok.col),
   2161                  "wasm wat: expected module field");
   2162     wat_next(&p);
   2163     p.field_loc = wat_tok_loc(&p, p.tok);
   2164     if (tok_is(p.tok, "type")) {
   2165       wat_next(&p);
   2166       wat_parse_type_field(&p);
   2167     } else if (tok_is(p.tok, "func")) {
   2168       p.pos = (size_t)(p.tok.p - p.src);
   2169       p.line = p.tok.line;
   2170       p.col = p.tok.col;
   2171       p.tok.kind = WT_LPAREN;
   2172       p.tok.p = p.src + p.pos - 1u;
   2173       p.tok.len = 1;
   2174       p.tok.line = p.line;
   2175       p.tok.col = p.col - 1u;
   2176       wat_parse_func(&p);
   2177     } else if (tok_is(p.tok, "export")) {
   2178       wat_next(&p);
   2179       wat_parse_export_field(&p);
   2180     } else if (tok_is(p.tok, "memory")) {
   2181       wat_next(&p);
   2182       wat_parse_memory_field(&p);
   2183     } else if (tok_is(p.tok, "data")) {
   2184       wat_next(&p);
   2185       wat_parse_data_field(&p);
   2186     } else if (tok_is(p.tok, "import")) {
   2187       wat_next(&p);
   2188       wat_parse_import_field(&p);
   2189     } else if (tok_is(p.tok, "table")) {
   2190       wat_next(&p);
   2191       wat_parse_table_field(&p);
   2192     } else if (tok_is(p.tok, "global")) {
   2193       wat_next(&p);
   2194       wat_parse_global_field(&p);
   2195     } else if (tok_is(p.tok, "elem")) {
   2196       wat_next(&p);
   2197       wat_parse_elem_field(&p);
   2198     } else if (tok_is(p.tok, "start")) {
   2199       wat_next(&p);
   2200       wat_parse_start_field(&p);
   2201     } else if (tok_is(p.tok, "custom") || tok_is(p.tok, "@custom")) {
   2202       wat_next(&p);
   2203       wat_parse_custom_field(&p);
   2204     } else {
   2205       wat_skip_list(&p);
   2206     }
   2207   }
   2208   wat_expect(&p, WT_RPAREN, "')'");
   2209   if (p.tok.kind != WT_EOF)
   2210     wasm_error(c, wasm_loc(p.tok.line, p.tok.col),
   2211                "wasm wat: trailing tokens after module");
   2212   if (p.labels)
   2213     out->heap->free(out->heap, p.labels, sizeof(WatLabel) * p.cap_labels);
   2214 }