porffor 0.17.0-c2af76d41 → 0.17.0-c2dd8f88f
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/README.md +6 -4
- package/compiler/assemble.js +19 -4
- package/compiler/builtins/array.ts +28 -0
- package/compiler/builtins/date.ts +104 -106
- package/compiler/builtins/error.js +2 -5
- package/compiler/builtins/set.ts +4 -5
- package/compiler/builtins/string_f64.ts +4 -6
- package/compiler/builtins/symbol.ts +2 -1
- package/compiler/builtins/typedarray.js +46 -4
- package/compiler/builtins/z_ecma262.ts +1 -0
- package/compiler/builtins.js +2 -2
- package/compiler/codegen.js +189 -98
- package/compiler/generated_builtins.js +1329 -1237
- package/compiler/precompile.js +1 -1
- package/compiler/prototype.js +0 -69
- package/package.json +1 -1
- package/rhemyn/compile.js +41 -13
package/compiler/codegen.js
CHANGED
@@ -123,6 +123,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
123
123
|
case 'EmptyStatement':
|
124
124
|
return generateEmpty(scope, decl);
|
125
125
|
|
126
|
+
case 'MetaProperty':
|
127
|
+
return generateMeta(scope, decl);
|
128
|
+
|
126
129
|
case 'ConditionalExpression':
|
127
130
|
return generateConditional(scope, decl);
|
128
131
|
|
@@ -295,10 +298,10 @@ const generateIdent = (scope, decl) => {
|
|
295
298
|
}
|
296
299
|
|
297
300
|
// todo: enable this by default in future
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
301
|
+
if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
|
302
|
+
includeBuiltin(scope, name);
|
303
|
+
return number(funcIndex[name] - importedFuncs.length);
|
304
|
+
}
|
302
305
|
|
303
306
|
if (isExistingProtoFunc(name) || Object.hasOwn(internalConstrs, name) || Object.hasOwn(builtinFuncs, name)) {
|
304
307
|
// todo: return an actual something
|
@@ -1032,7 +1035,7 @@ const asmFuncToAsm = (func, scope) => {
|
|
1032
1035
|
});
|
1033
1036
|
};
|
1034
1037
|
|
1035
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1038
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false, constr = false }) => {
|
1036
1039
|
const existing = funcs.find(x => x.name === name);
|
1037
1040
|
if (existing) return existing;
|
1038
1041
|
|
@@ -1059,7 +1062,8 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1059
1062
|
returnType,
|
1060
1063
|
internal: true,
|
1061
1064
|
index: currentFuncIndex++,
|
1062
|
-
table
|
1065
|
+
table,
|
1066
|
+
constr
|
1063
1067
|
};
|
1064
1068
|
|
1065
1069
|
funcs.push(func);
|
@@ -1089,15 +1093,35 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1089
1093
|
|
1090
1094
|
if (table) {
|
1091
1095
|
for (const inst of wasm) {
|
1092
|
-
if (inst
|
1096
|
+
if (inst.at(-1) === 'read func lut') {
|
1093
1097
|
inst.splice(2, 99);
|
1094
|
-
inst.push(...unsignedLEB128(allocPage({}, 'func
|
1098
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func lut') * pageSize));
|
1095
1099
|
}
|
1096
1100
|
}
|
1097
1101
|
|
1098
1102
|
funcs.table = true;
|
1099
1103
|
}
|
1100
1104
|
|
1105
|
+
if (constr) {
|
1106
|
+
func.params = [...func.params];
|
1107
|
+
func.params.unshift(Valtype.i32);
|
1108
|
+
|
1109
|
+
// move all locals +1 idx (sigh)
|
1110
|
+
func.localInd++;
|
1111
|
+
const locals = func.locals;
|
1112
|
+
for (const x in locals) {
|
1113
|
+
locals[x].idx++;
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
locals['#newtarget'] = { idx: 0, type: Valtype.i32 };
|
1117
|
+
|
1118
|
+
for (const inst of wasm) {
|
1119
|
+
if (inst[0] === Opcodes.local_get || inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) {
|
1120
|
+
inst[1]++;
|
1121
|
+
}
|
1122
|
+
}
|
1123
|
+
}
|
1124
|
+
|
1101
1125
|
func.wasm = wasm;
|
1102
1126
|
|
1103
1127
|
return func;
|
@@ -1224,20 +1248,7 @@ const getNodeType = (scope, node) => {
|
|
1224
1248
|
return TYPES.number;
|
1225
1249
|
}
|
1226
1250
|
|
1227
|
-
if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
|
1228
|
-
if (builtinFuncs[name + '$constructor'].typedReturns) {
|
1229
|
-
if (scope.locals['#last_type']) return getLastType(scope);
|
1230
|
-
|
1231
|
-
// presume
|
1232
|
-
// todo: warn here?
|
1233
|
-
return TYPES.number;
|
1234
|
-
}
|
1235
|
-
|
1236
|
-
return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
|
1237
|
-
}
|
1238
|
-
|
1239
1251
|
const func = funcs.find(x => x.name === name);
|
1240
|
-
|
1241
1252
|
if (func) {
|
1242
1253
|
if (func.returnType != null) return func.returnType;
|
1243
1254
|
}
|
@@ -1535,7 +1546,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1535
1546
|
name = func.name;
|
1536
1547
|
}
|
1537
1548
|
|
1538
|
-
if (name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1549
|
+
if (!decl._new && name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1539
1550
|
// literal eval hack
|
1540
1551
|
const code = decl.arguments[0]?.value ?? '';
|
1541
1552
|
|
@@ -1578,7 +1589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1578
1589
|
|
1579
1590
|
let protoName, target;
|
1580
1591
|
// ident.func()
|
1581
|
-
if (name && name.startsWith('__')) {
|
1592
|
+
if (!decl._new && name && name.startsWith('__')) {
|
1582
1593
|
const spl = name.slice(2).split('_');
|
1583
1594
|
|
1584
1595
|
protoName = spl[spl.length - 1];
|
@@ -1591,7 +1602,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1591
1602
|
}
|
1592
1603
|
|
1593
1604
|
// literal.func()
|
1594
|
-
if (!name && decl.callee.type === 'MemberExpression') {
|
1605
|
+
if (!decl._new && !name && decl.callee.type === 'MemberExpression') {
|
1595
1606
|
// megahack for /regex/.func()
|
1596
1607
|
const funcName = decl.callee.property.name;
|
1597
1608
|
if (decl.callee.object.regex && ['test'].includes(funcName)) {
|
@@ -1626,6 +1637,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1626
1637
|
target = decl.callee.object;
|
1627
1638
|
}
|
1628
1639
|
|
1640
|
+
let out = [];
|
1629
1641
|
if (protoName) {
|
1630
1642
|
if (['search'].includes(protoName)) {
|
1631
1643
|
const regex = decl.arguments[0]?.regex?.pattern;
|
@@ -1667,6 +1679,14 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1667
1679
|
const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
|
1668
1680
|
|
1669
1681
|
if (!decl._protoInternalCall && builtinProtoCands.length > 0) {
|
1682
|
+
out.push(
|
1683
|
+
...generate(scope, target),
|
1684
|
+
[ Opcodes.local_set, localTmp(scope, '#proto_target') ],
|
1685
|
+
|
1686
|
+
...getNodeType(scope, target),
|
1687
|
+
[ Opcodes.local_set, localTmp(scope, '#proto_target#type', Valtype.i32) ],
|
1688
|
+
);
|
1689
|
+
|
1670
1690
|
for (const x of builtinProtoCands) {
|
1671
1691
|
const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
|
1672
1692
|
if (type == null) continue;
|
@@ -1676,7 +1696,14 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1676
1696
|
type: 'Identifier',
|
1677
1697
|
name: x
|
1678
1698
|
},
|
1679
|
-
arguments: [
|
1699
|
+
arguments: [
|
1700
|
+
{
|
1701
|
+
type: 'Identifier',
|
1702
|
+
name: '#proto_target'
|
1703
|
+
},
|
1704
|
+
|
1705
|
+
...decl.arguments
|
1706
|
+
],
|
1680
1707
|
_protoInternalCall: true
|
1681
1708
|
});
|
1682
1709
|
}
|
@@ -1770,29 +1797,37 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1770
1797
|
}
|
1771
1798
|
|
1772
1799
|
if (Object.keys(protoBC).length > 0) {
|
1773
|
-
return
|
1774
|
-
...
|
1800
|
+
return [
|
1801
|
+
...out,
|
1802
|
+
|
1803
|
+
...typeSwitch(scope, builtinProtoCands.length > 0 ? [ [ Opcodes.local_get, localTmp(scope, '#proto_target#type', Valtype.i32) ] ] : getNodeType(scope, target), {
|
1804
|
+
...protoBC,
|
1775
1805
|
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1806
|
+
// TODO: error better
|
1807
|
+
default: internalThrow(scope, 'TypeError', `'${protoName}' proto func tried to be called on a type without an impl`)
|
1808
|
+
}, valtypeBinary)
|
1809
|
+
];
|
1779
1810
|
}
|
1780
1811
|
}
|
1781
1812
|
|
1782
|
-
// TODO: only allows callee as
|
1783
|
-
if (!name) return todo(scope, `only
|
1813
|
+
// TODO: only allows callee as identifier
|
1814
|
+
if (!name) return todo(scope, `only identifier callees (got ${decl.callee.type})`);
|
1784
1815
|
|
1785
1816
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1786
1817
|
if (idx === undefined && builtinFuncs[name]) {
|
1787
1818
|
if (builtinFuncs[name].floatOnly && valtype !== 'f64') throw new Error(`Cannot use built-in ${unhackName(name)} with integer valtype`);
|
1819
|
+
if (decl._new && !builtinFuncs[name].constr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
1788
1820
|
|
1789
1821
|
includeBuiltin(scope, name);
|
1790
1822
|
idx = funcIndex[name];
|
1791
1823
|
}
|
1792
1824
|
|
1793
|
-
if (idx === undefined && internalConstrs[name])
|
1825
|
+
if (idx === undefined && internalConstrs[name]) {
|
1826
|
+
if (decl._new && internalConstrs[name].notConstr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
1827
|
+
return internalConstrs[name].generate(scope, decl, _global, _name);
|
1828
|
+
}
|
1794
1829
|
|
1795
|
-
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1830
|
+
if (idx === undefined && !decl._new && name.startsWith('__Porffor_wasm_')) {
|
1796
1831
|
const wasmOps = {
|
1797
1832
|
// pointer, align, offset
|
1798
1833
|
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
@@ -1847,7 +1882,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1847
1882
|
|
1848
1883
|
const indirectMode = Prefs.indirectCallMode ?? 'vararg';
|
1849
1884
|
// options: vararg, strict
|
1850
|
-
// - strict: simpler, smaller size usage, no func
|
1885
|
+
// - strict: simpler, smaller size usage, no func lut needed.
|
1851
1886
|
// ONLY works when arg count of call == arg count of function being called
|
1852
1887
|
// - vararg: large size usage, cursed.
|
1853
1888
|
// works when arg count of call != arg count of function being called*
|
@@ -1857,8 +1892,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1857
1892
|
scope.table = true;
|
1858
1893
|
|
1859
1894
|
let args = decl.arguments;
|
1860
|
-
let out = [];
|
1861
|
-
|
1862
1895
|
let locals = [];
|
1863
1896
|
|
1864
1897
|
if (indirectMode === 'vararg') {
|
@@ -1922,24 +1955,67 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1922
1955
|
// *for argc 0-3, in future (todo:) the max number should be
|
1923
1956
|
// dynamically changed to the max argc of any func in the js file.
|
1924
1957
|
|
1925
|
-
const funcLocal = localTmp(scope,
|
1958
|
+
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
1959
|
+
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
1926
1960
|
|
1927
1961
|
const gen = argc => {
|
1928
|
-
const
|
1962
|
+
const argsOut = [];
|
1929
1963
|
for (let i = 0; i < argc; i++) {
|
1930
|
-
|
1964
|
+
argsOut.push(
|
1931
1965
|
[ Opcodes.local_get, locals[i][0] ],
|
1932
1966
|
[ Opcodes.local_get, locals[i][1] ]
|
1933
1967
|
);
|
1934
1968
|
}
|
1935
1969
|
|
1936
|
-
|
1937
|
-
[ Opcodes.local_get,
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1970
|
+
const checkFlag = (flag, pass, fail) => [
|
1971
|
+
[ Opcodes.local_get, flags ],
|
1972
|
+
...number(flag, Valtype.i32),
|
1973
|
+
[ Opcodes.i32_and ],
|
1974
|
+
[ Opcodes.if, valtypeBinary ],
|
1975
|
+
...pass,
|
1976
|
+
[ Opcodes.else ],
|
1977
|
+
...fail,
|
1978
|
+
[ Opcodes.end ]
|
1979
|
+
];
|
1941
1980
|
|
1942
|
-
|
1981
|
+
// pain.
|
1982
|
+
// return checkFlag(0b10, [ // constr
|
1983
|
+
// [ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
1984
|
+
// ...argsOut,
|
1985
|
+
// [ Opcodes.local_get, funcLocal ],
|
1986
|
+
// [ Opcodes.call_indirect, argc, 0, 'constr' ],
|
1987
|
+
// ...setLastType(scope),
|
1988
|
+
// ], [
|
1989
|
+
// ...argsOut,
|
1990
|
+
// [ Opcodes.local_get, funcLocal ],
|
1991
|
+
// [ Opcodes.call_indirect, argc, 0 ],
|
1992
|
+
// ...setLastType(scope),
|
1993
|
+
// ]);
|
1994
|
+
|
1995
|
+
return checkFlag(0b1, // no type return
|
1996
|
+
checkFlag(0b10, [ // no type return & constr
|
1997
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
1998
|
+
...argsOut,
|
1999
|
+
[ Opcodes.local_get, funcLocal ],
|
2000
|
+
[ Opcodes.call_indirect, argc, 0, 'no_type_return', 'constr' ],
|
2001
|
+
], [
|
2002
|
+
...argsOut,
|
2003
|
+
[ Opcodes.local_get, funcLocal ],
|
2004
|
+
[ Opcodes.call_indirect, argc, 0, 'no_type_return' ]
|
2005
|
+
]),
|
2006
|
+
checkFlag(0b10, [ // type return & constr
|
2007
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2008
|
+
...argsOut,
|
2009
|
+
[ Opcodes.local_get, funcLocal ],
|
2010
|
+
[ Opcodes.call_indirect, argc, 0, 'constr' ],
|
2011
|
+
...setLastType(scope),
|
2012
|
+
], [
|
2013
|
+
...argsOut,
|
2014
|
+
[ Opcodes.local_get, funcLocal ],
|
2015
|
+
[ Opcodes.call_indirect, argc, 0 ],
|
2016
|
+
...setLastType(scope),
|
2017
|
+
]),
|
2018
|
+
);
|
1943
2019
|
};
|
1944
2020
|
|
1945
2021
|
const tableBc = {};
|
@@ -1957,13 +2033,32 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1957
2033
|
Opcodes.i32_to_u,
|
1958
2034
|
[ Opcodes.local_set, funcLocal ],
|
1959
2035
|
|
2036
|
+
// get if func we are calling is a constructor or not
|
2037
|
+
[ Opcodes.local_get, funcLocal ],
|
2038
|
+
...number(3, Valtype.i32),
|
2039
|
+
[ Opcodes.i32_mul ],
|
2040
|
+
...number(2, Valtype.i32),
|
2041
|
+
[ Opcodes.i32_add ],
|
2042
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
|
2043
|
+
[ Opcodes.local_set, flags ],
|
2044
|
+
|
2045
|
+
// check if non-constructor was called with new, if so throw
|
2046
|
+
[ Opcodes.local_get, flags ],
|
2047
|
+
...number(0b10, Valtype.i32),
|
2048
|
+
[ Opcodes.i32_and ],
|
2049
|
+
[ Opcodes.i32_eqz ],
|
2050
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2051
|
+
[ Opcodes.i32_and ],
|
2052
|
+
[ Opcodes.if, Blocktype.void ],
|
2053
|
+
...internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`),
|
2054
|
+
[ Opcodes.end ],
|
2055
|
+
|
1960
2056
|
...brTable([
|
1961
2057
|
// get argc of func we are calling
|
1962
2058
|
[ Opcodes.local_get, funcLocal ],
|
1963
|
-
...number(
|
2059
|
+
...number(3, Valtype.i32),
|
1964
2060
|
[ Opcodes.i32_mul ],
|
1965
|
-
|
1966
|
-
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func argc lut') * pageSize), 'read_argc' ]
|
2061
|
+
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ]
|
1967
2062
|
], tableBc, valtypeBinary)
|
1968
2063
|
],
|
1969
2064
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
@@ -1977,7 +2072,16 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1977
2072
|
const userFunc = func && !func.internal;
|
1978
2073
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1979
2074
|
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1980
|
-
|
2075
|
+
let paramCount = func && (typedParams ? Math.floor(func.params.length / 2) : func.params.length);
|
2076
|
+
|
2077
|
+
let paramOffset = 0;
|
2078
|
+
if (func && func.constr) {
|
2079
|
+
// new.target arg
|
2080
|
+
if (func.internal) paramOffset = 1;
|
2081
|
+
if (!typedParams) paramCount--;
|
2082
|
+
out.push([ Opcodes.i32_const, decl._new ? 1 : 0 ]);
|
2083
|
+
} else if (decl._new)
|
2084
|
+
return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
1981
2085
|
|
1982
2086
|
let args = decl.arguments;
|
1983
2087
|
if (func && args.length < paramCount) {
|
@@ -1992,7 +2096,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1992
2096
|
|
1993
2097
|
if (func && func.throws) scope.throws = true;
|
1994
2098
|
|
1995
|
-
let out = [];
|
1996
2099
|
for (let i = 0; i < args.length; i++) {
|
1997
2100
|
const arg = args[i];
|
1998
2101
|
out = out.concat(generate(scope, arg));
|
@@ -2005,13 +2108,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2005
2108
|
}
|
2006
2109
|
|
2007
2110
|
if (valtypeBinary !== Valtype.i32 &&
|
2008
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2111
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2009
2112
|
) {
|
2010
2113
|
out.push(Opcodes.i32_to);
|
2011
2114
|
}
|
2012
2115
|
|
2013
2116
|
if (valtypeBinary === Valtype.i32 &&
|
2014
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
2117
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.f64)
|
2015
2118
|
) {
|
2016
2119
|
out.push([ Opcodes.f64_convert_i32_s ]);
|
2017
2120
|
}
|
@@ -2044,32 +2147,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2044
2147
|
return out;
|
2045
2148
|
};
|
2046
2149
|
|
2047
|
-
const generateNew = (scope, decl, _global, _name) => {
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
2051
|
-
if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
|
2052
|
-
|
2053
|
-
if (builtinFuncs[name + '$constructor']) {
|
2054
|
-
// custom ...$constructor override builtin func
|
2055
|
-
return generateCall(scope, {
|
2056
|
-
...decl,
|
2057
|
-
callee: {
|
2058
|
-
type: 'Identifier',
|
2059
|
-
name: name + '$constructor'
|
2060
|
-
}
|
2061
|
-
}, _global, _name);
|
2062
|
-
}
|
2063
|
-
|
2064
|
-
if (
|
2065
|
-
(builtinFuncs[name] && !builtinFuncs[name].constr) ||
|
2066
|
-
(internalConstrs[name] && builtinFuncs[name].notConstr)
|
2067
|
-
) return internalThrow(scope, 'TypeError', `${name} is not a constructor`, true);
|
2068
|
-
|
2069
|
-
if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet`, true); // return todo(scope, `new statement is not supported yet (new ${unhackName(name)})`);
|
2070
|
-
|
2071
|
-
return generateCall(scope, decl, _global, _name);
|
2072
|
-
};
|
2150
|
+
const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
|
2151
|
+
...decl,
|
2152
|
+
_new: true
|
2153
|
+
}, _global, _name);
|
2073
2154
|
|
2074
2155
|
// bad hack for undefined and null working without additional logic
|
2075
2156
|
const DEFAULT_VALUE = {
|
@@ -2426,8 +2507,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2426
2507
|
|
2427
2508
|
// arr[i]
|
2428
2509
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2429
|
-
const newValueTmp = localTmp(scope, '
|
2430
|
-
const pointerTmp =
|
2510
|
+
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
2511
|
+
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
2431
2512
|
|
2432
2513
|
return [
|
2433
2514
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
@@ -2439,11 +2520,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2439
2520
|
...generate(scope, decl.left.property),
|
2440
2521
|
Opcodes.i32_to_u,
|
2441
2522
|
|
2442
|
-
// turn into byte offset by * valtypeSize
|
2523
|
+
// turn into byte offset by * valtypeSize + 1
|
2443
2524
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2444
2525
|
[ Opcodes.i32_mul ],
|
2445
2526
|
[ Opcodes.i32_add ],
|
2446
|
-
|
2527
|
+
[ Opcodes.local_tee, pointerTmp ],
|
2447
2528
|
|
2448
2529
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2449
2530
|
[ Opcodes.local_get, pointerTmp ],
|
@@ -2453,7 +2534,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2453
2534
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2454
2535
|
], getNodeType(scope, decl.right), false, name, true)),
|
2455
2536
|
[ Opcodes.local_tee, newValueTmp ],
|
2456
|
-
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2537
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
2538
|
+
|
2539
|
+
[ Opcodes.local_get, pointerTmp ],
|
2540
|
+
...getNodeType(scope, decl),
|
2541
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
2457
2542
|
],
|
2458
2543
|
|
2459
2544
|
...wrapBC({
|
@@ -3491,6 +3576,22 @@ const generateEmpty = (scope, decl) => {
|
|
3491
3576
|
return [];
|
3492
3577
|
};
|
3493
3578
|
|
3579
|
+
const generateMeta = (scope, decl) => {
|
3580
|
+
if (decl.meta.name !== 'new') return todo(scope, `meta property object ${decl.meta.name} is not supported yet`, true);
|
3581
|
+
|
3582
|
+
switch (`${decl.meta.name}.${decl.property.name}`) {
|
3583
|
+
case 'new.target': {
|
3584
|
+
scope.constr = true;
|
3585
|
+
|
3586
|
+
return [
|
3587
|
+
[ Opcodes.local_get, -1 ],
|
3588
|
+
Opcodes.i32_from_u,
|
3589
|
+
...setLastType(scope, TYPES.boolean)
|
3590
|
+
];
|
3591
|
+
}
|
3592
|
+
}
|
3593
|
+
};
|
3594
|
+
|
3494
3595
|
let pages = new Map();
|
3495
3596
|
const allocPage = (scope, reason, type) => {
|
3496
3597
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3843,20 +3944,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3843
3944
|
const func = funcs.find(x => x.name === name);
|
3844
3945
|
if (func) {
|
3845
3946
|
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3846
|
-
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3847
|
-
}
|
3848
|
-
|
3849
|
-
if (builtinFuncs[name + '$constructor']) {
|
3850
|
-
const regularFunc = builtinFuncs[name];
|
3851
|
-
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3852
|
-
|
3853
|
-
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3854
|
-
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3855
|
-
|
3856
|
-
return withType(scope, number(Math.max(regularParams, constructorParams)), TYPES.number);
|
3947
|
+
return withType(scope, number(typedParams ? Math.floor(func.params.length / 2) : (func.constr ? (func.params.length - 1) : func.params.length)), TYPES.number);
|
3857
3948
|
}
|
3858
3949
|
|
3859
|
-
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
|
3950
|
+
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? Math.floor(builtinFuncs[name].params.length / 2) : (builtinFuncs[name].constr ? (builtinFuncs[name].params.length - 1) : builtinFuncs[name].params.length)), TYPES.number);
|
3860
3951
|
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3861
3952
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3862
3953
|
|
@@ -4164,8 +4255,8 @@ const generateFunc = (scope, decl) => {
|
|
4164
4255
|
|
4165
4256
|
if (typedInput && decl.returnType) {
|
4166
4257
|
const { type } = extractTypeAnnotation(decl.returnType);
|
4167
|
-
|
4168
|
-
if (type != null) {
|
4258
|
+
if (type != null && !Prefs.indirectCalls) {
|
4259
|
+
// if (type != null) {
|
4169
4260
|
func.returnType = type;
|
4170
4261
|
func.returns = [ valtypeBinary ];
|
4171
4262
|
}
|