watr 1.1.1 → 1.2.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.
Files changed (4) hide show
  1. package/package.json +1 -1
  2. package/readme.md +16 -10
  3. package/watr.js +236 -155
  4. package/watr.min.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "watr",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Ligth & fast WAT compiler",
5
5
  "main": "watr.js",
6
6
  "type": "module",
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # watr
1
+ # watr [![Test](https://github.com/audio-lab/watr/actions/workflows/test.js.yml/badge.svg)](https://github.com/audio-lab/watr/actions/workflows/test.js.yml)
2
2
 
3
3
  > Light & fast WAT compiler.
4
4
 
@@ -17,9 +17,9 @@ Performance (op/s) | 45000 | 2500 | 3100
17
17
 
18
18
    | Size (gzipped) | Performance (op/s)
19
19
  ---|---|---
20
- watr | 3.3 kb | 45,000
21
- wat-compiler | 6 kb | 2,500
22
- wabt | 300 kb | 3,100
20
+ watr | 3.8 kb | 1900
21
+ wat-compiler | 6 kb | 135
22
+ wabt | 300 kb | 250
23
23
 
24
24
  ## Usage
25
25
 
@@ -62,8 +62,9 @@ double(108) // 216
62
62
 
63
63
  ## Limitations
64
64
 
65
- Ambiguous syntax is intentionally prohibited in favor of explicit lispy structure.<br>
66
- Each instruction has prefix signature with parenthesized immediates and arguments.
65
+ Ambiguous syntax is prohibited in favor of explicit lispy structure.<br>
66
+ Each instruction must have prefix signature with parenthesized immediates and arguments.<br>
67
+ It may be supported, but discouraged.
67
68
 
68
69
  ```wast
69
70
  (func (result i32)
@@ -95,11 +96,16 @@ end
95
96
  )
96
97
  ```
97
98
 
98
- Numbers format limitation:
99
+ ```wast
100
+ (f32.const 0x1.fffffep+127) ;; ✘ floating HEX (not supported)
101
+ ```
102
+
103
+ ```wast
104
+ (global.set $pc (;(i32.const <new-pc>);)) ✘ default arguments must be explicit
105
+ ```
99
106
 
100
- * Int64 input format `0x7fffffffffffffff` is not supported (at the moment), only Int32.
101
- * Floating HEX like `0x1.fffffep+127` format is not supported.
102
- * Numeric placeholders `122_000.11_3_54E0_2_3` are not supported.
107
+ It may also miss some edge cases and nice error messages.
108
+ For good REPL experience better use wabt.
103
109
 
104
110
  <!--
105
111
  Main goal is to get very fluent with wasm text.
package/watr.js CHANGED
@@ -1,3 +1,106 @@
1
+ // encoding ref: https://github.com/j-s-n/WebBS/blob/master/compiler/byteCode.js
2
+ const uleb = (number, buffer=[]) => {
3
+ if (typeof number === 'string') number = parseInt(number.replaceAll('_',''));
4
+
5
+ let byte = number & 0b01111111;
6
+ number = number >>> 7;
7
+
8
+ if (number === 0) {
9
+ buffer.push(byte);
10
+ return buffer;
11
+ } else {
12
+ buffer.push(byte | 0b10000000);
13
+ return uleb(number, buffer);
14
+ }
15
+ };
16
+
17
+ function leb (n, buffer=[]) {
18
+ if (typeof n === 'string') n = parseInt(n.replaceAll('_',''));
19
+
20
+ while (true) {
21
+ const byte = Number(n & 0x7F);
22
+ n >>= 7;
23
+ if ((n === 0 && (byte & 0x40) === 0) || (n === -1 && (byte & 0x40) !== 0)) {
24
+ buffer.push(byte);
25
+ break
26
+ }
27
+ buffer.push((byte | 0x80));
28
+ }
29
+ return buffer
30
+ }
31
+
32
+ function bigleb(n, buffer=[]) {
33
+ if (typeof n === 'string') {
34
+ n = n.replaceAll('_','');
35
+ n = n[0]==='-'?-BigInt(n.slice(1)):BigInt(n);
36
+ byteView.setBigInt64(0, n);
37
+ n = byteView.getBigInt64(0);
38
+ }
39
+
40
+ while (true) {
41
+ const byte = Number(n & 0x7Fn);
42
+ n >>= 7n;
43
+ if ((n === 0n && (byte & 0x40) === 0) || (n === -1n && (byte & 0x40) !== 0)) {
44
+ buffer.push(byte);
45
+ break
46
+ }
47
+ buffer.push((byte | 0x80));
48
+ }
49
+ return buffer
50
+ }
51
+
52
+ // generalized float cases parser
53
+ const flt = input => input==='nan'||input==='+nan'?NaN:input==='-nan'?-NaN:
54
+ input==='inf'||input==='+inf'?Infinity:input==='-inf'?-Infinity:parseFloat(input.replaceAll('_',''));
55
+
56
+ const byteView = new DataView(new BigInt64Array(1).buffer);
57
+
58
+ const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000;
59
+ function f32 (input, value, idx) {
60
+ if (~(idx=input.indexOf('nan:'))) {
61
+ value = parseInt(input.slice(idx+4));
62
+ value |= F32_NAN;
63
+ if (input[0] === '-') value |= F32_SIGN;
64
+ byteView.setInt32(0, value);
65
+ }
66
+ else {
67
+ value=typeof input === 'string' ? flt(input) : input;
68
+ byteView.setFloat32(0, value);
69
+ }
70
+
71
+ return [
72
+ byteView.getUint8(3),
73
+ byteView.getUint8(2),
74
+ byteView.getUint8(1),
75
+ byteView.getUint8(0)
76
+ ];
77
+ }
78
+
79
+ const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n;
80
+ function f64 (input, value, idx) {
81
+ if (~(idx=input.indexOf('nan:'))) {
82
+ value = BigInt(input.slice(idx+4));
83
+ value |= F64_NAN;
84
+ if (input[0] === '-') value |= F64_SIGN;
85
+ byteView.setBigInt64(0, value);
86
+ }
87
+ else {
88
+ value=typeof input === 'string' ? flt(input) : input;
89
+ byteView.setFloat64(0, value);
90
+ }
91
+
92
+ return [
93
+ byteView.getUint8(7),
94
+ byteView.getUint8(6),
95
+ byteView.getUint8(5),
96
+ byteView.getUint8(4),
97
+ byteView.getUint8(3),
98
+ byteView.getUint8(2),
99
+ byteView.getUint8(1),
100
+ byteView.getUint8(0)
101
+ ];
102
+ }
103
+
1
104
  // ref: https://github.com/stagas/wat-compiler/blob/main/lib/const.js
2
105
  // NOTE: squashing into a string doesn't save up gzipped size
3
106
  const OP = [
@@ -37,7 +140,11 @@ ALIGN = {
37
140
  'i64.store': 8, 'f32.store': 4, 'f64.store': 8,
38
141
  'i32.store8': 1, 'i32.store16': 2, 'i64.store8': 1, 'i64.store16': 2, 'i64.store32': 4,
39
142
  };
40
- OP.map((op,i)=>OP[op]=i); // init op names
143
+
144
+ OP.map((op,i)=>OP[op]=i); // init op names
145
+
146
+ // some inlinable instructions
147
+ const INLINE = {loop: 1, block: 1, if: 1, end: -1, return: -1};
41
148
 
42
149
  // convert wat tree to wasm binary
43
150
  var compile = (nodes) => {
@@ -49,22 +156,44 @@ var compile = (nodes) => {
49
156
  0x01, 0x00, 0x00, 0x00, // version
50
157
  ];
51
158
 
159
+ // 1. transform tree
52
160
  // (func) → [(func)]
53
161
  if (typeof nodes[0] === 'string' && nodes[0] !== 'module') nodes = [nodes];
54
162
 
55
- // build nodes in order of sections, to properly initialize indexes/aliases
56
- // must come separate from binary builder: func can define types etc.
57
- for (let name in sections) {
163
+ // (global $a (import "a" "b") (mut i32)) (import "a" "b" (global $a (mut i32)))
164
+ // (memory (import "a" "b") min max shared) (import "a" "b" (memory min max shared))
165
+ nodes = nodes.map(node => {
166
+ if (node[2]?.[0]==='import') {
167
+ let [kind, name, imp, ...args] = node;
168
+ return [...imp, [kind, name, ...args]]
169
+ }
170
+ else if (node[1]?.[0]==='import') {
171
+ let [kind, imp, ...args] = node;
172
+ return [...imp, [kind, ...args]]
173
+ }
174
+ return node
175
+ });
176
+
177
+ // 2. build IR. import must be initialized first, global before func, elem after func
178
+ let order = ['type', 'import', 'table', 'memory', 'global', 'func', 'export', 'start', 'elem', 'data'], postcall = [];
179
+
180
+ for (let name of order) {
58
181
  let remaining = [];
59
- for (let node of nodes) node[0] === name ? build[name](node, sections) : remaining.push(node);
182
+ for (let node of nodes) {
183
+ node[0] === name ? postcall.push(build[name](node, sections)) : remaining.push(node);
184
+ }
185
+
60
186
  nodes = remaining;
61
187
  }
62
188
 
63
- // console.log(sections)
64
- // build binary sections
189
+ // code must be compiled after all definitions
190
+ for (let cb of postcall) cb && cb.call && cb();
191
+
192
+
193
+ // 3. build binary
65
194
  for (let name in sections) {
66
195
  let items=sections[name];
67
- if (items.importc) items = items.slice(items.importc); // discard imported functions
196
+ if (items.importc) items = items.slice(items.importc); // discard imported functions/globals
68
197
  if (!items.length) continue
69
198
  let sectionCode = SECTION[name], bytes = [];
70
199
  if (sectionCode!==8) bytes.push(items.length); // skip start section count
@@ -108,15 +237,14 @@ const build = {
108
237
 
109
238
  // (func $name? ...params result ...body)
110
239
  func([,...body], ctx) {
111
- let idx=ctx.func.length, // fn index comes after impoted fns
112
- locals=[], // list of local variables
240
+ let locals=[], // list of local variables
113
241
  callstack=[];
114
242
 
115
243
  // fn name
116
- if (body[0]?.[0] === '$') ctx.func[body.shift()] = idx;
244
+ if (body[0]?.[0] === '$') ctx.func[body.shift()] = ctx.func.length;
117
245
 
118
246
  // export binding
119
- if (body[0]?.[0] === 'export') build.export([...body.shift(), ['func', idx]], ctx);
247
+ if (body[0]?.[0] === 'export') build.export([...body.shift(), ['func', ctx.func.length]], ctx);
120
248
 
121
249
  // register type
122
250
  let [typeIdx, params, result] = build.type([,['func',...body]], ctx);
@@ -133,11 +261,13 @@ const build = {
133
261
  locals.push(...types.map(t => TYPE[t]));
134
262
  }
135
263
 
136
- // map code instruction into bytes: [args, opCode, immediates]
137
- const instr = ([op, ...nodes]) => {
138
- if (op.length===1) err(`Inline instructions are not supported \`${op+nodes.join('')}\``);
264
+ // squash local types
265
+ let locTypes = locals.reduce((a, type) => (type==a[a.length-1] ? a[a.length-2]++ : a.push(1,type), a), []);
139
266
 
140
- let opCode = OP[op], argc=0, args=[], imm=[], id;
267
+ // map code instruction into bytes: [args, opCode, immediates]
268
+ const instr = (group) => {
269
+ let [op, ...nodes] = group;
270
+ let opCode = OP[op], argc=0, before=[], after=[], id;
141
271
 
142
272
  // NOTE: we could reorganize ops by groups and detect signature as `op in STORE`
143
273
  // but numeric comparison is faster than generic hash lookup
@@ -159,28 +289,31 @@ const build = {
159
289
  // FIXME: figure out point in Math.log2 aligns
160
290
  let o = {align: ALIGN[op], offset: 0}, p;
161
291
  while (nodes[0]?.[0] in o) p = nodes.shift(), o[p[0]] = +p[1];
162
- imm = [Math.log2(o.align), o.offset];
292
+ after = [Math.log2(o.align), ...uleb(o.offset)];
163
293
  argc = opCode >= 54 ? 2 : 1;
164
294
  }
165
295
 
166
296
  // (i32.const 123)
167
- else if (opCode>=65&&opCode<=68) imm = opCode < 67 ? leb(nodes.shift()) : (opCode==67 ? f32 : f64)(nodes.shift());
297
+ else if (opCode>=65&&opCode<=68) {
298
+ after = (opCode==65?leb:opCode==66?bigleb:opCode==67?f32:f64)(nodes.shift());
299
+ }
168
300
 
169
301
  // (local.get $id), (local.tee $id x)
170
302
  else if (opCode>=32&&opCode<=34) {
171
- imm = uleb(nodes[0]?.[0]==='$' ? params[id=nodes.shift()] || locals[id] : nodes.shift());
303
+ after = uleb(nodes[0]?.[0]==='$' ? params[id=nodes.shift()] || locals[id] : nodes.shift());
172
304
  if (opCode>32) argc = 1;
173
305
  }
174
306
 
175
307
  // (global.get id), (global.set id)
176
308
  else if (opCode==35||opCode==36) {
177
- imm = uleb(nodes[0]?.[0]==='$' ? ctx.global[nodes.shift()] : nodes.shift());
309
+ after = uleb(nodes[0]?.[0]==='$' ? ctx.global[nodes.shift()] : nodes.shift());
178
310
  if (opCode>35) argc = 1;
179
311
  }
180
312
 
181
313
  // (call id ...nodes)
182
314
  else if (opCode==16) {
183
- imm = uleb(id = nodes[0]?.[0]==='$' ? ctx.func[nodes.shift()] : nodes.shift());
315
+ let fnName = nodes.shift();
316
+ after = uleb(id = fnName[0]==='$' ? ctx.func[fnName] ?? err('Unknown function `' + fnName + '`') : fnName);
184
317
  // FIXME: how to get signature of imported function
185
318
  [,argc] = ctx.type[ctx.func[id][0]];
186
319
  }
@@ -190,12 +323,12 @@ const build = {
190
323
  let typeId = nodes.shift()[1];
191
324
  [,argc] = ctx.type[typeId = typeId[0]==='$'?ctx.type[typeId]:typeId];
192
325
  argc++;
193
- imm = uleb(typeId), imm.push(0); // extra immediate indicates table idx (reserved)
326
+ after = uleb(typeId), after.push(0); // extra afterediate indicates table idx (reserved)
194
327
  }
195
328
 
196
329
  // FIXME (memory.grow $idx?)
197
330
  else if (opCode==63||opCode==64) {
198
- imm = [0];
331
+ after = [0];
199
332
  argc = 1;
200
333
  }
201
334
 
@@ -203,23 +336,24 @@ const build = {
203
336
  else if (opCode==4) {
204
337
  callstack.push(opCode);
205
338
  let [,type] = nodes[0][0]==='result' ? nodes.shift() : [,'void'];
206
- imm=[TYPE[type]];
207
- argc = 0, args.push(...instr(nodes.shift()));
339
+ after=[TYPE[type]];
340
+
341
+ argc = 0, before.push(...instr(nodes.shift()));
208
342
  let body;
209
- if (nodes[0][0]==='then') [,...body] = nodes.shift(); else body = nodes;
210
- while (body.length) imm.push(...instr(body.shift()));
343
+ if (nodes[0]?.[0]==='then') [,...body] = nodes.shift(); else body = nodes;
344
+ after.push(...consume(body));
211
345
 
212
346
  callstack.pop(), callstack.push(OP.else);
213
347
  if (nodes[0]?.[0]==='else') {
214
348
  [,...body] = nodes.shift();
215
- imm.push(OP.else, ...body.flatMap(instr));
349
+ if (body.length) after.push(OP.else,...consume(body));
216
350
  }
217
351
  callstack.pop();
218
- imm.push(OP.end);
352
+ after.push(OP.end);
219
353
  }
220
354
 
221
- // (drop arg), (return arg), (end arg)
222
- else if (opCode==0x1a || opCode==0x0f || opCode==0x0b) { argc = 1; }
355
+ // (drop arg?), (return arg?)
356
+ else if (opCode==0x1a || opCode==0x0f) { argc = nodes.length?1:0; }
223
357
 
224
358
  // (select a b cond)
225
359
  else if (opCode==0x1b) { argc = 3; }
@@ -229,25 +363,27 @@ const build = {
229
363
  callstack.push(opCode);
230
364
  if (nodes[0]?.[0]==='$') (callstack[nodes.shift()] = callstack.length);
231
365
  let [,type] = nodes[0]?.[0]==='result' ? nodes.shift() : [,'void'];
232
- imm=[TYPE[type]];
233
- while (nodes.length) imm.push(...instr(nodes.shift()));
234
- imm.push(OP.end);
235
- callstack.pop();
366
+ after=[TYPE[type], ...consume(nodes)];
367
+
368
+ if (!group.inline) callstack.pop(), after.push(OP.end); // inline loop/block expects end to be separately provided
236
369
  }
237
370
 
371
+ // (end)
372
+ else if (opCode==0x0b) callstack.pop();
373
+
238
374
  // (br $label result?)
239
375
  // (br_if $label cond result?)
240
376
  else if (opCode==0x0c||opCode==0x0d) {
241
377
  // br index indicates how many callstack items to pop
242
- imm = uleb(nodes[0]?.[0]==='$' ? callstack.length-callstack[nodes.shift()] : nodes.shift());
378
+ after = uleb(nodes[0]?.[0]==='$' ? callstack.length-callstack[nodes.shift()] : nodes.shift());
243
379
  argc = (opCode==0x0d ? 1 + (nodes.length > 1) : !!nodes.length);
244
380
  }
245
381
 
246
382
  // (br_table 1 2 3 4 0 selector result?)
247
383
  else if (opCode==0x0e) {
248
- imm = [];
249
- while (!Array.isArray(nodes[0])) id=nodes.shift(), imm.push(...uleb(id[0][0]==='$'?callstack.length-callstack[id]:id));
250
- imm.unshift(...uleb(imm.length-1));
384
+ after = [];
385
+ while (!Array.isArray(nodes[0])) id=nodes.shift(), after.push(...uleb(id[0][0]==='$'?callstack.length-callstack[id]:id));
386
+ after.unshift(...uleb(after.length-1));
251
387
  argc = 1 + (nodes.length>1);
252
388
  }
253
389
 
@@ -256,44 +392,55 @@ const build = {
256
392
 
257
393
  // consume arguments
258
394
  if (nodes.length < argc) err(`Stack arguments are not supported at \`${op}\``);
259
- while (argc--) args.push(...instr(nodes.shift()));
395
+ while (argc--) before.push(...instr(nodes.shift()));
260
396
  if (nodes.length) err(`Too many arguments for \`${op}\`.`);
261
397
 
262
- return [...args, opCode, ...imm]
398
+ return [...before, opCode, ...after]
263
399
  };
264
400
 
265
- let code = body.flatMap(instr);
401
+ // consume sequence of nodes
402
+ const consume = nodes => {
403
+ let result = [];
404
+ while (nodes.length) {
405
+ let node = nodes.shift(), c;
406
+
407
+ if (typeof node === 'string') {
408
+ // permit some inline instructions: loop $label ... end, br $label, arg return
409
+ if (c=INLINE[node]) {
410
+ node = [node], node.inline = true;
411
+ if (c>0) nodes[0]?.[0]==='$' && node.push(nodes.shift());
412
+ }
413
+ else err(`Inline instruction \`${node}\` is not supported`);
414
+ }
266
415
 
267
- // squash local types
268
- let locTypes = locals.reduce((a, type) => (type==a[a.length-1] ? a[a.length-2]++ : a.push(1,type), a), []);
416
+ node && result.push(...instr(node));
417
+ }
418
+ return result
419
+ };
269
420
 
270
- ctx.code.push([...uleb(code.length+2+locTypes.length), ...uleb(locTypes.length>>1), ...locTypes, ...code, OP.end]);
421
+ // evaluates after all definitions
422
+ return () => {
423
+ let code = consume(body);
424
+ ctx.code.push([...uleb(code.length+2+locTypes.length), ...uleb(locTypes.length>>1), ...locTypes, ...code, OP.end]);
425
+ }
271
426
  },
272
427
 
273
428
  // (memory min max shared)
274
429
  // (memory $name min max shared)
275
- // (memory (import "js" "mem") min max shared)
430
+ // (memory (export "mem") 5)
276
431
  memory([, ...parts], ctx) {
277
432
  if (parts[0][0]==='$') ctx.memory[parts.shift()] = ctx.memory.length;
278
- if (parts[0][0] === 'import') {
279
- let [imp, ...limits] = parts;
280
- // (import "js" "mem" (memory 1))
281
- return build.import([...imp, ['memory', ...limits]], ctx)
282
- }
283
-
433
+ if (parts[0][0] === 'export') build.export([...parts.shift(), ['memory', ctx.memory.length]], ctx);
284
434
  ctx.memory.push(range(parts));
285
435
  },
286
436
 
287
437
  // (global i32 (i32.const 42))
288
438
  // (global $id i32 (i32.const 42))
289
439
  // (global $id (mut i32) (i32.const 42))
290
- // FIXME (global $g1 (import "js" "g1") (mut i32)) ;; import from js
291
440
  global([, ...args], ctx) {
292
441
  let name = args[0][0]==='$' && args.shift();
293
442
  if (name) ctx.global[name] = ctx.global.length;
294
-
295
- let [type, init] = args, mut = type[0] === 'mut';
296
-
443
+ let [type, init] = args, mut = type[0] === 'mut' ? 1 : 0;
297
444
  ctx.global.push([TYPE[mut ? type[1] : type], mut, ...iinit(init)]);
298
445
  },
299
446
 
@@ -302,7 +449,6 @@ const build = {
302
449
  table([, ...args], ctx) {
303
450
  let name = args[0][0]==='$' && args.shift();
304
451
  if (name) ctx.table[name] = ctx.table.length;
305
-
306
452
  let lims = range(args);
307
453
  ctx.table.push([TYPE[args.pop()], ...lims]);
308
454
  },
@@ -322,30 +468,39 @@ const build = {
322
468
  // (import "math" "add" (func $add (param i32 i32 externref) (result i32)))
323
469
  // (import "js" "mem" (memory 1))
324
470
  // (import "js" "mem" (memory $name 1))
325
- import([, mod, name, ref], ctx) {
326
- // FIXME: forward here from particular nodes instead: definition for import is same, we should DRY import code
327
- // build[ref[0]]([ref[0], ['import', mod, name], ...ref.slice(1)])
471
+ // (import "js" "v" (global $name (mut f64)))
472
+ import([, mod, field, ref], ctx) {
473
+ let details, [kind, ...parts] = ref,
474
+ name = parts[0]?.[0]==='$' && parts.shift();
328
475
 
329
- let details, [kind, ...parts] = ref;
330
476
  if (kind==='func') {
331
477
  // we track imported funcs in func section to share namespace, and skip them on final build
332
- if (parts[0]?.[0]==='$') ctx.func[parts.shift()] = ctx.func.length;
478
+ if (name) ctx.func[name] = ctx.func.length;
333
479
  let [typeIdx] = build.type([, ['func', ...parts]], ctx);
334
480
  ctx.func.push(details = uleb(typeIdx));
335
481
  ctx.func.importc = (ctx.func.importc||0)+1;
336
482
  }
337
483
  else if (kind==='memory') {
338
- if (parts[0][0]==='$') ctx.memory[parts.shift()] = ctx.memory.length;
484
+ if (name) ctx.memory[name] = ctx.memory.length;
339
485
  details = range(parts);
340
486
  }
487
+ else if (kind==='global') {
488
+ // imported globals share namespace with internal globals - we skip them in final build
489
+ if (name) ctx.global[name] = ctx.global.length;
490
+ let [type] = parts, mut = type[0] === 'mut' ? 1 : 0;
491
+ details = [TYPE[mut ? type[1] : type], mut];
492
+ ctx.global.push(details);
493
+ ctx.global.importc = (ctx.global.importc||0)+1;
494
+ }
495
+ else throw Error('Unimplemented ' + kind)
341
496
 
342
- ctx.import.push([...str(mod), ...str(name), KIND[kind], ...details]);
497
+ ctx.import.push([...str(mod), ...str(field), KIND[kind], ...details]);
343
498
  },
344
499
 
345
- // (data (i32.const 0) "\2a")
346
- data([, offset, init], ctx) {
500
+ // (data (i32.const 0) "\aa" "\bb"?)
501
+ data([, offset, ...inits], ctx) {
347
502
  // FIXME: first is mem index
348
- ctx.data.push([0, ...iinit(offset,ctx), ...str(init)]);
503
+ ctx.data.push([0, ...iinit(offset,ctx), ...str(inits.map(i=>i[0]==='"'?i.slice(1,-1):i).join(''))]);
349
504
  },
350
505
 
351
506
  // (start $main)
@@ -356,15 +511,21 @@ const build = {
356
511
 
357
512
  // (i32.const 0) - instantiation time initializer
358
513
  const iinit = ([op, literal], ctx) => op[0]==='f' ?
359
- [OP[op], ...(op=='f32'?f32:f64)(literal), OP.end] :
360
- [OP[op], ...leb(literal[0] === '$' ? ctx.global[literal] : literal), OP.end];
514
+ [OP[op], ...(op[1]==='3'?f32:f64)(literal), OP.end] :
515
+ [OP[op], ...(op[1]==='3'?leb:bigleb)(literal[0] === '$' ? ctx.global[literal] : literal), OP.end];
516
+
517
+ const escape = {n:10, r:13, t:9, v:1};
361
518
 
362
519
  // build string binary
363
520
  const str = str => {
364
521
  str = str[0]==='"' ? str.slice(1,-1) : str;
365
522
  let res = [], i = 0, c, BSLASH=92;
366
523
  // spec https://webassembly.github.io/spec/core/text/values.html#strings
367
- for (;i < str.length;) c=str.charCodeAt(i++), res.push(...uleb(c===BSLASH ? parseInt(str.slice(i,i+=2), 16) : c));
524
+ for (;i < str.length;) {
525
+ c=str.charCodeAt(i++);
526
+ res.push(c===BSLASH ? escape[str[i++]] || parseInt(str.slice(i-1,++i), 16) : c);
527
+ }
528
+
368
529
  res.unshift(...uleb(res.length));
369
530
  return res
370
531
  };
@@ -372,105 +533,25 @@ const str = str => {
372
533
  // build range/limits sequence (non-consuming)
373
534
  const range = ([min, max, shared]) => isNaN(parseInt(max)) ? [0, ...uleb(min)] : [shared==='shared'?3:1, ...uleb(min), ...uleb(max)];
374
535
 
375
-
376
- // encoding ref: https://github.com/j-s-n/WebBS/blob/master/compiler/byteCode.js
377
- function leb (number, buffer) {
378
- if (!buffer) buffer = [], number = parseInt(number);
379
-
380
- let byte = number & 0b01111111;
381
- let signBit = byte & 0b01000000;
382
- number = number >> 7;
383
-
384
- if ((number === 0 && signBit === 0) || (number === -1 && signBit !== 0)) {
385
- buffer.push(byte);
386
- return buffer;
387
- } else {
388
- buffer.push(byte | 0b10000000);
389
- return leb(number, buffer);
390
- }
391
- }
392
-
393
- const uleb = (number, buffer) => {
394
- if (!buffer) buffer = [], number = parseInt(number);
395
-
396
- let byte = number & 0b01111111;
397
- number = number >>> 7;
398
-
399
- if (number === 0) {
400
- buffer.push(byte);
401
- return buffer;
402
- } else {
403
- buffer.push(byte | 0b10000000);
404
- return uleb(number, buffer);
405
- }
406
- };
407
-
408
- const byteView = new DataView(new BigInt64Array(1).buffer);
409
-
410
- const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000;
411
- function f32 (input, value, idx) {
412
- if (~(idx=input.indexOf('nan:'))) {
413
- value = parseInt(input.slice(idx+4));
414
- value |= F32_NAN;
415
- if (input[0] === '-') value |= F32_SIGN;
416
- byteView.setInt32(0, value);
417
- }
418
- else {
419
- value=input==='nan'||input==='+nan'?NaN:input==='-nan'?-NaN:input==='inf'||input==='+inf'?Infinity:input==='-inf'?-Infinity:parseFloat(input);
420
- byteView.setFloat32(0, value);
421
- }
422
-
423
- return [
424
- byteView.getUint8(3),
425
- byteView.getUint8(2),
426
- byteView.getUint8(1),
427
- byteView.getUint8(0)
428
- ];
429
- }
430
-
431
- const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n;
432
- function f64 (input, value, idx) {
433
- if (~(idx=input.indexOf('nan:'))) {
434
- value = BigInt(input.slice(idx+4));
435
- value |= F64_NAN;
436
- if (input[0] === '-') value |= F64_SIGN;
437
- byteView.setBigInt64(0, value);
438
- }
439
- else {
440
- value=input==='nan'||input==='+nan'?NaN:input==='-nan'?-NaN:input==='inf'||input==='+inf'?Infinity:input==='-inf'?-Infinity:parseFloat(input);
441
- byteView.setFloat64(0, value);
442
- }
443
-
444
- return [
445
- byteView.getUint8(7),
446
- byteView.getUint8(6),
447
- byteView.getUint8(5),
448
- byteView.getUint8(4),
449
- byteView.getUint8(3),
450
- byteView.getUint8(2),
451
- byteView.getUint8(1),
452
- byteView.getUint8(0)
453
- ];
454
- }
455
-
456
536
  const err = text => { throw Error(text) };
457
537
 
458
- const OPAREN=40, CPAREN=41, SPACE=32, SEMIC=59;
538
+ const OPAREN=40, CPAREN=41, SPACE=32, DQUOTE=34, SEMIC=59;
459
539
 
460
540
  var parse = (str) => {
461
541
  let i = 0, level = [], buf='';
462
542
 
463
543
  const commit = () => buf && (
464
- level.push(~buf.indexOf('=') ? buf.split('=') : buf),
544
+ level.push(buf[0]!=='"' && ~buf.indexOf('=') ? buf.split('=') : buf),
465
545
  buf = ''
466
546
  );
467
547
 
468
548
  const parseLevel = () => {
469
549
  for (let c, root; i < str.length; ) {
470
550
  c = str.charCodeAt(i);
471
- if (c === OPAREN) {
551
+ if (c === DQUOTE) commit(), buf = str.slice(i++, i=str.indexOf('"', i)+1), commit();
552
+ else if (c === OPAREN) {
472
553
  if (str.charCodeAt(i+1) === SEMIC) i=str.indexOf(';)', i)+2; // (; ... ;)
473
- else i++, (root=level).push(level=[]), parseLevel(), level=root;
554
+ else commit(), i++, (root=level).push(level=[]), parseLevel(), level=root;
474
555
  }
475
556
  else if (c === SEMIC) i=str.indexOf('\n', i)+1; // ; ...
476
557
  else if (c <= SPACE) commit(), i++;
package/watr.min.js CHANGED
@@ -1 +1 @@
1
- const e=["unreachable","nop","block","loop","if","else",,,,,,"end","br","br_if","br_table","return","call","call_indirect",,,,,,,,,"drop","select",,,,,"local.get","local.set","local.tee","global.get","global.set",,,,"i32.load","i64.load","f32.load","f64.load","i32.load8_s","i32.load8_u","i32.load16_s","i32.load16_u","i64.load8_s","i64.load8_u","i64.load16_s","i64.load16_u","i64.load32_s","i64.load32_u","i32.store","i64.store","f32.store","f64.store","i32.store8","i32.store16","i64.store8","i64.store16","i64.store32","memory.size","memory.grow","i32.const","i64.const","f32.const","f64.const","i32.eqz","i32.eq","i32.ne","i32.lt_s","i32.lt_u","i32.gt_s","i32.gt_u","i32.le_s","i32.le_u","i32.ge_s","i32.ge_u","i64.eqz","i64.eq","i64.ne","i64.lt_s","i64.lt_u","i64.gt_s","i64.gt_u","i64.le_s","i64.le_u","i64.ge_s","i64.ge_u","f32.eq","f32.ne","f32.lt","f32.gt","f32.le","f32.ge","f64.eq","f64.ne","f64.lt","f64.gt","f64.le","f64.ge","i32.clz","i32.ctz","i32.popcnt","i32.add","i32.sub","i32.mul","i32.div_s","i32.div_u","i32.rem_s","i32.rem_u","i32.and","i32.or","i32.xor","i32.shl","i32.shr_s","i32.shr_u","i32.rotl","i32.rotr","i64.clz","i64.ctz","i64.popcnt","i64.add","i64.sub","i64.mul","i64.div_s","i64.div_u","i64.rem_s","i64.rem_u","i64.and","i64.or","i64.xor","i64.shl","i64.shr_s","i64.shr_u","i64.rotl","i64.rotr","f32.abs","f32.neg","f32.ceil","f32.floor","f32.trunc","f32.nearest","f32.sqrt","f32.add","f32.sub","f32.mul","f32.div","f32.min","f32.max","f32.copysign","f64.abs","f64.neg","f64.ceil","f64.floor","f64.trunc","f64.nearest","f64.sqrt","f64.add","f64.sub","f64.mul","f64.div","f64.min","f64.max","f64.copysign","i32.wrap_i64","i32.trunc_f32_s","i32.trunc_f32_u","i32.trunc_f64_s","i32.trunc_f64_u","i64.extend_i32_s","i64.extend_i32_u","i64.trunc_f32_s","i64.trunc_f32_u","i64.trunc_f64_s","i64.trunc_f64_u","f32.convert_i32_s","f32.convert_i32_u","f32.convert_i64_s","f32.convert_i64_u","f32.demote_f64","f64.convert_i32_s","f64.convert_i32_u","f64.convert_i64_s","f64.convert_i64_u","f64.promote_f32","i32.reinterpret_f32","i64.reinterpret_f64","f32.reinterpret_i32","f64.reinterpret_i64"],t={type:1,import:2,func:3,table:4,memory:5,global:6,export:7,start:8,elem:9,code:10,data:11},i={i32:127,i64:126,f32:125,f64:124,void:64,func:96,funcref:112},n={func:0,table:1,memory:2,global:3},s={"i32.load":4,"i64.load":8,"f32.load":4,"f64.load":8,"i32.load8_s":1,"i32.load8_u":1,"i32.load16_s":2,"i32.load16_u":2,"i64.load8_s":1,"i64.load8_u":1,"i64.load16_s":2,"i64.load16_u":2,"i64.load32_s":4,"i64.load32_u":4,"i32.store":4,"i64.store":8,"f32.store":4,"f64.store":8,"i32.store8":1,"i32.store16":2,"i64.store8":1,"i64.store16":2,"i64.store32":4};e.map(((t,i)=>e[t]=i));var l=e=>{let i={type:[],import:[],func:[],table:[],memory:[],global:[],export:[],start:[],elem:[],code:[],data:[]},n=[0,97,115,109,1,0,0,0];"string"==typeof e[0]&&"module"!==e[0]&&(e=[e]);for(let t in i){let n=[];for(let s of e)s[0]===t?f[t](s,i):n.push(s);e=n}for(let e in i){let s=i[e];if(s.importc&&(s=s.slice(s.importc)),!s.length)continue;let l=t[e],f=[];8!==l&&f.push(s.length);for(let e of s)f.push(...e);n.push(l,...h(f.length),...f)}return new Uint8Array(n)};const f={type([,e,t],n){"$"!==e[0]&&(t=e,e=null);let s,l,f=[],r=[],[o,...u]=t;if("func"===o){for(;"param"===u[0]?.[0];){let[,...e]=u.shift();"$"===e[0]?.[0]&&(f[e.shift()]=f.length),f.push(...e.map((e=>i[e])))}"result"===u[0]?.[0]&&(r=u.shift().slice(1).map((e=>i[e]))),l=[i.func,...h(f.length),...f,...h(r.length),...r],s=n.type.findIndex((e=>e.every(((e,t)=>e===l[t])))),s<0&&(s=n.type.push(l)-1)}return e&&(n.type[e]=s),[s,f,r]},func([,...t],n){let l=n.func.length,r=[],o=[];"$"===t[0]?.[0]&&(n.func[t.shift()]=l),"export"===t[0]?.[0]&&f.export([...t.shift(),["func",l]],n);let[u,p,_]=f.type([,["func",...t]],n);for(;"param"===t[0]?.[0]||"result"===t[0]?.[0];)t.shift();for(n.func.push([u]);"local"===t[0]?.[0];){let e,[,...n]=t.shift();"$"===n[0][0]&&(p[e=n.shift()]?m("Ambiguous name "+e):r[e]=p.length+r.length),r.push(...n.map((e=>i[e])))}const g=([t,...l])=>{1===t.length&&m(`Inline instructions are not supported \`${t+l.join("")}\``);let f,u=e[t],_=0,y=[],b=[];if(u>=69)_=u>=167||u<=159&&u>=153||u<=145&&u>=139||u<=123&&u>=121||u<=105&&u>=103||80==u||69==u?1:2;else if(u>=40&&u<=62){let e,i={align:s[t],offset:0};for(;l[0]?.[0]in i;)e=l.shift(),i[e[0]]=+e[1];b=[Math.log2(i.align),i.offset],_=u>=54?2:1}else if(u>=65&&u<=68)b=u<67?a(l.shift()):(67==u?c:d)(l.shift());else if(u>=32&&u<=34)b=h("$"===l[0]?.[0]?p[f=l.shift()]||r[f]:l.shift()),u>32&&(_=1);else if(35==u||36==u)b=h("$"===l[0]?.[0]?n.global[l.shift()]:l.shift()),u>35&&(_=1);else if(16==u)b=h(f="$"===l[0]?.[0]?n.func[l.shift()]:l.shift()),[,_]=n.type[n.func[f][0]];else if(17==u){let e=l.shift()[1];[,_]=n.type[e="$"===e[0]?n.type[e]:e],_++,b=h(e),b.push(0)}else if(63==u||64==u)b=[0],_=1;else if(4==u){o.push(u);let t,[,n]="result"===l[0][0]?l.shift():[,"void"];for(b=[i[n]],_=0,y.push(...g(l.shift())),"then"===l[0][0]?[,...t]=l.shift():t=l;t.length;)b.push(...g(t.shift()));o.pop(),o.push(e.else),"else"===l[0]?.[0]&&([,...t]=l.shift(),b.push(e.else,...t.flatMap(g))),o.pop(),b.push(e.end)}else if(26==u||15==u||11==u)_=1;else if(27==u)_=3;else if(2==u||3==u){o.push(u),"$"===l[0]?.[0]&&(o[l.shift()]=o.length);let[,t]="result"===l[0]?.[0]?l.shift():[,"void"];for(b=[i[t]];l.length;)b.push(...g(l.shift()));b.push(e.end),o.pop()}else if(12==u||13==u)b=h("$"===l[0]?.[0]?o.length-o[l.shift()]:l.shift()),_=13==u?1+(l.length>1):!!l.length;else if(14==u){for(b=[];!Array.isArray(l[0]);)f=l.shift(),b.push(...h("$"===f[0][0]?o.length-o[f]:f));b.unshift(...h(b.length-1)),_=1+(l.length>1)}else null==u&&m(`Unknown instruction \`${t}\``);for(l.length<_&&m(`Stack arguments are not supported at \`${t}\``);_--;)y.push(...g(l.shift()));return l.length&&m(`Too many arguments for \`${t}\`.`),[...y,u,...b]};let y=t.flatMap(g),b=r.reduce(((e,t)=>(t==e[e.length-1]?e[e.length-2]++:e.push(1,t),e)),[]);n.code.push([...h(y.length+2+b.length),...h(b.length>>1),...b,...y,e.end])},memory([,...e],t){if("$"===e[0][0]&&(t.memory[e.shift()]=t.memory.length),"import"===e[0][0]){let[i,...n]=e;return f.import([...i,["memory",...n]],t)}t.memory.push(u(e))},global([,...e],t){let n="$"===e[0][0]&&e.shift();n&&(t.global[n]=t.global.length);let[s,l]=e,f="mut"===s[0];t.global.push([i[f?s[1]:s],f,...r(l)])},table([,...e],t){let n="$"===e[0][0]&&e.shift();n&&(t.table[n]=t.table.length);let s=u(e);t.table.push([i[e.pop()],...s])},elem([,e,...t],i){i.elem.push([0,...r(e,i),...h(t.length),...t.flatMap((e=>h("$"===e[0]?i.func[e]:e)))])},export([,e,[t,i]],s){"$"===i[0]&&(i=s[t][i]),s.export.push([...o(e),n[t],...h(i)])},import([,e,t,i],s){let l,[r,...a]=i;if("func"===r){"$"===a[0]?.[0]&&(s.func[a.shift()]=s.func.length);let[e]=f.type([,["func",...a]],s);s.func.push(l=h(e)),s.func.importc=(s.func.importc||0)+1}else"memory"===r&&("$"===a[0][0]&&(s.memory[a.shift()]=s.memory.length),l=u(a));s.import.push([...o(e),...o(t),n[r],...l])},data([,e,t],i){i.data.push([0,...r(e,i),...o(t)])},start([,e],t){t.start.length||t.start.push(["$"===e[0]?t.func[e]:e])}},r=([t,i],n)=>"f"===t[0]?[e[t],...("f32"==t?c:d)(i),e.end]:[e[t],...a("$"===i[0]?n.global[i]:i),e.end],o=e=>{e='"'===e[0]?e.slice(1,-1):e;let t,i=[],n=0;for(;n<e.length;)t=e.charCodeAt(n++),i.push(...h(92===t?parseInt(e.slice(n,n+=2),16):t));return i.unshift(...h(i.length)),i},u=([e,t,i])=>isNaN(parseInt(t))?[0,...h(e)]:["shared"===i?3:1,...h(e),...h(t)];function a(e,t){t||(t=[],e=parseInt(e));let i=127&e,n=64&i;return 0==(e>>=7)&&0===n||-1===e&&0!==n?(t.push(i),t):(t.push(128|i),a(e,t))}const h=(e,t)=>{t||(t=[],e=parseInt(e));let i=127&e;return 0==(e>>>=7)?(t.push(i),t):(t.push(128|i),h(e,t))},p=new DataView(new BigInt64Array(1).buffer);function c(e,t,i){return~(i=e.indexOf("nan:"))?(t=parseInt(e.slice(i+4)),t|=2139095040,"-"===e[0]&&(t|=2147483648),p.setInt32(0,t)):(t="nan"===e||"+nan"===e||"-nan"===e?NaN:"inf"===e||"+inf"===e?1/0:"-inf"===e?-1/0:parseFloat(e),p.setFloat32(0,t)),[p.getUint8(3),p.getUint8(2),p.getUint8(1),p.getUint8(0)]}const _=0x8000000000000000n,g=0x7ff0000000000000n;function d(e,t,i){return~(i=e.indexOf("nan:"))?(t=BigInt(e.slice(i+4)),t|=g,"-"===e[0]&&(t|=_),p.setBigInt64(0,t)):(t="nan"===e||"+nan"===e||"-nan"===e?NaN:"inf"===e||"+inf"===e?1/0:"-inf"===e?-1/0:parseFloat(e),p.setFloat64(0,t)),[p.getUint8(7),p.getUint8(6),p.getUint8(5),p.getUint8(4),p.getUint8(3),p.getUint8(2),p.getUint8(1),p.getUint8(0)]}const m=e=>{throw Error(e)};var y=e=>{let t=0,i=[],n="";const s=()=>n&&(i.push(~n.indexOf("=")?n.split("="):n),n=""),l=()=>{for(let f,r;t<e.length;)if(f=e.charCodeAt(t),40===f)59===e.charCodeAt(t+1)?t=e.indexOf(";)",t)+2:(t++,(r=i).push(i=[]),l(),i=r);else if(59===f)t=e.indexOf("\n",t)+1;else if(f<=32)s(),t++;else{if(41===f)return s(),t++;n+=e[t++]}s()};return l(),i.length>1?i:i[0]},b=e=>(e="string"==typeof e?y(e):e,l(e));export{l as compile,b as default,y as parse};
1
+ const e=(t,i=[])=>{"string"==typeof t&&(t=parseInt(t.replaceAll("_","")));let l=127&t;return 0==(t>>>=7)?(i.push(l),i):(i.push(128|l),e(t,i))};function t(e,t=[]){for("string"==typeof e&&(e=parseInt(e.replaceAll("_","")));;){const i=Number(127&e);if(0==(e>>=7)&&0==(64&i)||-1===e&&0!=(64&i)){t.push(i);break}t.push(128|i)}return t}function i(e,t=[]){for("string"==typeof e&&(e="-"===(e=e.replaceAll("_",""))[0]?-BigInt(e.slice(1)):BigInt(e),n.setBigInt64(0,e),e=n.getBigInt64(0));;){const i=Number(0x7Fn&e);if(0n===(e>>=7n)&&0==(64&i)||-1n===e&&0!=(64&i)){t.push(i);break}t.push(128|i)}return t}const l=e=>"nan"===e||"+nan"===e||"-nan"===e?NaN:"inf"===e||"+inf"===e?1/0:"-inf"===e?-1/0:parseFloat(e.replaceAll("_","")),n=new DataView(new BigInt64Array(1).buffer);function s(e,t,i){return~(i=e.indexOf("nan:"))?(t=parseInt(e.slice(i+4)),t|=2139095040,"-"===e[0]&&(t|=2147483648),n.setInt32(0,t)):(t="string"==typeof e?l(e):e,n.setFloat32(0,t)),[n.getUint8(3),n.getUint8(2),n.getUint8(1),n.getUint8(0)]}const r=0x8000000000000000n,o=0x7ff0000000000000n;function f(e,t,i){return~(i=e.indexOf("nan:"))?(t=BigInt(e.slice(i+4)),t|=o,"-"===e[0]&&(t|=r),n.setBigInt64(0,t)):(t="string"==typeof e?l(e):e,n.setFloat64(0,t)),[n.getUint8(7),n.getUint8(6),n.getUint8(5),n.getUint8(4),n.getUint8(3),n.getUint8(2),n.getUint8(1),n.getUint8(0)]}const u=["unreachable","nop","block","loop","if","else",,,,,,"end","br","br_if","br_table","return","call","call_indirect",,,,,,,,,"drop","select",,,,,"local.get","local.set","local.tee","global.get","global.set",,,,"i32.load","i64.load","f32.load","f64.load","i32.load8_s","i32.load8_u","i32.load16_s","i32.load16_u","i64.load8_s","i64.load8_u","i64.load16_s","i64.load16_u","i64.load32_s","i64.load32_u","i32.store","i64.store","f32.store","f64.store","i32.store8","i32.store16","i64.store8","i64.store16","i64.store32","memory.size","memory.grow","i32.const","i64.const","f32.const","f64.const","i32.eqz","i32.eq","i32.ne","i32.lt_s","i32.lt_u","i32.gt_s","i32.gt_u","i32.le_s","i32.le_u","i32.ge_s","i32.ge_u","i64.eqz","i64.eq","i64.ne","i64.lt_s","i64.lt_u","i64.gt_s","i64.gt_u","i64.le_s","i64.le_u","i64.ge_s","i64.ge_u","f32.eq","f32.ne","f32.lt","f32.gt","f32.le","f32.ge","f64.eq","f64.ne","f64.lt","f64.gt","f64.le","f64.ge","i32.clz","i32.ctz","i32.popcnt","i32.add","i32.sub","i32.mul","i32.div_s","i32.div_u","i32.rem_s","i32.rem_u","i32.and","i32.or","i32.xor","i32.shl","i32.shr_s","i32.shr_u","i32.rotl","i32.rotr","i64.clz","i64.ctz","i64.popcnt","i64.add","i64.sub","i64.mul","i64.div_s","i64.div_u","i64.rem_s","i64.rem_u","i64.and","i64.or","i64.xor","i64.shl","i64.shr_s","i64.shr_u","i64.rotl","i64.rotr","f32.abs","f32.neg","f32.ceil","f32.floor","f32.trunc","f32.nearest","f32.sqrt","f32.add","f32.sub","f32.mul","f32.div","f32.min","f32.max","f32.copysign","f64.abs","f64.neg","f64.ceil","f64.floor","f64.trunc","f64.nearest","f64.sqrt","f64.add","f64.sub","f64.mul","f64.div","f64.min","f64.max","f64.copysign","i32.wrap_i64","i32.trunc_f32_s","i32.trunc_f32_u","i32.trunc_f64_s","i32.trunc_f64_u","i64.extend_i32_s","i64.extend_i32_u","i64.trunc_f32_s","i64.trunc_f32_u","i64.trunc_f64_s","i64.trunc_f64_u","f32.convert_i32_s","f32.convert_i32_u","f32.convert_i64_s","f32.convert_i64_u","f32.demote_f64","f64.convert_i32_s","f64.convert_i32_u","f64.convert_i64_s","f64.convert_i64_u","f64.promote_f32","i32.reinterpret_f32","i64.reinterpret_f64","f32.reinterpret_i32","f64.reinterpret_i64"],a={type:1,import:2,func:3,table:4,memory:5,global:6,export:7,start:8,elem:9,code:10,data:11},p={i32:127,i64:126,f32:125,f64:124,void:64,func:96,funcref:112},h={func:0,table:1,memory:2,global:3},c={"i32.load":4,"i64.load":8,"f32.load":4,"f64.load":8,"i32.load8_s":1,"i32.load8_u":1,"i32.load16_s":2,"i32.load16_u":2,"i64.load8_s":1,"i64.load8_u":1,"i64.load16_s":2,"i64.load16_u":2,"i64.load32_s":4,"i64.load32_u":4,"i32.store":4,"i64.store":8,"f32.store":4,"f64.store":8,"i32.store8":1,"i32.store16":2,"i64.store8":1,"i64.store16":2,"i64.store32":4};u.map(((e,t)=>u[e]=t));const g={loop:1,block:1,if:1,end:-1,return:-1};var _=t=>{let i={type:[],import:[],func:[],table:[],memory:[],global:[],export:[],start:[],elem:[],code:[],data:[]},l=[0,97,115,109,1,0,0,0];"string"==typeof t[0]&&"module"!==t[0]&&(t=[t]),t=t.map((e=>{if("import"===e[2]?.[0]){let[t,i,l,...n]=e;return[...l,[t,i,...n]]}if("import"===e[1]?.[0]){let[t,i,...l]=e;return[...i,[t,...l]]}return e}));let n=["type","import","table","memory","global","func","export","start","elem","data"],s=[];for(let e of n){let l=[];for(let n of t)n[0]===e?s.push(d[e](n,i)):l.push(n);t=l}for(let e of s)e&&e.call&&e();for(let t in i){let n=i[t];if(n.importc&&(n=n.slice(n.importc)),!n.length)continue;let s=a[t],r=[];8!==s&&r.push(n.length);for(let e of n)r.push(...e);l.push(s,...e(r.length),...r)}return new Uint8Array(l)};const d={type([,t,i],l){"$"!==t[0]&&(i=t,t=null);let n,s,r=[],o=[],[f,...u]=i;if("func"===f){for(;"param"===u[0]?.[0];){let[,...e]=u.shift();"$"===e[0]?.[0]&&(r[e.shift()]=r.length),r.push(...e.map((e=>p[e])))}"result"===u[0]?.[0]&&(o=u.shift().slice(1).map((e=>p[e]))),s=[p.func,...e(r.length),...r,...e(o.length),...o],n=l.type.findIndex((e=>e.every(((e,t)=>e===s[t])))),n<0&&(n=l.type.push(s)-1)}return t&&(l.type[t]=n),[n,r,o]},func([,...l],n){let r=[],o=[];"$"===l[0]?.[0]&&(n.func[l.shift()]=n.func.length),"export"===l[0]?.[0]&&d.export([...l.shift(),["func",n.func.length]],n);let[a,h,_]=d.type([,["func",...l]],n);for(;"param"===l[0]?.[0]||"result"===l[0]?.[0];)l.shift();for(n.func.push([a]);"local"===l[0]?.[0];){let e,[,...t]=l.shift();"$"===t[0][0]&&(h[e=t.shift()]?$("Ambiguous name "+e):r[e]=h.length+r.length),r.push(...t.map((e=>p[e])))}let m=r.reduce(((e,t)=>(t==e[e.length-1]?e[e.length-2]++:e.push(1,t),e)),[]);const b=l=>{let a,[g,..._]=l,d=u[g],m=0,x=[],v=[];if(d>=69)m=d>=167||d<=159&&d>=153||d<=145&&d>=139||d<=123&&d>=121||d<=105&&d>=103||80==d||69==d?1:2;else if(d>=40&&d<=62){let t,i={align:c[g],offset:0};for(;_[0]?.[0]in i;)t=_.shift(),i[t[0]]=+t[1];v=[Math.log2(i.align),...e(i.offset)],m=d>=54?2:1}else if(d>=65&&d<=68)v=(65==d?t:66==d?i:67==d?s:f)(_.shift());else if(d>=32&&d<=34)v=e("$"===_[0]?.[0]?h[a=_.shift()]||r[a]:_.shift()),d>32&&(m=1);else if(35==d||36==d)v=e("$"===_[0]?.[0]?n.global[_.shift()]:_.shift()),d>35&&(m=1);else if(16==d){let t=_.shift();v=e(a="$"===t[0]?n.func[t]??$("Unknown function `"+t+"`"):t),[,m]=n.type[n.func[a][0]]}else if(17==d){let t=_.shift()[1];[,m]=n.type[t="$"===t[0]?n.type[t]:t],m++,v=e(t),v.push(0)}else if(63==d||64==d)v=[0],m=1;else if(4==d){o.push(d);let e,[,t]="result"===_[0][0]?_.shift():[,"void"];v=[p[t]],m=0,x.push(...b(_.shift())),"then"===_[0]?.[0]?[,...e]=_.shift():e=_,v.push(...y(e)),o.pop(),o.push(u.else),"else"===_[0]?.[0]&&([,...e]=_.shift(),e.length&&v.push(u.else,...y(e))),o.pop(),v.push(u.end)}else if(26==d||15==d)m=_.length?1:0;else if(27==d)m=3;else if(2==d||3==d){o.push(d),"$"===_[0]?.[0]&&(o[_.shift()]=o.length);let[,e]="result"===_[0]?.[0]?_.shift():[,"void"];v=[p[e],...y(_)],l.inline||(o.pop(),v.push(u.end))}else if(11==d)o.pop();else if(12==d||13==d)v=e("$"===_[0]?.[0]?o.length-o[_.shift()]:_.shift()),m=13==d?1+(_.length>1):!!_.length;else if(14==d){for(v=[];!Array.isArray(_[0]);)a=_.shift(),v.push(...e("$"===a[0][0]?o.length-o[a]:a));v.unshift(...e(v.length-1)),m=1+(_.length>1)}else null==d&&$(`Unknown instruction \`${g}\``);for(_.length<m&&$(`Stack arguments are not supported at \`${g}\``);m--;)x.push(...b(_.shift()));return _.length&&$(`Too many arguments for \`${g}\`.`),[...x,d,...v]},y=e=>{let t=[];for(;e.length;){let i,l=e.shift();"string"==typeof l&&((i=g[l])?(l=[l],l.inline=!0,i>0&&"$"===e[0]?.[0]&&l.push(e.shift())):$(`Inline instruction \`${l}\` is not supported`)),l&&t.push(...b(l))}return t};return()=>{let t=y(l);n.code.push([...e(t.length+2+m.length),...e(m.length>>1),...m,...t,u.end])}},memory([,...e],t){"$"===e[0][0]&&(t.memory[e.shift()]=t.memory.length),"export"===e[0][0]&&d.export([...e.shift(),["memory",t.memory.length]],t),t.memory.push(x(e))},global([,...e],t){let i="$"===e[0][0]&&e.shift();i&&(t.global[i]=t.global.length);let[l,n]=e,s="mut"===l[0]?1:0;t.global.push([p[s?l[1]:l],s,...m(n)])},table([,...e],t){let i="$"===e[0][0]&&e.shift();i&&(t.table[i]=t.table.length);let l=x(e);t.table.push([p[e.pop()],...l])},elem([,t,...i],l){l.elem.push([0,...m(t,l),...e(i.length),...i.flatMap((t=>e("$"===t[0]?l.func[t]:t)))])},export([,t,[i,l]],n){"$"===l[0]&&(l=n[i][l]),n.export.push([...y(t),h[i],...e(l)])},import([,t,i,l],n){let s,[r,...o]=l,f="$"===o[0]?.[0]&&o.shift();if("func"===r){f&&(n.func[f]=n.func.length);let[t]=d.type([,["func",...o]],n);n.func.push(s=e(t)),n.func.importc=(n.func.importc||0)+1}else if("memory"===r)f&&(n.memory[f]=n.memory.length),s=x(o);else{if("global"!==r)throw Error("Unimplemented "+r);{f&&(n.global[f]=n.global.length);let[e]=o,t="mut"===e[0]?1:0;s=[p[t?e[1]:e],t],n.global.push(s),n.global.importc=(n.global.importc||0)+1}}n.import.push([...y(t),...y(i),h[r],...s])},data([,e,...t],i){i.data.push([0,...m(e,i),...y(t.map((e=>'"'===e[0]?e.slice(1,-1):e)).join(""))])},start([,e],t){t.start.length||t.start.push(["$"===e[0]?t.func[e]:e])}},m=([e,l],n)=>"f"===e[0]?[u[e],...("3"===e[1]?s:f)(l),u.end]:[u[e],...("3"===e[1]?t:i)("$"===l[0]?n.global[l]:l),u.end],b={n:10,r:13,t:9,v:1},y=t=>{t='"'===t[0]?t.slice(1,-1):t;let i,l=[],n=0;for(;n<t.length;)i=t.charCodeAt(n++),l.push(92===i?b[t[n++]]||parseInt(t.slice(n-1,++n),16):i);return l.unshift(...e(l.length)),l},x=([t,i,l])=>isNaN(parseInt(i))?[0,...e(t)]:["shared"===l?3:1,...e(t),...e(i)],$=e=>{throw Error(e)};var v=e=>{let t=0,i=[],l="";const n=()=>l&&(i.push('"'!==l[0]&&~l.indexOf("=")?l.split("="):l),l=""),s=()=>{for(let r,o;t<e.length;)if(r=e.charCodeAt(t),34===r)n(),l=e.slice(t++,t=e.indexOf('"',t)+1),n();else if(40===r)59===e.charCodeAt(t+1)?t=e.indexOf(";)",t)+2:(n(),t++,(o=i).push(i=[]),s(),i=o);else if(59===r)t=e.indexOf("\n",t)+1;else if(r<=32)n(),t++;else{if(41===r)return n(),t++;l+=e[t++]}n()};return s(),i.length>1?i:i[0]},U=e=>(e="string"==typeof e?v(e):e,_(e));export{_ as compile,U as default,v as parse};