porffor 0.2.0-fdf0fc5 → 0.14.0-4e46400a9

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 (40) 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 +26 -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 +0 -2
  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.js +4 -7
  21. package/compiler/codegen.js +78 -121
  22. package/compiler/decompile.js +2 -2
  23. package/compiler/embedding.js +2 -2
  24. package/compiler/encoding.js +0 -14
  25. package/compiler/expression.js +1 -1
  26. package/compiler/generated_builtins.js +303 -204
  27. package/compiler/index.js +0 -2
  28. package/compiler/opt.js +7 -7
  29. package/compiler/parse.js +1 -3
  30. package/compiler/precompile.js +17 -25
  31. package/compiler/prototype.js +5 -5
  32. package/compiler/wasmSpec.js +5 -0
  33. package/compiler/wrap.js +75 -57
  34. package/package.json +1 -1
  35. package/runner/compare.js +0 -1
  36. package/runner/debug.js +1 -6
  37. package/runner/profiler.js +15 -42
  38. package/runner/repl.js +3 -9
  39. package/runner/sizes.js +2 -2
  40. package/runner/version.js +10 -8
@@ -1,5 +1,187 @@
1
- // @porf --funsafe-no-unlikely-proto-checks
1
+ // dark wasm magic for dealing with memory, sorry.
2
+ export const __Porffor_allocate = (): number => {
3
+ Porffor.wasm`i32.const 1
4
+ memory.grow 0
5
+ drop
6
+ memory.size 0
7
+ i32.const 1
8
+ i32.sub
9
+ i32.const 65536
10
+ i32.mul
11
+ i32.from_u
12
+ return`;
13
+ };
2
14
 
