porffor 0.2.0-fdf0fc5 → 0.14.0-0d97d1e6a

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 (42) hide show
  1. package/README.md +9 -2
  2. package/byg/index.js +3 -24
  3. package/compiler/2c.js +2 -53
  4. package/compiler/assemble.js +37 -11
  5. package/compiler/builtins/annexb_string.js +10 -10
  6. package/compiler/builtins/annexb_string.ts +3 -3
  7. package/compiler/builtins/array.ts +2 -6
  8. package/compiler/builtins/base64.ts +1 -1
  9. package/compiler/builtins/boolean.ts +1 -3
  10. package/compiler/builtins/crypto.ts +1 -1
  11. package/compiler/builtins/date.ts +1 -4
  12. package/compiler/builtins/escape.ts +1 -1
  13. package/compiler/builtins/function.ts +0 -2
  14. package/compiler/builtins/int.ts +0 -2
  15. package/compiler/builtins/number.ts +3 -8
  16. package/compiler/builtins/object.ts +0 -2
  17. package/compiler/builtins/porffor.d.ts +9 -8
  18. package/compiler/builtins/set.ts +184 -2
  19. package/compiler/builtins/string.ts +1 -1
  20. package/compiler/builtins/symbol.ts +61 -0
  21. package/compiler/builtins.js +8 -9
  22. package/compiler/codegen.js +121 -124
  23. package/compiler/decompile.js +3 -3
  24. package/compiler/embedding.js +2 -2
  25. package/compiler/encoding.js +0 -14
  26. package/compiler/expression.js +1 -1
  27. package/compiler/generated_builtins.js +348 -204
  28. package/compiler/index.js +3 -10
  29. package/compiler/opt.js +7 -7
  30. package/compiler/parse.js +1 -3
  31. package/compiler/precompile.js +17 -25
  32. package/compiler/prefs.js +6 -2
  33. package/compiler/prototype.js +5 -5
  34. package/compiler/wasmSpec.js +5 -0
  35. package/compiler/wrap.js +88 -57
  36. package/package.json +1 -1
  37. package/runner/compare.js +0 -1
  38. package/runner/debug.js +1 -6
  39. package/runner/profiler.js +15 -42
  40. package/runner/repl.js +3 -9
  41. package/runner/sizes.js +2 -2
  42. package/runner/version.js +10 -8
@@ -1,14 +1,14 @@
1
- import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from "./wasmSpec.js";
2
- import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from "./encoding.js";
3
- import { operatorOpcode } from "./expression.js";
4
- import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from "./builtins.js";
5
- import { PrototypeFuncs } from "./prototype.js";
6
- import { number, i32x4, enforceOneByte, enforceTwoBytes, enforceFourBytes, enforceEightBytes } from "./embedding.js";
7
- import { log } from "./log.js";
8
- import parse from "./parse.js";
9
- import * as Rhemyn from "../rhemyn/compile.js";
10
- import Prefs from './prefs.js';
1
+ import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from './wasmSpec.js';
2
+ import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from './encoding.js';
3
+ import { operatorOpcode } from './expression.js';
4
+ import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
5
+ import { PrototypeFuncs } from './prototype.js';
6
+ import { number } from './embedding.js';
11
7
  import { TYPES, TYPE_NAMES } from './types.js';
8
+ import * as Rhemyn from '../rhemyn/compile.js';
9
+ import parse from './parse.js';
10
+ import { log } from './log.js';
11
+ import Prefs from './prefs.js';
12
12
 
13
13
  let globals = {};
14
14
  let globalInd = 0;
@@ -19,24 +19,6 @@ let funcIndex = {};
19
19
  let currentFuncIndex = importedFuncs.length;
20
20
  let builtinFuncs = {}, builtinVars = {}, prototypeFuncs = {};
21
21
 
