porffor 0.17.0-048c6f2ee → 0.17.0-55678f69e
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/array.ts +22 -0
- package/compiler/builtins/math.ts +6 -2
- package/compiler/builtins/set.ts +2 -9
- package/compiler/builtins/typedarray.js +42 -0
- package/compiler/builtins.js +14 -0
- package/compiler/codegen.js +359 -21
- package/compiler/generated_builtins.js +304 -122
- package/compiler/types.js +31 -5
- package/compiler/wasmSpec.js +2 -0
- package/compiler/wrap.js +47 -2
- package/package.json +1 -1
- package/runner/index.js +4 -2
- package/runner/repl.js +11 -6
@@ -225,6 +225,16 @@ export const __Array_prototype_every = (_this: any[], callbackFn: any) => {
|
|
225
225
|
return true;
|
226
226
|
};
|
227
227
|
|
228
|
+
export const __Array_prototype_some = (_this: any[], callbackFn: any) => {
|
229
|
+
const len: i32 = _this.length;
|
230
|
+
let i: i32 = 0;
|
231
|
+
while (i < len) {
|
232
|
+
if (Boolean(callbackFn(_this[i], i++, _this))) return true;
|
233
|
+
}
|
234
|
+
|
235
|
+
return false;
|
236
|
+
};
|
237
|
+
|
228
238
|
export const __Array_prototype_reduce = (_this: any[], callbackFn: any, initialValue: any) => {
|
229
239
|
let acc: any = initialValue ?? _this[0];
|
230
240
|
|
@@ -237,6 +247,18 @@ export const __Array_prototype_reduce = (_this: any[], callbackFn: any, initialV
|
|
237
247
|
return acc;
|
238
248
|
};
|
239
249
|
|
250
|
+
export const __Array_prototype_reduceRight = (_this: any[], callbackFn: any, initialValue: any) => {
|
251
|
+
const len: i32 = _this.length;
|
252
|
+
let acc: any = initialValue ?? _this[len - 1];
|
253
|
+
|
254
|
+
let i: i32 = len;
|
255
|
+
while (i > 0) {
|
256
|
+
acc = callbackFn(acc, _this[--i], i, _this);
|
257
|
+
}
|
258
|
+
|
259
|
+
return acc;
|
260
|
+
};
|
261
|
+
|
240
262
|
export const __Array_prototype_toString = (_this: any[]) => {
|
241
263
|
// todo: this is bytestring only!
|
242
264
|
|
@@ -16,7 +16,7 @@ export const __Math_exp = (x: number): number => {
|
|
16
16
|
return 1 / Math.exp(-x);
|
17
17
|
}
|
18
18
|
|
19
|
-
|
19
|
+
let k: number = Math.floor(x / Math.LN2);
|
20
20
|
const r: number = x - k * Math.LN2;
|
21
21
|
|
22
22
|
// Taylor series via Horner's method
|
@@ -30,7 +30,11 @@ export const __Math_exp = (x: number): number => {
|
|
30
30
|
i++;
|
31
31
|
}
|
32
32
|
|
33
|
-
|
33
|
+
while (k-- > 0) {
|
34
|
+
sum *= 2;
|
35
|
+
}
|
36
|
+
|
37
|
+
return sum;
|
34
38
|
};
|
35
39
|
|
36
40
|
export const __Math_log2 = (y: number): number => {
|
package/compiler/builtins/set.ts
CHANGED
@@ -170,15 +170,8 @@ export const Set = () => {
|
|
170
170
|
export const Set$constructor = (iterable: any): Set => {
|
171
171
|
const out: Set = __Porffor_allocate();
|
172
172
|
|
173
|
-
|
174
|
-
|
175
|
-
type == Porffor.TYPES.array,
|
176
|
-
type == Porffor.TYPES.string, type == Porffor.TYPES.bytestring,
|
177
|
-
type == Porffor.TYPES.set
|
178
|
-
)) {
|
179
|
-
for (const x of iterable) {
|
180
|
-
__Set_prototype_add(out, x);
|
181
|
-
}
|
173
|
+
if (Porffor.rawType(iterable) != Porffor.TYPES.undefined) for (const x of iterable) {
|
174
|
+
__Set_prototype_add(out, x);
|
182
175
|
}
|
183
176
|
|
184
177
|
return out;
|
@@ -0,0 +1,42 @@
|
|
1
|
+
export default () => {
|
2
|
+
let out = '';
|
3
|
+
|
4
|
+
const constr = name => out += `export const ${name} = () => {
|
5
|
+
throw new TypeError("Constructor ${name} requires 'new'");
|
6
|
+
};
|
7
|
+
|
8
|
+
export const ${name}$constructor = (arg: any): ${name} => {
|
9
|
+
const out: ${name} = Porffor.allocate();
|
10
|
+
let len: i32 = 0;
|
11
|
+
|
12
|
+
const type: i32 = Porffor.rawType(arg);
|
13
|
+
if (Porffor.fastOr(
|
14
|
+
type == Porffor.TYPES.array,
|
15
|
+
type == Porffor.TYPES.string, type == Porffor.TYPES.bytestring,
|
16
|
+
type == Porffor.TYPES.set
|
17
|
+
)) {
|
18
|
+
let i: i32 = 0;
|
19
|
+
for (const x of arg) {
|
20
|
+
out[i++] = x;
|
21
|
+
}
|
22
|
+
len = i;
|
23
|
+
} else if (type == Porffor.TYPES.number) {
|
24
|
+
len = arg;
|
25
|
+
}
|
26
|
+
|
27
|
+
out.length = len;
|
28
|
+
return out;
|
29
|
+
};`;
|
30
|
+
|
31
|
+
constr('Uint8Array');
|
32
|
+
constr('Int8Array');
|
33
|
+
constr('Uint8ClampedArray');
|
34
|
+
constr('Uint16Array');
|
35
|
+
constr('Int16Array');
|
36
|
+
constr('Uint32Array');
|
37
|
+
constr('Int32Array');
|
38
|
+
constr('Float32Array');
|
39
|
+
constr('Float64Array');
|
40
|
+
|
41
|
+
return out;
|
42
|
+
};
|
package/compiler/builtins.js
CHANGED
@@ -184,6 +184,20 @@ export const BuiltinFuncs = function() {
|
|
184
184
|
]
|
185
185
|
};
|
186
186
|
|
187
|
+
this['f64_**'] = this['i32_**'] = {
|
188
|
+
params: [ valtypeBinary, valtypeBinary ],
|
189
|
+
locals: [],
|
190
|
+
returns: [ valtypeBinary ],
|
191
|
+
returnType: TYPES.number,
|
192
|
+
wasm: (scope, { builtin }) => [
|
193
|
+
[ Opcodes.local_get, 0 ],
|
194
|
+
...number(TYPES.number, Valtype.i32),
|
195
|
+
[ Opcodes.local_get, 1 ],
|
196
|
+
...number(TYPES.number, Valtype.i32),
|
197
|
+
[ Opcodes.call, builtin('__Math_pow') ]
|
198
|
+
]
|
199
|
+
};
|
200
|
+
|
187
201
|
// add bitwise ops by converting operands to i32 first
|
188
202
|
for (const [ char, op ] of [ ['&', Opcodes.i32_and], ['|', Opcodes.i32_or], ['^', Opcodes.i32_xor], ['<<', Opcodes.i32_shl], ['>>', Opcodes.i32_shr_s], ['>>>', Opcodes.i32_shr_u] ]) {
|
189
203
|
this[`f64_${char}`] = {
|
package/compiler/codegen.js
CHANGED
@@ -4,7 +4,7 @@ import { operatorOpcode } from './expression.js';
|
|
4
4
|
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
|
5
5
|
import { PrototypeFuncs } from './prototype.js';
|
6
6
|
import { number } from './embedding.js';
|
7
|
-
import { TYPES, TYPE_NAMES } from './types.js';
|
7
|
+
import { TYPES, TYPE_FLAGS, TYPE_NAMES, typeHasFlag } from './types.js';
|
8
8
|
import * as Rhemyn from '../rhemyn/compile.js';
|
9
9
|
import parse from './parse.js';
|
10
10
|
import { log } from './log.js';
|
@@ -72,6 +72,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
72
72
|
case 'ExpressionStatement':
|
73
73
|
return generateExp(scope, decl);
|
74
74
|
|
75
|
+
case 'SequenceExpression':
|
76
|
+
return generateSequence(scope, decl);
|
77
|
+
|
75
78
|
case 'CallExpression':
|
76
79
|
return generateCall(scope, decl, global, name, valueUnused);
|
77
80
|
|
@@ -291,12 +294,13 @@ const generateIdent = (scope, decl) => {
|
|
291
294
|
return wasm.slice();
|
292
295
|
}
|
293
296
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
297
|
+
// todo: enable this by default in future
|
298
|
+
// if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
|
299
|
+
// includeBuiltin(scope, name);
|
300
|
+
// return number(funcIndex[name] - importedFuncs.length);
|
301
|
+
// }
|
298
302
|
|
299
|
-
if (isExistingProtoFunc(name)) {
|
303
|
+
if (isExistingProtoFunc(name) || Object.hasOwn(internalConstrs, name) || Object.hasOwn(builtinFuncs, name)) {
|
300
304
|
// todo: return an actual something
|
301
305
|
return number(1);
|
302
306
|
}
|
@@ -975,6 +979,33 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
975
979
|
};
|
976
980
|
|
977
981
|
const generateBinaryExp = (scope, decl, _global, _name) => {
|
982
|
+
if (decl.operator === 'instanceof') {
|
983
|
+
// very hacky basic instanceof
|
984
|
+
// todo: support dynamic right-hand side
|
985
|
+
|
986
|
+
const out = generate(scope, decl.left);
|
987
|
+
disposeLeftover(out);
|
988
|
+
|
989
|
+
const rightName = decl.right.name;
|
990
|
+
if (!rightName) return todo(scope, 'instanceof dynamic right-hand side is not supported yet', true);
|
991
|
+
|
992
|
+
const checkType = TYPES[rightName.toLowerCase()];
|
993
|
+
if (checkType == null || rightName !== TYPE_NAMES[checkType] || checkType === TYPES.undefined) return todo(scope, 'instanceof right-hand side type unsupported', true);
|
994
|
+
|
995
|
+
if ([TYPES.number, TYPES.boolean, TYPES.string, TYPES.symbol, TYPES.object].includes(checkType)) {
|
996
|
+
out.push(...number(0));
|
997
|
+
} else {
|
998
|
+
out.push(
|
999
|
+
...getNodeType(scope, decl.left),
|
1000
|
+
...number(checkType, Valtype.i32),
|
1001
|
+
[ Opcodes.i32_eq ],
|
1002
|
+
Opcodes.i32_from_u
|
1003
|
+
);
|
1004
|
+
}
|
1005
|
+
|
1006
|
+
return out;
|
1007
|
+
}
|
1008
|
+
|
978
1009
|
const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
|
979
1010
|
|
980
1011
|
if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
|
@@ -1281,7 +1312,7 @@ const getNodeType = (scope, node) => {
|
|
1281
1312
|
}
|
1282
1313
|
|
1283
1314
|
if (node.type === 'BinaryExpression') {
|
1284
|
-
if (['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(node.operator)) return TYPES.boolean;
|
1315
|
+
if (['==', '===', '!=', '!==', '>', '>=', '<', '<=', 'instanceof'].includes(node.operator)) return TYPES.boolean;
|
1285
1316
|
if (node.operator !== '+') return TYPES.number;
|
1286
1317
|
|
1287
1318
|
const knownLeft = knownType(scope, getNodeType(scope, node.left));
|
@@ -1314,7 +1345,7 @@ const getNodeType = (scope, node) => {
|
|
1314
1345
|
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1315
1346
|
if (objectKnownType != null) {
|
1316
1347
|
if (name === 'length') {
|
1317
|
-
if (
|
1348
|
+
if (typeHasFlag(objectKnownType, TYPE_FLAGS.length)) return TYPES.number;
|
1318
1349
|
else return TYPES.undefined;
|
1319
1350
|
}
|
1320
1351
|
|
@@ -1426,6 +1457,18 @@ const generateExp = (scope, decl) => {
|
|
1426
1457
|
return out;
|
1427
1458
|
};
|
1428
1459
|
|
1460
|
+
const generateSequence = (scope, decl) => {
|
1461
|
+
let out = [];
|
1462
|
+
|
1463
|
+
const exprs = decl.expressions;
|
1464
|
+
for (let i = 0; i < exprs.length; i++) {
|
1465
|
+
if (i > 0) disposeLeftover(out);
|
1466
|
+
out.push(...generate(scope, exprs[i]));
|
1467
|
+
}
|
1468
|
+
|
1469
|
+
return out;
|
1470
|
+
};
|
1471
|
+
|
1429
1472
|
const CTArrayUtil = {
|
1430
1473
|
getLengthI32: pointer => [
|
1431
1474
|
...number(0, Valtype.i32),
|
@@ -2014,7 +2057,7 @@ const unhackName = name => {
|
|
2014
2057
|
|
2015
2058
|
const knownType = (scope, type) => {
|
2016
2059
|
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
2017
|
-
return type[0]
|
2060
|
+
return read_signedLEB128(type[0].slice(1));
|
2018
2061
|
}
|
2019
2062
|
|
2020
2063
|
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
@@ -2301,11 +2344,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2301
2344
|
const { type, name } = decl.left;
|
2302
2345
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2303
2346
|
|
2304
|
-
if (type === 'ObjectPattern') {
|
2305
|
-
// hack: ignore object parts of `var a = {} = 2`
|
2306
|
-
return generate(scope, decl.right);
|
2307
|
-
}
|
2308
|
-
|
2309
2347
|
if (isFuncType(decl.right.type)) {
|
2310
2348
|
// hack for a = function () { ... }
|
2311
2349
|
decl.right.id = { name };
|
@@ -2378,10 +2416,160 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2378
2416
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2379
2417
|
], getNodeType(scope, decl.right), false, name, true)),
|
2380
2418
|
[ Opcodes.local_tee, newValueTmp ],
|
2381
|
-
|
2382
2419
|
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2383
2420
|
],
|
2384
2421
|
|
2422
|
+
...wrapBC({
|
2423
|
+
[TYPES.uint8array]: [
|
2424
|
+
[ Opcodes.i32_add ],
|
2425
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2426
|
+
|
2427
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2428
|
+
[ Opcodes.local_get, pointerTmp ],
|
2429
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2430
|
+
Opcodes.i32_from_u
|
2431
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2432
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2433
|
+
|
2434
|
+
Opcodes.i32_to_u,
|
2435
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2436
|
+
],
|
2437
|
+
[TYPES.uint8clampedarray]: [
|
2438
|
+
[ Opcodes.i32_add ],
|
2439
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2440
|
+
|
2441
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2442
|
+
[ Opcodes.local_get, pointerTmp ],
|
2443
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2444
|
+
Opcodes.i32_from_u
|
2445
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2446
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2447
|
+
|
2448
|
+
...number(0),
|
2449
|
+
[ Opcodes.f64_max ],
|
2450
|
+
...number(255),
|
2451
|
+
[ Opcodes.f64_min ],
|
2452
|
+
Opcodes.i32_to_u,
|
2453
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2454
|
+
],
|
2455
|
+
[TYPES.int8array]: [
|
2456
|
+
[ Opcodes.i32_add ],
|
2457
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2458
|
+
|
2459
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2460
|
+
[ Opcodes.local_get, pointerTmp ],
|
2461
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
2462
|
+
Opcodes.i32_from
|
2463
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2464
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2465
|
+
|
2466
|
+
Opcodes.i32_to,
|
2467
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2468
|
+
],
|
2469
|
+
[TYPES.uint16array]: [
|
2470
|
+
...number(2, Valtype.i32),
|
2471
|
+
[ Opcodes.i32_mul ],
|
2472
|
+
[ Opcodes.i32_add ],
|
2473
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2474
|
+
|
2475
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2476
|
+
[ Opcodes.local_get, pointerTmp ],
|
2477
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
2478
|
+
Opcodes.i32_from_u
|
2479
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2480
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2481
|
+
|
2482
|
+
Opcodes.i32_to_u,
|
2483
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2484
|
+
],
|
2485
|
+
[TYPES.int16array]: [
|
2486
|
+
...number(2, Valtype.i32),
|
2487
|
+
[ Opcodes.i32_mul ],
|
2488
|
+
[ Opcodes.i32_add ],
|
2489
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2490
|
+
|
2491
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2492
|
+
[ Opcodes.local_get, pointerTmp ],
|
2493
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
2494
|
+
Opcodes.i32_from
|
2495
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2496
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2497
|
+
|
2498
|
+
Opcodes.i32_to,
|
2499
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2500
|
+
],
|
2501
|
+
[TYPES.uint32array]: [
|
2502
|
+
...number(4, Valtype.i32),
|
2503
|
+
[ Opcodes.i32_mul ],
|
2504
|
+
[ Opcodes.i32_add ],
|
2505
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2506
|
+
|
2507
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2508
|
+
[ Opcodes.local_get, pointerTmp ],
|
2509
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2510
|
+
Opcodes.i32_from_u
|
2511
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2512
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2513
|
+
|
2514
|
+
Opcodes.i32_to_u,
|
2515
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2516
|
+
],
|
2517
|
+
[TYPES.int32array]: [
|
2518
|
+
...number(4, Valtype.i32),
|
2519
|
+
[ Opcodes.i32_mul ],
|
2520
|
+
[ Opcodes.i32_add ],
|
2521
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2522
|
+
|
2523
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2524
|
+
[ Opcodes.local_get, pointerTmp ],
|
2525
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2526
|
+
Opcodes.i32_from
|
2527
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2528
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2529
|
+
|
2530
|
+
Opcodes.i32_to,
|
2531
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2532
|
+
],
|
2533
|
+
[TYPES.float32array]: [
|
2534
|
+
...number(4, Valtype.i32),
|
2535
|
+
[ Opcodes.i32_mul ],
|
2536
|
+
[ Opcodes.i32_add ],
|
2537
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2538
|
+
|
2539
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2540
|
+
[ Opcodes.local_get, pointerTmp ],
|
2541
|
+
[ Opcodes.f32_load, 0, 4 ],
|
2542
|
+
[ Opcodes.f64_promote_f32 ]
|
2543
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2544
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2545
|
+
|
2546
|
+
[ Opcodes.f32_demote_f64 ],
|
2547
|
+
[ Opcodes.f32_store, 0, 4 ]
|
2548
|
+
],
|
2549
|
+
[TYPES.float64array]: [
|
2550
|
+
...number(8, Valtype.i32),
|
2551
|
+
[ Opcodes.i32_mul ],
|
2552
|
+
[ Opcodes.i32_add ],
|
2553
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2554
|
+
|
2555
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2556
|
+
[ Opcodes.local_get, pointerTmp ],
|
2557
|
+
[ Opcodes.f64_load, 0, 4 ]
|
2558
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2559
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2560
|
+
|
2561
|
+
[ Opcodes.f64_store, 0, 4 ]
|
2562
|
+
],
|
2563
|
+
}, {
|
2564
|
+
prelude: [
|
2565
|
+
...generate(scope, decl.left.object),
|
2566
|
+
Opcodes.i32_to_u,
|
2567
|
+
...generate(scope, decl.left.property),
|
2568
|
+
Opcodes.i32_to_u,
|
2569
|
+
],
|
2570
|
+
postlude: setLastType(scope, TYPES.number)
|
2571
|
+
}),
|
2572
|
+
|
2385
2573
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2386
2574
|
}, Blocktype.void),
|
2387
2575
|
|
@@ -2959,6 +3147,7 @@ const generateForOf = (scope, decl) => {
|
|
2959
3147
|
[ Opcodes.end ],
|
2960
3148
|
[ Opcodes.end ]
|
2961
3149
|
],
|
3150
|
+
// todo: typed arrays
|
2962
3151
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
2963
3152
|
}, Blocktype.void));
|
2964
3153
|
|
@@ -3047,13 +3236,14 @@ const generateThrow = (scope, decl) => {
|
|
3047
3236
|
idx: tags.length
|
3048
3237
|
});
|
3049
3238
|
|
3050
|
-
let exceptId = exceptions.
|
3239
|
+
let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
|
3240
|
+
if (exceptId === -1) exceptId = exceptions.push({ constructor, message }) - 1;
|
3051
3241
|
|
3052
3242
|
scope.exceptions ??= [];
|
3053
3243
|
scope.exceptions.push(exceptId);
|
3054
3244
|
|
3055
3245
|
return [
|
3056
|
-
|
3246
|
+
...number(exceptId, Valtype.i32),
|
3057
3247
|
[ Opcodes.throw, tags[0].idx ]
|
3058
3248
|
];
|
3059
3249
|
}
|
@@ -3071,6 +3261,61 @@ const generateThrow = (scope, decl) => {
|
|
3071
3261
|
[ Opcodes.throw, tags[0].idx ]
|
3072
3262
|
];
|
3073
3263
|
}
|
3264
|
+
|
3265
|
+
if (exceptionMode === 'stackest') {
|
3266
|
+
let message = decl.argument, constructor = null;
|
3267
|
+
|
3268
|
+
// support `throw (new)? Error(...)`
|
3269
|
+
if (message.type === 'NewExpression' || message.type === 'CallExpression') {
|
3270
|
+
constructor = decl.argument.callee;
|
3271
|
+
message = decl.argument.arguments[0];
|
3272
|
+
}
|
3273
|
+
|
3274
|
+
message ??= DEFAULT_VALUE;
|
3275
|
+
|
3276
|
+
if (tags.length === 0) tags.push({
|
3277
|
+
params: [ valtypeBinary, valtypeBinary, Valtype.i32 ],
|
3278
|
+
results: [],
|
3279
|
+
idx: tags.length
|
3280
|
+
});
|
3281
|
+
|
3282
|
+
return [
|
3283
|
+
...(constructor == null ? number(-1) : generate(scope, constructor)),
|
3284
|
+
...generate(scope, message),
|
3285
|
+
...getNodeType(scope, message),
|
3286
|
+
[ Opcodes.throw, tags[0].idx ]
|
3287
|
+
];
|
3288
|
+
}
|
3289
|
+
|
3290
|
+
if (exceptionMode === 'partial') {
|
3291
|
+
let message = decl.argument, constructor = null;
|
3292
|
+
|
3293
|
+
// support `throw (new)? Error(...)`
|
3294
|
+
if (message.type === 'NewExpression' || message.type === 'CallExpression') {
|
3295
|
+
constructor = decl.argument.callee.name;
|
3296
|
+
message = decl.argument.arguments[0];
|
3297
|
+
}
|
3298
|
+
|
3299
|
+
message ??= DEFAULT_VALUE;
|
3300
|
+
|
3301
|
+
if (tags.length === 0) tags.push({
|
3302
|
+
params: [ Valtype.i32, valtypeBinary, Valtype.i32 ],
|
3303
|
+
results: [],
|
3304
|
+
idx: tags.length
|
3305
|
+
});
|
3306
|
+
|
3307
|
+
let exceptId = exceptions.push({ constructor }) - 1;
|
3308
|
+
|
3309
|
+
scope.exceptions ??= [];
|
3310
|
+
scope.exceptions.push(exceptId);
|
3311
|
+
|
3312
|
+
return [
|
3313
|
+
...number(exceptId, Valtype.i32),
|
3314
|
+
...generate(scope, message),
|
3315
|
+
...getNodeType(scope, message),
|
3316
|
+
[ Opcodes.throw, tags[0].idx ]
|
3317
|
+
];
|
3318
|
+
}
|
3074
3319
|
};
|
3075
3320
|
|
3076
3321
|
const generateTry = (scope, decl) => {
|
@@ -3423,6 +3668,19 @@ const withType = (scope, wasm, type) => [
|
|
3423
3668
|
...setLastType(scope, type)
|
3424
3669
|
];
|
3425
3670
|
|
3671
|
+
const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
3672
|
+
const out = {};
|
3673
|
+
for (const x in bc) {
|
3674
|
+
out[x] = [
|
3675
|
+
...prelude,
|
3676
|
+
...bc[x],
|
3677
|
+
...postlude
|
3678
|
+
];
|
3679
|
+
}
|
3680
|
+
|
3681
|
+
return out;
|
3682
|
+
};
|
3683
|
+
|
3426
3684
|
const generateMember = (scope, decl, _global, _name) => {
|
3427
3685
|
const name = decl.object.name;
|
3428
3686
|
|
@@ -3476,7 +3734,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3476
3734
|
const type = getNodeType(scope, decl.object);
|
3477
3735
|
const known = knownType(scope, type);
|
3478
3736
|
if (known != null) {
|
3479
|
-
if (
|
3737
|
+
if (typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3480
3738
|
...generate(scope, decl.object),
|
3481
3739
|
Opcodes.i32_to_u,
|
3482
3740
|
|
@@ -3488,7 +3746,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3488
3746
|
}
|
3489
3747
|
|
3490
3748
|
return [
|
3491
|
-
...
|
3749
|
+
...getNodeType(scope, decl.object),
|
3750
|
+
...number(TYPE_FLAGS.length, Valtype.i32),
|
3751
|
+
[ Opcodes.i32_and ],
|
3492
3752
|
[ Opcodes.if, valtypeBinary ],
|
3493
3753
|
...generate(scope, decl.object),
|
3494
3754
|
Opcodes.i32_to_u,
|
@@ -3537,7 +3797,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3537
3797
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3538
3798
|
// hack: this is naughty and will break things!
|
3539
3799
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3540
|
-
|
3800
|
+
|
3801
|
+
const known = knownType(scope, getNodeType(scope, decl.object));
|
3802
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
3541
3803
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3542
3804
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3543
3805
|
rawElements: new Array(0)
|
@@ -3611,6 +3873,82 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3611
3873
|
...setLastType(scope, TYPES.bytestring)
|
3612
3874
|
],
|
3613
3875
|
|
3876
|
+
...wrapBC({
|
3877
|
+
[TYPES.uint8array]: [
|
3878
|
+
[ Opcodes.i32_add ],
|
3879
|
+
|
3880
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3881
|
+
Opcodes.i32_from_u
|
3882
|
+
],
|
3883
|
+
[TYPES.uint8clampedarray]: [
|
3884
|
+
[ Opcodes.i32_add ],
|
3885
|
+
|
3886
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3887
|
+
Opcodes.i32_from_u
|
3888
|
+
],
|
3889
|
+
[TYPES.int8array]: [
|
3890
|
+
[ Opcodes.i32_add ],
|
3891
|
+
|
3892
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3893
|
+
Opcodes.i32_from
|
3894
|
+
],
|
3895
|
+
[TYPES.uint16array]: [
|
3896
|
+
...number(2, Valtype.i32),
|
3897
|
+
[ Opcodes.i32_mul ],
|
3898
|
+
[ Opcodes.i32_add ],
|
3899
|
+
|
3900
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
3901
|
+
Opcodes.i32_from_u
|
3902
|
+
],
|
3903
|
+
[TYPES.int16array]: [
|
3904
|
+
...number(2, Valtype.i32),
|
3905
|
+
[ Opcodes.i32_mul ],
|
3906
|
+
[ Opcodes.i32_add ],
|
3907
|
+
|
3908
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
3909
|
+
Opcodes.i32_from
|
3910
|
+
],
|
3911
|
+
[TYPES.uint32array]: [
|
3912
|
+
...number(4, Valtype.i32),
|
3913
|
+
[ Opcodes.i32_mul ],
|
3914
|
+
[ Opcodes.i32_add ],
|
3915
|
+
|
3916
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3917
|
+
Opcodes.i32_from_u
|
3918
|
+
],
|
3919
|
+
[TYPES.int32array]: [
|
3920
|
+
...number(4, Valtype.i32),
|
3921
|
+
[ Opcodes.i32_mul ],
|
3922
|
+
[ Opcodes.i32_add ],
|
3923
|
+
|
3924
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3925
|
+
Opcodes.i32_from
|
3926
|
+
],
|
3927
|
+
[TYPES.float32array]: [
|
3928
|
+
...number(4, Valtype.i32),
|
3929
|
+
[ Opcodes.i32_mul ],
|
3930
|
+
[ Opcodes.i32_add ],
|
3931
|
+
|
3932
|
+
[ Opcodes.f32_load, 0, 4 ],
|
3933
|
+
[ Opcodes.f64_promote_f32 ]
|
3934
|
+
],
|
3935
|
+
[TYPES.float64array]: [
|
3936
|
+
...number(8, Valtype.i32),
|
3937
|
+
[ Opcodes.i32_mul ],
|
3938
|
+
[ Opcodes.i32_add ],
|
3939
|
+
|
3940
|
+
[ Opcodes.f64_load, 0, 4 ]
|
3941
|
+
],
|
3942
|
+
}, {
|
3943
|
+
prelude: [
|
3944
|
+
...object,
|
3945
|
+
Opcodes.i32_to_u,
|
3946
|
+
...property,
|
3947
|
+
Opcodes.i32_to_u
|
3948
|
+
],
|
3949
|
+
postlude: setLastType(scope, TYPES.number)
|
3950
|
+
}),
|
3951
|
+
|
3614
3952
|
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
|
3615
3953
|
});
|
3616
3954
|
};
|
@@ -3788,7 +4126,7 @@ const internalConstrs = {
|
|
3788
4126
|
|
3789
4127
|
// todo: check in wasm instead of here
|
3790
4128
|
const literalValue = arg.value ?? 0;
|
3791
|
-
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, '
|
4129
|
+
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeError', 'Invalid array length', true);
|
3792
4130
|
|
3793
4131
|
return [
|
3794
4132
|
...out,
|