porffor 0.55.36 → 0.56.1

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.
@@ -93,7 +93,7 @@ const funcRef = func => {
93
93
  }
94
94
 
95
95
  const wasm = [];
96
- const offset = func.constr ? 0 : 4;
96
+ const offset = func.constr ? 0 : (func.method ? 2 : 4);
97
97
  for (let i = 0; i < func.params.length; i++) {
98
98
  if (func.internal && func.name.includes('_prototype_') && i < 2) {
99
99
  // special case: use real this for prototype internals
@@ -456,7 +456,7 @@ const lookup = (scope, name, failEarly = false) => {
456
456
  // todo: not compliant
457
457
  let len = countLength(scope);
458
458
  const names = new Array(len);
459
- const off = scope.constr ? 4 : 0;
459
+ const off = scope.constr ? 4 : (scope.method ? 2 : 0);
460
460
  for (const x in scope.locals) {
461
461
  const i = scope.locals[x].idx - off;
462
462
  if (i >= 0 && i % 2 === 0 && i < len * 2) {
@@ -809,12 +809,23 @@ const compareStrings = (scope, left, right, leftType, rightType, noConv = false)
809
809
  };
810
810
 
811
811
  const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
812
+ const truthyMode = forceTruthyMode ?? Prefs.truthy ?? 'full';
812
813
  if (isIntToFloatOp(wasm[wasm.length - 1])) return [
813
814
  ...wasm,
814
- ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
815
+ ...(truthyMode === 'full' ? [
816
+ [ Opcodes.f64_const, 0 ],
817
+ [ Opcodes.f64_ne ],
818
+ ...(!intOut ? [ Opcodes.i32_from_u ] : [])
819
+ ] : [
820
+ ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
821
+ ])
815
822
  ];
816
823
  if (isIntOp(wasm[wasm.length - 1])) return [
817
824
  ...wasm,
825
+ ...(truthyMode === 'full' ? [
826
+ [ Opcodes.i32_eqz ],
827
+ [ Opcodes.i32_eqz ]
828
+ ] : []),
818
829
  ...(intOut ? [] : [ Opcodes.i32_from ]),
819
830
  ];
820
831
 
@@ -822,8 +833,6 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
822
833
 
823
834
  const useTmp = knownType(scope, type) == null;
824
835
  const tmp = useTmp && localTmp(scope, `#logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
825
-
826
- const truthyMode = forceTruthyMode ?? Prefs.truthy ?? 'full';
827
836
  const def = (() => {
828
837
  if (truthyMode === 'full') return [
829
838
  // if value != 0 or NaN
@@ -1059,21 +1068,9 @@ const performOp = (scope, op, left, right, leftType, rightType) => {
1059
1068
 
1060
1069
  let ops = operatorOpcode[valtype][op];
1061
1070
 
1062
- // some complex ops are implemented as builtin funcs
1063
- const builtinName = `${valtype}_${op}`;
1064
- if (!ops && builtinFuncs[builtinName]) {
1065
- includeBuiltin(scope, builtinName);
1066
- const idx = funcIndex[builtinName];
1067
-
1068
- return finalize([
1069
- ...left,
1070
- ...right,
1071
- [ Opcodes.call, idx ]
1072
- ]);
1073
- }
1074
-
1071
+ // some complex ops are implemented in funcs
1072
+ if (typeof ops === 'function') return finalize(asmFuncToAsm(scope, ops, { left, right }));
1075
1073
  if (!ops) return todo(scope, `operator ${op} not implemented yet`, true);
1076
-
1077
1074
  if (!Array.isArray(ops)) ops = [ ops ];
1078
1075
  ops = [ ops ];
1079
1076
 
@@ -1244,7 +1241,7 @@ const generateBinaryExp = (scope, decl) => {
1244
1241
  return out;
1245
1242
  };
1246
1243
 
1247
- const asmFuncToAsm = (scope, func) => {
1244
+ const asmFuncToAsm = (scope, func, extra) => {
1248
1245
  return func(scope, {
1249
1246
  Valtype, Opcodes, TYPES, TYPE_NAMES, usedTypes, typeSwitch, makeString, internalThrow,
1250
1247
  getNodeType, generate, generateIdent,
@@ -1325,7 +1322,7 @@ const asmFuncToAsm = (scope, func) => {
1325
1322
  return wasm;
1326
1323
  },
1327
1324
  allocPage: (scope, name) => allocPage({ scope, pages }, name)
1328
- });
1325
+ }, extra);
1329
1326
  };
1330
1327
 
1331
1328
  const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTypes = [], globals: globalTypes = [], globalInits = [], returns = [], returnType, localNames = [], globalNames = [], table = false, constr = false, hasRestArgument = false, usesTag = false, usesImports = false, usedTypes = [] } = {}) => {
@@ -1719,7 +1716,7 @@ const getNodeType = (scope, node) => {
1719
1716
 
1720
1717
  if (node.type === 'ThisExpression') {
1721
1718
  if (scope.overrideThisType) return scope.overrideThisType;
1722
- if (!scope.constr) return getType(scope, 'globalThis');
1719
+ if (!scope.constr && !scope.method) return getType(scope, 'globalThis');
1723
1720
  return [ [ Opcodes.local_get, scope.locals['#this#type'].idx ] ];
1724
1721
  }
1725
1722
 
@@ -2639,6 +2636,11 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2639
2636
  paramOffset += 4;
2640
2637
  }
2641
2638
 
2639
+ if (func && func.method) {
2640
+ out.push(...(decl._thisWasm ?? createThisArg(scope, decl)));
2641
+ paramOffset += 2;
2642
+ }
2643
+
2642
2644
  if (func && args.length < paramCount) {
2643
2645
  // too little args, push undefineds
2644
2646
  const underflow = paramCount - (func.hasRestArgument ? 1 : 0) - args.length;
@@ -2723,7 +2725,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2723
2725
  const generateThis = (scope, decl) => {
2724
2726
  if (scope.overrideThis) return scope.overrideThis;
2725
2727
 
2726
- if (!scope.constr) {
2728
+ if (!scope.constr && !scope.method) {
2727
2729
  // this in a non-constructor context is a reference to globalThis
2728
2730
  return [
2729
2731
  ...generate(scope, { type: 'Identifier', name: 'globalThis' })
@@ -5530,7 +5532,10 @@ const generateObject = (scope, decl, global = false, name = '$undeclared') => {
5530
5532
 
5531
5533
  for (const x of decl.properties) {
5532
5534
  // method, shorthand are made into useful values by parser for us :)
5533
- let { type, argument, computed, kind, value } = x;
5535
+ let { type, argument, computed, kind, value, method } = x;
5536
+
5537
+ // tag function as not a constructor
5538
+ if (method) value._method = true;
5534
5539
 
5535
5540
  if (type === 'SpreadElement') {
5536
5541
  out.push(
@@ -5623,6 +5628,7 @@ const countParams = (func, name = undefined) => {
5623
5628
  name ??= func.name;
5624
5629
  let params = func.params.length;
5625
5630
  if (func.constr) params -= 4;
5631
+ if (func.method) params -= 2;
5626
5632
  if (!func.internal || builtinFuncs[name]?.typedParams) params = Math.floor(params / 2);
5627
5633
 
5628
5634
  return func.argc = params;
@@ -6126,6 +6132,9 @@ const generateClass = (scope, decl) => {
6126
6132
  let { type, value, kind, static: _static, computed } = x;
6127
6133
  if (kind === 'constructor') continue;
6128
6134
 
6135
+ // tag function as not a constructor
6136
+ if (type === 'MethodDefinition') value._method = true;
6137
+
6129
6138
  if (type === 'StaticBlock') {
6130
6139
  // todo: make this more compliant
6131
6140
  out.push(
@@ -6451,7 +6460,8 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6451
6460
  name,
6452
6461
  index: currentFuncIndex++,
6453
6462
  arrow,
6454
- constr: !arrow && !decl.generator && !decl.async,
6463
+ constr: !arrow && !decl.generator && !decl.async && !decl._method, // constructable
6464
+ method: decl._method || decl.generator || decl.async, // has this but not constructable
6455
6465
  async: decl.async,
6456
6466
  subclass: decl._subclass, _onlyConstr: decl._onlyConstr, _onlyThisMethod: decl._onlyThisMethod,
6457
6467
  strict: scope.strict || decl.strict,
@@ -6682,6 +6692,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6682
6692
 
6683
6693
  const args = [];
6684
6694
  if (func.constr) args.push({ name: '#newtarget' }, { name: '#this' });
6695
+ if (func.method) args.push({ name: '#this' });
6685
6696
 
6686
6697
  let jsLength = 0;
6687
6698
  for (let i = 0; i < params.length; i++) {
@@ -6722,7 +6733,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6722
6733
  args.push({ name, def, destr, type: typedInput && params[i].typeAnnotation });
6723
6734
  }
6724
6735
 
6725
- func.params = new Array((params.length + (func.constr ? 2 : 0)) * 2).fill(0).map((_, i) => i % 2 ? Valtype.i32 : valtypeBinary);
6736
+ func.params = new Array((params.length + (func.constr ? 2 : (func.method ? 1 : 0))) * 2).fill(0).map((_, i) => i % 2 ? Valtype.i32 : valtypeBinary);
6726
6737
  func.jsLength = jsLength;
6727
6738
 
6728
6739
  // force generate for main
@@ -1,4 +1,14 @@
1
- import { Opcodes } from './wasmSpec.js';
1
+ import { Opcodes, Valtype } from './wasmSpec.js';
2
+ import { TYPES } from './types.js';
3
+
4
+ const f64ifyBitwise = op => (_1, _2, { left, right }) => [
5
+ ...left,
6
+ Opcodes.i32_trunc_sat_f64_s,
7
+ ...right,
8
+ Opcodes.i32_trunc_sat_f64_s,
9
+ [ op ],
10
+ [ Opcodes.f64_convert_i32_s ]
11
+ ];
2
12
 
3
13
  export const operatorOpcode = {
4
14
  i32: {
@@ -23,7 +33,17 @@ export const operatorOpcode = {
23
33
  '>': Opcodes.i32_gt_s,
24
34
  '>=': Opcodes.i32_ge_s,
25
35
  '<': Opcodes.i32_lt_s,
26
- '<=': Opcodes.i32_le_s
36
+ '<=': Opcodes.i32_le_s,
37
+
38
+ '**': (_, { builtin }, { left, right }) => [
39
+ ...left,
40
+ [ Opcodes.f64_convert_i32_s ],
41
+ [ Opcodes.i32_const, TYPES.number ],
42
+ ...right,
43
+ [ Opcodes.f64_convert_i32_s ],
44
+ [ Opcodes.i32_const, TYPES.number ],
45
+ [ Opcodes.call, builtin('__Math_pow') ]
46
+ ]
27
47
  },
28
48
 
29
49
  i64: {
@@ -65,6 +85,38 @@ export const operatorOpcode = {
65
85
  '>': Opcodes.f64_gt,
66
86
  '>=': Opcodes.f64_ge,
67
87
  '<': Opcodes.f64_lt,
68
- '<=': Opcodes.f64_le
88
+ '<=': Opcodes.f64_le,
89
+
90
+ '**': (_, { builtin }, { left, right }) => [
91
+ ...left,
92
+ [ Opcodes.i32_const, TYPES.number ],
93
+ ...right,
94
+ [ Opcodes.i32_const, TYPES.number ],
95
+ [ Opcodes.call, builtin('__Math_pow') ]
96
+ ],
97
+
98
+ '%': (_, { builtin, loc }, { left, right }) => [
99
+ // a - truncf(a / b) * b
100
+ ...left,
101
+ [ Opcodes.local_tee, loc('#math_a', Valtype.f64) ],
102
+ ...right,
103
+ [ Opcodes.local_tee, loc('#math_b', Valtype.f64) ],
104
+
105
+ [ Opcodes.local_get, loc('#math_a', Valtype.f64) ],
106
+ [ Opcodes.local_get, loc('#math_b', Valtype.f64) ],
107
+ [ Opcodes.f64_div ],
108
+ [ Opcodes.f64_trunc ],
109
+
110
+ [ Opcodes.f64_mul ],
111
+ [ Opcodes.f64_sub ]
112
+ ],
113
+
114
+ // add bitwise ops by converting operands to i32 first
115
+ '&': f64ifyBitwise(Opcodes.i32_and),
116
+ '|': f64ifyBitwise(Opcodes.i32_or),
117
+ '^': f64ifyBitwise(Opcodes.i32_xor),
118
+ '<<': f64ifyBitwise(Opcodes.i32_shl),
119
+ '>>': f64ifyBitwise(Opcodes.i32_shr_s),
120
+ '>>>': f64ifyBitwise(Opcodes.i32_shr_u)
69
121
  }
70
122
  };
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.36",
4
+ "version": "0.56.1",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/r.cjs CHANGED
@@ -1,8 +1,8 @@
1
- function* foo() {
2
- yield* [1, 2, 3];
3
- }
1
+ let obj = {
2
+ wow() {}
3
+ };
4
4
 
5
- console.log(foo().next());
5
+ console.log(obj.wow.prototype);
6
6
 
7
7
  // var EQUAL = 1;
8
8
  // var NOT_EQUAL = -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.36';
3
+ globalThis.version = '0.56.1';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {