watr 1.3.0 → 1.3.2
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/watr.js +167 -122
- package/watr.min.js +1 -1
package/package.json
CHANGED
package/watr.js
CHANGED
|
@@ -143,11 +143,45 @@ ALIGN = {
|
|
|
143
143
|
|
|
144
144
|
OP.map((op,i)=>OP[op]=i); // init op names
|
|
145
145
|
|
|
146
|
+
const OPAREN = 40, CPAREN = 41, SPACE = 32, DQUOTE = 34, SEMIC = 59;
|
|
147
|
+
|
|
148
|
+
var parse = (str) => {
|
|
149
|
+
let i = 0, level = [], buf = '';
|
|
150
|
+
|
|
151
|
+
const commit = () => buf && (
|
|
152
|
+
level.push(buf),
|
|
153
|
+
buf = ''
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const parseLevel = () => {
|
|
157
|
+
for (let c, root; i < str.length;) {
|
|
158
|
+
c = str.charCodeAt(i);
|
|
159
|
+
if (c === DQUOTE) commit(), buf = str.slice(i++, i = str.indexOf('"', i) + 1), commit();
|
|
160
|
+
else if (c === OPAREN) {
|
|
161
|
+
if (str.charCodeAt(i + 1) === SEMIC) i = str.indexOf(';)', i) + 2; // (; ... ;)
|
|
162
|
+
else commit(), i++, (root = level).push(level = []), parseLevel(), level = root;
|
|
163
|
+
}
|
|
164
|
+
else if (c === SEMIC) i = str.indexOf('\n', i) + 1; // ; ...
|
|
165
|
+
else if (c <= SPACE) commit(), i++;
|
|
166
|
+
else if (c === CPAREN) return commit(), i++
|
|
167
|
+
else buf += str[i++];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
commit();
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
parseLevel();
|
|
174
|
+
|
|
175
|
+
return level.length > 1 ? level : level[0]
|
|
176
|
+
};
|
|
177
|
+
|
|
146
178
|
// some inlinable instructions
|
|
147
|
-
const INLINE = {loop: 1, block: 1, if: 1, end: -1, return: -1};
|
|
179
|
+
const INLINE = { loop: 1, block: 1, if: 1, end: -1, return: -1 };
|
|
148
180
|
|
|
149
181
|
// convert wat tree to wasm binary
|
|
150
182
|
var compile = (nodes) => {
|
|
183
|
+
if (typeof nodes === 'string') nodes = parse(nodes);
|
|
184
|
+
|
|
151
185
|
// IR. Alias is stored directly to section array by key, eg. section.func.$name = idx
|
|
152
186
|
let sections = {
|
|
153
187
|
type: [], import: [], func: [], table: [], memory: [], global: [], export: [], start: [], elem: [], code: [], data: []
|
|
@@ -163,11 +197,11 @@ var compile = (nodes) => {
|
|
|
163
197
|
// (global $a (import "a" "b") (mut i32)) → (import "a" "b" (global $a (mut i32)))
|
|
164
198
|
// (memory (import "a" "b") min max shared) → (import "a" "b" (memory min max shared))
|
|
165
199
|
nodes = nodes.map(node => {
|
|
166
|
-
if (node[2]?.[0]==='import') {
|
|
200
|
+
if (node[2]?.[0] === 'import') {
|
|
167
201
|
let [kind, name, imp, ...args] = node;
|
|
168
202
|
return [...imp, [kind, name, ...args]]
|
|
169
203
|
}
|
|
170
|
-
else if (node[1]?.[0]==='import') {
|
|
204
|
+
else if (node[1]?.[0] === 'import') {
|
|
171
205
|
let [kind, imp, ...args] = node;
|
|
172
206
|
return [...imp, [kind, ...args]]
|
|
173
207
|
}
|
|
@@ -192,11 +226,11 @@ var compile = (nodes) => {
|
|
|
192
226
|
|
|
193
227
|
// 3. build binary
|
|
194
228
|
for (let name in sections) {
|
|
195
|
-
let items=sections[name];
|
|
229
|
+
let items = sections[name];
|
|
196
230
|
if (items.importc) items = items.slice(items.importc); // discard imported functions/globals
|
|
197
231
|
if (!items.length) continue
|
|
198
232
|
let sectionCode = SECTION[name], bytes = [];
|
|
199
|
-
if (sectionCode!==8) bytes.push(items.length); // skip start section count
|
|
233
|
+
if (sectionCode !== 8) bytes.push(items.length); // skip start section count
|
|
200
234
|
for (let item of items) bytes.push(...item);
|
|
201
235
|
binary.push(sectionCode, ...uleb(bytes.length), ...bytes);
|
|
202
236
|
}
|
|
@@ -209,10 +243,10 @@ const build = {
|
|
|
209
243
|
// signature part is identical to function
|
|
210
244
|
// FIXME: handle non-function types
|
|
211
245
|
type([, typeName, decl], ctx) {
|
|
212
|
-
if (typeName[0]!=='$') decl=typeName, typeName=null;
|
|
213
|
-
let params = [], result = [], [kind
|
|
246
|
+
if (typeName[0] !== '$') decl = typeName, typeName = null;
|
|
247
|
+
let params = [], result = [], [kind, ...sig] = decl, idx, bytes;
|
|
214
248
|
|
|
215
|
-
if (kind==='func') {
|
|
249
|
+
if (kind === 'func') {
|
|
216
250
|
// collect params
|
|
217
251
|
while (sig[0]?.[0] === 'param') {
|
|
218
252
|
let [, ...types] = sig.shift();
|
|
@@ -227,7 +261,7 @@ const build = {
|
|
|
227
261
|
bytes = [TYPE.func, ...uleb(params.length), ...params, ...uleb(result.length), ...result];
|
|
228
262
|
|
|
229
263
|
idx = ctx.type.findIndex((prevType) => prevType.every((byte, i) => byte === bytes[i]));
|
|
230
|
-
if (idx < 0) idx = ctx.type.push(bytes)-1;
|
|
264
|
+
if (idx < 0) idx = ctx.type.push(bytes) - 1;
|
|
231
265
|
}
|
|
232
266
|
|
|
233
267
|
if (typeName) ctx.type[typeName] = idx;
|
|
@@ -236,9 +270,9 @@ const build = {
|
|
|
236
270
|
},
|
|
237
271
|
|
|
238
272
|
// (func $name? ...params result ...body)
|
|
239
|
-
func([
|
|
240
|
-
let locals=[], // list of local variables
|
|
241
|
-
|
|
273
|
+
func([, ...body], ctx) {
|
|
274
|
+
let locals = [], // list of local variables
|
|
275
|
+
callstack = [];
|
|
242
276
|
|
|
243
277
|
// fn name
|
|
244
278
|
if (body[0]?.[0] === '$') ctx.func[body.shift()] = ctx.func.length;
|
|
@@ -247,7 +281,7 @@ const build = {
|
|
|
247
281
|
if (body[0]?.[0] === 'export') build.export([...body.shift(), ['func', ctx.func.length]], ctx);
|
|
248
282
|
|
|
249
283
|
// register type
|
|
250
|
-
let [typeIdx, params, result] = build.type([,['func'
|
|
284
|
+
let [typeIdx, params, result] = build.type([, ['func', ...body]], ctx);
|
|
251
285
|
// FIXME: try merging with build.type: it should be able to consume body
|
|
252
286
|
while (body[0]?.[0] === 'param' || body[0]?.[0] === 'result') body.shift();
|
|
253
287
|
ctx.func.push([typeIdx]);
|
|
@@ -255,139 +289,139 @@ const build = {
|
|
|
255
289
|
// collect locals
|
|
256
290
|
while (body[0]?.[0] === 'local') {
|
|
257
291
|
let [, ...types] = body.shift(), name;
|
|
258
|
-
if (types[0][0]==='$')
|
|
259
|
-
params[name=types.shift()] ? err('Ambiguous name '+name) :
|
|
260
|
-
|
|
292
|
+
if (types[0][0] === '$')
|
|
293
|
+
params[name = types.shift()] ? err('Ambiguous name ' + name) :
|
|
294
|
+
locals[name] = params.length + locals.length;
|
|
261
295
|
locals.push(...types.map(t => TYPE[t]));
|
|
262
296
|
}
|
|
263
297
|
|
|
264
298
|
// squash local types
|
|
265
|
-
let locTypes = locals.reduce((a, type) => (type==a[a.length-1] ? a[a.length-2]++ : a.push(1,type), a), []);
|
|
299
|
+
let locTypes = locals.reduce((a, type) => (type == a[a.length - 1] ? a[a.length - 2]++ : a.push(1, type), a), []);
|
|
266
300
|
|
|
267
301
|
// map code instruction into bytes: [args, opCode, immediates]
|
|
268
302
|
const instr = (group) => {
|
|
269
303
|
let [op, ...nodes] = group;
|
|
270
|
-
let opCode = OP[op], argc=0, before=[], after=[], id;
|
|
304
|
+
let opCode = OP[op], argc = 0, before = [], after = [], id;
|
|
271
305
|
|
|
272
306
|
// NOTE: we could reorganize ops by groups and detect signature as `op in STORE`
|
|
273
307
|
// but numeric comparison is faster than generic hash lookup
|
|
274
308
|
// FIXME: we often use OP.end or alike: what if we had list of global constants?
|
|
275
309
|
|
|
276
310
|
// binary/unary
|
|
277
|
-
if (opCode>=69) {
|
|
278
|
-
|
|
279
|
-
(opCode<=159 && opCode>=153) ||
|
|
280
|
-
(opCode<=145 && opCode>=139) ||
|
|
281
|
-
(opCode<=123 && opCode>=121) ||
|
|
282
|
-
(opCode<=105 && opCode>=103) ||
|
|
283
|
-
opCode==80 || opCode==69 ? 1 : 2;
|
|
311
|
+
if (opCode >= 69) {
|
|
312
|
+
argc = opCode >= 167 ||
|
|
313
|
+
(opCode <= 159 && opCode >= 153) ||
|
|
314
|
+
(opCode <= 145 && opCode >= 139) ||
|
|
315
|
+
(opCode <= 123 && opCode >= 121) ||
|
|
316
|
+
(opCode <= 105 && opCode >= 103) ||
|
|
317
|
+
opCode == 80 || opCode == 69 ? 1 : 2;
|
|
284
318
|
}
|
|
285
319
|
// instruction
|
|
286
320
|
else {
|
|
287
321
|
// (i32.store align=n offset=m at value)
|
|
288
|
-
if (opCode>=40&&opCode<=62) {
|
|
322
|
+
if (opCode >= 40 && opCode <= 62) {
|
|
289
323
|
// FIXME: figure out point in Math.log2 aligns
|
|
290
|
-
let o = {align: ALIGN[op], offset: 0}, p;
|
|
291
|
-
while (nodes[0]?.
|
|
324
|
+
let o = { align: ALIGN[op], offset: 0 }, p;
|
|
325
|
+
while (nodes[0]?.includes('=')) p = nodes.shift().split('='), o[p[0]] = Number(p[1]);
|
|
292
326
|
after = [Math.log2(o.align), ...uleb(o.offset)];
|
|
293
327
|
argc = opCode >= 54 ? 2 : 1;
|
|
294
328
|
}
|
|
295
329
|
|
|
296
330
|
// (i32.const 123)
|
|
297
|
-
else if (opCode>=65&&opCode<=68) {
|
|
298
|
-
after = (opCode==65?leb:opCode==66?bigleb:opCode==67?f32:f64)(nodes.shift());
|
|
331
|
+
else if (opCode >= 65 && opCode <= 68) {
|
|
332
|
+
after = (opCode == 65 ? leb : opCode == 66 ? bigleb : opCode == 67 ? f32 : f64)(nodes.shift());
|
|
299
333
|
}
|
|
300
334
|
|
|
301
335
|
// (local.get $id), (local.tee $id x)
|
|
302
|
-
else if (opCode>=32&&opCode<=34) {
|
|
303
|
-
after = uleb(nodes[0]?.[0]==='$' ? params[id=nodes.shift()] || locals[id] : nodes.shift());
|
|
304
|
-
if (opCode>32) argc = 1;
|
|
336
|
+
else if (opCode >= 32 && opCode <= 34) {
|
|
337
|
+
after = uleb(nodes[0]?.[0] === '$' ? params[id = nodes.shift()] || locals[id] : nodes.shift());
|
|
338
|
+
if (opCode > 32) argc = 1;
|
|
305
339
|
}
|
|
306
340
|
|
|
307
341
|
// (global.get id), (global.set id)
|
|
308
|
-
else if (opCode==35||opCode==36) {
|
|
309
|
-
after = uleb(nodes[0]?.[0]==='$' ? ctx.global[nodes.shift()] : nodes.shift());
|
|
310
|
-
if (opCode>35) argc = 1;
|
|
342
|
+
else if (opCode == 35 || opCode == 36) {
|
|
343
|
+
after = uleb(nodes[0]?.[0] === '$' ? ctx.global[nodes.shift()] : nodes.shift());
|
|
344
|
+
if (opCode > 35) argc = 1;
|
|
311
345
|
}
|
|
312
346
|
|
|
313
347
|
// (call id ...nodes)
|
|
314
|
-
else if (opCode==16) {
|
|
348
|
+
else if (opCode == 16) {
|
|
315
349
|
let fnName = nodes.shift();
|
|
316
|
-
after = uleb(id = fnName[0]==='$' ? ctx.func[fnName] ?? err('Unknown function `' + fnName + '`') : fnName);
|
|
350
|
+
after = uleb(id = fnName[0] === '$' ? ctx.func[fnName] ?? err('Unknown function `' + fnName + '`') : fnName);
|
|
317
351
|
// FIXME: how to get signature of imported function
|
|
318
|
-
[,argc] = ctx.type[ctx.func[id][0]];
|
|
352
|
+
[, argc] = ctx.type[ctx.func[id][0]];
|
|
319
353
|
}
|
|
320
354
|
|
|
321
355
|
// (call_indirect (type $typeName) (idx) ...nodes)
|
|
322
|
-
else if (opCode==17) {
|
|
356
|
+
else if (opCode == 17) {
|
|
323
357
|
let typeId = nodes.shift()[1];
|
|
324
|
-
[,argc] = ctx.type[typeId = typeId[0]==='$'?ctx.type[typeId]:typeId];
|
|
358
|
+
[, argc] = ctx.type[typeId = typeId[0] === '$' ? ctx.type[typeId] : typeId];
|
|
325
359
|
argc++;
|
|
326
360
|
after = uleb(typeId), after.push(0); // extra afterediate indicates table idx (reserved)
|
|
327
361
|
}
|
|
328
362
|
|
|
329
363
|
// FIXME (memory.grow $idx?)
|
|
330
|
-
else if (opCode==63||opCode==64) {
|
|
364
|
+
else if (opCode == 63 || opCode == 64) {
|
|
331
365
|
after = [0];
|
|
332
366
|
argc = 1;
|
|
333
367
|
}
|
|
334
368
|
|
|
335
369
|
// (if (result i32)? (local.get 0) (then a b) (else a b)?)
|
|
336
|
-
else if (opCode==4) {
|
|
370
|
+
else if (opCode == 4) {
|
|
337
371
|
callstack.push(opCode);
|
|
338
|
-
let [,type] = nodes[0][0]==='result' ? nodes.shift() : [,'void'];
|
|
339
|
-
after=[TYPE[type]];
|
|
372
|
+
let [, type] = nodes[0][0] === 'result' ? nodes.shift() : [, 'void'];
|
|
373
|
+
after = [TYPE[type]];
|
|
340
374
|
|
|
341
375
|
argc = 0, before.push(...instr(nodes.shift()));
|
|
342
376
|
let body;
|
|
343
|
-
if (nodes[0]?.[0]==='then') [
|
|
377
|
+
if (nodes[0]?.[0] === 'then') [, ...body] = nodes.shift(); else body = nodes;
|
|
344
378
|
after.push(...consume(body));
|
|
345
379
|
|
|
346
380
|
callstack.pop(), callstack.push(OP.else);
|
|
347
|
-
if (nodes[0]?.[0]==='else') {
|
|
348
|
-
[
|
|
349
|
-
if (body.length) after.push(OP.else
|
|
381
|
+
if (nodes[0]?.[0] === 'else') {
|
|
382
|
+
[, ...body] = nodes.shift();
|
|
383
|
+
if (body.length) after.push(OP.else, ...consume(body));
|
|
350
384
|
}
|
|
351
385
|
callstack.pop();
|
|
352
386
|
after.push(OP.end);
|
|
353
387
|
}
|
|
354
388
|
|
|
355
389
|
// (drop arg?), (return arg?)
|
|
356
|
-
else if (opCode==0x1a || opCode==0x0f) { argc = nodes.length?1:0; }
|
|
390
|
+
else if (opCode == 0x1a || opCode == 0x0f) { argc = nodes.length ? 1 : 0; }
|
|
357
391
|
|
|
358
392
|
// (select a b cond)
|
|
359
|
-
else if (opCode==0x1b) { argc = 3; }
|
|
393
|
+
else if (opCode == 0x1b) { argc = 3; }
|
|
360
394
|
|
|
361
395
|
// (block ...), (loop ...)
|
|
362
|
-
else if (opCode==2||opCode==3) {
|
|
396
|
+
else if (opCode == 2 || opCode == 3) {
|
|
363
397
|
callstack.push(opCode);
|
|
364
|
-
if (nodes[0]?.[0]==='$') (callstack[nodes.shift()] = callstack.length);
|
|
365
|
-
let [,type] = nodes[0]?.[0]==='result' ? nodes.shift() : [,'void'];
|
|
366
|
-
after=[TYPE[type], ...consume(nodes)];
|
|
398
|
+
if (nodes[0]?.[0] === '$') (callstack[nodes.shift()] = callstack.length);
|
|
399
|
+
let [, type] = nodes[0]?.[0] === 'result' ? nodes.shift() : [, 'void'];
|
|
400
|
+
after = [TYPE[type], ...consume(nodes)];
|
|
367
401
|
|
|
368
402
|
if (!group.inline) callstack.pop(), after.push(OP.end); // inline loop/block expects end to be separately provided
|
|
369
403
|
}
|
|
370
404
|
|
|
371
405
|
// (end)
|
|
372
|
-
else if (opCode==0x0b) callstack.pop();
|
|
406
|
+
else if (opCode == 0x0b) callstack.pop();
|
|
373
407
|
|
|
374
408
|
// (br $label result?)
|
|
375
409
|
// (br_if $label cond result?)
|
|
376
|
-
else if (opCode==0x0c||opCode==0x0d) {
|
|
410
|
+
else if (opCode == 0x0c || opCode == 0x0d) {
|
|
377
411
|
// br index indicates how many callstack items to pop
|
|
378
|
-
after = uleb(nodes[0]?.[0]==='$' ? callstack.length-callstack[nodes.shift()] : nodes.shift());
|
|
379
|
-
argc = (opCode==0x0d ? 1 + (nodes.length > 1) : !!nodes.length);
|
|
412
|
+
after = uleb(nodes[0]?.[0] === '$' ? callstack.length - callstack[nodes.shift()] : nodes.shift());
|
|
413
|
+
argc = (opCode == 0x0d ? 1 + (nodes.length > 1) : !!nodes.length);
|
|
380
414
|
}
|
|
381
415
|
|
|
382
416
|
// (br_table 1 2 3 4 0 selector result?)
|
|
383
|
-
else if (opCode==0x0e) {
|
|
417
|
+
else if (opCode == 0x0e) {
|
|
384
418
|
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));
|
|
387
|
-
argc = 1 + (nodes.length>1);
|
|
419
|
+
while (!Array.isArray(nodes[0])) id = nodes.shift(), after.push(...uleb(id[0][0] === '$' ? callstack.length - callstack[id] : id));
|
|
420
|
+
after.unshift(...uleb(after.length - 1));
|
|
421
|
+
argc = 1 + (nodes.length > 1);
|
|
388
422
|
}
|
|
389
423
|
|
|
390
|
-
else if (opCode==null) err(`Unknown instruction \`${op}\``);
|
|
424
|
+
else if (opCode == null) err(`Unknown instruction \`${op}\``);
|
|
391
425
|
}
|
|
392
426
|
|
|
393
427
|
// consume arguments
|
|
@@ -406,9 +440,9 @@ const build = {
|
|
|
406
440
|
|
|
407
441
|
if (typeof node === 'string') {
|
|
408
442
|
// permit some inline instructions: loop $label ... end, br $label, arg return
|
|
409
|
-
if (c=INLINE[node]) {
|
|
443
|
+
if (c = INLINE[node]) {
|
|
410
444
|
node = [node], node.inline = true;
|
|
411
|
-
if (c>0) nodes[0]?.[0]==='$' && node.push(nodes.shift());
|
|
445
|
+
if (c > 0) nodes[0]?.[0] === '$' && node.push(nodes.shift());
|
|
412
446
|
}
|
|
413
447
|
else err(`Inline instruction \`${node}\` is not supported`);
|
|
414
448
|
}
|
|
@@ -421,7 +455,7 @@ const build = {
|
|
|
421
455
|
// evaluates after all definitions
|
|
422
456
|
return () => {
|
|
423
457
|
let code = consume(body);
|
|
424
|
-
ctx.code.push([...uleb(code.length+2+locTypes.length), ...uleb(locTypes.length>>1), ...locTypes, ...code, OP.end]);
|
|
458
|
+
ctx.code.push([...uleb(code.length + 2 + locTypes.length), ...uleb(locTypes.length >> 1), ...locTypes, ...code, OP.end]);
|
|
425
459
|
}
|
|
426
460
|
},
|
|
427
461
|
|
|
@@ -429,7 +463,7 @@ const build = {
|
|
|
429
463
|
// (memory $name min max shared)
|
|
430
464
|
// (memory (export "mem") 5)
|
|
431
465
|
memory([, ...parts], ctx) {
|
|
432
|
-
if (parts[0][0]==='$') ctx.memory[parts.shift()] = ctx.memory.length;
|
|
466
|
+
if (parts[0][0] === '$') ctx.memory[parts.shift()] = ctx.memory.length;
|
|
433
467
|
if (parts[0][0] === 'export') build.export([...parts.shift(), ['memory', ctx.memory.length]], ctx);
|
|
434
468
|
ctx.memory.push(range(parts));
|
|
435
469
|
},
|
|
@@ -438,7 +472,7 @@ const build = {
|
|
|
438
472
|
// (global $id i32 (i32.const 42))
|
|
439
473
|
// (global $id (mut i32) (i32.const 42))
|
|
440
474
|
global([, ...args], ctx) {
|
|
441
|
-
let name = args[0][0]==='$' && args.shift();
|
|
475
|
+
let name = args[0][0] === '$' && args.shift();
|
|
442
476
|
if (name) ctx.global[name] = ctx.global.length;
|
|
443
477
|
let [type, init] = args, mut = type[0] === 'mut' ? 1 : 0;
|
|
444
478
|
ctx.global.push([TYPE[mut ? type[1] : type], mut, ...iinit(init)]);
|
|
@@ -447,7 +481,7 @@ const build = {
|
|
|
447
481
|
// (table 1 2? funcref)
|
|
448
482
|
// (table $name 1 2? funcref)
|
|
449
483
|
table([, ...args], ctx) {
|
|
450
|
-
let name = args[0][0]==='$' && args.shift();
|
|
484
|
+
let name = args[0][0] === '$' && args.shift();
|
|
451
485
|
if (name) ctx.table[name] = ctx.table.length;
|
|
452
486
|
let lims = range(args);
|
|
453
487
|
ctx.table.push([TYPE[args.pop()], ...lims]);
|
|
@@ -456,12 +490,12 @@ const build = {
|
|
|
456
490
|
// (elem (i32.const 0) $f1 $f2), (elem (global.get 0) $f1 $f2)
|
|
457
491
|
elem([, offset, ...elems], ctx) {
|
|
458
492
|
const tableIdx = 0; // FIXME: table index can be defined
|
|
459
|
-
ctx.elem.push([tableIdx, ...iinit(offset, ctx), ...uleb(elems.length), ...elems.flatMap(el => uleb(el[0]==='$' ? ctx.func[el] : el))]);
|
|
493
|
+
ctx.elem.push([tableIdx, ...iinit(offset, ctx), ...uleb(elems.length), ...elems.flatMap(el => uleb(el[0] === '$' ? ctx.func[el] : el))]);
|
|
460
494
|
},
|
|
461
495
|
|
|
462
496
|
// (export "name" (kind $name|idx))
|
|
463
497
|
export([, name, [kind, idx]], ctx) {
|
|
464
|
-
if (idx[0]==='$') idx = ctx[kind][idx];
|
|
498
|
+
if (idx[0] === '$') idx = ctx[kind][idx];
|
|
465
499
|
ctx.export.push([...str(name), KIND[kind], ...uleb(idx)]);
|
|
466
500
|
},
|
|
467
501
|
|
|
@@ -471,26 +505,26 @@ const build = {
|
|
|
471
505
|
// (import "js" "v" (global $name (mut f64)))
|
|
472
506
|
import([, mod, field, ref], ctx) {
|
|
473
507
|
let details, [kind, ...parts] = ref,
|
|
474
|
-
|
|
508
|
+
name = parts[0]?.[0] === '$' && parts.shift();
|
|
475
509
|
|
|
476
|
-
if (kind==='func') {
|
|
510
|
+
if (kind === 'func') {
|
|
477
511
|
// we track imported funcs in func section to share namespace, and skip them on final build
|
|
478
512
|
if (name) ctx.func[name] = ctx.func.length;
|
|
479
513
|
let [typeIdx] = build.type([, ['func', ...parts]], ctx);
|
|
480
514
|
ctx.func.push(details = uleb(typeIdx));
|
|
481
|
-
ctx.func.importc = (ctx.func.importc||0)+1;
|
|
515
|
+
ctx.func.importc = (ctx.func.importc || 0) + 1;
|
|
482
516
|
}
|
|
483
|
-
else if (kind==='memory') {
|
|
517
|
+
else if (kind === 'memory') {
|
|
484
518
|
if (name) ctx.memory[name] = ctx.memory.length;
|
|
485
519
|
details = range(parts);
|
|
486
520
|
}
|
|
487
|
-
else if (kind==='global') {
|
|
521
|
+
else if (kind === 'global') {
|
|
488
522
|
// imported globals share namespace with internal globals - we skip them in final build
|
|
489
523
|
if (name) ctx.global[name] = ctx.global.length;
|
|
490
524
|
let [type] = parts, mut = type[0] === 'mut' ? 1 : 0;
|
|
491
525
|
details = [TYPE[mut ? type[1] : type], mut];
|
|
492
526
|
ctx.global.push(details);
|
|
493
|
-
ctx.global.importc = (ctx.global.importc||0)+1;
|
|
527
|
+
ctx.global.importc = (ctx.global.importc || 0) + 1;
|
|
494
528
|
}
|
|
495
529
|
else throw Error('Unimplemented ' + kind)
|
|
496
530
|
|
|
@@ -500,76 +534,87 @@ const build = {
|
|
|
500
534
|
// (data (i32.const 0) "\aa" "\bb"?)
|
|
501
535
|
data([, offset, ...inits], ctx) {
|
|
502
536
|
// FIXME: first is mem index
|
|
503
|
-
ctx.data.push([0, ...iinit(offset,ctx), ...str(inits.map(i=>i[0]==='"'?i.slice(1
|
|
537
|
+
ctx.data.push([0, ...iinit(offset, ctx), ...str(inits.map(i => i[0] === '"' ? i.slice(1, -1) : i).join(''))]);
|
|
504
538
|
},
|
|
505
539
|
|
|
506
540
|
// (start $main)
|
|
507
|
-
start([, name],ctx) {
|
|
508
|
-
if (!ctx.start.length) ctx.start.push([name[0]==='$' ? ctx.func[name] : name]);
|
|
541
|
+
start([, name], ctx) {
|
|
542
|
+
if (!ctx.start.length) ctx.start.push([name[0] === '$' ? ctx.func[name] : name]);
|
|
509
543
|
}
|
|
510
544
|
};
|
|
511
545
|
|
|
512
546
|
// (i32.const 0) - instantiation time initializer
|
|
513
|
-
const iinit = ([op, literal], ctx) => op[0]==='f' ?
|
|
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];
|
|
547
|
+
const iinit = ([op, literal], ctx) => op[0] === 'f' ?
|
|
548
|
+
[OP[op], ...(op[1] === '3' ? f32 : f64)(literal), OP.end] :
|
|
549
|
+
[OP[op], ...(op[1] === '3' ? leb : bigleb)(literal[0] === '$' ? ctx.global[literal] : literal), OP.end];
|
|
516
550
|
|
|
517
|
-
const escape = {n:10, r:13, t:9, v:1};
|
|
551
|
+
const escape = { n: 10, r: 13, t: 9, v: 1 };
|
|
518
552
|
|
|
519
553
|
// build string binary
|
|
520
554
|
const str = str => {
|
|
521
|
-
str = str[0]==='"' ? str.slice(1
|
|
522
|
-
let res = [], i = 0, c, BSLASH=92;
|
|
555
|
+
str = str[0] === '"' ? str.slice(1, -1) : str;
|
|
556
|
+
let res = [], i = 0, c, BSLASH = 92;
|
|
523
557
|
// spec https://webassembly.github.io/spec/core/text/values.html#strings
|
|
524
|
-
for (;i < str.length;) {
|
|
525
|
-
c=str.charCodeAt(i++);
|
|
526
|
-
res.push(c===BSLASH ? escape[str[i++]] || parseInt(str.slice(i-1
|
|
558
|
+
for (; i < str.length;) {
|
|
559
|
+
c = str.charCodeAt(i++);
|
|
560
|
+
res.push(c === BSLASH ? escape[str[i++]] || parseInt(str.slice(i - 1, ++i), 16) : c);
|
|
527
561
|
}
|
|
528
562
|
|
|
529
563
|
res.unshift(...uleb(res.length));
|
|
530
564
|
return res
|
|
531
565
|
};
|
|
532
566
|
|
|
567
|
+
|
|
533
568
|
// build range/limits sequence (non-consuming)
|
|
534
|
-
const range = ([min, max, shared]) => isNaN(parseInt(max)) ? [0, ...uleb(min)] : [shared==='shared'?3:1, ...uleb(min), ...uleb(max)];
|
|
569
|
+
const range = ([min, max, shared]) => isNaN(parseInt(max)) ? [0, ...uleb(min)] : [shared === 'shared' ? 3 : 1, ...uleb(min), ...uleb(max)];
|
|
535
570
|
|
|
536
571
|
const err = text => { throw Error(text) };
|
|
537
572
|
|
|
538
|
-
|
|
573
|
+
let indent = '', newline = '\n', pad = '', comments = false;
|
|
539
574
|
|
|
540
|
-
|
|
541
|
-
|
|
575
|
+
function print(tree, options = {}) {
|
|
576
|
+
if (typeof tree === 'string') tree = parse(tree);
|
|
542
577
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
578
|
+
({ indent, newline, pad, comments } = options);
|
|
579
|
+
newline ||= '';
|
|
580
|
+
pad ||= '';
|
|
581
|
+
indent ||= '';
|
|
547
582
|
|
|
548
|
-
|
|
549
|
-
for (let c, root; i < str.length; ) {
|
|
550
|
-
c = str.charCodeAt(i);
|
|
551
|
-
if (c === DQUOTE) commit(), buf = str.slice(i++, i=str.indexOf('"', i)+1), commit();
|
|
552
|
-
else if (c === OPAREN) {
|
|
553
|
-
if (str.charCodeAt(i+1) === SEMIC) i=str.indexOf(';)', i)+2; // (; ... ;)
|
|
554
|
-
else commit(), i++, (root=level).push(level=[]), parseLevel(), level=root;
|
|
555
|
-
}
|
|
556
|
-
else if (c === SEMIC) i=str.indexOf('\n', i)+1; // ; ...
|
|
557
|
-
else if (c <= SPACE) commit(), i++;
|
|
558
|
-
else if (c === CPAREN) return commit(), i++
|
|
559
|
-
else buf+=str[i++];
|
|
560
|
-
}
|
|
583
|
+
let out = typeof tree[0] === 'string' ? printNode(tree) : tree.map(node => printNode(node)).join(newline);
|
|
561
584
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
parseLevel();
|
|
585
|
+
return out
|
|
586
|
+
}
|
|
566
587
|
|
|
567
|
-
|
|
568
|
-
|
|
588
|
+
const flats = ['param', 'local', 'global', 'result', 'export'];
|
|
589
|
+
|
|
590
|
+
function printNode(node, level = 0) {
|
|
591
|
+
if (!Array.isArray(node)) return node + ''
|
|
592
|
+
|
|
593
|
+
let content = node[0];
|
|
594
|
+
|
|
595
|
+
for (let i = 1; i < node.length; i++) {
|
|
596
|
+
// new node doesn't need space separator, eg. [x,[y]] -> `x(y)`
|
|
597
|
+
if (Array.isArray(node[i])) {
|
|
598
|
+
// inline nodes like (param x)(param y)
|
|
599
|
+
// (func (export "xxx")..., but not (func (export "a")(param "b")...
|
|
600
|
+
if (
|
|
601
|
+
flats.includes(node[i][0]) &&
|
|
602
|
+
(!Array.isArray(node[i - 1]) || node[i][0] === node[i - 1][0])
|
|
603
|
+
) {
|
|
604
|
+
if (!Array.isArray(node[i - 1])) content += ` `;
|
|
605
|
+
} else {
|
|
606
|
+
content += newline;
|
|
607
|
+
if (node[i]) content += indent.repeat(level + 1);
|
|
608
|
+
}
|
|
569
609
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
610
|
+
content += printNode(node[i], level + 1);
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
content += ` `;
|
|
614
|
+
content += node[i];
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return `(${content})`
|
|
618
|
+
}
|
|
574
619
|
|
|
575
|
-
export { compile,
|
|
620
|
+
export { compile, compile as default, parse, print };
|
package/watr.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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};
|
|
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 r(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 s=0x8000000000000000n,o=0x7ff0000000000000n;function f(e,t,i){return~(i=e.indexOf("nan:"))?(t=BigInt(e.slice(i+4)),t|=o,"-"===e[0]&&(t|=s),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));var g=e=>{let t=0,i=[],l="";const n=()=>l&&(i.push(l),l=""),r=()=>{for(let s,o;t<e.length;)if(s=e.charCodeAt(t),34===s)n(),l=e.slice(t++,t=e.indexOf('"',t)+1),n();else if(40===s)59===e.charCodeAt(t+1)?t=e.indexOf(";)",t)+2:(n(),t++,(o=i).push(i=[]),r(),i=o);else if(59===s)t=e.indexOf("\n",t)+1;else if(s<=32)n(),t++;else{if(41===s)return n(),t++;l+=e[t++]}n()};return r(),i.length>1?i:i[0]};const _={loop:1,block:1,if:1,end:-1,return:-1};var d=t=>{"string"==typeof t&&(t=g(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"],r=[];for(let e of n){let l=[];for(let n of t)n[0]===e?r.push(m[e](n,i)):l.push(n);t=l}for(let e of r)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 r=a[t],s=[];8!==r&&s.push(n.length);for(let e of n)s.push(...e);l.push(r,...e(s.length),...s)}return new Uint8Array(l)};const m={type([,t,i],l){"$"!==t[0]&&(i=t,t=null);let n,r,s=[],o=[],[f,...u]=i;if("func"===f){for(;"param"===u[0]?.[0];){let[,...e]=u.shift();"$"===e[0]?.[0]&&(s[e.shift()]=s.length),s.push(...e.map((e=>p[e])))}"result"===u[0]?.[0]&&(o=u.shift().slice(1).map((e=>p[e]))),r=[p.func,...e(s.length),...s,...e(o.length),...o],n=l.type.findIndex((e=>e.every(((e,t)=>e===r[t])))),n<0&&(n=l.type.push(r)-1)}return t&&(l.type[t]=n),[n,s,o]},func([,...l],n){let s=[],o=[];"$"===l[0]?.[0]&&(n.func[l.shift()]=n.func.length),"export"===l[0]?.[0]&&m.export([...l.shift(),["func",n.func.length]],n);let[a,h,g]=m.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()]?v("Ambiguous name "+e):s[e]=h.length+s.length),s.push(...t.map((e=>p[e])))}let d=s.reduce(((e,t)=>(t==e[e.length-1]?e[e.length-2]++:e.push(1,t),e)),[]);const y=l=>{let a,[g,..._]=l,d=u[g],m=0,x=[],$=[];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]?.includes("=");)t=_.shift().split("="),i[t[0]]=Number(t[1]);$=[Math.log2(i.align),...e(i.offset)],m=d>=54?2:1}else if(d>=65&&d<=68)$=(65==d?t:66==d?i:67==d?r:f)(_.shift());else if(d>=32&&d<=34)$=e("$"===_[0]?.[0]?h[a=_.shift()]||s[a]:_.shift()),d>32&&(m=1);else if(35==d||36==d)$=e("$"===_[0]?.[0]?n.global[_.shift()]:_.shift()),d>35&&(m=1);else if(16==d){let t=_.shift();$=e(a="$"===t[0]?n.func[t]??v("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++,$=e(t),$.push(0)}else if(63==d||64==d)$=[0],m=1;else if(4==d){o.push(d);let e,[,t]="result"===_[0][0]?_.shift():[,"void"];$=[p[t]],m=0,x.push(...y(_.shift())),"then"===_[0]?.[0]?[,...e]=_.shift():e=_,$.push(...b(e)),o.pop(),o.push(u.else),"else"===_[0]?.[0]&&([,...e]=_.shift(),e.length&&$.push(u.else,...b(e))),o.pop(),$.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"];$=[p[e],...b(_)],l.inline||(o.pop(),$.push(u.end))}else if(11==d)o.pop();else if(12==d||13==d)$=e("$"===_[0]?.[0]?o.length-o[_.shift()]:_.shift()),m=13==d?1+(_.length>1):!!_.length;else if(14==d){for($=[];!Array.isArray(_[0]);)a=_.shift(),$.push(...e("$"===a[0][0]?o.length-o[a]:a));$.unshift(...e($.length-1)),m=1+(_.length>1)}else null==d&&v(`Unknown instruction \`${g}\``);for(_.length<m&&v(`Stack arguments are not supported at \`${g}\``);m--;)x.push(...y(_.shift()));return _.length&&v(`Too many arguments for \`${g}\`.`),[...x,d,...$]},b=e=>{let t=[];for(;e.length;){let i,l=e.shift();"string"==typeof l&&((i=_[l])?(l=[l],l.inline=!0,i>0&&"$"===e[0]?.[0]&&l.push(e.shift())):v(`Inline instruction \`${l}\` is not supported`)),l&&t.push(...y(l))}return t};return()=>{let t=b(l);n.code.push([...e(t.length+2+d.length),...e(d.length>>1),...d,...t,u.end])}},memory([,...e],t){"$"===e[0][0]&&(t.memory[e.shift()]=t.memory.length),"export"===e[0][0]&&m.export([...e.shift(),["memory",t.memory.length]],t),t.memory.push($(e))},global([,...e],t){let i="$"===e[0][0]&&e.shift();i&&(t.global[i]=t.global.length);let[l,n]=e,r="mut"===l[0]?1:0;t.global.push([p[r?l[1]:l],r,...y(n)])},table([,...e],t){let i="$"===e[0][0]&&e.shift();i&&(t.table[i]=t.table.length);let l=$(e);t.table.push([p[e.pop()],...l])},elem([,t,...i],l){l.elem.push([0,...y(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([...x(t),h[i],...e(l)])},import([,t,i,l],n){let r,[s,...o]=l,f="$"===o[0]?.[0]&&o.shift();if("func"===s){f&&(n.func[f]=n.func.length);let[t]=m.type([,["func",...o]],n);n.func.push(r=e(t)),n.func.importc=(n.func.importc||0)+1}else if("memory"===s)f&&(n.memory[f]=n.memory.length),r=$(o);else{if("global"!==s)throw Error("Unimplemented "+s);{f&&(n.global[f]=n.global.length);let[e]=o,t="mut"===e[0]?1:0;r=[p[t?e[1]:e],t],n.global.push(r),n.global.importc=(n.global.importc||0)+1}}n.import.push([...x(t),...x(i),h[s],...r])},data([,e,...t],i){i.data.push([0,...y(e,i),...x(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])}},y=([e,l],n)=>"f"===e[0]?[u[e],...("3"===e[1]?r: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},x=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},$=([t,i,l])=>isNaN(parseInt(i))?[0,...e(t)]:["shared"===l?3:1,...e(t),...e(i)],v=e=>{throw Error(e)};let A="",U="\n",I="",w=!1;function q(e,t={}){return"string"==typeof e&&(e=g(e)),({indent:A,newline:U,pad:I,comments:w}=t),U||="",I||="",A||="","string"==typeof e[0]?z(e):e.map((e=>z(e))).join(U)}const k=["param","local","global","result","export"];function z(e,t=0){if(!Array.isArray(e))return e+"";let i=e[0];for(let l=1;l<e.length;l++)Array.isArray(e[l])?(!k.includes(e[l][0])||Array.isArray(e[l-1])&&e[l][0]!==e[l-1][0]?(i+=U,e[l]&&(i+=A.repeat(t+1))):Array.isArray(e[l-1])||(i+=" "),i+=z(e[l],t+1)):(i+=" ",i+=e[l]);return`(${i})`}export{d as compile,d as default,g as parse,q as print};
|