porffor 0.55.35 → 0.56.0

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.
@@ -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
@@ -995,22 +1004,29 @@ const performOp = (scope, op, left, right, leftType, rightType) => {
995
1004
  const finalize = out => startOut.concat(out, endOut);
996
1005
 
997
1006
  // if strict (in)equal check types match, skip if known
998
- if (strictOp && !(knownLeft && knownLeft === knownRight)) {
999
- endOut.push(
1000
- ...leftType,
1001
- number(TYPE_FLAGS.parity, Valtype.i32),
1002
- [ Opcodes.i32_or ],
1003
- ...rightType,
1004
- number(TYPE_FLAGS.parity, Valtype.i32),
1005
- [ Opcodes.i32_or ],
1006
- ...(op === '===' ? [
1007
- [ Opcodes.i32_eq ],
1008
- [ Opcodes.i32_and ]
1009
- ] : [
1010
- [ Opcodes.i32_ne ],
1011
- [ Opcodes.i32_or ]
1012
- ])
1013
- );
1007
+ if (strictOp) {
1008
+ if (knownLeft != null && knownRight != null) {
1009
+ if ((knownLeft | TYPE_FLAGS.parity) !== (knownRight | TYPE_FLAGS.parity)) endOut.push(
1010
+ number(op === '===' ? 0 : 1, Valtype.i32),
1011
+ [ op === '===' ? Opcodes.i32_and : Opcodes.i32_or ]
1012
+ );
1013
+ } else {
1014
+ endOut.push(
1015
+ ...leftType,
1016
+ number(TYPE_FLAGS.parity, Valtype.i32),
1017
+ [ Opcodes.i32_or ],
1018
+ ...rightType,
1019
+ number(TYPE_FLAGS.parity, Valtype.i32),
1020
+ [ Opcodes.i32_or ],
1021
+ ...(op === '===' ? [
1022
+ [ Opcodes.i32_eq ],
1023
+ [ Opcodes.i32_and ]
1024
+ ] : [
1025
+ [ Opcodes.i32_ne ],
1026
+ [ Opcodes.i32_or ]
1027
+ ])
1028
+ );
1029
+ }
1014
1030
  }
1015
1031
 
1016
1032
  if (!eqOp && (knownLeft === TYPES.bigint || knownRight === TYPES.bigint) && !(knownLeft === TYPES.bigint && knownRight === TYPES.bigint)) {
@@ -1041,10 +1057,10 @@ const performOp = (scope, op, left, right, leftType, rightType) => {
1041
1057
 
1042
1058
  // string comparison
1043
1059
  if (op === '===' || op === '==' || op === '!==' || op === '!=') {
1044
- return [
1060
+ return finalize([
1045
1061
  ...compareStrings(scope, left, right, leftType, rightType, knownLeftStr && knownRightStr),
1046
1062
  ...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
1047
- ];
1063
+ ]);
1048
1064
  }
1049
1065
 
1050
1066
  // todo: proper >|>=|<|<=
@@ -1052,21 +1068,9 @@ const performOp = (scope, op, left, right, leftType, rightType) => {
1052
1068
 
1053
1069
  let ops = operatorOpcode[valtype][op];
1054
1070
 
1055
- // some complex ops are implemented as builtin funcs
1056
- const builtinName = `${valtype}_${op}`;
1057
- if (!ops && builtinFuncs[builtinName]) {
1058
- includeBuiltin(scope, builtinName);
1059
- const idx = funcIndex[builtinName];
1060
-
1061
- return finalize([
1062
- ...left,
1063
- ...right,
1064
- [ Opcodes.call, idx ]
1065
- ]);
1066
- }
1067
-
1071
+ // some complex ops are implemented in funcs
1072
+ if (typeof ops === 'function') return finalize(asmFuncToAsm(scope, ops, { left, right }));
1068
1073
  if (!ops) return todo(scope, `operator ${op} not implemented yet`, true);
1069
-
1070
1074
  if (!Array.isArray(ops)) ops = [ ops ];
1071
1075
  ops = [ ops ];
1072
1076
 
@@ -1237,7 +1241,7 @@ const generateBinaryExp = (scope, decl) => {
1237
1241
  return out;
1238
1242
  };
1239
1243
 
1240
- const asmFuncToAsm = (scope, func) => {
1244
+ const asmFuncToAsm = (scope, func, extra) => {
1241
1245
  return func(scope, {
1242
1246
  Valtype, Opcodes, TYPES, TYPE_NAMES, usedTypes, typeSwitch, makeString, internalThrow,
1243
1247
  getNodeType, generate, generateIdent,
@@ -1318,7 +1322,7 @@ const asmFuncToAsm = (scope, func) => {
1318
1322
  return wasm;
1319
1323
  },
1320
1324
  allocPage: (scope, name) => allocPage({ scope, pages }, name)
1321
- });
1325
+ }, extra);
1322
1326
  };
1323
1327
 
1324
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 = [] } = {}) => {
@@ -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.35",
4
+ "version": "0.56.0",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/r.cjs CHANGED
@@ -1,8 +1,107 @@
1
- function* foo() {
2
- yield* [1, 2, 3];
1
+ var assert = mustBeTrue => {
2
+ if (mustBeTrue === true) {
3
+ return;
4
+ }
5
+
6
+ throw new Test262Error('assert failed');
7
+ };
8
+
9
+ function isConfigurable(obj, name) {
10
+ if (Object.hasOwn(obj, name)) return Object.getOwnPropertyDescriptor(obj, name).configurable;
11
+ return true;
12
+ }
13
+
14
+ function isEnumerable(obj, name) {
15
+ return Object.hasOwn(obj, name) && Object.getOwnPropertyDescriptor(obj, name).enumerable;
16
+ }
17
+
18
+ function isSameValue(a, b) {
19
+ if (a === 0 && b === 0) return 1 / a === 1 / b;
20
+ if (a !== a && b !== b) return true;
21
+
22
+ return a === b;
23
+ }
24
+
25
+ function isWritable(obj, name, verifyProp, value) {
26
+ if (Object.hasOwn(obj, name) && Object.getOwnPropertyDescriptor(obj, name).writable != null) return Object.getOwnPropertyDescriptor(obj, name).writable;
27
+ if (!Object.hasOwn(obj, name) && Object.isExtensible(obj)) return true;
28
+
29
+ var unlikelyValue = Array.isArray(obj) && name === "length" ?
30
+ Math.pow(2, 32) - 1 :
31
+ "unlikelyValue";
32
+ var newValue = value || unlikelyValue;
33
+ var hadValue = Object.hasOwn(obj, name);
34
+ var oldValue = obj[name];
35
+ var writeSucceeded;
36
+
37
+ try {
38
+ obj[name] = newValue;
39
+ } catch {}
40
+
41
+ writeSucceeded = isSameValue(obj[verifyProp || name], newValue);
42
+
43
+ if (writeSucceeded) {
44
+ if (hadValue) {
45
+ obj[name] = oldValue;
46
+ } else {
47
+ delete obj[name];
48
+ }
49
+ }
50
+
51
+ return writeSucceeded;
3
52
  }
4
53
 
5
- console.log(foo().next());
54
+ function verifyProperty(obj, name, desc, options) {
55
+ var originalDesc = Object.getOwnPropertyDescriptor(obj, name);
56
+
57
+ if (desc === undefined) {
58
+ if (originalDesc !== undefined) {
59
+ throw new Test262Error('verifyProperty: expected undefined descriptor');
60
+ }
61
+
62
+ return true;
63
+ }
64
+
65
+ if (!Object.hasOwn(obj, name)) throw new Test262Error('verifyProperty: obj should have own property');
66
+
67
+ if (Object.hasOwn(desc, 'value')) {
68
+ const v = desc.value;
69
+ if (!isSameValue(originalDesc.value, v)) throw new Test262Error('verifyProperty: descriptor value mismatch');
70
+ // if (!isSameValue(obj[name], v)) throw new Test262Error('verifyProperty: object value mismatch');
71
+ }
72
+
73
+ if (Object.hasOwn(desc, 'enumerable')) {
74
+ if (desc.enumerable !== originalDesc.enumerable ||
75
+ desc.enumerable !== isEnumerable(obj, name)) {
76
+ throw new Test262Error('enumerable fail');
77
+ }
78
+ }
79
+
80
+ if (Object.hasOwn(desc, 'writable')) {
81
+ if (desc.writable !== originalDesc.writable ||
82
+ desc.writable !== isWritable(obj, name)) {
83
+ throw new Test262Error('writable fail');
84
+ }
85
+ }
86
+
87
+ if (Object.hasOwn(desc, 'configurable')) {
88
+ if (desc.configurable !== originalDesc.configurable ||
89
+ desc.configurable !== isConfigurable(obj, name)) {
90
+ throw new Test262Error('configurable fail');
91
+ }
92
+ }
93
+
94
+ if (options && options.restore) {
95
+ Object.defineProperty(obj, name, originalDesc);
96
+ }
97
+
98
+ return true;
99
+ }
100
+
101
+ const desc = { enumerable: true, configurable: true, writable: true };
102
+ const obj = Object.defineProperty({}, 'wow', desc);
103
+ assert(verifyProperty(obj, 'wow', desc));
104
+
6
105
 
7
106
  // var EQUAL = 1;
8
107
  // 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.35';
3
+ globalThis.version = '0.56.0';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {