porffor 0.55.17 → 0.55.19

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.
@@ -136,7 +136,12 @@ const funcRef = func => {
136
136
  }
137
137
  }
138
138
 
139
- if (func.returns.length === 1) {
139
+ if (func.returns.length === 0) {
140
+ // add to stack if returns nothing
141
+ wasm.push(number(UNDEFINED));
142
+ }
143
+
144
+ if (func.returns.length < 2) {
140
145
  // add built-in returnType if only returns a value
141
146
  wasm.push(number(func.returnType ?? TYPES.number, Valtype.i32));
142
147
  }
@@ -353,6 +358,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
353
358
 
354
359
  return cacheAst(decl, [ number(UNDEFINED) ]);
355
360
 
361
+ case 'TSAsExpression':
362
+ return cacheAst(decl, generate(scope, decl.expression));
363
+
356
364
  default:
357
365
  // ignore typescript nodes
358
366
  if (decl.type.startsWith('TS') ||
@@ -497,7 +505,7 @@ const lookup = (scope, name, failEarly = false) => {
497
505
 
498
506
  if (failEarly) return null;
499
507
 
500
- return [ [ null, () => hoistLookup(scope, name), 1 ] ];
508
+ return [ [ null, () => hoistLookup(scope, name) ] ];
501
509
  }
502
510
 
503
511
  return [
@@ -539,12 +547,10 @@ const generateYield = (scope, decl) => {
539
547
  ...getNodeType(scope, arg),
540
548
 
541
549
  [ Opcodes.call, includeBuiltin(scope, scope.async ? '__Porffor_AsyncGenerator_yield' : '__Porffor_Generator_yield').index ],
542
- [ Opcodes.drop ],
543
- [ Opcodes.drop ],
544
550
 
545
551
  // return generator
546
552
  [ Opcodes.local_get, scope.locals['#generator_out'].idx ],
547
- number(scope.async ? TYPES.__porffor_asyncgenerator : TYPES.__porffor_generator, Valtype.i32),
553
+ ...(scope.returnType != null ? [] : [ number(scope.async ? TYPES.__porffor_asyncgenerator : TYPES.__porffor_generator, Valtype.i32) ]),
548
554
  [ Opcodes.return ],
549
555
 
550
556
  // use undefined as yield expression value
@@ -565,8 +571,9 @@ const generateReturn = (scope, decl) => {
565
571
  ...generate(scope, arg),
566
572
  ...getNodeType(scope, arg),
567
573
 
574
+ // return generator
568
575
  [ Opcodes.call, includeBuiltin(scope, scope.async ? '__Porffor_AsyncGenerator_return' : '__Porffor_Generator_return').index ],
569
- // returns generator
576
+ ...(scope.returnType != null ? [] : [ number(scope.async ? TYPES.__porffor_asyncgenerator : TYPES.__porffor_generator, Valtype.i32) ]),
570
577
  [ Opcodes.return ]
571
578
  ];
572
579
  }
@@ -581,16 +588,18 @@ const generateReturn = (scope, decl) => {
581
588
  number(TYPES.promise, Valtype.i32),
582
589
 
583
590
  [ Opcodes.call, includeBuiltin(scope, '__Porffor_promise_resolve').index ],
584
- [ Opcodes.drop ],
585
- [ Opcodes.drop ],
586
591
 
587
592
  // return promise
588
593
  [ Opcodes.local_get, scope.locals['#async_out_promise'].idx ],
589
- number(TYPES.promise, Valtype.i32),
594
+ ...(scope.returnType != null ? [] : [ number(TYPES.promise, Valtype.i32) ]),
590
595
  [ Opcodes.return ]
591
596
  ];
592
597
  }
593
598
 
599
+ if (scope.returns.length === 0) return [
600
+ [ Opcodes.return ]
601
+ ];
602
+
594
603
  if (
595
604
  scope.constr && // only do this in constructors
596
605
  !globalThis.precompile // skip in precompiled built-ins, we should not require this and handle it ourselves
@@ -650,7 +659,7 @@ const generateReturn = (scope, decl) => {
650
659
  ]),
651
660
 
652
661
  [ Opcodes.local_get, localTmp(scope, '#return') ],
653
- [ Opcodes.local_get, localTmp(scope, '#return#type', Valtype.i32) ],
662
+ ...(scope.returnType != null ? [] : [ [ Opcodes.local_get, localTmp(scope, '#return#type', Valtype.i32) ] ]),
654
663
  [ Opcodes.return ]
655
664
  ];
656
665
  }
@@ -757,8 +766,7 @@ const compareStrings = (scope, left, right, leftType, rightType, noConv = false)
757
766
  Opcodes.i32_to_u,
758
767
  ...rightType,
759
768
 
