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.
- package/package.json +1 -1
- package/readme.md +16 -10
- package/watr.js +236 -155
- package/watr.min.js +1 -1
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# watr
|
|
1
|
+
# watr [](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.
|
|
21
|
-
wat-compiler | 6 kb |
|
|
22
|
-
wabt | 300 kb |
|
|
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
|
|
66
|
-
Each instruction
|
|
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
|
-
|
|
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
|
-
|
|
101
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
56
|
-
//
|
|
57
|
-
|
|
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)
|
|
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
|
-
//
|
|
64
|
-
|
|
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
|
|
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()] =
|
|
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',
|
|
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
|
-
//
|
|
137
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
207
|
-
|
|
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
|
-
|
|
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
|
-
|
|
349
|
+
if (body.length) after.push(OP.else,...consume(body));
|
|
216
350
|
}
|
|
217
351
|
callstack.pop();
|
|
218
|
-
|
|
352
|
+
after.push(OP.end);
|
|
219
353
|
}
|
|
220
354
|
|
|
221
|
-
// (drop arg), (return arg)
|
|
222
|
-
else if (opCode==0x1a || opCode==0x0f
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
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
|
-
|
|
249
|
-
while (!Array.isArray(nodes[0])) id=nodes.shift(),
|
|
250
|
-
|
|
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--)
|
|
395
|
+
while (argc--) before.push(...instr(nodes.shift()));
|
|
260
396
|
if (nodes.length) err(`Too many arguments for \`${op}\`.`);
|
|
261
397
|
|
|
262
|
-
return [...
|
|
398
|
+
return [...before, opCode, ...after]
|
|
263
399
|
};
|
|
264
400
|
|
|
265
|
-
|
|
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
|
-
|
|
268
|
-
|
|
416
|
+
node && result.push(...instr(node));
|
|
417
|
+
}
|
|
418
|
+
return result
|
|
419
|
+
};
|
|
269
420
|
|
|
270
|
-
|
|
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 (
|
|
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] === '
|
|
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(
|
|
326
|
-
|
|
327
|
-
|
|
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 (
|
|
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 (
|
|
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(
|
|
497
|
+
ctx.import.push([...str(mod), ...str(field), KIND[kind], ...details]);
|
|
343
498
|
},
|
|
344
499
|
|
|
345
|
-
// (data (i32.const 0) "\
|
|
346
|
-
data([, offset,
|
|
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(
|
|
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
|
|
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;)
|
|
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 ===
|
|
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};
|