3
- export const Set = (iterable: any): Set => {
15
+ export const __Porffor_set_read = (_this: Set, index: number): any => {
16
+ Porffor.wasm`
17
+ local offset i32
18
+ local.get ${index}
19
+ i32.to_u
20
+ i32.const 9
21
+ i32.mul
22
+ local.get ${_this}
23
+ i32.to_u
24
+ i32.add
25
+ local.set offset
4
26
 
27
+ local.get offset
28
+ f64.load 0 4
29
+
30
+ local.get offset
31
+ i32.load8_u 0 12
32
+ return`;
33
+ };
34
+
35
+ export const __Porffor_set_write = (_this: Set, index: number, value: any): boolean => {
36
+ Porffor.wasm`
37
+ local offset i32
38
+ local.get ${index}
39
+ i32.to_u
40
+ i32.const 9
41
+ i32.mul
42
+ local.get ${_this}
43
+ i32.to_u
44
+ i32.add
45
+ local.set offset
46
+
47
+ local.get offset
48
+ local.get ${value}
49
+ f64.store 0 4
50
+
51
+ local.get offset
52
+ local.get ${value+1}
53
+ i32.store8 0 12`;
54
+
55
+ return true;
56
+ };
57
+
58
+
59
+ // todo: this should be a getter somehow not a method
60
+ export const __Set_prototype_size = (_this: Set) => {
61
+ return Porffor.wasm.i32.load(_this, 0, 0);
62
+ };
63
+
64
+ export const __Set_prototype_values = (_this: Set) => {
65
+ // todo: this should return an iterator not array
66
+ const size: number = __Set_prototype_size(_this);
67
+
68
+ const out: any[] = __Porffor_allocate();
69
+ for (let i: number = 0; i < size; i++) {
70
+ const val: any = __Porffor_set_read(_this, i);
71
+ out.push(val);
72
+ }
73
+
74
+ return out;
75
+ };
76
+
77
+ export const __Set_prototype_keys = (_this: Set) => {
78
+ return __Set_prototype_values(_this);
79
+ };
80
+
81
+ export const __Set_prototype_has = (_this: Set, value: any) => {
82
+ const size: number = __Set_prototype_size(_this);
83
+
84
+ for (let i: number = 0; i < size; i++) {
85
+ if (__Porffor_set_read(_this, i) === value) return true;
86
+ }
87
+
88
+ return false;
89
+ };
90
+
91
+ export const __Set_prototype_add = (_this: Set, value: any) => {
92
+ const size: number = __Set_prototype_size(_this);
93
+
94
+ // check if already in set
95
+ for (let i: number = 0; i < size; i++) {
96
+ if (__Porffor_set_read(_this, i) === value) return _this;
97
+ }
98
+
99
+ // not, add it
100
+ // increment size by 1
101
+ Porffor.wasm.i32.store(_this, size + 1, 0, 0);
102
+
103
+ // write new value at end
104
+ __Porffor_set_write(_this, size, value);
105
+
106
+ return _this;
107
+ };
108
+
109
+ export const __Set_prototype_delete = (_this: Set, value: any) => {
110
+ const size: number = __Set_prototype_size(_this);
111
+
112
+ // check if already in set
113
+ for (let i: number = 0; i < size; i++) {
114
+ if (__Porffor_set_read(_this, i) === value) {
115
+ // found, delete
116
+ // decrement size by 1
117
+ Porffor.wasm.i32.store(_this, size - 1, 0, 0);
118
+
119
+ // offset all elements after by -1 ind
120
+ Porffor.wasm`
121
+ local offset i32
122
+ local.get ${i}
123
+ i32.to_u
124
+ i32.const 9
125
+ i32.mul
126
+ local.get ${_this}
127
+ i32.to_u
128
+ i32.add
129
+ i32.const 4
130
+ i32.add
131
+ local.set offset
132
+
133
+ ;; dst = offset (this element)
134
+ local.get offset
135
+
136
+ ;; src = offset + 9 (this element + 1 element)
137
+ local.get offset
138
+ i32.const 9
139
+ i32.add
140
+
141
+ ;; size = (size - i - 1) * 9
142
+ local.get ${size}
143
+ local.get ${i}
144
+ f64.sub
145
+ i32.to_u
146
+ i32.const 1
147
+ i32.sub
148
+ i32.const 9
149
+ i32.mul
150
+
151
+ memory.copy 0 0`;
152
+
153
+ return true;
154
+ }
155
+ }
156
+
157
+ // not, return false
158
+ return false;
159
+ };
160
+
161
+ export const __Set_prototype_clear = (_this: Set) => {
162
+ // just set size to 0
163
+ // do not need to delete any as will not be accessed anymore,
164
+ // and will be overwritten with new add
165
+ Porffor.wasm.i32.store(_this, 0, 0, 0);
166
+ };
167
+
168
+ export const Set = () => {
169
+ throw new TypeError("Constructor Set requires 'new'");
170
+ };
171
+
172
+ export const Set$constructor = (iterable: any): Set => {
173
+ const out: Set = __Porffor_allocate();
174
+
175
+ const type: number = Porffor.rawType(iterable);
176
+ if (Porffor.fastOr(
177
+ type == Porffor.TYPES.array,
178
+ type == Porffor.TYPES.string, type == Porffor.TYPES.bytestring,
179
+ type == Porffor.TYPES.set
180
+ )) {
181
+ for (const x of iterable) {
182
+ __Set_prototype_add(out, x);
183
+ }
184
+ }
185
+
186
+ return out;
5
187
  };
@@ -1,4 +1,4 @@
1
- // @porf --funsafe-no-unlikely-proto-checks --valtype=i32
1
+ // @porf --valtype=i32
2
2
 
3
3
  export const __String_fromCharCode = (code: i32) => {
4
4
  // todo: support >1 arg
@@ -1,8 +1,8 @@
1
- import { Blocktype, Opcodes, Valtype, ValtypeSize } from "./wasmSpec.js";
2
- import { number, i32x4 } from "./embedding.js";
3
- import Prefs from './prefs.js';
4
1
  import * as GeneratedBuiltins from './generated_builtins.js';
2
+ import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
3
+ import { number } from './embedding.js';
5
4
  import { TYPES } from './types.js';
5
+ import Prefs from './prefs.js';
6
6
 
7
7
  export const importedFuncs = [
8
8
  {
@@ -48,8 +48,6 @@ for (let i = 0; i < importedFuncs.length; i++) {
48
48
  importedFuncs[f.name] = i;
49
49
  }
50
50
 
51
- const char = c => number(c.charCodeAt(0));
52
-
53
51
  const printStaticStr = str => {
54
52
  const out = [];
55
53
 
@@ -140,7 +138,7 @@ export const BuiltinVars = function() {
140
138
  this.Math = number(1);
141
139
 
142
140
  // wintercg(tm)
143
- this.__navigator_userAgent = (scope, { makeString }) => makeString(scope, `Porffor/0.2.0`, false, '__navigator_userAgent');
141
+ this.__navigator_userAgent = (scope, { makeString }) => makeString(scope, `Porffor/0.14.0`, false, '__navigator_userAgent');
144
142
  this.__navigator_userAgent.type = Prefs.bytestring ? TYPES.bytestring : TYPES.string;
145
143
 
146
144
  for (const x in TYPES) {
@@ -569,7 +567,6 @@ export const BuiltinFuncs = function() {
569
567
 
570
568
  // this is an implementation of xorshift128+ (in wasm bytecode)
571
569
  // fun fact: v8, SM, JSC also use this (you will need this fun fact to maintain your sanity reading this code)
572
- // const prngSeed0 = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER), prngSeed1 = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
573
570
  const prngSeed0 = (Math.random() * (2 ** 30)) | 0, prngSeed1 = (Math.random() * (2 ** 30)) | 0;
574
571
 
575
572
  const prng = ({
@@ -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('__')) {
@@ -858,31 +836,6 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
858
836
 
859
837
  // if strict (in)equal check types match
860
838
  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
839
  endOut.push(
887
840
  ...leftType,
888
841
  ...rightType,
@@ -1089,7 +1042,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
1089
1042
 
1090
1043
  const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals = [], returns = [], localInd = 0 }) => {
1091
1044
  return func({ name, params, locals, returns, localInd }, {
1092
- TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage,
1045
+ TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
1093
1046
  builtin: name => {
1094
1047
  let idx = funcIndex[name] ?? importedFuncs[name];
1095
1048
  if (idx === undefined && builtinFuncs[name]) {
@@ -1248,7 +1201,7 @@ const setLastType = scope => {
1248
1201
  };
1249
1202
 
1250
1203
  const getNodeType = (scope, node) => {
1251
- const inner = () => {
1204
+ const ret = (() => {
1252
1205
  if (node.type === 'Literal') {
1253
1206
  if (node.regex) return TYPES.regexp;
1254
1207
 
@@ -1291,7 +1244,6 @@ const getNodeType = (scope, node) => {
1291
1244
  const func = funcs.find(x => x.name === name);
1292
1245
 
1293
1246
  if (func) {
1294
- // console.log(scope, func, func.returnType);
1295
1247
  if (func.returnType) return func.returnType;
1296
1248
  }
1297
1249
 
@@ -1435,10 +1387,8 @@ const getNodeType = (scope, node) => {
1435
1387
  // presume
1436
1388
  // todo: warn here?
1437
1389
  return TYPES.number;
1438
- };
1390
+ })();
1439
1391
 
1440
- const ret = inner();
1441
- // console.trace(node, ret);
1442
1392
  if (typeof ret === 'number') return number(ret, Valtype.i32);
1443
1393
  return ret;
1444
1394
  };
@@ -1577,15 +1527,6 @@ const RTArrayUtil = {
1577
1527
  };
1578
1528
 
1579
1529
  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
1530
  let name = mapName(decl.callee.name);
1590
1531
  if (isFuncType(decl.callee.type)) { // iife
1591
1532
  const func = generateFunc(scope, decl.callee);
@@ -1759,8 +1700,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1759
1700
  continue;
1760
1701
  }
1761
1702
 
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
1703
  const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
1765
1704
  const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
1766
1705
 
@@ -1837,22 +1776,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1837
1776
 
1838
1777
  includeBuiltin(scope, name);
1839
1778
  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
1779
  }
1857
1780
 
1858
1781
  if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
@@ -1909,7 +1832,23 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1909
1832
  }
1910
1833
 
1911
1834
  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);
1835
+ if (scope.locals[name] !== undefined || globals[name] !== undefined || builtinVars[name] !== undefined) {
1836
+ if (!Prefs.indirectCalls) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
1837
+
1838
+ const [ local, global ] = lookupName(scope, name);
1839
+ funcs.table = true;
1840
+
1841
+ // todo: only works when:
1842
+ // 1. arg count matches arg count of function
1843
+ // 2. function uses typedParams and typedReturns
1844
+ return typeSwitch(scope, getNodeType(decl.callee), {
1845
+ [TYPES.function]: [
1846
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
1847
+ [ Opcodes.call_indirect ]
1848
+ ],
1849
+ default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
1850
+ });
1851
+ }
1913
1852
  return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
1914
1853
  }
1915
1854
 
@@ -1938,11 +1877,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1938
1877
  const arg = args[i];
1939
1878
  out = out.concat(generate(scope, arg));
1940
1879
 
1941
- if (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32 && valtypeBinary !== Valtype.i32) {
1942
- out.push(Opcodes.i32_to);
1943
- }
1944
-
1945
- if (importedFuncs[name] && name.startsWith('profile')) {
1880
+ if (valtypeBinary !== Valtype.i32 && (
1881
+ (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
1882
+ (importedFuncs[name] && name.startsWith('profile'))
1883
+ )) {
1946
1884
  out.push(Opcodes.i32_to);
1947
1885
  }
1948
1886
 
@@ -2178,7 +2116,6 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
2178
2116
  const typeAnnoToPorfType = x => {
2179
2117
  if (!x) return null;
2180
2118
  if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
2181
- if (TYPES['_' + x.toLowerCase()] != null) return TYPES['_' + x.toLowerCase()];
2182
2119
 
2183
2120
  switch (x) {
2184
2121
  case 'i32':
@@ -2219,9 +2156,8 @@ const generateVar = (scope, decl) => {
2219
2156
 
2220
2157
  const topLevel = scope.name === 'main';
2221
2158
 
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;
2159
+ // global variable if in top scope (main) or if internally wanted
2160
+ const global = topLevel || decl._bare;
2225
2161
 
2226
2162
  for (const x of decl.declarations) {
2227
2163
  const name = mapName(x.id.name);
@@ -2235,7 +2171,6 @@ const generateVar = (scope, decl) => {
2235
2171
  continue;
2236
2172
  }
2237
2173
 
2238
- // console.log(name);
2239
2174
  if (topLevel && builtinVars[name]) {
2240
2175
  // cannot redeclare
2241
2176
  if (decl.kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
@@ -2255,6 +2190,22 @@ const generateVar = (scope, decl) => {
2255
2190
  }
2256
2191
 
2257
2192
  if (x.init) {
2193
+ // if (isFuncType(x.init.type)) {
2194
+ // // let a = function () { ... }
2195
+ // x.init.id = { name };
2196
+
2197
+ // const func = generateFunc(scope, x.init);
2198
+
2199
+ // out.push(
2200
+ // ...number(func.index - importedFuncs.length),
2201
+ // [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
2202
+
2203
+ // ...setType(scope, name, TYPES.function)
2204
+ // );
2205
+
2206
+ // continue;
2207
+ // }
2208
+
2258
2209
  const generated = generate(scope, x.init, global, name);
2259
2210
  if (scope.arrays?.get(name) != null) {
2260
2211
  // hack to set local as pointer before
@@ -2266,6 +2217,7 @@ const generateVar = (scope, decl) => {
2266
2217
  out = out.concat(generated);
2267
2218
  out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2268
2219
  }
2220
+
2269
2221
  out.push(...setType(scope, name, getNodeType(scope, x.init)));
2270
2222
  }
2271
2223
 
@@ -2279,6 +2231,7 @@ const generateVar = (scope, decl) => {
2279
2231
  // todo: optimize this func for valueUnused
2280
2232
  const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2281
2233
  const { type, name } = decl.left;
2234
+ const [ local, isGlobal ] = lookupName(scope, name);
2282
2235
 
2283
2236
  if (type === 'ObjectPattern') {
2284
2237
  // hack: ignore object parts of `var a = {} = 2`
@@ -2288,8 +2241,18 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2288
2241
  if (isFuncType(decl.right.type)) {
2289
2242
  // hack for a = function () { ... }
2290
2243
  decl.right.id = { name };
2291
- generateFunc(scope, decl.right);
2292
- return [];
2244
+
2245
+ const func = generateFunc(scope, decl.right);
2246
+
2247
+ return [
2248
+ ...number(func.index - importedFuncs.length),
2249
+ ...(local != null ? [
2250
+ [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2251
+ [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
2252
+
2253
+ ...setType(scope, name, TYPES.function)
2254
+ ] : [])
2255
+ ];
2293
2256
  }
2294
2257
 
2295
2258
  const op = decl.operator.slice(0, -1) || '=';
@@ -2388,8 +2351,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2388
2351
 
2389
2352
  if (!name) return todo(scope, 'destructuring is not supported yet', true);
2390
2353
 
2391
- const [ local, isGlobal ] = lookupName(scope, name);
2392
-
2393
2354
  if (local === undefined) {
2394
2355
  // todo: this should be a sloppy mode only thing
2395
2356
 
@@ -3036,13 +2997,6 @@ const generateEmpty = (scope, decl) => {
3036
2997
  return [];
3037
2998
  };
3038
2999
 
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
3000
  let pages = new Map();
3047
3001
  const allocPage = (scope, reason, type) => {
3048
3002
  if (pages.has(reason)) return pages.get(reason).ind;
@@ -3455,8 +3409,11 @@ const generateFunc = (scope, decl) => {
3455
3409
  };
3456
3410
 
3457
3411
  if (typedInput && decl.returnType) {
3458
- innerScope.returnType = extractTypeAnnotation(decl.returnType).type;
3459
- innerScope.returns = [ valtypeBinary ];
3412
+ const { type } = extractTypeAnnotation(decl.returnType);
3413
+ if (type != null && !Prefs.indirectCalls) {
3414
+ innerScope.returnType = type;
3415
+ innerScope.returns = [ valtypeBinary ];
3416
+ }
3460
3417
  }
3461
3418
 
3462
3419
  for (let i = 0; i < params.length; i++) {
@@ -3498,7 +3455,7 @@ const generateFunc = (scope, decl) => {
3498
3455
  if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
3499
3456
  wasm.push(
3500
3457
  ...number(0),
3501
- ...number(TYPES.undefined, Valtype.i32),
3458
+ ...(innerScope.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
3502
3459
  [ Opcodes.return ]
3503
3460
  );
3504
3461
  }
@@ -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);
@@ -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: {