watr 4.7.1 → 5.0.0
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 +141 -3872
- package/dist/watr.min.js +6 -6
- package/dist/watr.wasm +0 -0
- package/package.json +12 -2
- package/readme.md +9 -6
- package/src/compile.js +92 -13
- package/src/optimize.js +5 -2
- package/src/template.js +23 -5
- package/types/src/compile.d.ts +10 -9
- package/types/src/compile.d.ts.map +1 -1
- package/types/src/optimize.d.ts.map +1 -1
- package/types/src/template.d.ts.map +1 -1
- package/types/watr.d.ts +4 -5
- package/types/watr.d.ts.map +1 -1
- package/watr.js +10 -7
package/src/compile.js
CHANGED
|
@@ -37,17 +37,10 @@ const cleanup = (node, result) => {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
* @returns {Uint8Array} The compiled WASM binary. When the WAT carries
|
|
45
|
-
* `@metadata.code.<type>` annotations, the result also exposes a `.metadata`
|
|
46
|
-
* property — `{ [type]: [[absoluteByteOffset, data], ...] }`, each offset the
|
|
47
|
-
* instruction's position in the final binary. That's the hook a source-map
|
|
48
|
-
* emitter needs to correlate generated wasm back to its source.
|
|
49
|
-
*/
|
|
50
|
-
export default function compile(nodes) {
|
|
40
|
+
// Internal: assemble the module. sizeOnly=false → wasm bytes (Uint8Array); sizeOnly=true →
|
|
41
|
+
// just the byte LENGTH, skipping materialization of the multi-MB binary — that's size()'s
|
|
42
|
+
// reason to exist (the optimizer's size-revert guard can't afford to build bytes it discards).
|
|
43
|
+
function assemble(nodes, sizeOnly) {
|
|
51
44
|
// normalize to (module ...) form
|
|
52
45
|
if (typeof nodes === 'string') err.src = nodes, nodes = parse(nodes) || []
|
|
53
46
|
else err.src = '' // clear source if AST passed directly
|
|
@@ -63,10 +56,10 @@ export default function compile(nodes) {
|
|
|
63
56
|
else if (typeof nodes[0] === 'string') nodes = [nodes]
|
|
64
57
|
|
|
65
58
|
// binary abbr "\00" "\0x61" ...
|
|
66
|
-
if (nodes[idx] === 'binary')
|
|
59
|
+
if (nodes[idx] === 'binary') { const b = Uint8Array.from(nodes.slice(++idx).flat()); return sizeOnly ? b.length : b }
|
|
67
60
|
|
|
68
61
|
// quote "a" "b"
|
|
69
|
-
if (nodes[idx] === 'quote') return
|
|
62
|
+
if (nodes[idx] === 'quote') return assemble(nodes.slice(++idx).map(v => v.valueOf().slice(1, -1)).flat().join(''), sizeOnly)
|
|
70
63
|
|
|
71
64
|
// expand grouped imports: (import "mod" (item "name" type)*) -> individual imports
|
|
72
65
|
// compact import section (Phase 3)
|
|
@@ -241,6 +234,26 @@ export default function compile(nodes) {
|
|
|
241
234
|
// pre-compute sections that may collect string constants (for strings section ordering)
|
|
242
235
|
const globalSection = bin(SECTION.global)
|
|
243
236
|
const elemSection = bin(SECTION.elem)
|
|
237
|
+
// measure: byte LENGTH only — skip building + materializing the multi-MB code byte array
|
|
238
|
+
// (the optimizer's size-revert guard only needs the count). Sizes the code section via
|
|
239
|
+
// codeItemSize; other sections are small, built normally + summed. Same string-collection
|
|
240
|
+
// ORDER as the emit path (global, elem, code, meta, data → strings).
|
|
241
|
+
if (sizeOnly) {
|
|
242
|
+
const codeSizes = ctx.code.filter(Boolean).map(item => codeItemSize(item, ctx))
|
|
243
|
+
const innerLen = codeSizes.length ? ulebSize(codeSizes.length) + codeSizes.reduce((a, b) => a + b, 0) : 0
|
|
244
|
+
const codeSecLen = codeSizes.length ? 1 + ulebSize(innerLen) + innerLen : 0 // SECTION.code + vec(vec(items))
|
|
245
|
+
const metaSection = binMeta()
|
|
246
|
+
const dataSection = bin(SECTION.data)
|
|
247
|
+
const stringsSection = ctx.strings.length ? [SECTION.strings, ...vec([0x00, ...vec(ctx.strings.map(s => vec(s)))])] : []
|
|
248
|
+
const others = [
|
|
249
|
+
bin(SECTION.custom), bin(SECTION.type), bin(SECTION.import), bin(SECTION.func),
|
|
250
|
+
bin(SECTION.table), bin(SECTION.memory), bin(SECTION.tag), stringsSection,
|
|
251
|
+
globalSection, bin(SECTION.export), bin(SECTION.start, false), elemSection,
|
|
252
|
+
bin(SECTION.datacount, false), metaSection, dataSection
|
|
253
|
+
]
|
|
254
|
+
return 8 + codeSecLen + others.reduce((s, sec) => s + sec.length, 0) // 8 = magic + version
|
|
255
|
+
}
|
|
256
|
+
|
|
244
257
|
// inline bin(code) so the per-function item bytes survive — with ctx.codeSizePrefix
|
|
245
258
|
// they let us lift code-metadata positions to absolute binary offsets below
|
|
246
259
|
const codeItems = ctx.code.filter(Boolean).map(item => build[SECTION.code](item, ctx)).filter(Boolean)
|
|
@@ -317,6 +330,19 @@ export default function compile(nodes) {
|
|
|
317
330
|
}
|
|
318
331
|
}
|
|
319
332
|
|
|
333
|
+
/**
|
|
334
|
+
* Convert a WAT tree (or source string) to a wasm binary (Uint8Array). When the WAT carries
|
|
335
|
+
* `@metadata.code.<type>` annotations the result also exposes `.metadata` —
|
|
336
|
+
* `{ [type]: [[absByteOffset, data], ...] }`, the hook a source-map emitter needs.
|
|
337
|
+
*/
|
|
338
|
+
export default function compile(nodes) { return assemble(nodes) }
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Byte size of `compile(nodes)` without materializing the binary — a peer transform for
|
|
342
|
+
* tooling (the optimizer's size-revert guard, size budgeting). Exactly `compile(nodes).length`,
|
|
343
|
+
* summed from section sizes instead of building them (invariant-tested).
|
|
344
|
+
*/
|
|
345
|
+
export function size(nodes) { return assemble(nodes, true) }
|
|
320
346
|
|
|
321
347
|
/** Check if node is a valid index reference ($name or number) */
|
|
322
348
|
const isIdx = n => n?.[0] === '$' || !isNaN(n)
|
|
@@ -1062,6 +1088,59 @@ const instr = (nodes, ctx) => {
|
|
|
1062
1088
|
return out.push(0x0b), out
|
|
1063
1089
|
}
|
|
1064
1090
|
|
|
1091
|
+
// LEB128 byte-width of an unsigned integer (exact, reuses uleb so it can never drift).
|
|
1092
|
+
const ulebSize = (n) => uleb(n).length
|
|
1093
|
+
|
|
1094
|
+
// Size-only twin of instr(): the byte LENGTH of the encoded instruction stream,
|
|
1095
|
+
// WITHOUT building the (multi-MB) byte array. Reuses every HANDLER for exact
|
|
1096
|
+
// immediate widths + index resolution — only `out.push(...bytes)` accumulation is
|
|
1097
|
+
// replaced by integer summation (the dominant cost on large modules). The
|
|
1098
|
+
// opcode-value tweaks in instr() (typed-select / nullable-reftype) change a byte
|
|
1099
|
+
// VALUE, not the length, so they're irrelevant here. MUST equal instr(...).length
|
|
1100
|
+
// (asserted by the byteSize↔compile invariant test).
|
|
1101
|
+
const instrSize = (nodes, ctx) => {
|
|
1102
|
+
let size = 0, meta = []
|
|
1103
|
+
while (nodes?.length) {
|
|
1104
|
+
let op = nodes.shift()
|
|
1105
|
+
if (op?.[0] === '@metadata') { meta.push(op.slice(1)); continue }
|
|
1106
|
+
if (Array.isArray(op)) { op.loc != null && (err.loc = op.loc); err(`Unknown instruction ${op[0]}`) }
|
|
1107
|
+
const opc = INSTR[op] || err(`Unknown instruction ${op}`)
|
|
1108
|
+
let n = opc.length
|
|
1109
|
+
if (HANDLER[op]) n += HANDLER[op](nodes, ctx, op).length
|
|
1110
|
+
if (meta.length) { for (const [type, data] of meta) ((ctx.meta[type] ??= []).push([size, data])); meta = [] }
|
|
1111
|
+
size += n
|
|
1112
|
+
}
|
|
1113
|
+
return size + 1 // trailing 0x0b (end)
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// Size-only twin of build[SECTION.code]: byte LENGTH of one function's code item.
|
|
1117
|
+
// Mirrors the builder exactly (local setup, squash, metadata bookkeeping, vec
|
|
1118
|
+
// framing) but uses instrSize for the body — so locals/strings/metadata side
|
|
1119
|
+
// effects on ctx stay identical, only the body byte array is never materialized.
|
|
1120
|
+
const codeItemSize = (body, ctx) => {
|
|
1121
|
+
let [typeidx, param] = body.shift()
|
|
1122
|
+
if (!param) [, [param]] = ctx.type[id(typeidx, ctx.type)]
|
|
1123
|
+
ctx.local = Object.create(param); ctx.block = []
|
|
1124
|
+
ctx.local.name = 'local'; ctx.block.name = 'block'
|
|
1125
|
+
if (ctx._codeIdx === undefined) ctx._codeIdx = 0
|
|
1126
|
+
let codeIdx = ctx._codeIdx++
|
|
1127
|
+
while (body[0]?.[0] === 'local') {
|
|
1128
|
+
let [, ...types] = body.shift()
|
|
1129
|
+
if (isId(types[0])) { let nm = types.shift(); if (nm in ctx.local) err(`Duplicate local ${nm}`); else ctx.local[nm] = ctx.local.length }
|
|
1130
|
+
ctx.local.push(...types)
|
|
1131
|
+
}
|
|
1132
|
+
ctx.meta = {}
|
|
1133
|
+
const bytesLen = instrSize(body, ctx)
|
|
1134
|
+
let loctypes = ctx.local.slice(param.length).reduce((a, type) => (type == a[a.length - 1]?.[1] ? a[a.length - 1][0]++ : a.push([1, type]), a), [])
|
|
1135
|
+
const locals = vec(loctypes.map(([n, t]) => [...uleb(n), ...reftype(t, ctx)]))
|
|
1136
|
+
const funcIdx = ctx.import.filter(imp => imp[2][0] === 'func').length + codeIdx
|
|
1137
|
+
for (const type in ctx.meta) { for (const inst of ctx.meta[type]) inst[0] += locals.length; ((ctx.metadata ??= {})[type] ??= []).push([funcIdx, ctx.meta[type]]) }
|
|
1138
|
+
ctx.local = ctx.block = ctx.meta = null
|
|
1139
|
+
const bodyLen = locals.length + bytesLen
|
|
1140
|
+
;(ctx.codeSizePrefix ??= [])[codeIdx] = ulebSize(bodyLen) // = vec prefix width
|
|
1141
|
+
return ulebSize(bodyLen) + bodyLen // vec([...locals, ...bytes]).length
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1065
1144
|
// instantiation time value initializer (consuming) - normalize then encode + add end byte
|
|
1066
1145
|
const expr = (node, ctx) => instr(normalize([node], ctx), ctx)
|
|
1067
1146
|
|
package/src/optimize.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module wat/optimize
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import compile from './compile.js'
|
|
10
|
+
import compile, { size } from './compile.js'
|
|
11
11
|
import parse from './parse.js'
|
|
12
12
|
|
|
13
13
|
// Fixpoint round caps — empirical convergence bounds, not correctness limits.
|
|
@@ -68,7 +68,10 @@ const count = (node) => {
|
|
|
68
68
|
* @returns {number}
|
|
69
69
|
*/
|
|
70
70
|
const binarySize = (ast) => {
|
|
71
|
-
|
|
71
|
+
// `size` = byte length without materializing the binary — the size-revert guard only needs
|
|
72
|
+
// the count, and re-encoding the whole module each round is the optimizer's dominant cost on
|
|
73
|
+
// large modules. Exactly compile(ast).length (invariant-tested).
|
|
74
|
+
try { return size(ast) } catch { return Infinity }
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
/**
|
package/src/template.js
CHANGED
|
@@ -19,6 +19,24 @@ import { resultType } from './const.js'
|
|
|
19
19
|
/** Private Use Area character as placeholder for interpolation */
|
|
20
20
|
const PUA = '\uE000'
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Apply a backend transform (`polyfill`/`optimize`), or throw an actionable
|
|
24
|
+
* pointer when this entry doesn't bundle it. The default `watr` build wires a
|
|
25
|
+
* lean backend (parse + compile) and leaves the heavy transforms to their own
|
|
26
|
+
* entries, so `compile(src, { optimize })` here directs you to compose instead.
|
|
27
|
+
*
|
|
28
|
+
* @param {Function|undefined} fn - transform from the backend
|
|
29
|
+
* @param {string} name - 'polyfill' | 'optimize'
|
|
30
|
+
* @param {Array} ast
|
|
31
|
+
* @param {any} opt - the option value
|
|
32
|
+
* @returns {Array} transformed AST
|
|
33
|
+
*/
|
|
34
|
+
function applyTransform(fn, name, ast, opt) {
|
|
35
|
+
if (typeof fn !== 'function')
|
|
36
|
+
throw Error(`watr: '${name}' is not bundled in this entry \u2014 import it from 'watr/${name}' and compose: compile(${name}(src))`)
|
|
37
|
+
return fn(ast, opt)
|
|
38
|
+
}
|
|
39
|
+
|
|
22
40
|
/**
|
|
23
41
|
* Infer type of an expression AST node.
|
|
24
42
|
* Used for auto-import parameter type inference.
|
|
@@ -209,9 +227,9 @@ export function compile(backend, source, values) {
|
|
|
209
227
|
}
|
|
210
228
|
}
|
|
211
229
|
|
|
212
|
-
// Apply transforms
|
|
213
|
-
if (opts.polyfill) ast = polyfill
|
|
214
|
-
if (opts.optimize) ast = optimize
|
|
230
|
+
// Apply transforms (heavy passes live in separate entries — see applyTransform)
|
|
231
|
+
if (opts.polyfill) ast = applyTransform(polyfill, 'polyfill', ast, opts.polyfill)
|
|
232
|
+
if (opts.optimize) ast = applyTransform(optimize, 'optimize', ast, opts.optimize)
|
|
215
233
|
|
|
216
234
|
const binary = emit(ast)
|
|
217
235
|
// Attach imports for watr() to use
|
|
@@ -222,8 +240,8 @@ export function compile(backend, source, values) {
|
|
|
222
240
|
// String/AST source with options
|
|
223
241
|
if (opts.polyfill || opts.optimize) {
|
|
224
242
|
let ast = typeof source === 'string' ? parse(source) : source
|
|
225
|
-
if (opts.polyfill) ast = polyfill
|
|
226
|
-
if (opts.optimize) ast = optimize
|
|
243
|
+
if (opts.polyfill) ast = applyTransform(polyfill, 'polyfill', ast, opts.polyfill)
|
|
244
|
+
if (opts.optimize) ast = applyTransform(optimize, 'optimize', ast, opts.optimize)
|
|
227
245
|
return emit(ast)
|
|
228
246
|
}
|
|
229
247
|
return emit(source)
|
package/types/src/compile.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* @returns {Uint8Array} The compiled WASM binary. When the WAT carries
|
|
6
|
-
* `@metadata.code.<type>` annotations, the result also exposes a `.metadata`
|
|
7
|
-
* property — `{ [type]: [[absoluteByteOffset, data], ...] }`, each offset the
|
|
8
|
-
* instruction's position in the final binary. That's the hook a source-map
|
|
9
|
-
* emitter needs to correlate generated wasm back to its source.
|
|
2
|
+
* Convert a WAT tree (or source string) to a wasm binary (Uint8Array). When the WAT carries
|
|
3
|
+
* `@metadata.code.<type>` annotations the result also exposes `.metadata` —
|
|
4
|
+
* `{ [type]: [[absByteOffset, data], ...] }`, the hook a source-map emitter needs.
|
|
10
5
|
*/
|
|
11
|
-
export default function compile(nodes:
|
|
6
|
+
export default function compile(nodes: any): any;
|
|
7
|
+
/**
|
|
8
|
+
* Byte size of `compile(nodes)` without materializing the binary — a peer transform for
|
|
9
|
+
* tooling (the optimizer's size-revert guard, size budgeting). Exactly `compile(nodes).length`,
|
|
10
|
+
* summed from section sizes instead of building them (invariant-tested).
|
|
11
|
+
*/
|
|
12
|
+
export function size(nodes: any): any;
|
|
12
13
|
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compile.js"],"names":[],"mappings":"AA4UA;;;;GAIG;AACH,iDAAiE;AAEjE;;;;GAIG;AACH,sCAA4D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/optimize.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"optimize.d.ts","sourceRoot":"","sources":["../../src/optimize.js"],"names":[],"mappings":"AAsxHA,gEA6FC;AA/zHD;;;;GAIG;AACH,4BAHW,GAAG,GACD,MAAM,CAOlB;AAED;;;;GAIG;AACH,wCAFa,MAAM,CAOlB;AA8CD;;;;;GAKG;AACH,6CAgJC;AAwUD;;;;GAIG;AACH,wCAkDC;AA0YD;;;;GAIG;AACH,4CAqBC;AA+CD;;;;;GAKG;AACH,8CAmDC;AAndD;;;;GAIG;AACH,4CASC;AAID;;;;GAIG;AACH,4CAwDC;AAID;;;;GAIG;AACH,0CA6CC;AAuyBD,yCAqCC;AAmND;;;QAqEC;AAuQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;;UA+IC;AA/aD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,sCAwOC;AA0gDD;;;;;;;;GAQG;AACH,gCAHW,OAAO,GAAC,MAAM,MAAO,OAc/B;AAvBD,qEAAqE;AACrE,uBAA8D;AArlC9D;;;;;GAKG;AACH,0CA8DC;AA+ED;;;;GAIG;AACH,4CAQC;AAiCD;;;;;;;;;;;GAWG;AACH,2CAyDC;AAID,2EAA2E;AAC3E,sCAgEC;AAID;;;;GAIG;AACH,4CAyCC;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,2CAiDC;AAID;;;;;GAKG;AACH,4CAqBC;AAID;;;;;;GAMG;AACH,wCAmBC;AAID;;;;;GAKG;AACH,4CAiDC;AAoCD;;;;;GAKG;AACH,0CA8DC;AAwWD,uCAyBC;AA7XD;;;;;GAKG;AACH,8CAyEC;AA2ID;;;;GAIG;AACH,4CAyDC;AAqBD;;;;;GAKG;AACH,iDAgBC;AA/sCD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,+CAiFC;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,kDAyFC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/template.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/template.js"],"names":[],"mappings":"AA8IA;;;;;;;;;;GAUG;AACH,8CAPW,MAAM,WAAO,oBAAoB,UACjC,GAAG,EAAE,GAIH,UAAU,CAgGtB;AAED;;;;;;;GAOG;AACH,2CAJW,MAAM,WAAO,oBAAoB,UACjC,GAAG,EAAE,GACH,WAAW,CAAC,OAAO,CAO/B"}
|
package/types/watr.d.ts
CHANGED
|
@@ -17,18 +17,17 @@ export function watr(source: string | TemplateStringsArray, ...values: any[]): W
|
|
|
17
17
|
*
|
|
18
18
|
* @param {string|TemplateStringsArray} source - WAT source or template strings
|
|
19
19
|
* @param {...any} values - Interpolation values (for template literal).
|
|
20
|
-
* Last value can be an options object: { polyfill, optimize }.
|
|
21
20
|
* @returns {Uint8Array} WebAssembly binary
|
|
22
21
|
*
|
|
23
22
|
* @example
|
|
24
23
|
* compile('(func (export "f") (result i32) (i32.const 42))')
|
|
25
24
|
* compile`(func (export "f") (result f64) (f64.const ${Math.PI}))`
|
|
26
|
-
*
|
|
25
|
+
* // transforms ship as separate entries — compose them:
|
|
26
|
+
* // import optimize from 'watr/optimize'
|
|
27
|
+
* // compile(optimize(src))
|
|
27
28
|
*/
|
|
28
29
|
export function compile(source: string | TemplateStringsArray, ...values: any[]): Uint8Array;
|
|
29
30
|
import parse from './src/parse.js';
|
|
30
31
|
import print from './src/print.js';
|
|
31
|
-
|
|
32
|
-
import _optimize from './src/optimize.js';
|
|
33
|
-
export { parse, print, _polyfill as polyfill, _optimize as optimize };
|
|
32
|
+
export { parse, print };
|
|
34
33
|
//# sourceMappingURL=watr.d.ts.map
|
package/types/watr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watr.d.ts","sourceRoot":"","sources":["../watr.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"watr.d.ts","sourceRoot":"","sources":["../watr.js"],"names":[],"mappings":";AAoCA;;;;;;;;;;;GAWG;AACH,6BATW,MAAM,GAAC,oBAAoB,aACxB,GAAG,EAAA,GACJ,WAAW,CAAC,OAAO,CAS/B;AAhCD;;;;;;;;;;;;;GAaG;AACH,gCAXW,MAAM,GAAC,oBAAoB,aACxB,GAAG,EAAA,GACJ,UAAU,CAWtB;kBA3BiB,gBAAgB;kBAChB,gBAAgB"}
|
package/watr.js
CHANGED
|
@@ -7,25 +7,28 @@
|
|
|
7
7
|
import _compile from './src/compile.js'
|
|
8
8
|
import parse from './src/parse.js'
|
|
9
9
|
import print from './src/print.js'
|
|
10
|
-
import _polyfill from './src/polyfill.js'
|
|
11
|
-
import _optimize from './src/optimize.js'
|
|
12
10
|
import { compile as _tcompile, watr as _twatr } from './src/template.js'
|
|
13
11
|
|
|
14
|
-
/** JS-source backend primitives for the tagged-template layer.
|
|
15
|
-
|
|
12
|
+
/** JS-source backend primitives for the tagged-template layer.
|
|
13
|
+
* `polyfill` and `optimize` are intentionally NOT wired here — they're heavy
|
|
14
|
+
* (the optimizer alone is ~5× the core encoder) and ship as separate entries,
|
|
15
|
+
* `watr/polyfill` and `watr/optimize`, that you compose explicitly:
|
|
16
|
+
* `compile(optimize(src))`. This keeps the default bundle minimal. */
|
|
17
|
+
const backend = { parse, compile: _compile }
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* Compile WAT to binary. Supports both string and template literal.
|
|
19
21
|
*
|
|
20
22
|
* @param {string|TemplateStringsArray} source - WAT source or template strings
|
|
21
23
|
* @param {...any} values - Interpolation values (for template literal).
|
|
22
|
-
* Last value can be an options object: { polyfill, optimize }.
|
|
23
24
|
* @returns {Uint8Array} WebAssembly binary
|
|
24
25
|
*
|
|
25
26
|
* @example
|
|
26
27
|
* compile('(func (export "f") (result i32) (i32.const 42))')
|
|
27
28
|
* compile`(func (export "f") (result f64) (f64.const ${Math.PI}))`
|
|
28
|
-
*
|
|
29
|
+
* // transforms ship as separate entries — compose them:
|
|
30
|
+
* // import optimize from 'watr/optimize'
|
|
31
|
+
* // compile(optimize(src))
|
|
29
32
|
*/
|
|
30
33
|
function compile(source, ...values) {
|
|
31
34
|
return _tcompile(backend, source, values)
|
|
@@ -48,4 +51,4 @@ function watr(source, ...values) {
|
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
export default watr
|
|
51
|
-
export { watr, compile, parse, print
|
|
54
|
+
export { watr, compile, parse, print }
|