22
- const debug = str => {
23
- const code = [];
24
-
25
- const logChar = n => {
26
- code.push(...number(n));
27
-
28
- code.push([ Opcodes.call, 0 ]);
29
- };
30
-
31
- for (let i = 0; i < str.length; i++) {
32
- logChar(str.charCodeAt(i));
33
- }
34
-
35
- logChar(10); // new line
36
-
37
- return code;
38
- };
39
-
40
22
  class TodoError extends Error {
41
23
  constructor(message) {
42
24
  super(message);
@@ -76,10 +58,11 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
76
58
 
77
59
  case 'ArrowFunctionExpression':
78
60
  case 'FunctionDeclaration':
61
+ case 'FunctionExpression':
79
62
  const func = generateFunc(scope, decl);
80
63
 
81
64
  if (decl.type.endsWith('Expression')) {
82
- return number(func.index);
65
+ return number(func.index - importedFuncs.length);
83
66
  }
84
67
 
85
68
  return [];
@@ -171,11 +154,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
171
154
  newFunc.export = true;
172
155
  }
173
156
 
174
- // if (funcsBefore === funcs.length) throw new Error('no new func added in export');
175
-
176
- // const newFunc = funcs[funcs.length - 1];
177
- // newFunc.export = true;
178
-
179
157
  return [];
180
158
 
181
159
  case 'TaggedTemplateExpression': {
@@ -210,7 +188,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
210
188
  if (!Array.isArray(inst)) inst = [ inst ];
211
189
  const immediates = asm.slice(1).map(x => {
212
190
  const int = parseInt(x);
213
- if (Number.isNaN(int)) return scope.locals[x]?.idx;
191
+ if (Number.isNaN(int)) return scope.locals[x]?.idx ?? globals[x].idx;
214
192
  return int;
215
193
  });
216
194
 
@@ -336,10 +314,10 @@ const generateIdent = (scope, decl) => {
336
314
 
337
315
  if (local?.idx === undefined) {
338
316
  // no local var with name
339
- if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name]);
340
- if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name]);
341
-
342
317
  if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
318
+
319
+ if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name] - importedFuncs.length);
320
+ if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name] - importedFuncs.length);
343
321
  }
344
322
 
345
323
  if (local?.idx === undefined && rawName.startsWith('__')) {
@@ -373,9 +351,7 @@ const generateReturn = (scope, decl) => {
373
351
 
374
352
  return [
375
353
  ...generate(scope, decl.argument),
376
- ...(scope.returnType != null ? [] : [
377
- ...getNodeType(scope, decl.argument)
378
- ]),
354
+ ...(scope.returnType != null ? [] : getNodeType(scope, decl.argument)),
379
355
  [ Opcodes.return ]
380
356
  ];
381
357
  };
@@ -858,31 +834,6 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
858
834
 
859
835
  // if strict (in)equal check types match
860
836
  if (strictOp) {
861
- // startOut.push(
862
- // ...leftType,
863
- // ...rightType,
864
- // [ Opcodes.i32_eq ]
865
- // );
866
-
867
- // endOut.push(
868
- // [ Opcodes.i32_and ]
869
- // );
870
-
871
- // startOut.push(
872
- // [ Opcodes.block, Valtype.i32 ],
873
- // ...leftType,
874
- // ...rightType,
875
- // [ Opcodes.i32_ne ],
876
- // [ Opcodes.if, Blocktype.void ],
877
- // ...number(op === '===' ? 0 : 1, Valtype.i32),
878
- // [ Opcodes.br, 1 ],
879
- // [ Opcodes.end ]
880
- // );
881
-
882
- // endOut.push(
883
- // [ Opcodes.end ]
884
- // );
885
-
886
837
  endOut.push(
887
838
  ...leftType,
888
839
  ...rightType,
@@ -1089,7 +1040,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
1089
1040
 
1090
1041
  const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals = [], returns = [], localInd = 0 }) => {
1091
1042
  return func({ name, params, locals, returns, localInd }, {
1092
- TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage,
1043
+ TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
1093
1044
  builtin: name => {
1094
1045
  let idx = funcIndex[name] ?? importedFuncs[name];
1095
1046
  if (idx === undefined && builtinFuncs[name]) {
@@ -1248,7 +1199,7 @@ const setLastType = scope => {
1248
1199
  };
1249
1200
 
1250
1201
  const getNodeType = (scope, node) => {
1251
- const inner = () => {
1202
+ const ret = (() => {
1252
1203
  if (node.type === 'Literal') {
1253
1204
  if (node.regex) return TYPES.regexp;
1254
1205
 
@@ -1291,7 +1242,6 @@ const getNodeType = (scope, node) => {
1291
1242
  const func = funcs.find(x => x.name === name);
1292
1243
 
1293
1244
  if (func) {
1294
- // console.log(scope, func, func.returnType);
1295
1245
  if (func.returnType) return func.returnType;
1296
1246
  }
1297
1247
 
@@ -1435,10 +1385,8 @@ const getNodeType = (scope, node) => {
1435
1385
  // presume
1436
1386
  // todo: warn here?
1437
1387
  return TYPES.number;
1438
- };
1388
+ })();
1439
1389
 
1440
- const ret = inner();
1441
- // console.trace(node, ret);
1442
1390
  if (typeof ret === 'number') return number(ret, Valtype.i32);
1443
1391
  return ret;
1444
1392
  };
@@ -1501,6 +1449,10 @@ const countLeftover = wasm => {
1501
1449
  } else count--;
1502
1450
  if (func) count += func.returns.length;
1503
1451
  }
1452
+ } else if (inst[0] === Opcodes.call_indirect) {
1453
+ count--; // funcidx
1454
+ count -= inst[1] * 2; // params * 2 (typed)
1455
+ count += 2; // fixed return (value, type)
1504
1456
  } else count--;
1505
1457
 
1506
1458
  // console.log(count, decompile([ inst ]).slice(0, -1));
@@ -1577,15 +1529,6 @@ const RTArrayUtil = {
1577
1529
  };
1578
1530
 
1579
1531
  const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1580
- /* const callee = decl.callee;
1581
- const args = decl.arguments;
1582
-
1583
- return [
1584
- ...generate(args),
1585
- ...generate(callee),
1586
- Opcodes.call_indirect,
1587
- ]; */
1588
-
1589
1532
  let name = mapName(decl.callee.name);
1590
1533
  if (isFuncType(decl.callee.type)) { // iife
1591
1534
  const func = generateFunc(scope, decl.callee);
@@ -1759,8 +1702,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1759
1702
  continue;
1760
1703
  }
1761
1704
 
1762
- // const protoLocal = protoFunc.local ? localTmp(scope, `__${TYPE_NAMES[x]}_${protoName}_tmp`, protoFunc.local) : -1;
1763
- // const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${TYPE_NAMES[x]}_${protoName}_tmp2`, protoFunc.local2) : -1;
1764
1705
  const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
1765
1706
  const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
1766
1707
 
@@ -1837,22 +1778,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1837
1778
 
1838
1779
  includeBuiltin(scope, name);
1839
1780
  idx = funcIndex[name];
1840
-
1841
- // infer arguments types from builtins params
1842
- // const func = funcs.find(x => x.name === name);
1843
- // for (let i = 0; i < decl.arguments.length; i++) {
1844
- // const arg = decl.arguments[i];
1845
- // if (!arg.name) continue;
1846
-
1847
- // const local = scope.locals[arg.name];
1848
- // if (!local) continue;
1849
-
1850
- // local.type = func.params[i];
1851
- // if (local.type === Valtype.v128) {
1852
- // // specify vec subtype inferred from last vec type in function name
1853
- // local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1854
- // }
1855
- // }
1856
1781
  }
1857
1782
 
1858
1783
  if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
@@ -1909,7 +1834,45 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1909
1834
  }
1910
1835
 
1911
1836
  if (idx === undefined) {
1912
- if (scope.locals[name] !== undefined || globals[name] !== undefined || builtinVars[name] !== undefined) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
1837
+ if (scope.locals[name] !== undefined || globals[name] !== undefined || builtinVars[name] !== undefined) {
1838
+ const [ local, global ] = lookupName(scope, name);
1839
+ if (!Prefs.indirectCalls || local == null) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
1840
+
1841
+ // todo: only works when:
1842
+ // 1. arg count matches arg count of function
1843
+ // 2. function uses typedParams and typedReturns
1844
+
1845
+ funcs.table = true;
1846
+
1847
+ let args = decl.arguments;
1848
+ let argWasm = [];
1849
+
1850
+ for (let i = 0; i < args.length; i++) {
1851
+ const arg = args[i];
1852
+ argWasm = argWasm.concat(generate(scope, arg));
1853
+
1854
+ if (valtypeBinary !== Valtype.i32 && (
1855
+ (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
1856
+ (importedFuncs[name] && name.startsWith('profile'))
1857
+ )) {
1858
+ argWasm.push(Opcodes.i32_to);
1859
+ }
1860
+
1861
+ argWasm = argWasm.concat(getNodeType(scope, arg));
1862
+ }
1863
+
1864
+ return typeSwitch(scope, getNodeType(scope, decl.callee), {
1865
+ [TYPES.function]: [
1866
+ ...argWasm,
1867
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
1868
+ Opcodes.i32_to_u,
1869
+ [ Opcodes.call_indirect, args.length, 0 ],
1870
+ ...setLastType(scope)
1871
+ ],
1872
+ default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
1873
+ });
1874
+ }
1875
+
1913
1876
  return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
1914
1877
  }
1915
1878
 
@@ -1938,11 +1901,16 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1938
1901
  const arg = args[i];
1939
1902
  out = out.concat(generate(scope, arg));
1940
1903
 
1941
- if (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32 && valtypeBinary !== Valtype.i32) {
1942
- out.push(Opcodes.i32_to);
1904
+ if (i >= paramCount) {
1905
+ // over param count of func, drop arg
1906
+ out.push([ Opcodes.drop ]);
1907
+ continue;
1943
1908
  }
1944
1909
 
1945
- if (importedFuncs[name] && name.startsWith('profile')) {
1910
+ if (valtypeBinary !== Valtype.i32 && (
1911
+ (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
1912
+ (importedFuncs[name] && name.startsWith('profile'))
1913
+ )) {
1946
1914
  out.push(Opcodes.i32_to);
1947
1915
  }
1948
1916
 
@@ -1987,6 +1955,11 @@ const generateNew = (scope, decl, _global, _name) => {
1987
1955
  }, _global, _name);
1988
1956
  }
1989
1957
 
1958
+ if (
1959
+ (builtinFuncs[name] && !builtinFuncs[name].constr) ||
1960
+ (internalConstrs[name] && builtinFuncs[name].notConstr)
1961
+ ) return internalThrow(scope, 'TypeError', `${name} is not a constructor`);
1962
+
1990
1963
  if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet`); // return todo(scope, `new statement is not supported yet (new ${unhackName(name)})`);
1991
1964
 
1992
1965
  return generateCall(scope, decl, _global, _name);
@@ -2178,7 +2151,6 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
2178
2151
  const typeAnnoToPorfType = x => {
2179
2152
  if (!x) return null;
2180
2153
  if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
2181
- if (TYPES['_' + x.toLowerCase()] != null) return TYPES['_' + x.toLowerCase()];
2182
2154
 
2183
2155
  switch (x) {
2184
2156
  case 'i32':
@@ -2219,9 +2191,8 @@ const generateVar = (scope, decl) => {
2219
2191
 
2220
2192
  const topLevel = scope.name === 'main';
2221
2193
 
2222
- // global variable if in top scope (main) and var ..., or if wanted
2223
- const global = topLevel || decl._bare; // decl.kind === 'var';
2224
- const target = global ? globals : scope.locals;
2194
+ // global variable if in top scope (main) or if internally wanted
2195
+ const global = topLevel || decl._bare;
2225
2196
 
2226
2197
  for (const x of decl.declarations) {
2227
2198
  const name = mapName(x.id.name);
@@ -2235,7 +2206,6 @@ const generateVar = (scope, decl) => {
2235
2206
  continue;
2236
2207
  }
2237
2208
 
2238
- // console.log(name);
2239
2209
  if (topLevel && builtinVars[name]) {
2240
2210
  // cannot redeclare
2241
2211
  if (decl.kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
@@ -2255,6 +2225,22 @@ const generateVar = (scope, decl) => {
2255
2225
  }
2256
2226
 
2257
2227
  if (x.init) {
2228
+ // if (isFuncType(x.init.type)) {
2229
+ // // let a = function () { ... }
2230
+ // x.init.id = { name };
2231
+
2232
+ // const func = generateFunc(scope, x.init);
2233
+
2234
+ // out.push(
2235
+ // ...number(func.index - importedFuncs.length),
2236
+ // [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
2237
+
2238
+ // ...setType(scope, name, TYPES.function)
2239
+ // );
2240
+
2241
+ // continue;
2242
+ // }
2243
+
2258
2244
  const generated = generate(scope, x.init, global, name);
2259
2245
  if (scope.arrays?.get(name) != null) {
2260
2246
  // hack to set local as pointer before
@@ -2266,6 +2252,7 @@ const generateVar = (scope, decl) => {
2266
2252
  out = out.concat(generated);
2267
2253
  out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2268
2254
  }
2255
+
2269
2256
  out.push(...setType(scope, name, getNodeType(scope, x.init)));
2270
2257
  }
2271
2258
 
@@ -2279,6 +2266,7 @@ const generateVar = (scope, decl) => {
2279
2266
  // todo: optimize this func for valueUnused
2280
2267
  const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2281
2268
  const { type, name } = decl.left;
2269
+ const [ local, isGlobal ] = lookupName(scope, name);
2282
2270
 
2283
2271
  if (type === 'ObjectPattern') {
2284
2272
  // hack: ignore object parts of `var a = {} = 2`
@@ -2288,8 +2276,18 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2288
2276
  if (isFuncType(decl.right.type)) {
2289
2277
  // hack for a = function () { ... }
2290
2278
  decl.right.id = { name };
2291
- generateFunc(scope, decl.right);
2292
- return [];
2279
+
2280
+ const func = generateFunc(scope, decl.right);
2281
+
2282
+ return [
2283
+ ...number(func.index - importedFuncs.length),
2284
+ ...(local != null ? [
2285
+ [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2286
+ [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
2287
+
2288
+ ...setType(scope, name, TYPES.function)
2289
+ ] : [])
2290
+ ];
2293
2291
  }
2294
2292
 
2295
2293
  const op = decl.operator.slice(0, -1) || '=';
@@ -2388,8 +2386,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2388
2386
 
2389
2387
  if (!name) return todo(scope, 'destructuring is not supported yet', true);
2390
2388
 
2391
- const [ local, isGlobal ] = lookupName(scope, name);
2392
-
2393
2389
  if (local === undefined) {
2394
2390
  // todo: this should be a sloppy mode only thing
2395
2391
 
@@ -2538,6 +2534,7 @@ const generateUnary = (scope, decl) => {
2538
2534
  [TYPES.string]: makeString(scope, 'string', false, '#typeof_result'),
2539
2535
  [TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
2540
2536
  [TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
2537
+ [TYPES.symbol]: makeString(scope, 'symbol', false, '#typeof_result'),
2541
2538
 
2542
2539
  [TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2543
2540
 
@@ -3036,13 +3033,6 @@ const generateEmpty = (scope, decl) => {
3036
3033
  return [];
3037
3034
  };
3038
3035
 
3039
- const generateAssignPat = (scope, decl) => {
3040
- // TODO
3041
- // if identifier declared, use that
3042
- // else, use default (right)
3043
- return todo(scope, 'assignment pattern (optional arg)');
3044
- };
3045
-
3046
3036
  let pages = new Map();
3047
3037
  const allocPage = (scope, reason, type) => {
3048
3038
  if (pages.has(reason)) return pages.get(reason).ind;
@@ -3455,8 +3445,11 @@ const generateFunc = (scope, decl) => {
3455
3445
  };
3456
3446
 
3457
3447
  if (typedInput && decl.returnType) {
3458
- innerScope.returnType = extractTypeAnnotation(decl.returnType).type;
3459
- innerScope.returns = [ valtypeBinary ];
3448
+ const { type } = extractTypeAnnotation(decl.returnType);
3449
+ if (type != null && !Prefs.indirectCalls) {
3450
+ innerScope.returnType = type;
3451
+ innerScope.returns = [ valtypeBinary ];
3452
+ }
3460
3453
  }
3461
3454
 
3462
3455
  for (let i = 0; i < params.length; i++) {
@@ -3498,7 +3491,7 @@ const generateFunc = (scope, decl) => {
3498
3491
  if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
3499
3492
  wasm.push(
3500
3493
  ...number(0),
3501
- ...number(TYPES.undefined, Valtype.i32),
3494
+ ...(innerScope.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
3502
3495
  [ Opcodes.return ]
3503
3496
  );
3504
3497
  }
@@ -3671,8 +3664,10 @@ const internalConstrs = {
3671
3664
  }),
3672
3665
 
3673
3666
  // print space
3674
- ...number(32),
3675
- [ Opcodes.call, importedFuncs.printChar ]
3667
+ ...(i !== decl.arguments.length - 1 ? [
3668
+ ...number(32),
3669
+ [ Opcodes.call, importedFuncs.printChar ]
3670
+ ] : [])
3676
3671
  );
3677
3672
  }
3678
3673
 
@@ -3682,6 +3677,8 @@ const internalConstrs = {
3682
3677
  [ Opcodes.call, importedFuncs.printChar ]
3683
3678
  );
3684
3679
 
3680
+ out.push(...number(UNDEFINED));
3681
+
3685
3682
  return out;
3686
3683
  },
3687
3684
  type: TYPES.undefined,
@@ -1,5 +1,5 @@
1
- import { Blocktype, Opcodes, Valtype } from "./wasmSpec.js";
2
- import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from "./encoding.js";
1
+ import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
2
+ import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
3
3
 
4
4
  const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => { acc[keyMap(obj[x])] = x; return acc; }, {});
5
5
  const invOpcodes = inv(Opcodes);
@@ -119,7 +119,7 @@ export const highlightAsm = asm => asm
119
119
  .replace(/(local|global|memory)\.[^\s]*/g, _ => `\x1B[31m${_}\x1B[0m`)
120
120
  .replace(/(i(8|16|32|64)x[0-9]+|v128)(\.[^\s]*)?/g, _ => `\x1B[34m${_}\x1B[0m`)
121
121
  .replace(/(i32|i64|f32|f64|drop)(\.[^\s]*)?/g, _ => `\x1B[36m${_}\x1B[0m`)
122
- .replace(/(return_call|call|br_if|br|return|rethrow|throw)/g, _ => `\x1B[35m${_}\x1B[0m`)
122
+ .replace(/(return_call|call_indirect|call|br_if|br|return|rethrow|throw)/g, _ => `\x1B[35m${_}\x1B[0m`)
123
123
  .replace(/(block|loop|if|end|else|try|catch_all|catch|delegate)/g, _ => `\x1B[95m${_}\x1B[0m`)
124
124
  .replace(/unreachable/g, _ => `\x1B[91m${_}\x1B[0m`)
125
125
  .replace(/ \-?[0-9\.]+/g, _ => ` \x1B[33m${_.slice(1)}\x1B[0m`)
@@ -1,5 +1,5 @@
1
- import { Opcodes, Valtype } from "./wasmSpec.js";
2
- import { signedLEB128, ieee754_binary64 } from "./encoding.js";
1
+ import { Opcodes, Valtype } from './wasmSpec.js';
2
+ import { signedLEB128, ieee754_binary64 } from './encoding.js';
3
3
 
4
4
  export const number = (n, valtype = valtypeBinary) => {
5
5
  switch (valtype) {
@@ -7,21 +7,7 @@ export const codifyString = str => {
7
7
  return out;
8
8
  };
9
9
 
10
- // export const encodeString = str => [
11
- // str.length,
12
- // ...codifyString(str)
13
- // ];
14
10
  export const encodeString = str => unsignedLEB128(str.length).concat(codifyString(str));
15
-
16
- // export const encodeVector = data => [
17
- // ...unsignedLEB128(data.length),
18
- // ...data.flat()
19
- // ];
20
- // export const encodeVector = data => {
21
- // const out = data.flat();
22
- // out.unshift.apply(out, unsignedLEB128(data.length));
23
- // return out;
24
- // };
25
11
  export const encodeVector = data => unsignedLEB128(data.length).concat(data.flat());
26
12
 
27
13
  export const encodeLocal = (count, type) => [
@@ -1,4 +1,4 @@
1
- import { Opcodes } from "./wasmSpec.js";
1
+ import { Opcodes } from './wasmSpec.js';
2
2
 
3
3
  export const operatorOpcode = {
4
4
  i32: {