porffor 0.14.0-b5a80d8e3 → 0.14.0-b880d42f1
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/CONTRIBUTING.md +4 -2
- package/compiler/2c.js +65 -2
- package/compiler/builtins/annexb_string.ts +1 -0
- package/compiler/builtins/array.ts +8 -6
- package/compiler/builtins/base64.ts +1 -0
- package/compiler/builtins/boolean.ts +2 -0
- package/compiler/builtins/crypto.ts +1 -0
- package/compiler/builtins/date.ts +2 -0
- package/compiler/builtins/escape.ts +1 -2
- package/compiler/builtins/function.ts +2 -0
- package/compiler/builtins/int.ts +2 -0
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +2 -0
- package/compiler/builtins/object.ts +2 -0
- package/compiler/builtins/set.ts +2 -0
- package/compiler/builtins/string.ts +1 -0
- package/compiler/builtins/symbol.ts +2 -0
- package/compiler/builtins.js +26 -4
- package/compiler/codegen.js +120 -140
- package/compiler/generated_builtins.js +217 -10
- package/compiler/index.js +1 -1
- package/compiler/parse.js +1 -1
- package/compiler/precompile.js +2 -2
- package/package.json +1 -1
- package/runner/index.js +4 -3
package/compiler/builtins.js
CHANGED
@@ -40,6 +40,18 @@ export const importedFuncs = [
|
|
40
40
|
import: 'z',
|
41
41
|
params: 1,
|
42
42
|
returns: 0
|
43
|
+
},
|
44
|
+
{
|
45
|
+
name: '__Porffor_readArgv',
|
46
|
+
import: 'w',
|
47
|
+
params: 2,
|
48
|
+
returns: 0
|
49
|
+
},
|
50
|
+
{
|
51
|
+
name: '__Porffor_readFile',
|
52
|
+
import: 'q',
|
53
|
+
params: 2,
|
54
|
+
returns: 0
|
43
55
|
}
|
44
56
|
];
|
45
57
|
|
@@ -221,8 +233,7 @@ export const BuiltinFuncs = function() {
|
|
221
233
|
typedParams: true,
|
222
234
|
locals: [ Valtype.i32, Valtype.i32 ],
|
223
235
|
returns: [],
|
224
|
-
|
225
|
-
wasm: (scope, { typeSwitch }) => [
|
236
|
+
wasm: (scope, { typeSwitch, builtin }) => [
|
226
237
|
...typeSwitch(scope, [ [ Opcodes.local_get, 1 ] ], {
|
227
238
|
[TYPES.number]: [
|
228
239
|
[ Opcodes.local_get, 0 ],
|
@@ -327,14 +338,14 @@ export const BuiltinFuncs = function() {
|
|
327
338
|
|
328
339
|
[ Opcodes.loop, Blocktype.void ],
|
329
340
|
|
330
|
-
// print current
|
341
|
+
// print current array element
|
331
342
|
[ Opcodes.local_get, 2 ],
|
332
343
|
[ Opcodes.load, 0, ValtypeSize.i32 ],
|
333
344
|
|
334
345
|
[ Opcodes.local_get, 2 ],
|
335
346
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
336
347
|
|
337
|
-
[ Opcodes.call,
|
348
|
+
[ Opcodes.call, builtin('__Porffor_print') ],
|
338
349
|
|
339
350
|
// increment pointer by sizeof valtype
|
340
351
|
[ Opcodes.local_get, 2 ],
|
@@ -1084,5 +1095,16 @@ export const BuiltinFuncs = function() {
|
|
1084
1095
|
]
|
1085
1096
|
};
|
1086
1097
|
|
1098
|
+
|
1099
|
+
this.__fs_readFileSync = {
|
1100
|
+
params: [ valtypeBinary, valtypeBinary ],
|
1101
|
+
locals: [],
|
1102
|
+
returns: [ valtypeBinary ],
|
1103
|
+
returnType: TYPES.bytestring,
|
1104
|
+
wasm: [
|
1105
|
+
[ Opcodes.call, importedFuncs.__Porffor_readFile ],
|
1106
|
+
]
|
1107
|
+
};
|
1108
|
+
|
1087
1109
|
GeneratedBuiltins.BuiltinFuncs.call(this);
|
1088
1110
|
};
|
package/compiler/codegen.js
CHANGED
@@ -40,11 +40,11 @@ const todo = (scope, msg, expectsValue = undefined) => {
|
|
40
40
|
}
|
41
41
|
};
|
42
42
|
|
43
|
-
const isFuncType = type =>
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
const isFuncType = type =>
|
44
|
+
type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
|
45
|
+
const hasFuncWithName = name =>
|
46
|
+
funcIndex[name] != null || builtinFuncs[name] != null || importedFuncs[name] != null || internalConstrs[name] != null;
|
47
|
+
|
48
48
|
const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
|
49
49
|
switch (decl.type) {
|
50
50
|
case 'BinaryExpression':
|
@@ -147,14 +147,16 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
147
147
|
return generateMember(scope, decl, global, name);
|
148
148
|
|
149
149
|
case 'ExportNamedDeclaration':
|
150
|
-
|
151
|
-
const funcsBefore = funcs.length;
|
150
|
+
const funcsBefore = funcs.map(x => x.name);
|
152
151
|
generate(scope, decl.declaration);
|
153
152
|
|
154
|
-
|
155
|
-
|
156
|
-
const
|
157
|
-
|
153
|
+
// set new funcs as exported
|
154
|
+
if (funcsBefore.length !== funcs.length) {
|
155
|
+
const newFuncs = funcs.filter(x => !funcsBefore.includes(x.name)).filter(x => !x.internal);
|
156
|
+
|
157
|
+
for (const x of newFuncs) {
|
158
|
+
x.export = true;
|
159
|
+
}
|
158
160
|
}
|
159
161
|
|
160
162
|
return [];
|
@@ -361,7 +363,7 @@ const localTmp = (scope, name, type = valtypeBinary) => {
|
|
361
363
|
};
|
362
364
|
|
363
365
|
const isIntOp = op => op && ((op[0] >= 0x45 && op[0] <= 0x4f) || (op[0] >= 0x67 && op[0] <= 0x78) || op[0] === 0x41);
|
364
|
-
const
|
366
|
+
const isIntToFloatOp = op => op && (op[0] >= 0xb7 && op[0] <= 0xba);
|
365
367
|
|
366
368
|
const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
367
369
|
const checks = {
|
@@ -378,10 +380,10 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
|
378
380
|
|
379
381
|
// if we can, use int tmp and convert at the end to help prevent unneeded conversions
|
380
382
|
// (like if we are in an if condition - very common)
|
381
|
-
const
|
382
|
-
const
|
383
|
+
const leftWasInt = isIntToFloatOp(left[left.length - 1]);
|
384
|
+
const rightWasInt = isIntToFloatOp(right[right.length - 1]);
|
383
385
|
|
384
|
-
const canInt =
|
386
|
+
const canInt = leftWasInt && rightWasInt;
|
385
387
|
|
386
388
|
if (canInt) {
|
387
389
|
// remove int -> float conversions from left and right
|
@@ -646,9 +648,9 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
646
648
|
[ Opcodes.i32_add ],
|
647
649
|
[ Opcodes.local_tee, index ],
|
648
650
|
|
649
|
-
// if index
|
651
|
+
// if index < index end (length * sizeof valtype), loop
|
650
652
|
[ Opcodes.local_get, indexEnd ],
|
651
|
-
[ Opcodes.
|
653
|
+
[ Opcodes.i32_lt_s ],
|
652
654
|
[ Opcodes.br_if, 0 ],
|
653
655
|
[ Opcodes.end ],
|
654
656
|
|
@@ -666,8 +668,8 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
666
668
|
];
|
667
669
|
};
|
668
670
|
|
669
|
-
const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
670
|
-
if (
|
671
|
+
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
672
|
+
if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
671
673
|
...wasm,
|
672
674
|
...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
673
675
|
];
|
@@ -676,47 +678,38 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
676
678
|
const useTmp = knownType(scope, type) == null;
|
677
679
|
const tmp = useTmp && localTmp(scope, `#logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
|
678
680
|
|
679
|
-
const def =
|
680
|
-
|
681
|
-
|
681
|
+
const def = (truthyMode => {
|
682
|
+
if (truthyMode === 'full') return [
|
683
|
+
// if value != 0 or NaN
|
684
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
685
|
+
...(intIn ? [ ] : [ Opcodes.i32_to ]),
|
682
686
|
|
683
|
-
|
684
|
-
|
687
|
+
[ Opcodes.i32_eqz ],
|
688
|
+
[ Opcodes.i32_eqz ],
|
685
689
|
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
...(!intOut || (intIn && intOut) ? [] : [ Opcodes.i32_to_u ]),
|
704
|
-
|
705
|
-
/* Opcodes.eqz,
|
706
|
-
[ Opcodes.i32_eqz ],
|
707
|
-
Opcodes.i32_from */
|
708
|
-
];
|
690
|
+
...(intOut ? [] : [ Opcodes.i32_from ]),
|
691
|
+
];
|
692
|
+
|
693
|
+
if (truthyMode === 'no_negative') return [
|
694
|
+
// if value != 0 or NaN, non-binary output. negative numbers not truthy :/
|
695
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
696
|
+
...(intIn ? [] : [ Opcodes.i32_to ]),
|
697
|
+
...(intOut ? [] : [ Opcodes.i32_from ])
|
698
|
+
];
|
699
|
+
|
700
|
+
if (truthyMode === 'no_nan_negative') return [
|
701
|
+
// simpler and faster but makes NaN truthy and negative numbers not truthy,
|
702
|
+
// plus non-binary output
|
703
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
704
|
+
...(!intOut || (intIn && intOut) ? [] : [ Opcodes.i32_to_u ])
|
705
|
+
];
|
706
|
+
})(forceTruthyMode ?? Prefs.truthy ?? 'full');
|
709
707
|
|
710
708
|
return [
|
711
709
|
...wasm,
|
712
710
|
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
713
711
|
|
714
712
|
...typeSwitch(scope, type, {
|
715
|
-
// [TYPES.number]: def,
|
716
|
-
[TYPES.array]: [
|
717
|
-
// arrays are always truthy
|
718
|
-
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
719
|
-
],
|
720
713
|
[TYPES.string]: [
|
721
714
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
722
715
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
@@ -752,10 +745,6 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
752
745
|
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
753
746
|
|
754
747
|
...typeSwitch(scope, type, {
|
755
|
-
[TYPES.array]: [
|
756
|
-
// arrays are always truthy
|
757
|
-
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
758
|
-
],
|
759
748
|
[TYPES.string]: [
|
760
749
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
761
750
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
@@ -999,7 +988,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
999
988
|
// if both are true
|
1000
989
|
[ Opcodes.i32_and ],
|
1001
990
|
[ Opcodes.if, Blocktype.void ],
|
1002
|
-
...compareStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ]),
|
991
|
+
...compareStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ], false),
|
1003
992
|
...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : []),
|
1004
993
|
[ Opcodes.br, 1 ],
|
1005
994
|
[ Opcodes.end ],
|
@@ -1048,14 +1037,14 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
1048
1037
|
return out;
|
1049
1038
|
};
|
1050
1039
|
|
1051
|
-
const asmFuncToAsm = (func,
|
1052
|
-
return func(
|
1040
|
+
const asmFuncToAsm = (func, scope) => {
|
1041
|
+
return func(scope, {
|
1053
1042
|
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
|
1054
|
-
builtin:
|
1055
|
-
let idx = funcIndex[
|
1056
|
-
if (idx
|
1057
|
-
includeBuiltin(null,
|
1058
|
-
idx = funcIndex[
|
1043
|
+
builtin: n => {
|
1044
|
+
let idx = funcIndex[n] ?? importedFuncs[n];
|
1045
|
+
if (idx == null && builtinFuncs[n]) {
|
1046
|
+
includeBuiltin(null, n);
|
1047
|
+
idx = funcIndex[n];
|
1059
1048
|
}
|
1060
1049
|
|
1061
1050
|
return idx;
|
@@ -1063,7 +1052,7 @@ const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals =
|
|
1063
1052
|
});
|
1064
1053
|
};
|
1065
1054
|
|
1066
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false
|
1055
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1067
1056
|
const existing = funcs.find(x => x.name === name);
|
1068
1057
|
if (existing) return existing;
|
1069
1058
|
|
@@ -1081,7 +1070,22 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1081
1070
|
data.push(copy);
|
1082
1071
|
}
|
1083
1072
|
|
1084
|
-
|
1073
|
+
const func = {
|
1074
|
+
name,
|
1075
|
+
params,
|
1076
|
+
locals,
|
1077
|
+
localInd: allLocals.length,
|
1078
|
+
returns,
|
1079
|
+
returnType: returnType ?? TYPES.number,
|
1080
|
+
internal: true,
|
1081
|
+
index: currentFuncIndex++,
|
1082
|
+
table
|
1083
|
+
};
|
1084
|
+
|
1085
|
+
funcs.push(func);
|
1086
|
+
funcIndex[name] = func.index;
|
1087
|
+
|
1088
|
+
if (typeof wasm === 'function') wasm = asmFuncToAsm(wasm, func);
|
1085
1089
|
|
1086
1090
|
let baseGlobalIdx, i = 0;
|
1087
1091
|
for (const type of globalTypes) {
|
@@ -1100,23 +1104,6 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1100
1104
|
}
|
1101
1105
|
}
|
1102
1106
|
|
1103
|
-
const func = {
|
1104
|
-
name,
|
1105
|
-
params,
|
1106
|
-
locals,
|
1107
|
-
returns,
|
1108
|
-
returnType: returnType ?? TYPES.number,
|
1109
|
-
wasm,
|
1110
|
-
internal: true,
|
1111
|
-
index: currentFuncIndex++
|
1112
|
-
};
|
1113
|
-
|
1114
|
-
if (callsSelf) for (const inst of wasm) {
|
1115
|
-
if (inst[0] === Opcodes.call && inst[1] === -1) {
|
1116
|
-
inst[1] = func.index;
|
1117
|
-
}
|
1118
|
-
}
|
1119
|
-
|
1120
1107
|
if (table) for (const inst of wasm) {
|
1121
1108
|
if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
|
1122
1109
|
inst.splice(2, 99);
|
@@ -1124,10 +1111,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1124
1111
|
}
|
1125
1112
|
}
|
1126
1113
|
|
1127
|
-
|
1128
|
-
funcIndex[name] = func.index;
|
1129
|
-
|
1130
|
-
if (table) funcs.table = true;
|
1114
|
+
func.wasm = wasm;
|
1131
1115
|
|
1132
1116
|
return func;
|
1133
1117
|
};
|
@@ -1479,16 +1463,11 @@ const countLeftover = wasm => {
|
|
1479
1463
|
else if (inst[0] === Opcodes.return) count = 0;
|
1480
1464
|
else if (inst[0] === Opcodes.call) {
|
1481
1465
|
let func = funcs.find(x => x.index === inst[1]);
|
1482
|
-
if (inst[1]
|
1483
|
-
|
1484
|
-
|
1485
|
-
count -= importedFuncs[inst[1]].params;
|
1486
|
-
count += importedFuncs[inst[1]].returns;
|
1466
|
+
if (inst[1] < importedFuncs.length) {
|
1467
|
+
func = importedFuncs[inst[1]];
|
1468
|
+
count = count - func.params + func.returns;
|
1487
1469
|
} else {
|
1488
|
-
|
1489
|
-
count -= func.params.length;
|
1490
|
-
} else count--;
|
1491
|
-
if (func) count += func.returns.length;
|
1470
|
+
count = count - func.params.length + func.returns.length;
|
1492
1471
|
}
|
1493
1472
|
} else if (inst[0] === Opcodes.call_indirect) {
|
1494
1473
|
count--; // funcidx
|
@@ -1641,6 +1620,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1641
1620
|
|
1642
1621
|
if (!funcIndex[rhemynName]) {
|
1643
1622
|
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
1623
|
+
func.internal = true;
|
1644
1624
|
|
1645
1625
|
funcIndex[func.name] = func.index;
|
1646
1626
|
funcs.push(func);
|
@@ -1812,11 +1792,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1812
1792
|
|
1813
1793
|
if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1814
1794
|
|
1815
|
-
if (idx === undefined && name === scope.name) {
|
1816
|
-
// hack: calling self, func generator will fix later
|
1817
|
-
idx = -1;
|
1818
|
-
}
|
1819
|
-
|
1820
1795
|
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1821
1796
|
const wasmOps = {
|
1822
1797
|
// pointer, align, offset
|
@@ -1998,11 +1973,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1998
1973
|
return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
1999
1974
|
}
|
2000
1975
|
|
2001
|
-
const func = funcs.find(x => x.index === idx);
|
2002
|
-
|
2003
|
-
const userFunc = (funcIndex[name] && !importedFuncs[name] && !builtinFuncs[name] && !internalConstrs[name]) || idx === -1;
|
1976
|
+
const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
|
1977
|
+
const userFunc = func && !func.internal;
|
2004
1978
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
2005
|
-
const typedReturns = (func
|
1979
|
+
const typedReturns = (func && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
2006
1980
|
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
2007
1981
|
|
2008
1982
|
let args = decl.arguments;
|
@@ -2605,6 +2579,7 @@ const generateUnary = (scope, decl) => {
|
|
2605
2579
|
];
|
2606
2580
|
|
2607
2581
|
case '!':
|
2582
|
+
// todo/perf: optimize !!
|
2608
2583
|
// !=
|
2609
2584
|
return falsy(scope, generate(scope, decl.argument), getNodeType(scope, decl.argument), false, false);
|
2610
2585
|
|
@@ -3261,8 +3236,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3261
3236
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3262
3237
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
3263
3238
|
|
3264
|
-
|
3265
|
-
|
3239
|
+
let page;
|
3240
|
+
if (Prefs.scopedPageNames) page = allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType);
|
3241
|
+
else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
|
3242
|
+
|
3243
|
+
// hack: use 1 for page 0 pointer for fast truthiness
|
3244
|
+
const ptr = page === 0 ? 1 : (page * pageSize);
|
3245
|
+
scope.arrays.set(name, ptr);
|
3266
3246
|
}
|
3267
3247
|
|
3268
3248
|
const pointer = scope.arrays.get(name);
|
@@ -3449,8 +3429,19 @@ const withType = (scope, wasm, type) => [
|
|
3449
3429
|
|
3450
3430
|
const generateMember = (scope, decl, _global, _name) => {
|
3451
3431
|
const name = decl.object.name;
|
3452
|
-
const pointer = scope.arrays?.get(name);
|
3453
3432
|
|
3433
|
+
// hack: process.argv[n]
|
3434
|
+
if (name === '__process_argv') {
|
3435
|
+
const setPointer = scope.arrays?.get(_name);
|
3436
|
+
|
3437
|
+
return [
|
3438
|
+
...number(decl.property.value - 1),
|
3439
|
+
...(setPointer ? number(setPointer) : allocPage(scope, `__process_argv out (${randId()})`)),
|
3440
|
+
[ Opcodes.call, importedFuncs.__Porffor_readArgv ]
|
3441
|
+
];
|
3442
|
+
}
|
3443
|
+
|
3444
|
+
const pointer = scope.arrays?.get(name);
|
3454
3445
|
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3455
3446
|
|
3456
3447
|
// hack: .name
|
@@ -3471,8 +3462,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3471
3462
|
if (decl.property.name === 'length') {
|
3472
3463
|
const func = funcs.find(x => x.name === name);
|
3473
3464
|
if (func) {
|
3474
|
-
const
|
3475
|
-
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
3465
|
+
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3476
3466
|
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3477
3467
|
}
|
3478
3468
|
|
@@ -3698,34 +3688,39 @@ const generateFunc = (scope, decl) => {
|
|
3698
3688
|
const name = decl.id ? decl.id.name : `anonymous_${randId()}`;
|
3699
3689
|
const params = decl.params ?? [];
|
3700
3690
|
|
3701
|
-
// const innerScope = { ...scope };
|
3702
3691
|
// TODO: share scope/locals between !!!
|
3703
|
-
const
|
3692
|
+
const func = {
|
3704
3693
|
locals: {},
|
3705
3694
|
localInd: 0,
|
3706
3695
|
// value, type
|
3707
3696
|
returns: [ valtypeBinary, Valtype.i32 ],
|
3708
3697
|
throws: false,
|
3709
|
-
name
|
3698
|
+
name,
|
3699
|
+
index: currentFuncIndex++
|
3710
3700
|
};
|
3711
3701
|
|
3712
3702
|
if (typedInput && decl.returnType) {
|
3713
3703
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3714
3704
|
// if (type != null && !Prefs.indirectCalls) {
|
3715
3705
|
if (type != null) {
|
3716
|
-
|
3717
|
-
|
3706
|
+
func.returnType = type;
|
3707
|
+
func.returns = [ valtypeBinary ];
|
3718
3708
|
}
|
3719
3709
|
}
|
3720
3710
|
|
3721
3711
|
for (let i = 0; i < params.length; i++) {
|
3722
|
-
|
3712
|
+
const name = params[i].name;
|
3713
|
+
// if (name == null) return todo('non-identifier args are not supported');
|
3714
|
+
|
3715
|
+
allocVar(func, name, false);
|
3723
3716
|
|
3724
3717
|
if (typedInput && params[i].typeAnnotation) {
|
3725
|
-
addVarMetadata(
|
3718
|
+
addVarMetadata(func, name, false, extractTypeAnnotation(params[i]));
|
3726
3719
|
}
|
3727
3720
|
}
|
3728
3721
|
|
3722
|
+
func.params = Object.values(func.locals).map(x => x.type);
|
3723
|
+
|
3729
3724
|
let body = objectHack(decl.body);
|
3730
3725
|
if (decl.type === 'ArrowFunctionExpression' && decl.expression) {
|
3731
3726
|
// hack: () => 0 -> () => return 0
|
@@ -3735,37 +3730,23 @@ const generateFunc = (scope, decl) => {
|
|
3735
3730
|
};
|
3736
3731
|
}
|
3737
3732
|
|
3738
|
-
const wasm = generate(innerScope, body);
|
3739
|
-
const func = {
|
3740
|
-
name,
|
3741
|
-
params: Object.values(innerScope.locals).slice(0, params.length * 2).map(x => x.type),
|
3742
|
-
index: currentFuncIndex++,
|
3743
|
-
...innerScope
|
3744
|
-
};
|
3745
3733
|
funcIndex[name] = func.index;
|
3734
|
+
funcs.push(func);
|
3746
3735
|
|
3747
|
-
|
3736
|
+
const wasm = generate(func, body);
|
3737
|
+
func.wasm = wasm;
|
3748
3738
|
|
3749
|
-
|
3750
|
-
for (const inst of wasm) {
|
3751
|
-
if (inst[0] === Opcodes.call && inst[1] === -1) {
|
3752
|
-
inst[1] = func.index;
|
3753
|
-
}
|
3754
|
-
}
|
3739
|
+
if (name === 'main') func.gotLastType = true;
|
3755
3740
|
|
3756
3741
|
// add end return if not found
|
3757
3742
|
if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
3758
3743
|
wasm.push(
|
3759
3744
|
...number(0),
|
3760
|
-
...(
|
3745
|
+
...(func.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
|
3761
3746
|
[ Opcodes.return ]
|
3762
3747
|
);
|
3763
3748
|
}
|
3764
3749
|
|
3765
|
-
func.wasm = wasm;
|
3766
|
-
|
3767
|
-
funcs.push(func);
|
3768
|
-
|
3769
3750
|
return func;
|
3770
3751
|
};
|
3771
3752
|
|
@@ -3869,7 +3850,7 @@ const internalConstrs = {
|
|
3869
3850
|
generate: (scope, decl) => {
|
3870
3851
|
// todo: boolean object when used as constructor
|
3871
3852
|
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
3872
|
-
return truthy(scope, generate(scope, arg), getNodeType(scope, arg));
|
3853
|
+
return truthy(scope, generate(scope, arg), getNodeType(scope, arg), false, false, 'full');
|
3873
3854
|
},
|
3874
3855
|
type: TYPES.boolean,
|
3875
3856
|
length: 1
|
@@ -4014,9 +3995,8 @@ export default program => {
|
|
4014
3995
|
|
4015
3996
|
if (Prefs.astLog) console.log(JSON.stringify(program.body.body, null, 2));
|
4016
3997
|
|
4017
|
-
generateFunc(scope, program);
|
3998
|
+
const main = generateFunc(scope, program);
|
4018
3999
|
|
4019
|
-
const main = funcs[funcs.length - 1];
|
4020
4000
|
main.export = true;
|
4021
4001
|
main.returns = [ valtypeBinary, Valtype.i32 ];
|
4022
4002
|
|
@@ -4043,7 +4023,7 @@ export default program => {
|
|
4043
4023
|
}
|
4044
4024
|
|
4045
4025
|
// if blank main func and other exports, remove it
|
4046
|
-
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(
|
4026
|
+
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
4047
4027
|
|
4048
4028
|
return { funcs, globals, tags, exceptions, pages, data };
|
4049
4029
|
};
|