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.
@@ -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
- // if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
299
- // includeBuiltin(scope, name);
300
- // return number(funcIndex[name] - importedFuncs.length);
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[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
1096
+ if (inst.at(-1) === 'read func lut') {
1093
1097
  inst.splice(2, 99);
1094
- inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
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: [ target, ...decl.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 typeSwitch(scope, getNodeType(scope, target), {
1774
- ...protoBC,
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
- // TODO: error better
1777
- default: internalThrow(scope, 'TypeError', `'${protoName}' proto func tried to be called on a type without an impl`)
1778
- }, valtypeBinary);
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 literal
1783
- if (!name) return todo(scope, `only literal callees (got ${decl.callee.type})`);
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]) return internalConstrs[name].generate(scope, decl, _global, _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 argc lut needed.
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, `#indirect_func`, Valtype.i32);
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 out = [];
1962
+ const argsOut = [];
1929
1963
  for (let i = 0; i < argc; i++) {
1930
- out.push(
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
- out.push(
1937
- [ Opcodes.local_get, funcLocal ],
1938
- [ Opcodes.call_indirect, argc, 0 ],
1939
- ...setLastType(scope)
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
- return out;
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(ValtypeSize.i16, Valtype.i32),
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
- const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
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
- // hack: basically treat this as a normal call for builtins for now
2049
- const name = mapName(decl.callee.name);
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, '__member_setter_val_tmp');
2430
- const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
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 (4 for i32, 8 for i64/f64)
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
- ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
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
- // if (type != null && !Prefs.indirectCalls) {
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
  }