760
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_strcmp').index ],
761
- [ Opcodes.drop ]
769
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_strcmp').index ]
762
770
  ];
763
771
 
764
772
  return [
@@ -771,7 +779,6 @@ const compareStrings = (scope, left, right, leftType, rightType, noConv = false)
771
779
  ...rightType,
772
780
 
773
781
  [ Opcodes.call, includeBuiltin(scope, '__Porffor_compareStrings').index ],
774
- [ Opcodes.drop ],
775
782
 
776
783
  // convert valtype result to i32 as i32 output expected
777
784
  Opcodes.i32_trunc_sat_f64_u
@@ -997,6 +1004,18 @@ const performOp = (scope, op, left, right, leftType, rightType) => {
997
1004
  );
998
1005
  }
999
1006
 
1007
+ if (!eqOp && (knownLeft === TYPES.bigint || knownRight === TYPES.bigint) && !(knownLeft === TYPES.bigint && knownRight === TYPES.bigint)) {
1008
+ const unknownType = knownLeft === TYPES.bigint ? rightType : leftType;
1009
+ startOut.push(
1010
+ ...unknownType,
1011
+ number(TYPES.bigint, Valtype.i32),
1012
+ [ Opcodes.i32_ne ],
1013
+ [ Opcodes.if, Blocktype.void ],
1014
+ ...internalThrow(scope, 'TypeError', 'Cannot mix BigInts and non-BigInts in numeric expressions'),
1015
+ [ Opcodes.end ]
1016
+ );
1017
+ }
1018
+
1000
1019
  // todo: if equality op and an operand is undefined, return false
1001
1020
  // todo: niche null hell with 0
1002
1021
 
