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/dist/watr.js +326 -46
- package/dist/watr.min.js +6 -5
- package/package.json +1 -1
- package/readme.md +8 -13
- package/src/compile.js +160 -44
- package/src/const.js +31 -5
- package/src/parse.js +7 -3
- package/types/src/compile.d.ts.map +1 -1
- package/types/src/const.d.ts +12 -0
- package/types/src/const.d.ts.map +1 -1
- package/types/src/parse.d.ts.map +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
...
|
|
248
|
+
...stringsSection,
|
|
249
|
+
...globalSection,
|
|
217
250
|
...bin(SECTION.export),
|
|
218
251
|
...bin(SECTION.start, false),
|
|
219
|
-
...
|
|
252
|
+
...elemSection,
|
|
220
253
|
...bin(SECTION.datacount, false),
|
|
221
|
-
...
|
|
222
|
-
...
|
|
223
|
-
...
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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
|
-
(
|
|
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
|
-
|
|
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
|
-
|
|
470
|
-
|
|
471
|
-
|
|
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
|
-
|
|
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 [
|
|
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),
|
|
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.
|
|
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
|
|
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-
|
|
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 ;;
|
|
29
|
-
else if (q < 0) (
|
|
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,
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"AA+BA;;;;;GAKG;AACH,uCAHW,MAAM,QAAM,GACV,UAAU,CA8NtB"}
|
package/types/src/const.d.ts
CHANGED
|
@@ -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;
|
package/types/src/const.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/const.js"],"names":[],"mappings":"AAIA,
|
|
1
|
+
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../../src/const.js"],"names":[],"mappings":"AAIA,0CA2JC"}
|
package/types/src/parse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/parse.js"],"names":[],"mappings":"AASe,+BAHJ,MAAM,
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/parse.js"],"names":[],"mappings":"AASe,+BAHJ,MAAM,SAyDhB"}
|