watr 4.2.1 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/compile.js CHANGED
@@ -56,6 +56,20 @@ export default function compile(nodes) {
56
56
  // quote "a" "b"
57
57
  if (nodes[idx] === 'quote') return compile(nodes.slice(++idx).map(v => v.valueOf().slice(1, -1)).flat().join(''))
58
58
 
59
+ // expand grouped imports: (import "mod" (item "name" type)*) -> individual imports
60
+ // compact import section (Phase 3)
61
+ nodes = nodes.flatMap((n, i) => {
62
+ if (i < idx || !Array.isArray(n) || n[0] !== 'import') return [n]
63
+ const [, mod, ...rest] = n
64
+ if (!rest.some(r => Array.isArray(r) && r[0] === 'item')) return [n]
65
+ const lastIsType = Array.isArray(rest.at(-1)) && rest.at(-1)[0] !== 'item'
66
+ if (lastIsType) {
67
+ const type = rest.at(-1)
68
+ return rest.slice(0, -1).filter(r => r[0] === 'item').map(([, nm]) => ['import', mod, nm, type])
69
+ }
70
+ return rest.filter(r => r[0] === 'item').map(([, nm, type]) => ['import', mod, nm, type])
71
+ })
72
+
59
73
  // scopes are aliased by key as well, eg. section.func.$name = section[SECTION.func] = idx
60
74
  const ctx = []
61
75
  for (let kind in SECTION) (ctx[SECTION[kind]] = ctx[kind] = []).name = kind
@@ -91,8 +105,12 @@ export default function compile(nodes) {
91
105
  // add rest of subtypes as regular type nodes with subtype flag
92
106
  for (let i = 0; i < node.length; i++) {
93
107
  let [, ...subnode] = node[i]
94
- name(subnode, ctx.type);
95
- (subnode = typedef(subnode, ctx)).push(i ? true : [ctx.type.length, node.length])
108
+ name(subnode, ctx.type)
109
+ // extract top-level descriptor/describes (custom descriptors, Phase 3)
110
+ const tdesc = []
111
+ while (subnode[0]?.[0] === 'descriptor' || subnode[0]?.[0] === 'describes') tdesc.push(subnode.shift())
112
+ ;(subnode = typedef(subnode, ctx)).push(i ? true : [ctx.type.length, node.length])
113
+ if (tdesc.length) subnode.desc = subnode.desc ? [...tdesc, ...subnode.desc] : tdesc
96
114
  ctx.type.push(subnode)
97
115
  }
98
116
  }
@@ -101,8 +119,13 @@ export default function compile(nodes) {
101
119
  // (type (struct (field a)*)
102
120
  // (type (sub final? $nm* (struct|array|func ...)))
103
121
  else if (kind === 'type') {
104
- name(node, ctx.type);
105
- ctx.type.push(typedef(node, ctx));
122
+ name(node, ctx.type)
123
+ // extract top-level descriptor/describes (custom descriptors, Phase 3)
124
+ const tdesc = []
125
+ while (node[0]?.[0] === 'descriptor' || node[0]?.[0] === 'describes') tdesc.push(node.shift())
126
+ const td = typedef(node, ctx)
127
+ if (tdesc.length) td.desc = td.desc ? [...tdesc, ...td.desc] : tdesc
128
+ ctx.type.push(td)
106
129
  }
107
130
  // other sections may have id
108
131
  else if (kind === 'start' || kind === 'export') ctx[kind].push(node)
@@ -146,7 +169,8 @@ export default function compile(nodes) {
146
169
  else if (kind === 'memory') {
147
170
  const is64 = node[0] === 'i64', idx = is64 ? 1 : 0
148
171
  if (node[idx]?.[0] === 'data') {
149
- let [, ...data] = node.splice(idx, 1)[0], m = '' + Math.ceil(data.reduce((s, d) => s + d.length, 0) / 65536)
172
+ const ps = (node.find(n => Array.isArray(n) && n[0] === 'pagesize')?.[1]) ?? 65536
173
+ let [, ...data] = node.splice(idx, 1)[0], m = '' + Math.ceil(data.reduce((s, d) => s + d.length, 0) / ps)
150
174
  ctx.data.push([['memory', items.length], [is64 ? 'i64.const' : 'i32.const', is64 ? 0n : 0], ...data])
151
175
  node = is64 ? ['i64', m, m] : [m, m]
152
176
  }
@@ -202,6 +226,14 @@ export default function compile(nodes) {
202
226
  }
203
227
 
204
228
 
229
+ // pre-compute sections that may collect string constants (for strings section ordering)
230
+ const globalSection = bin(SECTION.global)
231
+ const elemSection = bin(SECTION.elem)
232
+ const codeSection = bin(SECTION.code)
233
+ const metaSection = binMeta()
234
+ const dataSection = bin(SECTION.data)
235
+ const stringsSection = ctx.strings.length ? [SECTION.strings, ...vec([0x00, ...vec(ctx.strings.map(s => vec(s)))])] : []
236
+
205
237
  // build final binary
206
238
  return Uint8Array.from([
207
239
  0x00, 0x61, 0x73, 0x6d, // magic
@@ -213,14 +245,15 @@ export default function compile(nodes) {
213
245
  ...bin(SECTION.table),
214
246
  ...bin(SECTION.memory),
215
247
  ...bin(SECTION.tag),
216
- ...bin(SECTION.global),
248
+ ...stringsSection,
249
+ ...globalSection,
217
250
  ...bin(SECTION.export),
218
251
  ...bin(SECTION.start, false),
219
- ...bin(SECTION.elem),
252
+ ...elemSection,
220
253
  ...bin(SECTION.datacount, false),
221
- ...bin(SECTION.code),
222
- ...binMeta(),
223
- ...bin(SECTION.data)
254
+ ...codeSection,
255
+ ...metaSection,
256
+ ...dataSection
224
257
  ])
225
258
  }
226
259
 
@@ -318,7 +351,7 @@ function normalize(nodes, ctx) {
318
351
  else {
319
352
  const imm = []
320
353
  // Collect immediate operands (non-arrays or special forms like type/param/result/ref)
321
- while (parts.length && (!Array.isArray(parts[0]) || 'type,param,result,ref'.includes(parts[0][0]))) imm.push(parts.shift())
354
+ while (parts.length && (!Array.isArray(parts[0]) || parts[0].valueOf !== Array.prototype.valueOf || 'type,param,result,ref,exact,on'.includes(parts[0][0]))) imm.push(parts.shift())
322
355
  out.push(...normalize(parts, ctx), op, ...imm)
323
356
  nodes.unshift(...out.splice(out.length - 1 - imm.length))
324
357
  }
@@ -418,18 +451,20 @@ const name = (node, list) => {
418
451
  }
419
452
 
420
453
  /**
421
- * Parse type definition: func, array, struct, or sub(type).
422
- * Handles recursive types and subtyping.
454
+ * Parse type definition: func, array, struct, cont, or sub(type).
455
+ * Handles recursive types, subtyping, and custom descriptor clauses (Phase 3).
423
456
  *
424
- * @param {Array} node - [definition] where definition is func/array/struct/sub
457
+ * @param {Array} node - [definition] where definition is func/array/struct/cont/sub
425
458
  * @param {Object} ctx - Compilation context
426
- * @returns {[string, any, string, string[]]} [kind, fields, subkind, supertypes]
459
+ * @returns {Array} [kind, fields, subkind, supertypes] with optional .desc property
427
460
  */
428
461
  const typedef = ([dfn], ctx) => {
429
- let subkind = 'subfinal', supertypes = [], compkind
462
+ let subkind = 'subfinal', supertypes = [], compkind, desc = []
430
463
  if (dfn[0] === 'sub') {
431
464
  subkind = dfn.shift(), dfn[0] === 'final' && (subkind += dfn.shift())
432
465
  dfn = (supertypes = dfn).pop() // last item is definition
466
+ // extract descriptor/describes from supertypes (custom descriptors, Phase 3)
467
+ supertypes = supertypes.filter(n => Array.isArray(n) && (n[0] === 'descriptor' || n[0] === 'describes') ? (desc.push(n), false) : true)
433
468
  }
434
469
 
435
470
  [compkind, ...dfn] = dfn // composite type kind
@@ -437,8 +472,11 @@ const typedef = ([dfn], ctx) => {
437
472
  if (compkind === 'func') dfn = paramres(dfn), ctx.type['$' + dfn.join('>')] ??= ctx.type.length
438
473
  else if (compkind === 'struct') dfn = fieldseq(dfn, 'field')
439
474
  else if (compkind === 'array') [dfn] = dfn
475
+ // cont type: (cont $ft) - continuation wrapping function type (stack switching, Phase 3)
440
476
 
441
- return [compkind, dfn, subkind, supertypes]
477
+ const result = [compkind, dfn, subkind, supertypes]
478
+ if (desc.length) result.desc = desc
479
+ return result
442
480
  }
443
481
 
444
482
 
@@ -460,40 +498,50 @@ const build = [
460
498
  // (func params result)
461
499
  // (array i8)
462
500
  // (struct ...fields)
463
- ([kind, fields, subkind, supertypes, rec], ctx) => {
501
+ // (cont $ft) - stack switching (Phase 3)
502
+ (node, ctx) => {
503
+ const [kind, fields, subkind, supertypes, rec] = node
464
504
  if (rec === true) return // ignore rec subtypes cept for 1st one
465
505
 
466
- let details
506
+ // descriptor/describes prefix bytes (custom descriptors, Phase 3)
507
+ const descPfx = (node.desc ?? []).flatMap(([clause, ref]) =>
508
+ [clause === 'descriptor' ? 0x4D : 0x4C, ...uleb(id(ref, ctx.type))])
509
+
510
+ // build comptype bytes without sub wrapper or descriptor prefix
511
+ const comptype = (k, f) => {
512
+ if (k === 'func') return [DEFTYPE.func, ...vec(f[0].map(t => reftype(t, ctx))), ...vec(f[1].map(t => reftype(t, ctx)))]
513
+ if (k === 'array') return [DEFTYPE.array, ...fieldtype(f, ctx)]
514
+ if (k === 'struct') return [DEFTYPE.struct, ...vec(f.map(t => fieldtype(t, ctx)))]
515
+ if (k === 'cont') return [DEFTYPE.cont, ...uleb(id(f[0] ?? f, ctx.type))]
516
+ return [DEFTYPE[k]]
517
+ }
518
+
467
519
  // (rec (sub ...)*)
468
520
  if (rec) {
469
- kind = 'rec'
470
- let [from, length] = rec, subtypes = Array.from({ length }, (_, i) => build[SECTION.type](ctx.type[from + i].slice(0, 4), ctx))
471
- details = vec(subtypes)
521
+ let [from, length] = rec
522
+ const subtypes = Array.from({ length }, (_, i) => {
523
+ const t = ctx.type[from + i], sub = t.slice(0, 4)
524
+ if (t.desc) sub.desc = t.desc
525
+ return build[SECTION.type](sub, ctx)
526
+ })
527
+ return [DEFTYPE.rec, ...vec(subtypes)]
472
528
  }
473
529
  // (sub final? sups* (type...))
474
530
  else if (subkind === 'sub' || supertypes?.length) {
475
- details = [...vec(supertypes.map(n => id(n, ctx.type))), ...build[SECTION.type]([kind, fields], ctx)]
476
- kind = subkind
477
- }
478
-
479
- else if (kind === 'func') {
480
- details = [...vec(fields[0].map(t => reftype(t, ctx))), ...vec(fields[1].map(t => reftype(t, ctx)))]
481
- }
482
- else if (kind === 'array') {
483
- details = fieldtype(fields, ctx)
484
- }
485
- else if (kind === 'struct') {
486
- details = vec(fields.map(t => fieldtype(t, ctx)))
531
+ return [DEFTYPE[subkind], ...vec(supertypes.map(n => id(n, ctx.type))), ...descPfx, ...comptype(kind, fields)]
487
532
  }
488
533
 
489
- return [DEFTYPE[kind], ...details]
534
+ return [...descPfx, ...comptype(kind, fields)]
490
535
  },
491
536
 
492
537
  // (import "math" "add" (func|table|global|memory|tag dfn?))
493
538
  ([mod, field, [kind, ...dfn]], ctx) => {
494
- let details
539
+ let details, kindByte = KIND[kind]
495
540
 
496
541
  if (kind === 'func') {
542
+ // exact func import: (func exact (type $t)) - custom descriptors (Phase 3)
543
+ const isExact = dfn[0] === 'exact' && dfn.shift()
544
+ if (isExact) kindByte = 0x20
497
545
  // we track imported funcs in func section to share namespace, and skip them on final build
498
546
  let [[, typeidx]] = dfn
499
547
  details = uleb(id(typeidx, ctx.type))
@@ -513,7 +561,7 @@ const build = [
513
561
  }
514
562
  else err(`Unknown kind ${kind}`)
515
563
 
516
- return ([...vec(mod), ...vec(field), KIND[kind], ...details])
564
+ return ([...vec(mod), ...vec(field), kindByte, ...details])
517
565
  },
518
566
 
519
567
  // (func $name? ...params result ...body)
@@ -677,6 +725,7 @@ const build = [
677
725
  // (data (i32.const 0) "\aa" "\bb"?)
678
726
  // (data (memory ref) (offset (i32.const 0)) "\aa" "\bb"?)
679
727
  // (data (global.get $x) "\aa" "\bb"?)
728
+ // (data (i8 1 2 3) ...) numeric values (WAT numeric values, Phase 2)
680
729
  (inits, ctx) => {
681
730
  let offset, memidx = 0
682
731
 
@@ -707,7 +756,7 @@ const build = [
707
756
  // passive: 1
708
757
  [1]
709
758
  ),
710
- ...vec(inits.flat())
759
+ ...vec(inits.flatMap(item => numdata(item) ?? [...item]))
711
760
  ])
712
761
  },
713
762
 
@@ -720,10 +769,15 @@ const build = [
720
769
 
721
770
  // Build reference type encoding (ref/refnull forms, not related to regtype which handles func types)
722
771
  // https://webassembly.github.io/gc/core/binary/types.html#reference-types
772
+ // (exact $T) support added for custom descriptors (Phase 3): encoded as 0x62 typeidx
723
773
  const reftype = (t, ctx) => (
724
774
  t[0] === 'ref' ?
725
775
  t[1] == 'null' ?
776
+ // (ref null (exact $T)) - exact nullable ref
777
+ Array.isArray(t[2]) && t[2][0] === 'exact' ? [TYPE.refnull, 0x62, ...uleb(id(t[2][1], ctx.type))] :
726
778
  TYPE[t[2]] ? [TYPE[t[2]]] : [TYPE.refnull, ...uleb(id(t[t.length - 1], ctx.type))] :
779
+ // (ref (exact $T)) - exact non-null ref
780
+ Array.isArray(t[1]) && t[1][0] === 'exact' ? [TYPE.ref, 0x62, ...uleb(id(t[1][1], ctx.type))] :
727
781
  [TYPE.ref, ...uleb(TYPE[t[t.length - 1]] || id(t[t.length - 1], ctx.type))] :
728
782
  // abbrs
729
783
  [TYPE[t] ?? err(`Unknown type ${t}`)]
@@ -770,11 +824,11 @@ const IMM = {
770
824
  return [...uleb(count - 1), ...labels]
771
825
  },
772
826
  select: (n, c) => { let r = n.shift() || []; return r.length ? vec(r.map(t => reftype(t, c))) : [] },
773
- ref_null: (n, c) => { let t = n.shift(); return TYPE[t] ? [TYPE[t]] : uleb(id(t, c.type)) },
827
+ ref_null: (n, c) => { let t = n.shift(); return Array.isArray(t) && t[0] === 'exact' ? [0x62, ...uleb(id(t[1], c.type))] : TYPE[t] ? [TYPE[t]] : uleb(id(t, c.type)) },
774
828
  memarg: (n, c, op) => memargEnc(n, op, isIdx(n[0]) && !isMemParam(n[0]) ? id(n.shift(), c.memory) : 0),
775
829
  opt_memory: (n, c) => uleb(id(isIdx(n[0]) ? n.shift() : 0, c.memory)),
776
830
  reftype: (n, c) => { let ht = reftype(n.shift(), c); return ht.length > 1 ? ht.slice(1) : ht },
777
- reftype2: (n, c) => { let b = blockid(n.shift(), c.block), h1 = reftype(n.shift(), c), h2 = reftype(n.shift(), c); return [((h2[0] !== TYPE.ref) << 1) | (h1[0] !== TYPE.ref), ...uleb(b), h1.pop(), h2.pop()] },
831
+ reftype2: (n, c) => { let b = blockid(n.shift(), c.block), h1 = reftype(n.shift(), c), h2 = reftype(n.shift(), c), ht = h => h.length > 1 ? h.slice(1) : h; return [((h2[0] !== TYPE.ref) << 1) | (h1[0] !== TYPE.ref), ...uleb(b), ...ht(h1), ...ht(h2)] },
778
832
  v128const: (n) => {
779
833
  let [t, num] = n.shift().split('x'), bits = +t.slice(1), stride = bits >>> 3; num = +num
780
834
  if (t[0] === 'i') {
@@ -812,6 +866,7 @@ const IMM = {
812
866
  elemidx: (n, c) => uleb(id(n.shift(), c.elem)),
813
867
  tagidx: (n, c) => uleb(id(n.shift(), c.tag)),
814
868
  'memoryidx?': (n, c) => uleb(id(isIdx(n[0]) ? n.shift() : 0, c.memory)),
869
+ stringidx: (n, c) => { let s = n.shift(), key = s.valueOf(), idx = c.strings.findIndex(x => x.valueOf() === key); if (idx < 0) idx = c.strings.push(s) - 1; return uleb(idx) },
815
870
 
816
871
  // Value type
817
872
  i32: (n) => encode.i32(n.shift()),
@@ -828,7 +883,45 @@ const IMM = {
828
883
  typeidx_typeidx: (n, c) => [...uleb(id(n.shift(), c.type)), ...uleb(id(n.shift(), c.type))],
829
884
  dataidx_memoryidx: (n, c) => [...uleb(id(n.shift(), c.data)), ...uleb(id(n.shift(), c.memory))],
830
885
  memoryidx_memoryidx: (n, c) => [...uleb(id(n.shift(), c.memory)), ...uleb(id(n.shift(), c.memory))],
831
- tableidx_tableidx: (n, c) => [...uleb(id(n.shift(), c.table)), ...uleb(id(n.shift(), c.table))]
886
+ tableidx_tableidx: (n, c) => [...uleb(id(n.shift(), c.table)), ...uleb(id(n.shift(), c.table))],
887
+
888
+ // stack switching handlers (Phase 3)
889
+ cont_bind: (n, c) => [...uleb(id(n.shift(), c.type)), ...uleb(id(n.shift(), c.type))],
890
+ switch_cont: (n, c) => [...uleb(id(n.shift(), c.type)), ...uleb(id(n.shift(), c.tag))],
891
+ resume: (n, c) => {
892
+ const typeidx = uleb(id(n.shift(), c.type))
893
+ const handlers = []; let cnt = 0
894
+ while (n[0]?.[0] === 'on') {
895
+ const [, tag, label] = n.shift()
896
+ if (label === 'switch') handlers.push(0x01, ...uleb(id(tag, c.tag)))
897
+ else handlers.push(0x00, ...uleb(id(tag, c.tag)), ...uleb(blockid(label, c.block)))
898
+ cnt++
899
+ }
900
+ return [...typeidx, ...uleb(cnt), ...handlers]
901
+ },
902
+ resume_throw: (n, c) => {
903
+ const typeidx = uleb(id(n.shift(), c.type))
904
+ const exnidx = uleb(id(n.shift(), c.tag))
905
+ const handlers = []; let cnt = 0
906
+ while (n[0]?.[0] === 'on') {
907
+ const [, tag, label] = n.shift()
908
+ if (label === 'switch') handlers.push(0x01, ...uleb(id(tag, c.tag)))
909
+ else handlers.push(0x00, ...uleb(id(tag, c.tag)), ...uleb(blockid(label, c.block)))
910
+ cnt++
911
+ }
912
+ return [...typeidx, ...exnidx, ...uleb(cnt), ...handlers]
913
+ },
914
+ resume_throw_ref: (n, c) => {
915
+ const typeidx = uleb(id(n.shift(), c.type))
916
+ const handlers = []; let cnt = 0
917
+ while (n[0]?.[0] === 'on') {
918
+ const [, tag, label] = n.shift()
919
+ if (label === 'switch') handlers.push(0x01, ...uleb(id(tag, c.tag)))
920
+ else handlers.push(0x00, ...uleb(id(tag, c.tag)), ...uleb(blockid(label, c.block)))
921
+ cnt++
922
+ }
923
+ return [...typeidx, ...uleb(cnt), ...handlers]
924
+ }
832
925
  };
833
926
 
834
927
  // per-op imm handlers
@@ -939,23 +1032,46 @@ const align = (op) => {
939
1032
  return Math.log2(m ? (m[2] === 'x' ? 8 : m[1] / 8) : +group / 8)
940
1033
  }
941
1034
 
1035
+ // Convert WAT numeric data (i8/i16/i32/i64/f32/f64 lists) to bytes (Phase 2: WAT numeric values)
1036
+ const numdata = (item) => {
1037
+ if (!Array.isArray(item)) return null
1038
+ const [t, ...vs] = item
1039
+ if (t !== 'i8' && t !== 'i16' && t !== 'i32' && t !== 'i64' && t !== 'f32' && t !== 'f64') return null
1040
+ const out = [], dv = new DataView(new ArrayBuffer(8))
1041
+ for (const v of vs) {
1042
+ if (t === 'i8') out.push((i32.parse(v) & 0xFF + 0x100) & 0xFF)
1043
+ else if (t === 'i16') (dv.setInt16(0, i32.parse(v), true), out.push(...new Uint8Array(dv.buffer, 0, 2)))
1044
+ else if (t === 'i32') (dv.setInt32(0, i32.parse(v), true), out.push(...new Uint8Array(dv.buffer, 0, 4)))
1045
+ else if (t === 'i64') (dv.setBigInt64(0, BigInt(v), true), out.push(...new Uint8Array(dv.buffer, 0, 8)))
1046
+ else if (t === 'f32') out.push(...encode.f32(v))
1047
+ else if (t === 'f64') out.push(...encode.f64(v))
1048
+ }
1049
+ return out
1050
+ }
1051
+
942
1052
  // build limits sequence (consuming)
943
1053
  // Memory64: i64 index type uses flags 0x04-0x07 (bit 2 = is_64)
1054
+ // Custom page sizes (Phase 3): (pagesize N) attr adds bit 3, appends log2(pagesize) as u32
944
1055
  const limits = (node) => {
945
1056
  const is64 = node[0] === 'i64' && node.shift()
946
1057
  const shared = node[node.length - 1] === 'shared' && node.pop()
1058
+ // custom page size: (pagesize N) sub-node
1059
+ const psIdx = node.findIndex(n => Array.isArray(n) && n[0] === 'pagesize')
1060
+ let psLog2 = -1
1061
+ if (psIdx >= 0) psLog2 = Math.log2(+node.splice(psIdx, 1)[0][1])
947
1062
  const hasMax = !isNaN(parseInt(node[1]))
948
- const flag = (is64 ? 4 : 0) | (shared ? 2 : 0) | (hasMax ? 1 : 0)
1063
+ const flag = (psLog2 >= 0 ? 8 : 0) | (is64 ? 4 : 0) | (shared ? 2 : 0) | (hasMax ? 1 : 0)
949
1064
  // For i64, parse as unsigned BigInt (limits are always unsigned)
950
1065
  const parse = is64 ? v => {
951
1066
  if (typeof v === 'bigint') return v
952
1067
  const str = typeof v === 'string' ? v.replaceAll('_', '') : String(v)
953
1068
  return BigInt(str)
954
1069
  } : parseUint
1070
+ const ps = psLog2 >= 0 ? uleb(psLog2) : []
955
1071
 
956
1072
  return hasMax
957
- ? [flag, ...uleb(parse(node.shift())), ...uleb(parse(node.shift()))]
958
- : [flag, ...uleb(parse(node.shift()))]
1073
+ ? [flag, ...uleb(parse(node.shift())), ...uleb(parse(node.shift())), ...ps]
1074
+ : [flag, ...uleb(parse(node.shift())), ...ps]
959
1075
  }
960
1076
 
961
1077
  // check if node is valid int in a range
package/src/const.js CHANGED
@@ -48,15 +48,37 @@ export const INSTR = [
48
48
  'i32.extend8_s', 'i32.extend16_s', 'i64.extend8_s', 'i64.extend16_s', 'i64.extend32_s', , , , , , , , , , , ,
49
49
  // 0xd0-0xd6: reference
50
50
  'ref.null ref_null', 'ref.is_null', 'ref.func funcidx', 'ref.eq', 'ref.as_non_null', 'br_on_null labelidx', 'br_on_non_null labelidx',
51
- // 0xd7-0xfa: padding to 0xfb (36 empty slots)
52
- , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
51
+ // 0xd7-0xdf: padding (9 empty slots)
52
+ , , , , , , , , ,
53
+ // 0xe0-0xe6: stack switching (Phase 3)
54
+ 'cont.new typeidx', 'cont.bind cont_bind', 'suspend tagidx', 'resume resume', 'resume_throw resume_throw', 'resume_throw_ref resume_throw_ref', 'switch switch_cont',
55
+ // 0xe7-0xfa: padding (20 empty slots)
56
+ , , , , , , , , , , , , , , , , , , , ,
53
57
  // 0xfb: GC instructions (nested array for multi-byte opcodes)
54
58
  [
55
59
  'struct.new typeidx', 'struct.new_default typeidx', 'struct.get typeidx_field', 'struct.get_s typeidx_field', 'struct.get_u typeidx_field', 'struct.set typeidx_field',
56
60
  'array.new typeidx', 'array.new_default typeidx', 'array.new_fixed typeidx_multi', 'array.new_data typeidx_dataidx', 'array.new_elem typeidx_elemidx',
57
61
  'array.get typeidx', 'array.get_s typeidx', 'array.get_u typeidx', 'array.set typeidx', 'array.len', 'array.fill typeidx', 'array.copy typeidx_typeidx',
58
62
  'array.init_data typeidx_dataidx', 'array.init_elem typeidx_elemidx', 'ref.test reftype', '', 'ref.cast reftype', '', 'br_on_cast reftype2', 'br_on_cast_fail reftype2',
59
- 'any.convert_extern', 'extern.convert_any', 'ref.i31', 'i31.get_s', 'i31.get_u'
63
+ 'any.convert_extern', 'extern.convert_any', 'ref.i31', 'i31.get_s', 'i31.get_u',
64
+ // custom descriptors (Phase 3): 0xFB 0x20-0x26
65
+ , 'struct.new_desc typeidx', 'struct.new_default_desc typeidx', 'ref.get_desc typeidx', 'ref.cast_desc_eq reftype', , 'br_on_cast_desc_eq reftype2', 'br_on_cast_desc_eq_fail reftype2',
66
+ // 0xFB 0x28-0x7F: padding (88 empty slots)
67
+ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
68
+ // stringref: 0xFB 0x80-0xB7
69
+ 'string.new_utf8 memoryidx?', 'string.new_wtf16 memoryidx?', 'string.const stringidx', 'string.measure_utf8', 'string.measure_wtf8', 'string.measure_wtf16',
70
+ 'string.encode_utf8 memoryidx?', 'string.encode_wtf16 memoryidx?', 'string.concat', 'string.eq', 'string.is_usv_sequence',
71
+ 'string.new_lossy_utf8 memoryidx?', 'string.new_wtf8 memoryidx?', 'string.encode_lossy_utf8 memoryidx?', 'string.encode_wtf8 memoryidx?',
72
+ , // 0x8F
73
+ 'string.as_wtf8', 'stringview_wtf8.advance', 'stringview_wtf8.encode_utf8 memoryidx?', 'stringview_wtf8.slice',
74
+ 'stringview_wtf8.encode_lossy_utf8 memoryidx?', 'stringview_wtf8.encode_wtf8 memoryidx?',
75
+ ,, // 0x96-0x97
76
+ 'string.as_wtf16', 'stringview_wtf16.length', 'stringview_wtf16.get_codeunit', 'stringview_wtf16.encode memoryidx?', 'stringview_wtf16.slice',
77
+ ,,, // 0x9D-0x9F
78
+ 'string.as_iter', 'stringview_iter.next', 'stringview_iter.advance', 'stringview_iter.rewind', 'stringview_iter.slice',
79
+ ,,,,,,,,,,, // 0xA5-0xAF
80
+ 'string.new_utf8_array', 'string.new_wtf16_array', 'string.encode_utf8_array', 'string.encode_wtf16_array',
81
+ 'string.new_lossy_utf8_array', 'string.new_wtf8_array', 'string.encode_lossy_utf8_array', 'string.encode_wtf8_array'
60
82
  ],
61
83
 
62
84
  // 0xfc: Bulk memory/table operations (nested array)
@@ -138,7 +160,7 @@ export const INSTR = [
138
160
  ]
139
161
 
140
162
  // Binary section type codes
141
- export const SECTION = { custom: 0, type: 1, import: 2, func: 3, table: 4, memory: 5, tag: 13, global: 6, export: 7, start: 8, elem: 9, datacount: 12, code: 10, data: 11 }
163
+ export const SECTION = { custom: 0, type: 1, import: 2, func: 3, table: 4, memory: 5, tag: 13, strings: 14, global: 6, export: 7, start: 8, elem: 9, datacount: 12, code: 10, data: 11 }
142
164
 
143
165
  // Type codes
144
166
  export const TYPE = {
@@ -146,9 +168,13 @@ export const TYPE = {
146
168
  i8: 0x78, i16: 0x77, i32: 0x7f, i64: 0x7e, f32: 0x7d, f64: 0x7c, void: 0x40, v128: 0x7B,
147
169
  // Heap types
148
170
  exn: 0x69, noexn: 0x74, nofunc: 0x73, noextern: 0x72, none: 0x71, func: 0x70, extern: 0x6F, any: 0x6E, eq: 0x6D, i31: 0x6C, struct: 0x6B, array: 0x6A,
171
+ cont: 0x68, nocont: 0x75, // stack switching (Phase 3)
172
+ string: 0x67, stringview_wtf8: 0x66, stringview_wtf16: 0x60, stringview_iter: 0x61, // stringref
149
173
  // Reference type abbreviations (absheaptype abbrs)
150
174
  nullfuncref: 0x73, nullexternref: 0x72, nullexnref: 0x74, nullref: 0x71,
151
175
  funcref: 0x70, externref: 0x6F, exnref: 0x69, anyref: 0x6E, eqref: 0x6D, i31ref: 0x6C, structref: 0x6B, arrayref: 0x6A,
176
+ contref: 0x68, nocontref: 0x75, // stack switching abbreviations
177
+ stringref: 0x67, // stringref abbreviation
152
178
  // ref, refnull
153
179
  ref: 0x64, // -0x1c
154
180
  refnull: 0x63, // -0x1d
@@ -157,7 +183,7 @@ export const TYPE = {
157
183
  }
158
184
 
159
185
  // Type definition codes (different from heap types - func is 0x60 not 0x70)
160
- export const DEFTYPE = { func: 0x60, struct: 0x5F, array: 0x5E, sub: 0x50, subfinal: 0x4F, rec: 0x4E }
186
+ export const DEFTYPE = { func: 0x60, struct: 0x5F, array: 0x5E, cont: 0x5D, sub: 0x50, subfinal: 0x4F, rec: 0x4E }
161
187
 
162
188
  // Import/export kind codes
163
189
  export const KIND = { func: 0, table: 1, memory: 2, global: 3, tag: 4 }
package/src/parse.js CHANGED
@@ -25,14 +25,18 @@ export default (str) => {
25
25
  c === 59 && str.charCodeAt(i + 1) === 41 ? (buf += str[i++] + str[i++], --q === 59 && (commit(), q = 0)) : // ;)
26
26
  buf += str[i++]
27
27
  )
28
- // inside ;; ...\n
29
- else if (q < 0) (c === 10 || c === 13 ? (buf += str[i++], commit(), q = 0) : buf += str[i++])
28
+ // inside ;; ..\n: q=-1 normal (has newline), q=-2 inline (no newline — ) ends comment)
29
+ else if (q < 0) (
30
+ c === 10 || c === 13 ? (buf += str[i++], commit(), q = 0) :
31
+ q === -2 && c === 41 ? (commit(), q = 0) :
32
+ buf += str[i++]
33
+ )
30
34
  // start "
31
35
  else if (c === 34) (buf !== '$' && commit(), q = 34, buf += str[i++])
32
36
  // start (;
33
37
  else if (c === 40 && str.charCodeAt(i + 1) === 59) (commit(), q = 60, buf = str[i++] + str[i++])
34
38
  // start ;;
35
- else if (c === 59 && str.charCodeAt(i + 1) === 59) (commit(), q = -1, buf = str[i++] + str[i++])
39
+ else if (c === 59 && str.charCodeAt(i + 1) === 59) (commit(), q = str.indexOf('\n', i) < 0 ? -2 : -1, buf = str[i++] + str[i++])
36
40
  // start (@
37
41
  else if (c === 40 && str.charCodeAt(i + 1) === 64) (commit(), p = i, i += 2, buf = '@', depth++, (root = level).push(level = []), parseLevel(p), level = root)
38
42
  // start (
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"AA+BA;;;;;GAKG;AACH,uCAHW,MAAM,QAAM,GACV,UAAU,CA6LtB"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"AA+BA;;;;;GAKG;AACH,uCAHW,MAAM,QAAM,GACV,UAAU,CA8NtB"}
@@ -8,6 +8,7 @@ export namespace SECTION {
8
8
  export let table: number;
9
9
  export let memory: number;
10
10
  export let tag: number;
11
+ export let strings: number;
11
12
  export let global: number;
12
13
  let _export: number;
13
14
  export { _export as export };
@@ -40,6 +41,12 @@ export namespace TYPE {
40
41
  export let i31: number;
41
42
  export let struct: number;
42
43
  export let array: number;
44
+ export let cont: number;
45
+ export let nocont: number;
46
+ export let string: number;
47
+ export let stringview_wtf8: number;
48
+ export let stringview_wtf16: number;
49
+ export let stringview_iter: number;
43
50
  export let nullfuncref: number;
44
51
  export let nullexternref: number;
45
52
  export let nullexnref: number;
@@ -52,6 +59,9 @@ export namespace TYPE {
52
59
  export let i31ref: number;
53
60
  export let structref: number;
54
61
  export let arrayref: number;
62
+ export let contref: number;
63
+ export let nocontref: number;
64
+ export let stringref: number;
55
65
  export let ref: number;
56
66
  export let refnull: number;
57
67
  export let sub: number;
@@ -65,6 +75,8 @@ export namespace DEFTYPE {
65
75
  export { struct_1 as struct };
66
76
  let array_1: number;
67
77
  export { array_1 as array };
78
+ let cont_1: number;
79
+ export { cont_1 as cont };
68
80
  let sub_1: number;
69
81
  export { sub_1 as sub };
70
82
  let subfinal_1: number;
@@ -1 +1 @@
1
- {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/const.js"],"names":[],"mappings":"AAIA,0CAqIC"}
1
+ {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/const.js"],"names":[],"mappings":"AAIA,0CA2JC"}
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/parse.js"],"names":[],"mappings":"AASe,+BAHJ,MAAM,SAqDhB"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/parse.js"],"names":[],"mappings":"AASe,+BAHJ,MAAM,SAyDhB"}