porffor 0.55.18 → 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.
@@ -0,0 +1,329 @@
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 end: i32 = 0;
80
+ if (n[0] === '-') {
81
+ negative = true;
82
+ end = 1;
83
+ } else if (n[0] === '+') {
84
+ end = 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
+ // 4294967298 -> [ 1, 2 ]
93
+ // 9007199254740992 -> [ 2097152 ]
94
+ // 9007199254740993 -> [ 2097152, 1 ]
95
+ // 9007199254740994 -> [ 2097152, 2 ]
96
+ // 9007199254740995 -> [ 2097152, 3 ]
97
+
98
+ let acc: number = 0;
99
+ let digits: i32[];
100
+ const BASE: i32 = 0x100000000; // 2^32
101
+
102
+ for (let i: i32 = end; i < len; i++) {
103
+ const char: i32 = n.charCodeAt(i);
104
+ const digit: i32 = char - 48;
105
+ if (digit < 0 || digit > 9) throw new SyntaxError('Invalid character in BigInt string');
106
+
107
+ if (acc == -1) {
108
+ let carry: i32 = digit;
109
+ for (let j: i32 = 0; j < digits.length; j++) {
110
+ const value: i32 = digits[j] * BASE + carry;
111
+ digits[j] = value % BASE;
112
+ carry = Math.trunc(value / BASE);
113
+ }
114
+
115
+ if (carry > 0) digits.push(carry);
116
+ } else {
117
+ acc = acc * 10 + digit;
118
+ if (acc >= BASE) {
119
+ digits = Porffor.allocate();
120
+ digits.length = 2;
121
+ digits[0] = Math.floor(acc / BASE);
122
+ digits[1] = acc % BASE;
123
+ acc = -1;
124
+ }
125
+ }
126
+ }
127
+
128
+ if (acc == -1) return __Porffor_bigint_fromDigits(negative, digits);
129
+ return (negative ? -acc : acc) as bigint;
130
+ };
131
+
132
+ export const __Porffor_bigint_toString = (x: number, radix: any): string => {
133
+ // todo: actually use bigint
134
+ return __Number_prototype_toFixed(__Porffor_bigint_toNumber(x), radix);
135
+ };
136
+
137
+ // todo: hook up all funcs below to codegen
138
+ export const __Porffor_bigint_add = (a: number, b: number, sub: boolean): bigint => {
139
+ if (Math.abs(a) < 0x8000000000000) {
140
+ if (Math.abs(b) < 0x8000000000000) {
141
+ if (sub) b = -b;
142
+ return __Porffor_bigint_fromNumber(Math.trunc(a + b));
143
+ }
144
+
145
+ a = __Porffor_bigint_inlineToDigitForm(a);
146
+ } else if (Math.abs(b) < 0x8000000000000) {
147
+ b = __Porffor_bigint_inlineToDigitForm(b);
148
+ }
149
+
150
+ a -= 0x8000000000000;
151
+ b -= 0x8000000000000;
152
+
153
+ const aNegative: boolean = Porffor.wasm.i32.load8_u(a, 0, 0) != 0;
154
+ const aLen: i32 = Porffor.wasm.i32.load16_u(a, 0, 2);
155
+
156
+ let bNegative: boolean = Porffor.wasm.i32.load8_u(b, 0, 0) != 0;
157
+ if (sub) bNegative = !bNegative;
158
+ const bLen: i32 = Porffor.wasm.i32.load16_u(b, 0, 2);
159
+
160
+ const maxLen: i32 = Math.max(aLen, bLen);
161
+ const digits: i32[] = Porffor.allocate();
162
+
163
+ // fast path: same sign
164
+ let negative: boolean = false;
165
+ let carry: i32 = 0;
166
+ if (aNegative == bNegative) {
167
+ negative = aNegative;
168
+
169
+ for (let i: i32 = 0; i < maxLen; i++) {
170
+ let aDigit: i32 = 0;
171
+ const aOffset: i32 = aLen - i;
172
+ if (aOffset > 0) aDigit = Porffor.wasm.i32.load(a + aOffset * 4, 0, 0);
173
+
174
+ let bDigit: i32 = 0;
175
+ const bOffset: i32 = bLen - i;
176
+ if (bOffset > 0) bDigit = Porffor.wasm.i32.load(b + bOffset * 4, 0, 0);
177
+
178
+ let sum: i32 = aDigit + bDigit + carry;
179
+ if (sum >= 0x100000000) {
180
+ sum -= 0x100000000;
181
+ carry = 1;
182
+ } else if (sum < 0) {
183
+ sum += 0x100000000;
184
+ carry = 1;
185
+ } else {
186
+ carry = 0;
187
+ }
188
+
189
+ digits.unshift(sum);
190
+ }
191
+ } else {
192
+ let aLarger: i32 = 0;
193
+ for (let i: i32 = 0; i < maxLen; i++) {
194
+ let aDigit: i32 = 0;
195
+ const aOffset: i32 = aLen - i;
196
+ if (aOffset > 0) aDigit = Porffor.wasm.i32.load(a + aOffset * 4, 0, 0);
197
+
198
+ let bDigit: i32 = 0;
199
+ const bOffset: i32 = bLen - i;
200
+ if (bOffset > 0) bDigit = Porffor.wasm.i32.load(b + bOffset * 4, 0, 0);
201
+
202
+ let sum: i32 = carry;
203
+ if (aNegative) sum -= aDigit;
204
+ else sum += aDigit;
205
+ if (bNegative) sum -= bDigit;
206
+ else sum += bDigit;
207
+
208
+ if (aDigit != bDigit) aLarger = aDigit > bDigit ? 1 : -1;
209
+
210
+ if (sum >= 0x100000000) {
211
+ sum -= 0x100000000;
212
+ carry = 1;
213
+ } else if (sum < 0) {
214
+ sum += 0x100000000;
215
+ carry = -1;
216
+ } else {
217
+ carry = 0;
218
+ }
219
+
220
+ digits.unshift(sum);
221
+ }
222
+
223
+ if (aLarger == 1) negative = aNegative;
224
+ else if (aLarger == -1) negative = bNegative;
225
+ }
226
+
227
+ if (carry != 0) {
228
+ digits.unshift(Math.abs(carry));
229
+ if (carry < 0) negative = !negative;
230
+ }
231
+
232
+ return __Porffor_bigint_fromDigits(negative, digits);
233
+ };
234
+
235
+ export const __Porffor_bigint_sub = (a: i32, b: i32): bigint => {
236
+ return __Porffor_bigint_add(a, b, true);
237
+ };
238
+
239
+ export const __Porffor_bigint_mul = (a: i32, b: i32): bigint => {
240
+ // todo
241
+ };
242
+
243
+ export const __Porffor_bigint_div = (a: i32, b: i32): bigint => {
244
+ // todo
245
+ };
246
+
247
+ export const __Porffor_bigint_rem = (a: i32, b: i32): bigint => {
248
+ // todo
249
+ };
250
+
251
+ export const __Porffor_bigint_eq = (a: i32, b: i32): boolean => {
252
+ // todo
253
+ };
254
+
255
+ export const __Porffor_bigint_ne = (a: i32, b: i32): boolean => {
256
+ return !__Porffor_bigint_eq(a, b);
257
+ };
258
+
259
+ export const __Porffor_bigint_gt = (a: i32, b: i32): boolean => {
260
+ // todo
261
+ };
262
+
263
+ export const __Porffor_bigint_ge = (a: i32, b: i32): boolean => {
264
+ // todo
265
+ };
266
+
267
+ export const __Porffor_bigint_lt = (a: i32, b: i32): boolean => {
268
+ return !__Porffor_bigint_ge(a, b);
269
+ };
270
+
271
+ export const __Porffor_bigint_le = (a: i32, b: i32): boolean => {
272
+ return !__Porffor_bigint_gt(a, b);
273
+ };
274
+
275
+ // 7.1.13 ToBigInt (argument)
276
+ // https://tc39.es/ecma262/#sec-tobigint
277
+ export const __ecma262_ToBigInt = (argument: any): bigint => {
278
+ // 1. Let prim be ? ToPrimitive(argument, number).
279
+ const prim: any = ecma262.ToPrimitive.Number(argument);
280
+
281
+ // 2. Return the value that prim corresponds to in Table 12.
282
+ // Table 12: BigInt Conversions
283
+ // Argument Type Result
284
+ // BigInt Return prim.
285
+ if (Porffor.rawType(prim) == Porffor.TYPES.bigint) return prim;
286
+
287
+ // String
288
+ // 1. Let n be StringToBigInt(prim).
289
+ // 2. If n is undefined, throw a SyntaxError exception.
290
+ // 3. Return n.
291
+ if ((Porffor.rawType(prim) | 0b10000000) == Porffor.TYPES.bytestring) return __Porffor_bigint_fromString(prim);
292
+
293
+ // Boolean Return 1n if prim is true and 0n if prim is false.
294
+ if (Porffor.rawType(prim) == Porffor.TYPES.boolean) return prim ? 1n : 0n;
295
+
296
+ // Number Throw a TypeError exception.
297
+ // Symbol Throw a TypeError exception.
298
+ // Undefined Throw a TypeError exception.
299
+ // Null Throw a TypeError exception.
300
+ throw new TypeError('Cannot convert to BigInt');
301
+ };
302
+
303
+ // 21.2.1.1 BigInt (value)
304
+ // https://tc39.es/ecma262/#sec-bigint-constructor-number-value
305
+ export const BigInt = (value: any): bigint => {
306
+ // 1. If NewTarget is not undefined, throw a TypeError exception.
307
+ // 2. Let prim be ? ToPrimitive(value, number).
308
+ const prim: any = ecma262.ToPrimitive.Number(value);
309
+
310
+ // 3. If prim is a Number, return ? NumberToBigInt(prim).
311
+ if (Porffor.rawType(prim) == Porffor.TYPES.number) return __Porffor_bigint_fromNumber(prim);
312
+
313
+ // 4. Otherwise, return ? ToBigInt(prim).
314
+ return __ecma262_ToBigInt(prim);
315
+ };
316
+
317
+ export const __BigInt_prototype_toString = (_this: bigint, radix: any) => {
318
+ return __Porffor_bigint_toString(_this, radix);
319
+ };
320
+
321
+ export const __BigInt_prototype_toLocaleString = (_this: bigint) => {
322
+ return __Porffor_bigint_toString(_this, 10);
323
+ };
324
+
325
+ export const __BigInt_prototype_valueOf = (_this: bigint) => {
326
+ return _this;
327
+ };
328
+
329
+ // todo: asIntN, asUintN
@@ -167,6 +167,11 @@ export const __Porffor_json_serialize = (value: any, depth: i32, space: bytestri
167
167
  return out;
168
168
  }
169
169
 
170
+ if (t == 0x04) {
171
+ // bigint
172
+ throw new TypeError('Cannot serialize BigInts');
173
+ }
174
+
170
175
  return undefined;
171
176
  };
172
177
 
@@ -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
- // todo: handle when bigints exist
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 = (): Promise => {
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
- // we do not have ToPrimitive
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
- // todo: do this when we have bigints
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(value);
85
+ return __ecma262_ToNumber(primValue);
81
86
  };
82
87
 
83
88
  // 7.1.5 ToIntegerOrInfinity (argument)