@@ -1211,7 +1230,7 @@ const generateBinaryExp = (scope, decl) => {
1211
1230
 
1212
1231
  const asmFuncToAsm = (scope, func) => {
1213
1232
  return func(scope, {
1214
- Valtype, Opcodes, TYPES, TYPE_NAMES, typeSwitch, makeString, internalThrow,
1233
+ Valtype, Opcodes, TYPES, TYPE_NAMES, usedTypes, typeSwitch, makeString, internalThrow,
1215
1234
  getNodeType, generate, generateIdent,
1216
1235
  builtin: (n, offset = false) => {
1217
1236
  let idx = funcIndex[n] ?? importedFuncs[n];
@@ -1282,7 +1301,7 @@ const asmFuncToAsm = (scope, func) => {
1282
1301
  return [ [ null, () => {
1283
1302
  if (types.some(x => usedTypes.has(x))) return wasm();
1284
1303
  return [];
1285
- }, 0 ] ];
1304
+ } ] ];
1286
1305
  }
1287
1306
  },
1288
1307
  i32ify: wasm => {
@@ -1432,7 +1451,11 @@ const setInferred = (scope, name, type, global = false) => {
1432
1451
  };
1433
1452
 
1434
1453
  const getType = (scope, name, failEarly = false) => {
1435
- const fallback = failEarly ? [ number(TYPES.undefined, Valtype.i32) ] : [ [ null, () => hoistLookupType(scope, name), 1 ] ];
1454
+ const fallback = failEarly ? [
1455
+ number(TYPES.undefined, Valtype.i32)
1456
+ ] : [
1457
+ [ null, () => hoistLookupType(scope, name) ]
1458
+ ];
1436
1459
 
1437
1460
  if (Object.hasOwn(builtinVars, name)) return [ number(builtinVars[name].type ?? TYPES.number, Valtype.i32) ];
1438
1461
 
@@ -1527,6 +1550,11 @@ const getNodeType = (scope, node) => {
1527
1550
  let guess = null;
1528
1551
  const ret = (() => {
1529
1552
  if (node._type) return node._type;
1553
+
1554
+ if (node.type === 'TSAsExpression') {
1555
+ return extractTypeAnnotation(node).type;
1556
+ }
1557
+
1530
1558
  if (node.type === 'Literal') {
1531
1559
  if (node.regex) return TYPES.regexp;
1532
1560
 
@@ -1549,7 +1577,7 @@ const getNodeType = (scope, node) => {
1549
1577
  }
1550
1578
 
1551
1579
  if (node.type === 'CallExpression' || node.type === 'NewExpression') {
1552
- const name = node.callee.name;
1580
+ let name = node.callee.name;
1553
1581
 
1554
1582
  // hack: special primitive object types
1555
1583
  if (node.type === 'NewExpression') {
@@ -1558,8 +1586,13 @@ const getNodeType = (scope, node) => {
1558
1586
  if (name === 'String') return TYPES.stringobject;
1559
1587
  }
1560
1588
 
1589
+ // hack: try reading from member if call
1590
+ if (name == null && node.callee.type === 'MemberExpression' && node.callee.property.name === 'call') {
1591
+ name = node.callee.object.name;
1592
+ }
1593
+
1561
1594
  if (name == null) {
1562
- // iife
1595
+ // unknown name
1563
1596
  return getLastType(scope);
1564
1597
  }
1565
1598
 
@@ -1568,7 +1601,7 @@ const getNodeType = (scope, node) => {
1568
1601
  if (func.returnType != null) return func.returnType;
1569
1602
  }
1570
1603
 
1571
- if (Object.hasOwn(builtinFuncs, name) && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
1604
+ if (Object.hasOwn(builtinFuncs, name) && builtinFuncs[name].returnType != null) return builtinFuncs[name].returnType;
1572
1605
  if (Object.hasOwn(internalConstrs, name) && internalConstrs[name].type != null) return internalConstrs[name].type;
1573
1606
 
1574
1607
  // check if this is a prototype function
@@ -1619,13 +1652,15 @@ const getNodeType = (scope, node) => {
1619
1652
 
1620
1653
  if (node.type === 'BinaryExpression') {
1621
1654
  if (['==', '===', '!=', '!==', '>', '>=', '<', '<=', 'instanceof', 'in'].includes(node.operator)) return TYPES.boolean;
1622
- if (node.operator !== '+') return TYPES.number;
1623
1655
 
1624
1656
  const leftType = getNodeType(scope, node.left);
1625
1657
  const rightType = getNodeType(scope, node.right);
1626
1658
  const knownLeft = knownTypeWithGuess(scope, leftType);
1627
1659
  const knownRight = knownTypeWithGuess(scope, rightType);
1628
1660
 
1661
+ if (knownLeft === TYPES.bigint || knownRight === TYPES.bigint) return TYPES.bigint;
1662
+ if (node.operator !== '+') return TYPES.number;
1663
+
1629
1664
  if ((knownLeft != null || knownRight != null) && !(
1630
1665
  (knownLeft === TYPES.string || knownRight === TYPES.string) ||
1631
1666
  (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) ||
@@ -1650,6 +1685,11 @@ const getNodeType = (scope, node) => {
1650
1685
  if (node.operator === 'delete') return TYPES.boolean;
1651
1686
  if (node.operator === 'typeof') return TYPES.bytestring;
1652
1687
 
1688
+ // todo: proper bigint support
1689
+ const type = getNodeType(scope, node.argument);
1690
+ const known = knownType(scope, type);
1691
+ if (known === TYPES.bigint) return TYPES.bigint;
1692
+
1653
1693
  return TYPES.number;
1654
1694
  }
1655
1695
 
@@ -1756,6 +1796,29 @@ const generateLiteral = (scope, decl, global, name) => {
1756
1796
  case 'string':
1757
1797
  return makeString(scope, decl.value);
1758
1798
 
1799
+ case 'bigint':
1800
+ let n = decl.value;
1801
+
1802
+ // inline if small enough
1803
+ if ((n < 0 ? -n : n) < 0x8000000000000n) {
1804
+ return [ number(Number(n)) ];
1805
+ }
1806
+
1807
+ // todo/opt: calculate and statically store digits
1808
+ return generate(scope, {
1809
+ type: 'CallExpression',
1810
+ callee: {
1811
+ type: 'Identifier',
1812
+ name: '__Porffor_bigint_fromString'
1813
+ },
1814
+ arguments: [
1815
+ {
1816
+ type: 'Literal',
1817
+ value: decl.value.toString()
1818
+ }
1819
+ ]
1820
+ });
1821
+
1759
1822
  default:
1760
1823
  return todo(scope, `cannot generate literal of type ${typeof decl.value}`, true);
1761
1824
  }
@@ -1816,14 +1879,6 @@ const ArrayUtil = {
1816
1879
  ]
1817
1880
  };
1818
1881
 
1819
- const getLastInst = wasm => {
1820
- for (let i = wasm.length - 1; i >= 0; i--) {
1821
- if (wasm[i]?.[0] != null) return wasm[i];
1822
- }
1823
-
1824
- return null;
1825
- };
1826
-
1827
1882
  const createNewTarget = (scope, decl, idx = 0, force = false) => {
1828
1883
  if (decl._new || force) {
1829
1884
  return [
@@ -1971,8 +2026,6 @@ const createThisArg = (scope, decl) => {
1971
2026
  number(TYPES.number, Valtype.i32),
1972
2027
 
1973
2028
  [ Opcodes.call, includeBuiltin(scope, '__Porffor_object_expr_initWithFlags').index ],
1974
- [ Opcodes.drop ],
1975
- [ Opcodes.drop ],
1976
2029
 
1977
2030
  [ Opcodes.local_get, tmp ],
1978
2031
  number(TYPES.object, Valtype.i32)
@@ -2083,14 +2136,15 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2083
2136
  }
2084
2137
 
2085
2138
  if (name === 'Function') {
2086
- const known = knownValue(scope, decl.arguments[0]);
2087
- if (known !== unknownValue) {
2088
- // new Function('with known/literal string')
2089
- const code = String(known);
2139
+ const knowns = decl.arguments.map(x => knownValue(scope, x));
2140
+ if (knowns.every(x => x !== unknownValue)) {
2141
+ // new Function('with known/literal strings')
2142
+ const code = String(knowns[knowns.length - 1]);
2143
+ const args = knowns.slice(0, -1).map(x => String(x));
2090
2144
 
2091
2145
  let parsed;
2092
2146
  try {
2093
- parsed = objectHack(parse(`(function(){${code}})`));
2147
+ parsed = objectHack(parse(`(function(${args.join(',')}){${code}})`));
2094
2148
  } catch (e) {
2095
2149
  if (e.name === 'SyntaxError') {
2096
2150
  // throw syntax errors of evals at runtime instead
@@ -2609,7 +2663,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2609
2663
 
2610
2664
  const userFunc = func && !func.internal;
2611
2665
  const typedParams = userFunc || func?.typedParams;
2612
- const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
2666
+ const typedReturns = func && func.returnType == null;
2613
2667
  let paramCount = countParams(func, name);
2614
2668
 
2615
2669
  let paramOffset = 0;
@@ -2709,17 +2763,19 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2709
2763
  // );
2710
2764
  } else out.push(...setLastType(scope));
2711
2765
 
2712
- if (builtinFuncs[name] && builtinFuncs[name].returns?.[0] === Valtype.i32 && valtypeBinary !== Valtype.i32) {
2713
- out.push(Opcodes.i32_from);
2766
+ if (
2767
+ func?.returns?.length === 0 ||
2768
+ (idx === importedFuncs[name] && importedFuncs[importedFuncs[name]]?.returns === 0)
2769
+ ) {
2770
+ out.push(number(UNDEFINED));
2714
2771
  }
2715
2772
 
2716
- if (builtinFuncs[name] && builtinFuncs[name].returns?.[0] === Valtype.f64 && valtypeBinary === Valtype.i32 && !globalThis.noi32F64CallConv) {
2717
- out.push(Opcodes.i32_trunc_sat_f64_s);
2773
+ if (func?.returns?.[0] === Valtype.i32 && valtypeBinary !== Valtype.i32) {
2774
+ out.push(Opcodes.i32_from);
2718
2775
  }
2719
2776
 
2720
- if ((builtinFuncs[name] && builtinFuncs[name].returns?.length === 0) ||
2721
- (idx === importedFuncs[name] && importedFuncs[importedFuncs[name]]?.returns === 0)) {
2722
- out.push(number(UNDEFINED));
2777
+ if (func?.returns?.[0] === Valtype.f64 && valtypeBinary === Valtype.i32 && !globalThis.noi32F64CallConv) {
2778
+ out.push(Opcodes.i32_trunc_sat_f64_s);
2723
2779
  }
2724
2780
 
2725
2781
  return out;
@@ -2756,7 +2812,7 @@ const generateThis = (scope, decl) => {
2756
2812
  [ Opcodes.local_set, scope.locals['#this#type'].idx ],
2757
2813
  [ Opcodes.end ]
2758
2814
  ];
2759
- }, 0 ],
2815
+ } ],
2760
2816
 
2761
2817
  [ Opcodes.local_get, scope.locals['#this'].idx ]
2762
2818
  ];
@@ -3038,7 +3094,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary, fallthrough = fals
3038
3094
  depth = oldDepth;
3039
3095
  }
3040
3096
  return out;
3041
- }, 0 ]);
3097
+ } ]);
3042
3098
  }
3043
3099
  }
3044
3100
  }
@@ -3143,6 +3199,7 @@ const extractTypeAnnotation = decl => {
3143
3199
  type = a.typeName.name;
3144
3200
  } else if (a.type.endsWith('Keyword')) {
3145
3201
  type = a.type.slice(2, -7).toLowerCase();
3202
+ if (type === 'void') type = 'undefined';
3146
3203
  } else if (a.type === 'TSArrayType') {
3147
3204
  type = 'array';
3148
3205
  elementType = extractTypeAnnotation(a.elementType).type;
@@ -4060,6 +4117,24 @@ const ifIdentifierErrors = (scope, decl) => {
4060
4117
  };
4061
4118
 
4062
4119
  const generateUnary = (scope, decl) => {
4120
+ const toNumeric = () => {
4121
+ // opt: skip if already known as number type
4122
+ generate(scope, decl.argument); // hack: fix last type not being defined for getNodeType before generation
4123
+ const known = knownType(scope, getNodeType(scope, decl.argument));
4124
+ if (known === TYPES.number) return generate(scope, decl.argument);
4125
+
4126
+ return generate(scope, {
4127
+ type: 'CallExpression',
4128
+ callee: {
4129
+ type: 'Identifier',
4130
+ name: '__ecma262_ToNumeric'
4131
+ },
4132
+ arguments: [
4133
+ decl.argument
4134
+ ]
4135
+ });
4136
+ };
4137
+
4063
4138
  switch (decl.operator) {
4064
4139
  case '+':
4065
4140
  // opt: skip ToNumber if already known as number type
@@ -4085,21 +4160,31 @@ const generateUnary = (scope, decl) => {
4085
4160
  case '-':
4086
4161
  // +x * -1
4087
4162
 
4088
- if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
4089
- // if -n, just return that as a const
4090
- return [ number(-1 * decl.argument.value) ];
4163
+ if (decl.prefix && decl.argument.type === 'Literal' && (typeof decl.argument.value === 'number' || typeof decl.argument.value === 'bigint')) {
4164
+ // if -n, just return that as a literal
4165
+ return generate(scope, {
4166
+ type: 'Literal',
4167
+ value: -decl.argument.value
4168
+ });
4091
4169
  }
4092
4170
 
4171
+ // todo: proper bigint support
4093
4172
  return [
4094
- ...generate(scope, {
4095
- type: 'UnaryExpression',
4096
- operator: '+',
4097
- prefix: true,
4098
- argument: decl.argument
4099
- }),
4173
+ ...toNumeric(),
4100
4174
  ...(valtype === 'f64' ? [ [ Opcodes.f64_neg ] ] : [ number(-1), [ Opcodes.mul ] ])
4101
4175
  ];
4102
4176
 
4177
+ case '~':
4178
+ // todo: proper bigint support
4179
+ return [
4180
+ ...toNumeric(),
4181
+ Opcodes.i32_to,
4182
+ [ Opcodes.i32_const, ...signedLEB128(-1) ],
4183
+ [ Opcodes.i32_xor ],
4184
+ Opcodes.i32_from
4185
+ ];
4186
+
4187
+
4103
4188
  case '!':
4104
4189
  const arg = decl.argument;
4105
4190
  if (arg.type === 'UnaryExpression' && arg.operator === '!') {
@@ -4110,20 +4195,6 @@ const generateUnary = (scope, decl) => {
4110
4195
  // !=
4111
4196
  return falsy(scope, generate(scope, arg), getNodeType(scope, arg), false, false);
4112
4197
 
4113
- case '~':
4114
- return [
4115
- ...generate(scope, {
4116
- type: 'UnaryExpression',
4117
- operator: '+',
4118
- prefix: true,
4119
- argument: decl.argument
4120
- }),
4121
- Opcodes.i32_to,
4122
- [ Opcodes.i32_const, ...signedLEB128(-1) ],
4123
- [ Opcodes.i32_xor ],
4124
- Opcodes.i32_from
4125
- ];
4126
-
4127
4198
  case 'void': {
4128
4199
  // drop current expression value after running, give undefined
4129
4200
  const out = generate(scope, decl.argument);
@@ -4155,7 +4226,6 @@ const generateUnary = (scope, decl) => {
4155
4226
  ...toPropertyKey(scope, generate(scope, property), getNodeType(scope, property), decl.argument.computed, true),
4156
4227
 
4157
4228
  [ Opcodes.call, includeBuiltin(scope, scope.strict ? '__Porffor_object_deleteStrict' : '__Porffor_object_delete').index ],
4158
- [ Opcodes.drop ],
4159
4229
  Opcodes.i32_from_u
4160
4230
  ];
4161
4231
 
@@ -5616,10 +5686,7 @@ const generateObject = (scope, decl, global = false, name = '$undeclared') => {
5616
5686
  ...(kind !== 'init' ? [ Opcodes.i32_to_u ] : []),
5617
5687
  ...getNodeType(scope, value),
5618
5688
 
5619
- [ Opcodes.call, includeBuiltin(scope, `__Porffor_object_expr_${kind}`).index ],
5620
-
5621
- [ Opcodes.drop ],
5622
- [ Opcodes.drop ]
5689
+ [ Opcodes.call, includeBuiltin(scope, `__Porffor_object_expr_${kind}`).index ]
5623
5690
  );
5624
5691
  }
5625
5692
  }
@@ -6264,10 +6331,7 @@ const generateClass = (scope, decl) => {
6264
6331
  ...(initKind !== 'value' && initKind !== 'method' ? [ Opcodes.i32_to_u ] : []),
6265
6332
  ...getNodeType(outScope, value),
6266
6333
 
6267
- [ Opcodes.call, includeBuiltin(outScope, `__Porffor_object_class_${initKind}`).index ],
6268
-
6269
- [ Opcodes.drop ],
6270
- [ Opcodes.drop ]
6334
+ [ Opcodes.call, includeBuiltin(outScope, `__Porffor_object_class_${initKind}`).index ]
6271
6335
  );
6272
6336
  }
6273
6337
 
@@ -6287,7 +6351,7 @@ const generateClass = (scope, decl) => {
6287
6351
  return out;
6288
6352
  };
6289
6353
 
6290
- export const generateTemplate = (scope, decl) => {
6354
+ const generateTemplate = (scope, decl) => {
6291
6355
  let current = null;
6292
6356
  const append = val => {
6293
6357
  if (!current) {
@@ -6575,9 +6639,10 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6575
6639
  number(0),
6576
6640
  number(TYPES.undefined, Valtype.i32),
6577
6641
  [ Opcodes.call, includeBuiltin(scope, '__Array_from').index ],
6642
+ [ Opcodes.local_set, func.locals[name].idx ],
6578
6643
 
6644
+ number(TYPES.array, Valtype.i32),
6579
6645
  [ Opcodes.local_set, func.locals[name].idx + 1 ],
6580
- [ Opcodes.local_set, func.locals[name].idx ],
6581
6646
  [ Opcodes.end ]
6582
6647
  );
6583
6648
  }
@@ -6664,9 +6729,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6664
6729
  // inject promise job runner func at the end of main if promises are made
6665
6730
  if (Object.hasOwn(funcIndex, 'Promise') || Object.hasOwn(funcIndex, '__Promise_resolve') || Object.hasOwn(funcIndex, '__Promise_reject')) {
6666
6731
  wasm.push(
6667
- [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ],
6668
- [ Opcodes.drop ],
6669
- [ Opcodes.drop ]
6732
+ [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ]
6670
6733
  );
6671
6734
  }
6672
6735
  } else {
@@ -6687,14 +6750,12 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6687
6750
  number(TYPES.array, Valtype.i32),
6688
6751
 
6689
6752
  [ Opcodes.call, includeBuiltin(func, func.async ? '__Porffor_AsyncGenerator' : '__Porffor_Generator').index ],
6690
- [ Opcodes.drop ],
6691
6753
  [ Opcodes.local_set, func.locals['#generator_out'].idx ]
6692
6754
  );
6693
6755
  } else if (func.async) {
6694
6756
  // make promise at the start
6695
6757
  wasm.unshift(
6696
6758
  [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_create').index ],
6697
- [ Opcodes.drop ],
6698
6759
  [ Opcodes.local_set, func.locals['#async_out_promise'].idx ],
6699
6760
 
6700
6761
  // wrap in try for later catch
@@ -6704,18 +6765,15 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6704
6765
  // reject with thrown value if caught error
6705
6766
  wasm.push(
6706
6767
  [ Opcodes.catch, 0 ],
6768
+ [ Opcodes.local_get, func.locals['#async_out_promise'].idx ],
6769
+ number(TYPES.promise, Valtype.i32),
6707
6770
 
6708
- [ Opcodes.local_get, func.locals['#async_out_promise'].idx ],
6709
- number(TYPES.promise, Valtype.i32),
6710
-
6711
- [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_reject').index ],
6712
- [ Opcodes.drop ],
6713
- [ Opcodes.drop ],
6771
+ [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_reject').index ],
6714
6772
  [ Opcodes.end ],
6715
6773
 
6716
6774
  // return promise at the end of func
6717
6775
  [ Opcodes.local_get, func.locals['#async_out_promise'].idx ],
6718
- number(TYPES.promise, Valtype.i32),
6776
+ ...(scope.returnType != null ? [] : [ number(TYPES.promise, Valtype.i32) ]),
6719
6777
  [ Opcodes.return ]
6720
6778
  );
6721
6779
 
@@ -6732,10 +6790,9 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6732
6790
 
6733
6791
  if (typedInput && decl.returnType) {
6734
6792
  const { type } = extractTypeAnnotation(decl.returnType);
6735
- if (type != null && !Prefs.indirectCalls) {
6736
- // if (type != null) {
6793
+ if (type != null) {
6737
6794
  func.returnType = type;
6738
- func.returns = [ valtypeBinary ];
6795
+ func.returns = func.returnType === TYPES.undefined && !func.async && !func.generator ? [] : [ valtypeBinary ];
6739
6796
  }
6740
6797
  }
6741
6798
 
@@ -7008,8 +7065,6 @@ export default program => {
7008
7065
  Opcodes.load = [ Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load ][valtypeInd];
7009
7066
  Opcodes.store = [ Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store ][valtypeInd];
7010
7067
 
7011
- Opcodes.lt = [ Opcodes.i32_lt_s, Opcodes.i64_lt_s, Opcodes.f64_lt ][valtypeInd];
7012
-
7013
7068
  builtinFuncs = new BuiltinFuncs();
7014
7069
  builtinVars = new BuiltinVars({ builtinFuncs });
7015
7070
  prototypeFuncs = new PrototypeFuncs();
@@ -17,11 +17,10 @@ globalThis.precompile = true;
17
17
  globalThis.valtypeOverrides = {
18
18
  returns: {
19
19
  __Porffor_object_get: [ Valtype.f64, Valtype.i32 ],
20
- __Porffor_object_getExplicit: [ Valtype.f64, Valtype.i32 ],
21
20
  __Porffor_object_readValue: [ Valtype.f64, Valtype.i32 ],
22
21
  __Porffor_object_set: [ Valtype.f64, Valtype.i32 ],
23
22
  __Porffor_object_setStrict: [ Valtype.f64, Valtype.i32 ],
24
- __Porffor_object_packAccessor: [ Valtype.f64, Valtype.i32 ]
23
+ __Porffor_object_packAccessor: [ Valtype.f64 ]
25
24
  },
26
25
  params: {
27
26
  __Porffor_object_set: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
@@ -209,10 +208,11 @@ const precompile = async () => {
209
208
  }
210
209
 
211
210
  const total = performance.now() - t;
212
- console.log(`\r${' '.repeat(80)}\r\u001b[2m${`[${total.toFixed(2)}ms]`.padEnd(12, ' ')}\u001b[0m\u001b[92mcompiled ${fileCount} files/${funcs.length} funcs\u001b[0m \u001b[90m(${['parse', 'codegen', 'opt'].map(x => `${x}: ${((timing[x] / total) * 100).toFixed(0)}%`).join(', ')})\u001b[0m`);
211
+ console.log(`\r${' '.repeat(80)}\r\u001b[2m${`[${total.toFixed(2)}ms]`.padEnd(12, ' ')}\u001b[0m\u001b[92mcompiled ${funcs.length} funcs from ${fileCount} files\u001b[0m \u001b[90m(${['parse', 'codegen', 'opt'].map(x => `${x}: ${((timing[x] / total) * 100).toFixed(0)}%`).join(', ')})\u001b[0m`);
213
212
 
214
213
  const comptimeFlagChecks = {
215
- hasFunc: x => `hasFunc('${x}')`
214
+ hasFunc: x => `hasFunc('${x}')`,
215
+ hasType: x => `usedTypes.has(${TYPES[x]})`
216
216
  };
217
217
 
218
218
  return `// autogenerated by compiler/precompile.js
@@ -243,10 +243,10 @@ ${funcs.map(x => {
243
243
  });
244
244
 
245
245
  const [ id, extra ] = flag.split('.');
246
- return `[null,()=>{if(${comptimeFlagChecks[id](extra)}){const r=()=>{valtype=Prefs.valtype??'f64';valtypeBinary=Valtype[valtype];const valtypeInd=['i32','i64','f64'].indexOf(valtype);Opcodes.i32_to=[[],[Opcodes.i32_wrap_i64],Opcodes.i32_trunc_sat_f64_s][valtypeInd];Opcodes.i32_to_u=[[],[Opcodes.i32_wrap_i64],Opcodes.i32_trunc_sat_f64_u][valtypeInd];Opcodes.i32_from=[[],[Opcodes.i64_extend_i32_s],[Opcodes.f64_convert_i32_s]][valtypeInd];Opcodes.i32_from_u=[[],[Opcodes.i64_extend_i32_u],[ Opcodes.f64_convert_i32_u]][valtypeInd]};const a=Prefs;Prefs=${prefs};r();const b=generate(_,${ast});Prefs=a;r();return b;}return []}]`;
246
+ return `[null,()=>{if(${comptimeFlagChecks[id](extra)}){const r=()=>{valtype=Prefs.valtype??'f64';valtypeBinary=Valtype[valtype];const valtypeInd=['i32','i64','f64'].indexOf(valtype);Opcodes.i32_to=[[],[Opcodes.i32_wrap_i64],Opcodes.i32_trunc_sat_f64_s][valtypeInd];Opcodes.i32_to_u=[[],[Opcodes.i32_wrap_i64],Opcodes.i32_trunc_sat_f64_u][valtypeInd];Opcodes.i32_from=[[],[Opcodes.i64_extend_i32_s],[Opcodes.f64_convert_i32_s]][valtypeInd];Opcodes.i32_from_u=[[],[Opcodes.i64_extend_i32_u],[ Opcodes.f64_convert_i32_u]][valtypeInd]};const a=Prefs;Prefs=${prefs};r();const b=generate(_,${ast}).slice(0,-1);Prefs=a;r();return b;}return []}]`;
247
247
  });
248
248
 
249
- return `(_,{${str.includes('hasFunc(') ? 'hasFunc,' : ''}${str.includes('Valtype[') ? 'Valtype,' : ''}${str.includes('i32ify') ? 'i32ify,' : ''}${str.includes('Opcodes.') ? 'Opcodes,' : ''}${str.includes('...t(') ? 't,' : ''}${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('makeString(') ? 'makeString,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('funcRef(') ? 'funcRef,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}${str.includes('generateIdent(') ? 'generateIdent,' : ''}${str.includes('generate(') ? 'generate,' : ''}`.slice(0, -1)}})=>`.replace('_,{}', '') + str;
249
+ return `(_,{${str.includes('usedTypes.') ? 'usedTypes,' : ''}${str.includes('hasFunc(') ? 'hasFunc,' : ''}${str.includes('Valtype[') ? 'Valtype,' : ''}${str.includes('i32ify') ? 'i32ify,' : ''}${str.includes('Opcodes.') ? 'Opcodes,' : ''}${str.includes('...t(') ? 't,' : ''}${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('makeString(') ? 'makeString,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('funcRef(') ? 'funcRef,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}${str.includes('generateIdent(') ? 'generateIdent,' : ''}${str.includes('generate(') ? 'generate,' : ''}`.slice(0, -1)}})=>`.replace('_,{}', '') + str;
250
250
  };
251
251
 
252
252
  const locals = Object.entries(x.locals).sort((a,b) => a[1].idx - b[1].idx)
@@ -258,7 +258,7 @@ ${funcs.map(x => {
258
258
 
259
259
  return `this${name} = {
260
260
  wasm:${rewriteWasm(x.wasm)},
261
- params:${JSON.stringify(x.params)},typedParams:1,returns:${JSON.stringify(x.returns)},${x.returnType != null ? `returnType:${JSON.stringify(x.returnType)}` : 'typedReturns:1'},
261
+ params:${JSON.stringify(x.params)},typedParams:1,returns:${JSON.stringify(x.returns)},${x.returnType != null ? `returnType:${JSON.stringify(x.returnType)},` : ''}
262
262
  locals:${JSON.stringify(locals.slice(x.params.length).map(x => x[1].type))},localNames:${JSON.stringify(locals.map(x => x[0]))},
263
263
  ${usedTypes.length > 0 ? `usedTypes:${JSON.stringify(usedTypes)},` : ''}
264
264
  ${x.globalInits ? `globalInits:{${Object.keys(x.globalInits).map(y => `${y}:${rewriteWasm(x.globalInits[y])}`).join(',')}},` : ''}${x.data && Object.keys(x.data).length > 0 ? `data:${JSON.stringify(x.data)},` : ''}
package/compiler/wrap.js CHANGED
@@ -336,11 +336,16 @@ ${flags & 0b0001 ? ` get func idx: ${get}
336
336
  }
337
337
 
338
338
  case TYPES.bigint: {
339
+ if (Math.abs(value) < 0x8000000000000) {
340
+ return BigInt(value);
341
+ }
342
+ value -= 0x8000000000000;
343
+
339
344
  const negative = read(Uint8Array, memory, value, 1)[0] !== 0;
340
345
  const len = read(Uint16Array, memory, value + 2, 1)[0];
341
346
  const digits = read(Uint32Array, memory, value + 4, len);
342
347
 
343
- console.log(digits);
348
+ if (Prefs.d) console.log(digits);
344
349
 
345
350
  let result = 0n;
346
351
  for (let i = 0; i < digits.length; i++) {
@@ -382,8 +387,8 @@ export default (source, module = undefined, customImports = {}, print = str => p
382
387
 
383
388
  const noAnsi = s => s && s.replace(/\u001b\[[0-9]+m/g, '');
384
389
  let longest = 0;
385
- for (let j = 0; j < disassemble.length; j++) {
386
- longest = Math.max(longest, noAnsi(disassemble[j])?.length ?? 0);
390
+ for (let j = 0; j < disasm.length; j++) {
391
+ longest = Math.max(longest, noAnsi(disasm[j])?.length ?? 0);
387
392
  }
388
393
 
389
394
  if (middleIndex != -1) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.55.17",
4
+ "version": "0.55.19",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/r.cjs CHANGED
@@ -1,3 +1,5 @@
1
+
2
+
1
3
  // let o = { set foo(x) { console.log('set foo', x); }, __proto__: { set bar(x) { console.log('set bar', x); } } };
2
4
 
3
5
  // o.foo = 1;
package/runner/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.55.17';
3
+ globalThis.version = '0.55.19';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {