porffor 0.17.0-f43ba190c → 0.18.2
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/2c.js +1 -1
- package/compiler/assemble.js +19 -4
- package/compiler/builtins/array.ts +102 -9
- 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 +58 -6
- package/compiler/builtins/z_ecma262.ts +1 -0
- package/compiler/builtins.js +13 -2
- package/compiler/codegen.js +486 -127
- package/compiler/generated_builtins.js +2714 -713
- package/compiler/opt.js +3 -0
- package/compiler/precompile.js +4 -2
- package/compiler/prototype.js +0 -69
- package/package.json +1 -1
- package/rhemyn/README.md +7 -4
- package/rhemyn/compile.js +170 -76
- package/runner/index.js +3 -2
- package/runner/repl.js +1 -2
- package/runner/version.js +0 -12
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
|
@@ -1026,12 +1029,13 @@ const asmFuncToAsm = (func, scope) => {
|
|
1026
1029
|
idx = funcIndex[n];
|
1027
1030
|
}
|
1028
1031
|
|
1032
|
+
if (idx == null) throw new Error(`builtin('${n}') failed to find a func (inside ${scope.name})`);
|
1029
1033
|
return idx;
|
1030
1034
|
}
|
1031
1035
|
});
|
1032
1036
|
};
|
1033
1037
|
|
1034
|
-
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 }) => {
|
1035
1039
|
const existing = funcs.find(x => x.name === name);
|
1036
1040
|
if (existing) return existing;
|
1037
1041
|
|
@@ -1058,13 +1062,17 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1058
1062
|
returnType,
|
1059
1063
|
internal: true,
|
1060
1064
|
index: currentFuncIndex++,
|
1061
|
-
table
|
1065
|
+
table,
|
1066
|
+
constr
|
1062
1067
|
};
|
1063
1068
|
|
1064
1069
|
funcs.push(func);
|
1065
1070
|
funcIndex[name] = func.index;
|
1066
1071
|
|
1067
|
-
if (typeof wasm === 'function')
|
1072
|
+
if (typeof wasm === 'function') {
|
1073
|
+
if (globalThis.precompile) wasm = [];
|
1074
|
+
else wasm = asmFuncToAsm(wasm, func);
|
1075
|
+
}
|
1068
1076
|
|
1069
1077
|
let baseGlobalIdx, i = 0;
|
1070
1078
|
for (const type of globalTypes) {
|
@@ -1085,15 +1093,35 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1085
1093
|
|
1086
1094
|
if (table) {
|
1087
1095
|
for (const inst of wasm) {
|
1088
|
-
if (inst
|
1096
|
+
if (inst.at(-1) === 'read func lut') {
|
1089
1097
|
inst.splice(2, 99);
|
1090
|
-
inst.push(...unsignedLEB128(allocPage({}, 'func
|
1098
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func lut') * pageSize));
|
1091
1099
|
}
|
1092
1100
|
}
|
1093
1101
|
|
1094
1102
|
funcs.table = true;
|
1095
1103
|
}
|
1096
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
|
+
|
1097
1125
|
func.wasm = wasm;
|
1098
1126
|
|
1099
1127
|
return func;
|
@@ -1220,20 +1248,7 @@ const getNodeType = (scope, node) => {
|
|
1220
1248
|
return TYPES.number;
|
1221
1249
|
}
|
1222
1250
|
|
1223
|
-
if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
|
1224
|
-
if (builtinFuncs[name + '$constructor'].typedReturns) {
|
1225
|
-
if (scope.locals['#last_type']) return getLastType(scope);
|
1226
|
-
|
1227
|
-
// presume
|
1228
|
-
// todo: warn here?
|
1229
|
-
return TYPES.number;
|
1230
|
-
}
|
1231
|
-
|
1232
|
-
return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
|
1233
|
-
}
|
1234
|
-
|
1235
1251
|
const func = funcs.find(x => x.name === name);
|
1236
|
-
|
1237
1252
|
if (func) {
|
1238
1253
|
if (func.returnType != null) return func.returnType;
|
1239
1254
|
}
|
@@ -1420,9 +1435,9 @@ const countLeftover = wasm => {
|
|
1420
1435
|
|
1421
1436
|
if (depth === 0)
|
1422
1437
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1423
|
-
else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
|
1438
|
+
else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.f32_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
|
1424
1439
|
else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
|
1425
|
-
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1440
|
+
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.f32_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1426
1441
|
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1427
1442
|
else if (inst[0] === Opcodes.return) count = 0;
|
1428
1443
|
else if (inst[0] === Opcodes.call) {
|
@@ -1531,7 +1546,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1531
1546
|
name = func.name;
|
1532
1547
|
}
|
1533
1548
|
|
1534
|
-
if (name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1549
|
+
if (!decl._new && name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1535
1550
|
// literal eval hack
|
1536
1551
|
const code = decl.arguments[0]?.value ?? '';
|
1537
1552
|
|
@@ -1574,7 +1589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1574
1589
|
|
1575
1590
|
let protoName, target;
|
1576
1591
|
// ident.func()
|
1577
|
-
if (name && name.startsWith('__')) {
|
1592
|
+
if (!decl._new && name && name.startsWith('__')) {
|
1578
1593
|
const spl = name.slice(2).split('_');
|
1579
1594
|
|
1580
1595
|
protoName = spl[spl.length - 1];
|
@@ -1587,12 +1602,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1587
1602
|
}
|
1588
1603
|
|
1589
1604
|
// literal.func()
|
1590
|
-
if (!name && decl.callee.type === 'MemberExpression') {
|
1605
|
+
if (!decl._new && !name && decl.callee.type === 'MemberExpression') {
|
1591
1606
|
// megahack for /regex/.func()
|
1592
1607
|
const funcName = decl.callee.property.name;
|
1593
|
-
if (decl.callee.object.regex &&
|
1608
|
+
if (decl.callee.object.regex && ['test'].includes(funcName)) {
|
1594
1609
|
const regex = decl.callee.object.regex.pattern;
|
1595
|
-
const rhemynName = `regex_${funcName}_${regex}`;
|
1610
|
+
const rhemynName = `regex_${funcName}_${sanitize(regex)}`;
|
1596
1611
|
|
1597
1612
|
if (!funcIndex[rhemynName]) {
|
1598
1613
|
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
@@ -1613,7 +1628,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1613
1628
|
[ Opcodes.call, idx ],
|
1614
1629
|
Opcodes.i32_from_u,
|
1615
1630
|
|
1616
|
-
...setLastType(scope,
|
1631
|
+
...setLastType(scope, Rhemyn.types[funcName])
|
1617
1632
|
];
|
1618
1633
|
}
|
1619
1634
|
|
@@ -1622,27 +1637,56 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1622
1637
|
target = decl.callee.object;
|
1623
1638
|
}
|
1624
1639
|
|
1625
|
-
|
1626
|
-
|
1640
|
+
let out = [];
|
1641
|
+
if (protoName) {
|
1642
|
+
if (['search'].includes(protoName)) {
|
1643
|
+
const regex = decl.arguments[0]?.regex?.pattern;
|
1644
|
+
if (!regex) return [
|
1645
|
+
// no/bad regex arg, return -1/0 for now
|
1646
|
+
...generate(scope, target),
|
1647
|
+
[ Opcodes.drop ],
|
1627
1648
|
|
1628
|
-
|
1629
|
-
|
1649
|
+
...number(Rhemyn.types[protoName] === TYPES.number ? -1 : 0),
|
1650
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1651
|
+
];
|
1630
1652
|
|
1631
|
-
|
1632
|
-
// generate(scope, decl.callee.object)
|
1653
|
+
const rhemynName = `regex_${protoName}_${sanitize(regex)}`;
|
1633
1654
|
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
// ];
|
1638
|
-
// }
|
1655
|
+
if (!funcIndex[rhemynName]) {
|
1656
|
+
const func = Rhemyn[protoName](regex, currentFuncIndex++, rhemynName);
|
1657
|
+
func.internal = true;
|
1639
1658
|
|
1640
|
-
|
1641
|
-
|
1659
|
+
funcIndex[func.name] = func.index;
|
1660
|
+
funcs.push(func);
|
1661
|
+
}
|
1662
|
+
|
1663
|
+
const idx = funcIndex[rhemynName];
|
1664
|
+
return [
|
1665
|
+
// make string arg
|
1666
|
+
...generate(scope, target),
|
1667
|
+
Opcodes.i32_to_u,
|
1668
|
+
...getNodeType(scope, target),
|
1669
|
+
|
1670
|
+
// call regex func
|
1671
|
+
[ Opcodes.call, idx ],
|
1672
|
+
Opcodes.i32_from,
|
1673
|
+
|
1674
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1675
|
+
];
|
1676
|
+
}
|
1642
1677
|
|
1678
|
+
const protoBC = {};
|
1643
1679
|
const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
|
1644
1680
|
|
1645
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
|
+
|
1646
1690
|
for (const x of builtinProtoCands) {
|
1647
1691
|
const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
|
1648
1692
|
if (type == null) continue;
|
@@ -1652,7 +1696,14 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1652
1696
|
type: 'Identifier',
|
1653
1697
|
name: x
|
1654
1698
|
},
|
1655
|
-
arguments: [
|
1699
|
+
arguments: [
|
1700
|
+
{
|
1701
|
+
type: 'Identifier',
|
1702
|
+
name: '#proto_target'
|
1703
|
+
},
|
1704
|
+
|
1705
|
+
...decl.arguments
|
1706
|
+
],
|
1656
1707
|
_protoInternalCall: true
|
1657
1708
|
});
|
1658
1709
|
}
|
@@ -1746,29 +1797,37 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1746
1797
|
}
|
1747
1798
|
|
1748
1799
|
if (Object.keys(protoBC).length > 0) {
|
1749
|
-
return
|
1750
|
-
...
|
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,
|
1751
1805
|
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
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
|
+
];
|
1755
1810
|
}
|
1756
1811
|
}
|
1757
1812
|
|
1758
|
-
// TODO: only allows callee as
|
1759
|
-
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})`);
|
1760
1815
|
|
1761
1816
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1762
1817
|
if (idx === undefined && builtinFuncs[name]) {
|
1763
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);
|
1764
1820
|
|
1765
1821
|
includeBuiltin(scope, name);
|
1766
1822
|
idx = funcIndex[name];
|
1767
1823
|
}
|
1768
1824
|
|
1769
|
-
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
|
+
}
|
1770
1829
|
|
1771
|
-
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1830
|
+
if (idx === undefined && !decl._new && name.startsWith('__Porffor_wasm_')) {
|
1772
1831
|
const wasmOps = {
|
1773
1832
|
// pointer, align, offset
|
1774
1833
|
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
@@ -1823,7 +1882,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1823
1882
|
|
1824
1883
|
const indirectMode = Prefs.indirectCallMode ?? 'vararg';
|
1825
1884
|
// options: vararg, strict
|
1826
|
-
// - strict: simpler, smaller size usage, no func
|
1885
|
+
// - strict: simpler, smaller size usage, no func lut needed.
|
1827
1886
|
// ONLY works when arg count of call == arg count of function being called
|
1828
1887
|
// - vararg: large size usage, cursed.
|
1829
1888
|
// works when arg count of call != arg count of function being called*
|
@@ -1833,8 +1892,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1833
1892
|
scope.table = true;
|
1834
1893
|
|
1835
1894
|
let args = decl.arguments;
|
1836
|
-
let out = [];
|
1837
|
-
|
1838
1895
|
let locals = [];
|
1839
1896
|
|
1840
1897
|
if (indirectMode === 'vararg') {
|
@@ -1898,24 +1955,67 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1898
1955
|
// *for argc 0-3, in future (todo:) the max number should be
|
1899
1956
|
// dynamically changed to the max argc of any func in the js file.
|
1900
1957
|
|
1901
|
-
const funcLocal = localTmp(scope,
|
1958
|
+
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
1959
|
+
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
1902
1960
|
|
1903
1961
|
const gen = argc => {
|
1904
|
-
const
|
1962
|
+
const argsOut = [];
|
1905
1963
|
for (let i = 0; i < argc; i++) {
|
1906
|
-
|
1964
|
+
argsOut.push(
|
1907
1965
|
[ Opcodes.local_get, locals[i][0] ],
|
1908
1966
|
[ Opcodes.local_get, locals[i][1] ]
|
1909
1967
|
);
|
1910
1968
|
}
|
1911
1969
|
|
1912
|
-
|
1913
|
-
[ Opcodes.local_get,
|
1914
|
-
|
1915
|
-
|
1916
|
-
|
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
|
+
];
|
1917
1980
|
|
1918
|
-
|
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
|
+
);
|
1919
2019
|
};
|
1920
2020
|
|
1921
2021
|
const tableBc = {};
|
@@ -1933,13 +2033,32 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1933
2033
|
Opcodes.i32_to_u,
|
1934
2034
|
[ Opcodes.local_set, funcLocal ],
|
1935
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
|
+
|
1936
2056
|
...brTable([
|
1937
2057
|
// get argc of func we are calling
|
1938
2058
|
[ Opcodes.local_get, funcLocal ],
|
1939
|
-
...number(
|
2059
|
+
...number(3, Valtype.i32),
|
1940
2060
|
[ Opcodes.i32_mul ],
|
1941
|
-
|
1942
|
-
[ 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' ]
|
1943
2062
|
], tableBc, valtypeBinary)
|
1944
2063
|
],
|
1945
2064
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
@@ -1953,14 +2072,35 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1953
2072
|
const userFunc = func && !func.internal;
|
1954
2073
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1955
2074
|
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1956
|
-
|
1957
|
-
|
1958
|
-
let
|
1959
|
-
if (func &&
|
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);
|
2085
|
+
|
2086
|
+
let args = [...decl.arguments];
|
2087
|
+
if (func && !func.hasRestArgument && args.length < paramCount) {
|
1960
2088
|
// too little args, push undefineds
|
1961
2089
|
args = args.concat(new Array(paramCount - args.length).fill(DEFAULT_VALUE));
|
1962
2090
|
}
|
1963
2091
|
|
2092
|
+
if (func && func.hasRestArgument) {
|
2093
|
+
if (args.length < paramCount) {
|
2094
|
+
args = args.concat(new Array(paramCount - 1 - args.length).fill(DEFAULT_VALUE));
|
2095
|
+
}
|
2096
|
+
const restArgs = args.slice(paramCount - 1);
|
2097
|
+
args = args.slice(0, paramCount - 1);
|
2098
|
+
args.push({
|
2099
|
+
type: 'ArrayExpression',
|
2100
|
+
elements: restArgs
|
2101
|
+
})
|
2102
|
+
}
|
2103
|
+
|
1964
2104
|
if (func && args.length > paramCount) {
|
1965
2105
|
// too many args, slice extras off
|
1966
2106
|
args = args.slice(0, paramCount);
|
@@ -1968,7 +2108,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1968
2108
|
|
1969
2109
|
if (func && func.throws) scope.throws = true;
|
1970
2110
|
|
1971
|
-
let out = [];
|
1972
2111
|
for (let i = 0; i < args.length; i++) {
|
1973
2112
|
const arg = args[i];
|
1974
2113
|
out = out.concat(generate(scope, arg));
|
@@ -1981,13 +2120,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1981
2120
|
}
|
1982
2121
|
|
1983
2122
|
if (valtypeBinary !== Valtype.i32 &&
|
1984
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2123
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1985
2124
|
) {
|
1986
2125
|
out.push(Opcodes.i32_to);
|
1987
2126
|
}
|
1988
2127
|
|
1989
2128
|
if (valtypeBinary === Valtype.i32 &&
|
1990
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
2129
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.f64)
|
1991
2130
|
) {
|
1992
2131
|
out.push([ Opcodes.f64_convert_i32_s ]);
|
1993
2132
|
}
|
@@ -2020,32 +2159,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2020
2159
|
return out;
|
2021
2160
|
};
|
2022
2161
|
|
2023
|
-
const generateNew = (scope, decl, _global, _name) => {
|
2024
|
-
|
2025
|
-
|
2026
|
-
|
2027
|
-
if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
|
2028
|
-
|
2029
|
-
if (builtinFuncs[name + '$constructor']) {
|
2030
|
-
// custom ...$constructor override builtin func
|
2031
|
-
return generateCall(scope, {
|
2032
|
-
...decl,
|
2033
|
-
callee: {
|
2034
|
-
type: 'Identifier',
|
2035
|
-
name: name + '$constructor'
|
2036
|
-
}
|
2037
|
-
}, _global, _name);
|
2038
|
-
}
|
2039
|
-
|
2040
|
-
if (
|
2041
|
-
(builtinFuncs[name] && !builtinFuncs[name].constr) ||
|
2042
|
-
(internalConstrs[name] && builtinFuncs[name].notConstr)
|
2043
|
-
) return internalThrow(scope, 'TypeError', `${name} is not a constructor`, true);
|
2044
|
-
|
2045
|
-
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)})`);
|
2046
|
-
|
2047
|
-
return generateCall(scope, decl, _global, _name);
|
2048
|
-
};
|
2162
|
+
const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
|
2163
|
+
...decl,
|
2164
|
+
_new: true
|
2165
|
+
}, _global, _name);
|
2049
2166
|
|
2050
2167
|
// bad hack for undefined and null working without additional logic
|
2051
2168
|
const DEFAULT_VALUE = {
|
@@ -2053,6 +2170,16 @@ const DEFAULT_VALUE = {
|
|
2053
2170
|
name: 'undefined'
|
2054
2171
|
};
|
2055
2172
|
|
2173
|
+
const codeToSanitizedStr = code => {
|
2174
|
+
let out = '';
|
2175
|
+
while (code > 0) {
|
2176
|
+
out += String.fromCharCode(97 + code % 26);
|
2177
|
+
code -= 26;
|
2178
|
+
}
|
2179
|
+
return out;
|
2180
|
+
};
|
2181
|
+
const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => codeToSanitizedStr(_.charCodeAt(0)));
|
2182
|
+
|
2056
2183
|
const unhackName = name => {
|
2057
2184
|
if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
|
2058
2185
|
return name;
|
@@ -2288,9 +2415,120 @@ const generateVar = (scope, decl) => {
|
|
2288
2415
|
const global = topLevel || decl._bare;
|
2289
2416
|
|
2290
2417
|
for (const x of decl.declarations) {
|
2291
|
-
|
2418
|
+
if (x.id.type === 'ArrayPattern') {
|
2419
|
+
const decls = [];
|
2420
|
+
const tmpName = '#destructure' + randId();
|
2421
|
+
|
2422
|
+
let i = 0;
|
2423
|
+
const elements = [...x.id.elements];
|
2424
|
+
for (const e of elements) {
|
2425
|
+
switch (e?.type) {
|
2426
|
+
case 'RestElement': { // let [ ...foo ] = []
|
2427
|
+
if (e.argument.type === 'ArrayPattern') {
|
2428
|
+
// let [ ...[a, b, c] ] = []
|
2429
|
+
elements.push(...e.argument.elements);
|
2430
|
+
} else {
|
2431
|
+
decls.push({
|
2432
|
+
type: 'VariableDeclarator',
|
2433
|
+
id: { type: 'Identifier', name: e.argument.name },
|
2434
|
+
init: {
|
2435
|
+
type: 'CallExpression',
|
2436
|
+
callee: {
|
2437
|
+
type: 'Identifier',
|
2438
|
+
name: '__Array_prototype_slice'
|
2439
|
+
},
|
2440
|
+
arguments: [
|
2441
|
+
{ type: 'Identifier', name: tmpName },
|
2442
|
+
{ type: 'Literal', value: i },
|
2443
|
+
{
|
2444
|
+
type: 'MemberExpression',
|
2445
|
+
object: { type: 'Identifier', name: tmpName, },
|
2446
|
+
property: { type: 'Identifier', name: 'length', }
|
2447
|
+
}
|
2448
|
+
]
|
2449
|
+
}
|
2450
|
+
});
|
2451
|
+
}
|
2452
|
+
|
2453
|
+
continue; // skip i++
|
2454
|
+
}
|
2455
|
+
|
2456
|
+
case 'Identifier': { // let [ foo ] = []
|
2457
|
+
decls.push({
|
2458
|
+
type: 'VariableDeclarator',
|
2459
|
+
id: e,
|
2460
|
+
init: {
|
2461
|
+
type: 'MemberExpression',
|
2462
|
+
object: { type: 'Identifier', name: tmpName },
|
2463
|
+
property: { type: 'Literal', value: i }
|
2464
|
+
}
|
2465
|
+
});
|
2466
|
+
|
2467
|
+
break;
|
2468
|
+
}
|
2469
|
+
|
2470
|
+
case 'AssignmentPattern': { // let [ foo = defaultValue ] = []
|
2471
|
+
decls.push({
|
2472
|
+
type: 'VariableDeclarator',
|
2473
|
+
id: e.left,
|
2474
|
+
init: {
|
2475
|
+
type: 'LogicalExpression',
|
2476
|
+
operator: '??',
|
2477
|
+
left: {
|
2478
|
+
type: 'MemberExpression',
|
2479
|
+
object: { type: 'Identifier', name: tmpName },
|
2480
|
+
property: { type: 'Literal', value: i }
|
2481
|
+
},
|
2482
|
+
right: e.right
|
2483
|
+
}
|
2484
|
+
});
|
2485
|
+
|
2486
|
+
break;
|
2487
|
+
}
|
2488
|
+
|
2489
|
+
case 'ArrayPattern': { // let [ [ foo, bar ] ] = []
|
2490
|
+
decls.push({
|
2491
|
+
type: 'VariableDeclarator',
|
2492
|
+
id: e,
|
2493
|
+
init: {
|
2494
|
+
type: 'MemberExpression',
|
2495
|
+
object: { type: 'Identifier', name: tmpName },
|
2496
|
+
property: { type: 'Literal', value: i }
|
2497
|
+
}
|
2498
|
+
});
|
2499
|
+
|
2500
|
+
break;
|
2501
|
+
}
|
2502
|
+
|
2503
|
+
case 'ObjectPattern':
|
2504
|
+
return todo(scope, 'object destructuring is not supported yet')
|
2505
|
+
}
|
2292
2506
|
|
2293
|
-
|
2507
|
+
i++;
|
2508
|
+
}
|
2509
|
+
|
2510
|
+
out = out.concat([
|
2511
|
+
...generateVar(scope, {
|
2512
|
+
type: 'VariableDeclaration',
|
2513
|
+
declarations: [{
|
2514
|
+
type: 'VariableDeclarator',
|
2515
|
+
id: { type: 'Identifier', name: tmpName },
|
2516
|
+
init: x.init
|
2517
|
+
}],
|
2518
|
+
kind: decl.kind
|
2519
|
+
}),
|
2520
|
+
...generateVar(scope, {
|
2521
|
+
type: 'VariableDeclaration',
|
2522
|
+
declarations: decls,
|
2523
|
+
kind: decl.kind
|
2524
|
+
})
|
2525
|
+
]);
|
2526
|
+
|
2527
|
+
continue;
|
2528
|
+
}
|
2529
|
+
|
2530
|
+
const name = mapName(x.id.name);
|
2531
|
+
if (!name) return todo(scope, 'object destructuring is not supported yet')
|
2294
2532
|
|
2295
2533
|
if (x.init && isFuncType(x.init.type)) {
|
2296
2534
|
// hack for let a = function () { ... }
|
@@ -2325,7 +2563,9 @@ const generateVar = (scope, decl) => {
|
|
2325
2563
|
// hack to set local as pointer before
|
2326
2564
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2327
2565
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
2328
|
-
generated.pop();
|
2566
|
+
// generated.pop();
|
2567
|
+
generated.push([ Opcodes.drop ]);
|
2568
|
+
|
2329
2569
|
out = out.concat(generated);
|
2330
2570
|
} else {
|
2331
2571
|
out = out.concat(generated);
|
@@ -2392,8 +2632,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2392
2632
|
|
2393
2633
|
// arr[i]
|
2394
2634
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2395
|
-
const newValueTmp = localTmp(scope, '
|
2396
|
-
const pointerTmp =
|
2635
|
+
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
2636
|
+
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
2397
2637
|
|
2398
2638
|
return [
|
2399
2639
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
@@ -2405,11 +2645,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2405
2645
|
...generate(scope, decl.left.property),
|
2406
2646
|
Opcodes.i32_to_u,
|
2407
2647
|
|
2408
|
-
// turn into byte offset by * valtypeSize
|
2648
|
+
// turn into byte offset by * valtypeSize + 1
|
2409
2649
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2410
2650
|
[ Opcodes.i32_mul ],
|
2411
2651
|
[ Opcodes.i32_add ],
|
2412
|
-
|
2652
|
+
[ Opcodes.local_tee, pointerTmp ],
|
2413
2653
|
|
2414
2654
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2415
2655
|
[ Opcodes.local_get, pointerTmp ],
|
@@ -2419,7 +2659,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2419
2659
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2420
2660
|
], getNodeType(scope, decl.right), false, name, true)),
|
2421
2661
|
[ Opcodes.local_tee, newValueTmp ],
|
2422
|
-
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2662
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
2663
|
+
|
2664
|
+
[ Opcodes.local_get, pointerTmp ],
|
2665
|
+
...getNodeType(scope, decl),
|
2666
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
2423
2667
|
],
|
2424
2668
|
|
2425
2669
|
...wrapBC({
|
@@ -2956,7 +3200,9 @@ const generateForOf = (scope, decl) => {
|
|
2956
3200
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2957
3201
|
// hack: this is naughty and will break things!
|
2958
3202
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2959
|
-
|
3203
|
+
|
3204
|
+
const known = knownType(scope, getNodeType(scope, decl.right));
|
3205
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
2960
3206
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2961
3207
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2962
3208
|
rawElements: new Array(0)
|
@@ -3004,6 +3250,7 @@ const generateForOf = (scope, decl) => {
|
|
3004
3250
|
[ Opcodes.end ],
|
3005
3251
|
[ Opcodes.end ]
|
3006
3252
|
],
|
3253
|
+
|
3007
3254
|
[TYPES.string]: [
|
3008
3255
|
...setType(scope, leftName, TYPES.string),
|
3009
3256
|
|
@@ -3112,6 +3359,7 @@ const generateForOf = (scope, decl) => {
|
|
3112
3359
|
[ Opcodes.end ],
|
3113
3360
|
[ Opcodes.end ]
|
3114
3361
|
],
|
3362
|
+
|
3115
3363
|
[TYPES.set]: [
|
3116
3364
|
[ Opcodes.loop, Blocktype.void ],
|
3117
3365
|
|
@@ -3150,7 +3398,106 @@ const generateForOf = (scope, decl) => {
|
|
3150
3398
|
[ Opcodes.end ],
|
3151
3399
|
[ Opcodes.end ]
|
3152
3400
|
],
|
3153
|
-
|
3401
|
+
|
3402
|
+
...wrapBC({
|
3403
|
+
[TYPES.uint8array]: [
|
3404
|
+
[ Opcodes.i32_add ],
|
3405
|
+
|
3406
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3407
|
+
Opcodes.i32_from_u
|
3408
|
+
],
|
3409
|
+
[TYPES.uint8clampedarray]: [
|
3410
|
+
[ Opcodes.i32_add ],
|
3411
|
+
|
3412
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3413
|
+
Opcodes.i32_from_u
|
3414
|
+
],
|
3415
|
+
[TYPES.int8array]: [
|
3416
|
+
[ Opcodes.i32_add ],
|
3417
|
+
|
3418
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3419
|
+
Opcodes.i32_from
|
3420
|
+
],
|
3421
|
+
[TYPES.uint16array]: [
|
3422
|
+
...number(2, Valtype.i32),
|
3423
|
+
[ Opcodes.i32_mul ],
|
3424
|
+
[ Opcodes.i32_add ],
|
3425
|
+
|
3426
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
3427
|
+
Opcodes.i32_from_u
|
3428
|
+
],
|
3429
|
+
[TYPES.int16array]: [
|
3430
|
+
...number(2, Valtype.i32),
|
3431
|
+
[ Opcodes.i32_mul ],
|
3432
|
+
[ Opcodes.i32_add ],
|
3433
|
+
|
3434
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
3435
|
+
Opcodes.i32_from
|
3436
|
+
],
|
3437
|
+
[TYPES.uint32array]: [
|
3438
|
+
...number(4, Valtype.i32),
|
3439
|
+
[ Opcodes.i32_mul ],
|
3440
|
+
[ Opcodes.i32_add ],
|
3441
|
+
|
3442
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3443
|
+
Opcodes.i32_from_u
|
3444
|
+
],
|
3445
|
+
[TYPES.int32array]: [
|
3446
|
+
...number(4, Valtype.i32),
|
3447
|
+
[ Opcodes.i32_mul ],
|
3448
|
+
[ Opcodes.i32_add ],
|
3449
|
+
|
3450
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3451
|
+
Opcodes.i32_from
|
3452
|
+
],
|
3453
|
+
[TYPES.float32array]: [
|
3454
|
+
...number(4, Valtype.i32),
|
3455
|
+
[ Opcodes.i32_mul ],
|
3456
|
+
[ Opcodes.i32_add ],
|
3457
|
+
|
3458
|
+
[ Opcodes.f32_load, 0, 4 ],
|
3459
|
+
[ Opcodes.f64_promote_f32 ]
|
3460
|
+
],
|
3461
|
+
[TYPES.float64array]: [
|
3462
|
+
...number(8, Valtype.i32),
|
3463
|
+
[ Opcodes.i32_mul ],
|
3464
|
+
[ Opcodes.i32_add ],
|
3465
|
+
|
3466
|
+
[ Opcodes.f64_load, 0, 4 ]
|
3467
|
+
],
|
3468
|
+
}, {
|
3469
|
+
prelude: [
|
3470
|
+
...setType(scope, leftName, TYPES.number),
|
3471
|
+
|
3472
|
+
[ Opcodes.loop, Blocktype.void ],
|
3473
|
+
|
3474
|
+
[ Opcodes.local_get, pointer ],
|
3475
|
+
[ Opcodes.local_get, counter ]
|
3476
|
+
],
|
3477
|
+
postlude: [
|
3478
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3479
|
+
|
3480
|
+
[ Opcodes.block, Blocktype.void ],
|
3481
|
+
[ Opcodes.block, Blocktype.void ],
|
3482
|
+
...generate(scope, decl.body),
|
3483
|
+
[ Opcodes.end ],
|
3484
|
+
|
3485
|
+
// increment counter by 1
|
3486
|
+
[ Opcodes.local_get, counter ],
|
3487
|
+
...number(1, Valtype.i32),
|
3488
|
+
[ Opcodes.i32_add ],
|
3489
|
+
[ Opcodes.local_tee, counter ],
|
3490
|
+
|
3491
|
+
// loop if counter != length
|
3492
|
+
[ Opcodes.local_get, length ],
|
3493
|
+
[ Opcodes.i32_ne ],
|
3494
|
+
[ Opcodes.br_if, 1 ],
|
3495
|
+
|
3496
|
+
[ Opcodes.end ],
|
3497
|
+
[ Opcodes.end ]
|
3498
|
+
]
|
3499
|
+
}),
|
3500
|
+
|
3154
3501
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
3155
3502
|
}, Blocktype.void));
|
3156
3503
|
|
@@ -3354,6 +3701,22 @@ const generateEmpty = (scope, decl) => {
|
|
3354
3701
|
return [];
|
3355
3702
|
};
|
3356
3703
|
|
3704
|
+
const generateMeta = (scope, decl) => {
|
3705
|
+
if (decl.meta.name !== 'new') return todo(scope, `meta property object ${decl.meta.name} is not supported yet`, true);
|
3706
|
+
|
3707
|
+
switch (`${decl.meta.name}.${decl.property.name}`) {
|
3708
|
+
case 'new.target': {
|
3709
|
+
scope.constr = true;
|
3710
|
+
|
3711
|
+
return [
|
3712
|
+
[ Opcodes.local_get, -1 ],
|
3713
|
+
Opcodes.i32_from_u,
|
3714
|
+
...setLastType(scope, TYPES.boolean)
|
3715
|
+
];
|
3716
|
+
}
|
3717
|
+
}
|
3718
|
+
};
|
3719
|
+
|
3357
3720
|
let pages = new Map();
|
3358
3721
|
const allocPage = (scope, reason, type) => {
|
3359
3722
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3706,20 +4069,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3706
4069
|
const func = funcs.find(x => x.name === name);
|
3707
4070
|
if (func) {
|
3708
4071
|
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3709
|
-
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
4072
|
+
return withType(scope, number(typedParams ? Math.floor(func.params.length / 2) : (func.constr ? (func.params.length - 1) : func.params.length)), TYPES.number);
|
3710
4073
|
}
|
3711
4074
|
|
3712
|
-
if (builtinFuncs[name
|
3713
|
-
const regularFunc = builtinFuncs[name];
|
3714
|
-
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3715
|
-
|
3716
|
-
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3717
|
-
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3718
|
-
|
3719
|
-
return withType(scope, number(Math.max(regularParams, constructorParams)), TYPES.number);
|
3720
|
-
}
|
3721
|
-
|
3722
|
-
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
|
4075
|
+
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);
|
3723
4076
|
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3724
4077
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3725
4078
|
|
@@ -3768,7 +4121,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3768
4121
|
}
|
3769
4122
|
|
3770
4123
|
// todo: generate this array procedurally during builtinFuncs creation
|
3771
|
-
if (['size', 'description'].includes(decl.property.name)) {
|
4124
|
+
if (['size', 'description', 'byteLength'].includes(decl.property.name)) {
|
3772
4125
|
const bc = {};
|
3773
4126
|
const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
|
3774
4127
|
|
@@ -3974,7 +4327,7 @@ const objectHack = node => {
|
|
3974
4327
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3975
4328
|
|
3976
4329
|
// if .name or .length, give up (hack within a hack!)
|
3977
|
-
if (['name', 'length', 'size', 'description'].includes(node.property.name)) {
|
4330
|
+
if (['name', 'length', 'size', 'description', 'byteLength'].includes(node.property.name)) {
|
3978
4331
|
node.object = objectHack(node.object);
|
3979
4332
|
return;
|
3980
4333
|
}
|
@@ -4027,8 +4380,8 @@ const generateFunc = (scope, decl) => {
|
|
4027
4380
|
|
4028
4381
|
if (typedInput && decl.returnType) {
|
4029
4382
|
const { type } = extractTypeAnnotation(decl.returnType);
|
4030
|
-
|
4031
|
-
if (type != null) {
|
4383
|
+
if (type != null && !Prefs.indirectCalls) {
|
4384
|
+
// if (type != null) {
|
4032
4385
|
func.returnType = type;
|
4033
4386
|
func.returns = [ valtypeBinary ];
|
4034
4387
|
}
|
@@ -4049,6 +4402,12 @@ const generateFunc = (scope, decl) => {
|
|
4049
4402
|
defaultValues[name] = x.right;
|
4050
4403
|
break;
|
4051
4404
|
}
|
4405
|
+
|
4406
|
+
case 'RestElement': {
|
4407
|
+
name = x.argument.name;
|
4408
|
+
func.hasRestArgument = true;
|
4409
|
+
break;
|
4410
|
+
}
|
4052
4411
|
}
|
4053
4412
|
|
4054
4413
|
// if (name == null) return todo('non-identifier args are not supported');
|