porffor 0.14.0-c6edfd328 → 0.14.0-d6c141d91
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/bf_bun +0 -0
- package/bf_deno +0 -0
- package/bf_porf +0 -0
- package/bf_porf_fast +0 -0
- package/bf_porf_lto +0 -0
- package/compiler/2c.js +65 -2
- package/compiler/builtins/annexb_string.ts +1 -0
- package/compiler/builtins/array.ts +71 -1
- 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 +126 -141
- package/compiler/generated_builtins.js +284 -7
- 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/w.js +1 -0
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
|
|
@@ -3144,14 +3119,18 @@ const generateThrow = (scope, decl) => {
|
|
3144
3119
|
};
|
3145
3120
|
|
3146
3121
|
const generateTry = (scope, decl) => {
|
3147
|
-
|
3122
|
+
// todo: handle control-flow pre-exit for finally
|
3123
|
+
// "Immediately before a control-flow statement (return, throw, break, continue) is executed in the try block or catch block."
|
3148
3124
|
|
3149
3125
|
const out = [];
|
3150
3126
|
|
3127
|
+
const finalizer = decl.finalizer ? generate(scope, decl.finalizer) : [];
|
3128
|
+
|
3151
3129
|
out.push([ Opcodes.try, Blocktype.void ]);
|
3152
3130
|
depth.push('try');
|
3153
3131
|
|
3154
3132
|
out.push(...generate(scope, decl.block));
|
3133
|
+
out.push(...finalizer);
|
3155
3134
|
|
3156
3135
|
if (decl.handler) {
|
3157
3136
|
depth.pop();
|
@@ -3159,6 +3138,7 @@ const generateTry = (scope, decl) => {
|
|
3159
3138
|
|
3160
3139
|
out.push([ Opcodes.catch_all ]);
|
3161
3140
|
out.push(...generate(scope, decl.handler.body));
|
3141
|
+
out.push(...finalizer);
|
3162
3142
|
}
|
3163
3143
|
|
3164
3144
|
out.push([ Opcodes.end ]);
|
@@ -3256,8 +3236,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3256
3236
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3257
3237
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
3258
3238
|
|
3259
|
-
|
3260
|
-
|
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);
|
3261
3246
|
}
|
3262
3247
|
|
3263
3248
|
const pointer = scope.arrays.get(name);
|
@@ -3444,8 +3429,19 @@ const withType = (scope, wasm, type) => [
|
|
3444
3429
|
|
3445
3430
|
const generateMember = (scope, decl, _global, _name) => {
|
3446
3431
|
const name = decl.object.name;
|
3447
|
-
const pointer = scope.arrays?.get(name);
|
3448
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);
|
3449
3445
|
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3450
3446
|
|
3451
3447
|
// hack: .name
|
@@ -3466,8 +3462,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3466
3462
|
if (decl.property.name === 'length') {
|
3467
3463
|
const func = funcs.find(x => x.name === name);
|
3468
3464
|
if (func) {
|
3469
|
-
const
|
3470
|
-
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
3465
|
+
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3471
3466
|
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3472
3467
|
}
|
3473
3468
|
|
@@ -3693,34 +3688,39 @@ const generateFunc = (scope, decl) => {
|
|
3693
3688
|
const name = decl.id ? decl.id.name : `anonymous_${randId()}`;
|
3694
3689
|
const params = decl.params ?? [];
|
3695
3690
|
|
3696
|
-
// const innerScope = { ...scope };
|
3697
3691
|
// TODO: share scope/locals between !!!
|
3698
|
-
const
|
3692
|
+
const func = {
|
3699
3693
|
locals: {},
|
3700
3694
|
localInd: 0,
|
3701
3695
|
// value, type
|
3702
3696
|
returns: [ valtypeBinary, Valtype.i32 ],
|
3703
3697
|
throws: false,
|
3704
|
-
name
|
3698
|
+
name,
|
3699
|
+
index: currentFuncIndex++
|
3705
3700
|
};
|
3706
3701
|
|
3707
3702
|
if (typedInput && decl.returnType) {
|
3708
3703
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3709
3704
|
// if (type != null && !Prefs.indirectCalls) {
|
3710
3705
|
if (type != null) {
|
3711
|
-
|
3712
|
-
|
3706
|
+
func.returnType = type;
|
3707
|
+
func.returns = [ valtypeBinary ];
|
3713
3708
|
}
|
3714
3709
|
}
|
3715
3710
|
|
3716
3711
|
for (let i = 0; i < params.length; i++) {
|
3717
|
-
|
3712
|
+
const name = params[i].name;
|
3713
|
+
// if (name == null) return todo('non-identifier args are not supported');
|
3714
|
+
|
3715
|
+
allocVar(func, name, false);
|
3718
3716
|
|
3719
3717
|
if (typedInput && params[i].typeAnnotation) {
|
3720
|
-
addVarMetadata(
|
3718
|
+
addVarMetadata(func, name, false, extractTypeAnnotation(params[i]));
|
3721
3719
|
}
|
3722
3720
|
}
|
3723
3721
|
|
3722
|
+
func.params = Object.values(func.locals).map(x => x.type);
|
3723
|
+
|
3724
3724
|
let body = objectHack(decl.body);
|
3725
3725
|
if (decl.type === 'ArrowFunctionExpression' && decl.expression) {
|
3726
3726
|
// hack: () => 0 -> () => return 0
|
@@ -3730,37 +3730,23 @@ const generateFunc = (scope, decl) => {
|
|
3730
3730
|
};
|
3731
3731
|
}
|
3732
3732
|
|
3733
|
-
const wasm = generate(innerScope, body);
|
3734
|
-
const func = {
|
3735
|
-
name,
|
3736
|
-
params: Object.values(innerScope.locals).slice(0, params.length * 2).map(x => x.type),
|
3737
|
-
index: currentFuncIndex++,
|
3738
|
-
...innerScope
|
3739
|
-
};
|
3740
3733
|
funcIndex[name] = func.index;
|
3734
|
+
funcs.push(func);
|
3741
3735
|
|
3742
|
-
|
3736
|
+
const wasm = generate(func, body);
|
3737
|
+
func.wasm = wasm;
|
3743
3738
|
|
3744
|
-
|
3745
|
-
for (const inst of wasm) {
|
3746
|
-
if (inst[0] === Opcodes.call && inst[1] === -1) {
|
3747
|
-
inst[1] = func.index;
|
3748
|
-
}
|
3749
|
-
}
|
3739
|
+
if (name === 'main') func.gotLastType = true;
|
3750
3740
|
|
3751
3741
|
// add end return if not found
|
3752
3742
|
if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
3753
3743
|
wasm.push(
|
3754
3744
|
...number(0),
|
3755
|
-
...(
|
3745
|
+
...(func.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
|
3756
3746
|
[ Opcodes.return ]
|
3757
3747
|
);
|
3758
3748
|
}
|
3759
3749
|
|
3760
|
-
func.wasm = wasm;
|
3761
|
-
|
3762
|
-
funcs.push(func);
|
3763
|
-
|
3764
3750
|
return func;
|
3765
3751
|
};
|
3766
3752
|
|
@@ -3864,7 +3850,7 @@ const internalConstrs = {
|
|
3864
3850
|
generate: (scope, decl) => {
|
3865
3851
|
// todo: boolean object when used as constructor
|
3866
3852
|
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
3867
|
-
return truthy(scope, generate(scope, arg), getNodeType(scope, arg));
|
3853
|
+
return truthy(scope, generate(scope, arg), getNodeType(scope, arg), false, false, 'full');
|
3868
3854
|
},
|
3869
3855
|
type: TYPES.boolean,
|
3870
3856
|
length: 1
|
@@ -4009,9 +3995,8 @@ export default program => {
|
|
4009
3995
|
|
4010
3996
|
if (Prefs.astLog) console.log(JSON.stringify(program.body.body, null, 2));
|
4011
3997
|
|
4012
|
-
generateFunc(scope, program);
|
3998
|
+
const main = generateFunc(scope, program);
|
4013
3999
|
|
4014
|
-
const main = funcs[funcs.length - 1];
|
4015
4000
|
main.export = true;
|
4016
4001
|
main.returns = [ valtypeBinary, Valtype.i32 ];
|
4017
4002
|
|
@@ -4038,7 +4023,7 @@ export default program => {
|
|
4038
4023
|
}
|
4039
4024
|
|
4040
4025
|
// if blank main func and other exports, remove it
|
4041
|
-
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);
|
4042
4027
|
|
4043
4028
|
return { funcs, globals, tags, exceptions, pages, data };
|
4044
4029
|
};
|