porffor 0.55.18 → 0.55.20
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/compiler/builtins/bigint.ts +331 -0
- package/compiler/builtins/json.ts +5 -0
- package/compiler/builtins/number.ts +7 -2
- package/compiler/builtins/promise.ts +1 -1
- package/compiler/builtins/z_ecma262.ts +8 -3
- package/compiler/builtins_precompiled.js +526 -404
- package/compiler/codegen.js +91 -41
- package/compiler/precompile.js +4 -3
- package/compiler/wrap.js +19 -0
- package/package.json +1 -1
- package/r.cjs +1 -1
- package/runner/index.js +1 -1
@@ -0,0 +1,331 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
3
|
+
// digits is an array of u32s as digits in base 2^32
|
4
|
+
export const __Porffor_bigint_fromDigits = (negative: boolean, digits: i32[]): bigint => {
|
5
|
+
const len: i32 = digits.length;
|
6
|
+
if (len > 16383) throw new RangeError('Maximum BigInt size exceeded'); // (65536 - 4) / 4
|
7
|
+
|
8
|
+
// const ptr: i32 = Porffor.allocate();
|
9
|
+
let ptr: i32 = Porffor.wasm`local.get ${digits}`;
|
10
|
+
|
11
|
+
Porffor.wasm.i32.store8(ptr, negative ? 1 : 0, 0, 0);
|
12
|
+
Porffor.wasm.i32.store16(ptr, len, 0, 2);
|
13
|
+
|
14
|
+
let allZero: boolean = true;
|
15
|
+
for (let i: i32 = 0; i < len; i++) {
|
16
|
+
const d: i32 = digits[i];
|
17
|
+
if (d != 0) allZero = false;
|
18
|
+
|
19
|
+
Porffor.wasm.i32.store(ptr + i * 4, d, 0, 4);
|
20
|
+
}
|
21
|
+
|
22
|
+
if (allZero) {
|
23
|
+
// todo: free ptr
|
24
|
+
ptr = 0;
|
25
|
+
}
|
26
|
+
|
27
|
+
return (ptr + 0x8000000000000) as bigint;
|
28
|
+
};
|
29
|
+
|
30
|
+
// store small (abs(n) < 2^51 (0x8000000000000)) values inline (no allocation)
|
31
|
+
// like a ~s52 (s53 exc 2^51+(0-2^32) for u32 as pointer) inside a f64
|
32
|
+
export const __Porffor_bigint_inlineToDigitForm = (n: number): number => {
|
33
|
+
const ptr: i32 = Porffor.allocateBytes(4); // 4 meta + 1 digit
|
34
|
+
Porffor.wasm.i32.store8(ptr, n < 0, 0, 0);
|
35
|
+
Porffor.wasm.i32.store16(ptr, 1, 0, 2);
|
36
|
+
Porffor.wasm.i32.store(ptr, Math.abs(n), 0, 4);
|
37
|
+
|
38
|
+
return ptr;
|
39
|
+
};
|
40
|
+
|
41
|
+
|
42
|
+
export const __Porffor_bigint_fromNumber = (n: number): bigint => {
|
43
|
+
if (!Number.isInteger(n) || !Number.isFinite(n)) throw new RangeError('Cannot use non-integer as BigInt');
|
44
|
+
if (Math.abs(n) < 0x8000000000000) return n as bigint;
|
45
|
+
|
46
|
+
const negative: boolean = n < 0;
|
47
|
+
n = Math.abs(n);
|
48
|
+
|
49
|
+
const digits: i32[] = Porffor.allocate();
|
50
|
+
while (n > 0) {
|
51
|
+
digits.unshift(n % 0x100000000);
|
52
|
+
n = Math.trunc(n / 0x100000000);
|
53
|
+
}
|
54
|
+
|
55
|
+
return __Porffor_bigint_fromDigits(negative, digits);
|
56
|
+
};
|
57
|
+
|
58
|
+
export const __Porffor_bigint_toNumber = (x: number): number => {
|
59
|
+
if (Math.abs(x) < 0x8000000000000) return x as number;
|
60
|
+
x -= 0x8000000000000;
|
61
|
+
|
62
|
+
const negative: boolean = Porffor.wasm.i32.load8_u(x, 0, 0) != 0;
|
63
|
+
const len: i32 = Porffor.wasm.i32.load16_u(x, 0, 2);
|
64
|
+
|
65
|
+
let out: number = 0;
|
66
|
+
for (let i: i32 = 0; i < len; i++) {
|
67
|
+
const d: i32 = Porffor.wasm.i32.load(x + i * 4, 0, 4);
|
68
|
+
out = out * 0x100000000 + d;
|
69
|
+
}
|
70
|
+
|
71
|
+
if (negative) out = -out;
|
72
|
+
return out;
|
73
|
+
};
|
74
|
+
|
75
|
+
export const __Porffor_bigint_fromString = (n: string|bytestring): bigint => {
|
76
|
+
const len: i32 = n.length;
|
77
|
+
|
78
|
+
let negative: boolean = false;
|
79
|
+
let offset: i32 = 0;
|
80
|
+
if (n[0] === '-') {
|
81
|
+
negative = true;
|
82
|
+
offset = 1;
|
83
|
+
} else if (n[0] === '+') {
|
84
|
+
offset = 1;
|
85
|
+
}
|
86
|
+
|
87
|
+
// n -> digits (base 2^32) (most to least significant)
|
88
|
+
// 4294967294 -> [ 4294967294 ]
|
89
|
+
// 4294967295 -> [ 4294967295 ]
|
90
|
+
// 4294967296 -> [ 1, 0 ]
|
91
|
+
// 4294967297 -> [ 1, 1 ]
|
92
|
+
// 9007199254740992 -> [ 2097152, 0 ]
|
93
|
+
// 9007199254740993 -> [ 2097152, 1 ]
|
94
|
+
// 9007199254740994 -> [ 2097152, 2 ]
|
95
|
+
|
96
|
+
const BASE: i32 = 0x100000000; // 2^32
|
97
|
+
const digits: i32[] = Porffor.allocate(); // todo: free later
|
98
|
+
digits.length = len - offset;
|
99
|
+
|
100
|
+
let i: i32 = 0;
|
101
|
+
let acc: number = 0;
|
102
|
+
while (i < len) {
|
103
|
+
const char: i32 = n.charCodeAt(offset + i);
|
104
|
+
const digit: i32 = char - 48;
|
105
|
+
if (Porffor.fastOr(digit < 0, digit > 9)) throw new SyntaxError('Invalid character in BigInt string');
|
106
|
+
|
107
|
+
digits[i++] = digit;
|
108
|
+
acc = acc * 10 + digit;
|
109
|
+
}
|
110
|
+
|
111
|
+
if (acc < 0x8000000000000) {
|
112
|
+
// inline if small enough
|
113
|
+
return acc as bigint;
|
114
|
+
}
|
115
|
+
|
116
|
+
const result: i32[] = Porffor.allocate();
|
117
|
+
while (digits.length > 0) {
|
118
|
+
let carry: i32 = 0;
|
119
|
+
for (let j: i32 = 0; j < digits.length; j++) {
|
120
|
+
let value: i32 = carry * 10 + digits[j];
|
121
|
+
let quotient: i32 = Math.floor(value / BASE);
|
122
|
+
carry = value % BASE;
|
123
|
+
|
124
|
+
digits[j] = quotient;
|
125
|
+
}
|
126
|
+
|
127
|
+
while (digits.length > 0 && digits[0] === 0) digits.shift();
|
128
|
+
if (carry !== 0 || digits.length > 0) result.unshift(carry);
|
129
|
+
}
|
130
|
+
|
131
|
+
return __Porffor_bigint_fromDigits(negative, result);
|
132
|
+
};
|
133
|
+
|
134
|
+
export const __Porffor_bigint_toString = (x: number, radix: any): string => {
|
135
|
+
// todo: actually use bigint
|
136
|
+
return __Number_prototype_toFixed(__Porffor_bigint_toNumber(x), radix);
|
137
|
+
};
|
138
|
+
|
139
|
+
// todo: hook up all funcs below to codegen
|
140
|
+
export const __Porffor_bigint_add = (a: number, b: number, sub: boolean): bigint => {
|
141
|
+
if (Math.abs(a) < 0x8000000000000) {
|
142
|
+
if (Math.abs(b) < 0x8000000000000) {
|
143
|
+
if (sub) b = -b;
|
144
|
+
return __Porffor_bigint_fromNumber(Math.trunc(a + b));
|
145
|
+
}
|
146
|
+
|
147
|
+
a = __Porffor_bigint_inlineToDigitForm(a);
|
148
|
+
} else if (Math.abs(b) < 0x8000000000000) {
|
149
|
+
b = __Porffor_bigint_inlineToDigitForm(b);
|
150
|
+
}
|
151
|
+
|
152
|
+
a -= 0x8000000000000;
|
153
|
+
b -= 0x8000000000000;
|
154
|
+
|
155
|
+
const aNegative: boolean = Porffor.wasm.i32.load8_u(a, 0, 0) != 0;
|
156
|
+
const aLen: i32 = Porffor.wasm.i32.load16_u(a, 0, 2);
|
157
|
+
|
158
|
+
let bNegative: boolean = Porffor.wasm.i32.load8_u(b, 0, 0) != 0;
|
159
|
+
if (sub) bNegative = !bNegative;
|
160
|
+
const bLen: i32 = Porffor.wasm.i32.load16_u(b, 0, 2);
|
161
|
+
|
162
|
+
const maxLen: i32 = Math.max(aLen, bLen);
|
163
|
+
const digits: i32[] = Porffor.allocate();
|
164
|
+
|
165
|
+
// fast path: same sign
|
166
|
+
let negative: boolean = false;
|
167
|
+
let carry: i32 = 0;
|
168
|
+
if (aNegative == bNegative) {
|
169
|
+
negative = aNegative;
|
170
|
+
|
171
|
+
for (let i: i32 = 0; i < maxLen; i++) {
|
172
|
+
let aDigit: i32 = 0;
|
173
|
+
const aOffset: i32 = aLen - i;
|
174
|
+
if (aOffset > 0) aDigit = Porffor.wasm.i32.load(a + aOffset * 4, 0, 0);
|
175
|
+
|
176
|
+
let bDigit: i32 = 0;
|
177
|
+
const bOffset: i32 = bLen - i;
|
178
|
+
if (bOffset > 0) bDigit = Porffor.wasm.i32.load(b + bOffset * 4, 0, 0);
|
179
|
+
|
180
|
+
let sum: i32 = aDigit + bDigit + carry;
|
181
|
+
if (sum >= 0x100000000) {
|
182
|
+
sum -= 0x100000000;
|
183
|
+
carry = 1;
|
184
|
+
} else if (sum < 0) {
|
185
|
+
sum += 0x100000000;
|
186
|
+
carry = 1;
|
187
|
+
} else {
|
188
|
+
carry = 0;
|
189
|
+
}
|
190
|
+
|
191
|
+
digits.unshift(sum);
|
192
|
+
}
|
193
|
+
} else {
|
194
|
+
let aLarger: i32 = 0;
|
195
|
+
for (let i: i32 = 0; i < maxLen; i++) {
|
196
|
+
let aDigit: i32 = 0;
|
197
|
+
const aOffset: i32 = aLen - i;
|
198
|
+
if (aOffset > 0) aDigit = Porffor.wasm.i32.load(a + aOffset * 4, 0, 0);
|
199
|
+
|
200
|
+
let bDigit: i32 = 0;
|
201
|
+
const bOffset: i32 = bLen - i;
|
202
|
+
if (bOffset > 0) bDigit = Porffor.wasm.i32.load(b + bOffset * 4, 0, 0);
|
203
|
+
|
204
|
+
let sum: i32 = carry;
|
205
|
+
if (aNegative) sum -= aDigit;
|
206
|
+
else sum += aDigit;
|
207
|
+
if (bNegative) sum -= bDigit;
|
208
|
+
else sum += bDigit;
|
209
|
+
|
210
|
+
if (aDigit != bDigit) aLarger = aDigit > bDigit ? 1 : -1;
|
211
|
+
|
212
|
+
if (sum >= 0x100000000) {
|
213
|
+
sum -= 0x100000000;
|
214
|
+
carry = 1;
|
215
|
+
} else if (sum < 0) {
|
216
|
+
sum += 0x100000000;
|
217
|
+
carry = -1;
|
218
|
+
} else {
|
219
|
+
carry = 0;
|
220
|
+
}
|
221
|
+
|
222
|
+
digits.unshift(sum);
|
223
|
+
}
|
224
|
+
|
225
|
+
if (aLarger == 1) negative = aNegative;
|
226
|
+
else if (aLarger == -1) negative = bNegative;
|
227
|
+
}
|
228
|
+
|
229
|
+
if (carry != 0) {
|
230
|
+
digits.unshift(Math.abs(carry));
|
231
|
+
if (carry < 0) negative = !negative;
|
232
|
+
}
|
233
|
+
|
234
|
+
return __Porffor_bigint_fromDigits(negative, digits);
|
235
|
+
};
|
236
|
+
|
237
|
+
export const __Porffor_bigint_sub = (a: i32, b: i32): bigint => {
|
238
|
+
return __Porffor_bigint_add(a, b, true);
|
239
|
+
};
|
240
|
+
|
241
|
+
export const __Porffor_bigint_mul = (a: i32, b: i32): bigint => {
|
242
|
+
// todo
|
243
|
+
};
|
244
|
+
|
245
|
+
export const __Porffor_bigint_div = (a: i32, b: i32): bigint => {
|
246
|
+
// todo
|
247
|
+
};
|
248
|
+
|
249
|
+
export const __Porffor_bigint_rem = (a: i32, b: i32): bigint => {
|
250
|
+
// todo
|
251
|
+
};
|
252
|
+
|
253
|
+
export const __Porffor_bigint_eq = (a: i32, b: i32): boolean => {
|
254
|
+
// todo
|
255
|
+
};
|
256
|
+
|
257
|
+
export const __Porffor_bigint_ne = (a: i32, b: i32): boolean => {
|
258
|
+
return !__Porffor_bigint_eq(a, b);
|
259
|
+
};
|
260
|
+
|
261
|
+
export const __Porffor_bigint_gt = (a: i32, b: i32): boolean => {
|
262
|
+
// todo
|
263
|
+
};
|
264
|
+
|
265
|
+
export const __Porffor_bigint_ge = (a: i32, b: i32): boolean => {
|
266
|
+
// todo
|
267
|
+
};
|
268
|
+
|
269
|
+
export const __Porffor_bigint_lt = (a: i32, b: i32): boolean => {
|
270
|
+
return !__Porffor_bigint_ge(a, b);
|
271
|
+
};
|
272
|
+
|
273
|
+
export const __Porffor_bigint_le = (a: i32, b: i32): boolean => {
|
274
|
+
return !__Porffor_bigint_gt(a, b);
|
275
|
+
};
|
276
|
+
|
277
|
+
// 7.1.13 ToBigInt (argument)
|
278
|
+
// https://tc39.es/ecma262/#sec-tobigint
|
279
|
+
export const __ecma262_ToBigInt = (argument: any): bigint => {
|
280
|
+
// 1. Let prim be ? ToPrimitive(argument, number).
|
281
|
+
const prim: any = ecma262.ToPrimitive.Number(argument);
|
282
|
+
|
283
|
+
// 2. Return the value that prim corresponds to in Table 12.
|
284
|
+
// Table 12: BigInt Conversions
|
285
|
+
// Argument Type Result
|
286
|
+
// BigInt Return prim.
|
287
|
+
if (Porffor.rawType(prim) == Porffor.TYPES.bigint) return prim;
|
288
|
+
|
289
|
+
// String
|
290
|
+
// 1. Let n be StringToBigInt(prim).
|
291
|
+
// 2. If n is undefined, throw a SyntaxError exception.
|
292
|
+
// 3. Return n.
|
293
|
+
if ((Porffor.rawType(prim) | 0b10000000) == Porffor.TYPES.bytestring) return __Porffor_bigint_fromString(prim);
|
294
|
+
|
295
|
+
// Boolean Return 1n if prim is true and 0n if prim is false.
|
296
|
+
if (Porffor.rawType(prim) == Porffor.TYPES.boolean) return prim ? 1n : 0n;
|
297
|
+
|
298
|
+
// Number Throw a TypeError exception.
|
299
|
+
// Symbol Throw a TypeError exception.
|
300
|
+
// Undefined Throw a TypeError exception.
|
301
|
+
// Null Throw a TypeError exception.
|
302
|
+
throw new TypeError('Cannot convert to BigInt');
|
303
|
+
};
|
304
|
+
|
305
|
+
// 21.2.1.1 BigInt (value)
|
306
|
+
// https://tc39.es/ecma262/#sec-bigint-constructor-number-value
|
307
|
+
export const BigInt = (value: any): bigint => {
|
308
|
+
// 1. If NewTarget is not undefined, throw a TypeError exception.
|
309
|
+
// 2. Let prim be ? ToPrimitive(value, number).
|
310
|
+
const prim: any = ecma262.ToPrimitive.Number(value);
|
311
|
+
|
312
|
+
// 3. If prim is a Number, return ? NumberToBigInt(prim).
|
313
|
+
if (Porffor.rawType(prim) == Porffor.TYPES.number) return __Porffor_bigint_fromNumber(prim);
|
314
|
+
|
315
|
+
// 4. Otherwise, return ? ToBigInt(prim).
|
316
|
+
return __ecma262_ToBigInt(prim);
|
317
|
+
};
|
318
|
+
|
319
|
+
export const __BigInt_prototype_toString = (_this: bigint, radix: any) => {
|
320
|
+
return __Porffor_bigint_toString(_this, radix);
|
321
|
+
};
|
322
|
+
|
323
|
+
export const __BigInt_prototype_toLocaleString = (_this: bigint) => {
|
324
|
+
return __Porffor_bigint_toString(_this, 10);
|
325
|
+
};
|
326
|
+
|
327
|
+
export const __BigInt_prototype_valueOf = (_this: bigint) => {
|
328
|
+
return _this;
|
329
|
+
};
|
330
|
+
|
331
|
+
// todo: asIntN, asUintN
|
@@ -9,10 +9,15 @@ export const Number = function (value: any): number|NumberObject {
|
|
9
9
|
// todo: handle undefined (NaN) and not present (0) args differently
|
10
10
|
if (Porffor.rawType(value) != Porffor.TYPES.undefined) {
|
11
11
|
// a. Let prim be ? ToNumeric(value).
|
12
|
+
n = ecma262.ToNumeric(value);
|
13
|
+
|
12
14
|
// b. If prim is a BigInt, let n be 𝔽(ℝ(prim)).
|
13
|
-
|
15
|
+
if (Porffor.comptime.flag`hasType.bigint`) {
|
16
|
+
if (Porffor.rawType(n) == Porffor.TYPES.bigint)
|
17
|
+
n = Porffor.bigint.toNumber(n);
|
18
|
+
}
|
19
|
+
|
14
20
|
// c. Otherwise, let n be prim.
|
15
|
-
n = ecma262.ToNumeric(value);
|
16
21
|
}
|
17
22
|
|
18
23
|
// 2. Else,
|
@@ -242,7 +242,7 @@ export const Promise = function (executor: any): Promise {
|
|
242
242
|
return obj as Promise;
|
243
243
|
};
|
244
244
|
|
245
|
-
export const __Promise_withResolvers = ():
|
245
|
+
export const __Promise_withResolvers = (): object => {
|
246
246
|
const obj: any[] = __Porffor_promise_create();
|
247
247
|
activePromise = obj;
|
248
248
|
|
@@ -71,13 +71,18 @@ export const __ecma262_ToNumber = (argument: unknown): number => {
|
|
71
71
|
// https://tc39.es/ecma262/#sec-tonumeric
|
72
72
|
export const __ecma262_ToNumeric = (value: unknown): number => {
|
73
73
|
// 1. Let primValue be ? ToPrimitive(value, number).
|
74
|
-
//
|
74
|
+
// only run ToPrimitive if pure object for perf
|
75
|
+
let primValue: any = value;
|
76
|
+
if (Porffor.rawType(value) == Porffor.TYPES.object && Porffor.wasm`local.get ${value}` != 0)
|
77
|
+
primValue = __ecma262_ToPrimitive_Number(value);
|
75
78
|
|
76
79
|
// 2. If primValue is a BigInt, return primValue.
|
77
|
-
|
80
|
+
if (Porffor.comptime.flag`hasType.bigint`) {
|
81
|
+
if (Porffor.rawType(primValue) == Porffor.TYPES.bigint) return primValue;
|
82
|
+
}
|
78
83
|
|
79
84
|
// 3. Return ? ToNumber(primValue).
|
80
|
-
return __ecma262_ToNumber(
|
85
|
+
return __ecma262_ToNumber(primValue);
|
81
86
|
};
|
82
87
|
|
83
88
|
// 7.1.5 ToIntegerOrInfinity (argument)
|