porffor 0.17.0-a818353a5 → 0.17.0-b4e7f7ee0

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.
@@ -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
 
@@ -616,11 +619,14 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
616
619
  };
617
620
 
618
621
  const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
619
- // if (isIntToFloatOp(wasm[wasm.length - 1])) return [
620
- // ...wasm,
621
- // ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
622
- // ];
623
- // if (isIntOp(wasm[wasm.length - 1])) return [ ...wasm ];
622
+ if (isIntToFloatOp(wasm[wasm.length - 1])) return [
623
+ ...wasm,
624
+ ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
625
+ ];
626
+ if (isIntOp(wasm[wasm.length - 1])) return [
627
+ ...wasm,
628
+ ...(intOut ? [] : [ Opcodes.i32_from ]),
629
+ ];
624
630
 
625
631
  // todo/perf: use knownType and custom bytecode here instead of typeSwitch
626
632
 
@@ -976,6 +982,33 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
976
982
  };
977
983
 
978
984
  const generateBinaryExp = (scope, decl, _global, _name) => {
985
+ if (decl.operator === 'instanceof') {
986
+ // very hacky basic instanceof
987
+ // todo: support dynamic right-hand side
988
+
989
+ const out = generate(scope, decl.left);
990
+ disposeLeftover(out);
991
+
992
+ const rightName = decl.right.name;
993
+ if (!rightName) return todo(scope, 'instanceof dynamic right-hand side is not supported yet', true);
994
+
995
+ const checkType = TYPES[rightName.toLowerCase()];
996
+ if (checkType == null || rightName !== TYPE_NAMES[checkType] || checkType === TYPES.undefined) return todo(scope, 'instanceof right-hand side type unsupported', true);
997
+
998
+ if ([TYPES.number, TYPES.boolean, TYPES.string, TYPES.symbol, TYPES.object].includes(checkType)) {
999
+ out.push(...number(0));
1000
+ } else {
1001
+ out.push(
1002
+ ...getNodeType(scope, decl.left),
1003
+ ...number(checkType, Valtype.i32),
1004
+ [ Opcodes.i32_eq ],
1005
+ Opcodes.i32_from_u
1006
+ );
1007
+ }
1008
+
1009
+ return out;
1010
+ }
1011
+
979
1012
  const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
980
1013
 
981
1014
  if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
@@ -1282,7 +1315,7 @@ const getNodeType = (scope, node) => {
1282
1315
  }
1283
1316
 
1284
1317
  if (node.type === 'BinaryExpression') {
1285
- if (['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(node.operator)) return TYPES.boolean;
1318
+ if (['==', '===', '!=', '!==', '>', '>=', '<', '<=', 'instanceof'].includes(node.operator)) return TYPES.boolean;
1286
1319
  if (node.operator !== '+') return TYPES.number;
1287
1320
 
1288
1321
  const knownLeft = knownType(scope, getNodeType(scope, node.left));
@@ -1315,7 +1348,7 @@ const getNodeType = (scope, node) => {
1315
1348
  const objectKnownType = knownType(scope, getNodeType(scope, node.object));
1316
1349
  if (objectKnownType != null) {
1317
1350
  if (name === 'length') {
1318
- if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(objectKnownType)) return TYPES.number;
1351
+ if (typeHasFlag(objectKnownType, TYPE_FLAGS.length)) return TYPES.number;
1319
1352
  else return TYPES.undefined;
1320
1353
  }
1321
1354
 
@@ -1387,9 +1420,9 @@ const countLeftover = wasm => {
1387
1420
 
1388
1421
  if (depth === 0)
1389
1422
  if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1390
- else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
1423
+ else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.f32_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
1391
1424
  else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
1392
- else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1425
+ else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.f32_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1393
1426
  else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
1394
1427
  else if (inst[0] === Opcodes.return) count = 0;
1395
1428
  else if (inst[0] === Opcodes.call) {
@@ -1427,6 +1460,18 @@ const generateExp = (scope, decl) => {
1427
1460
  return out;
1428
1461
  };
1429
1462
 
1463
+ const generateSequence = (scope, decl) => {
1464
+ let out = [];
1465
+
1466
+ const exprs = decl.expressions;
1467
+ for (let i = 0; i < exprs.length; i++) {
1468
+ if (i > 0) disposeLeftover(out);
1469
+ out.push(...generate(scope, exprs[i]));
1470
+ }
1471
+
1472
+ return out;
1473
+ };
1474
+
1430
1475
  const CTArrayUtil = {
1431
1476
  getLengthI32: pointer => [
1432
1477
  ...number(0, Valtype.i32),
@@ -2015,7 +2060,7 @@ const unhackName = name => {
2015
2060
 
2016
2061
  const knownType = (scope, type) => {
2017
2062
  if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
2018
- return type[0][1];
2063
+ return read_signedLEB128(type[0].slice(1));
2019
2064
  }
2020
2065
 
2021
2066
  if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
@@ -2302,11 +2347,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2302
2347
  const { type, name } = decl.left;
2303
2348
  const [ local, isGlobal ] = lookupName(scope, name);
2304
2349
 
2305
- if (type === 'ObjectPattern') {
2306
- // hack: ignore object parts of `var a = {} = 2`
2307
- return generate(scope, decl.right);
2308
- }
2309
-
2310
2350
  if (isFuncType(decl.right.type)) {
2311
2351
  // hack for a = function () { ... }
2312
2352
  decl.right.id = { name };
@@ -2379,10 +2419,160 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2379
2419
  [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
2380
2420
  ], getNodeType(scope, decl.right), false, name, true)),
2381
2421
  [ Opcodes.local_tee, newValueTmp ],
2382
-
2383
2422
  [ Opcodes.store, 0, ValtypeSize.i32 ]
2384
2423
  ],
2385
2424
 
2425
+ ...wrapBC({
2426
+ [TYPES.uint8array]: [
2427
+ [ Opcodes.i32_add ],
2428
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2429
+
2430
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2431
+ [ Opcodes.local_get, pointerTmp ],
2432
+ [ Opcodes.i32_load8_u, 0, 4 ],
2433
+ Opcodes.i32_from_u
2434
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2435
+ [ Opcodes.local_tee, newValueTmp ],
2436
+
2437
+ Opcodes.i32_to_u,
2438
+ [ Opcodes.i32_store8, 0, 4 ]
2439
+ ],
2440
+ [TYPES.uint8clampedarray]: [
2441
+ [ Opcodes.i32_add ],
2442
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2443
+
2444
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2445
+ [ Opcodes.local_get, pointerTmp ],
2446
+ [ Opcodes.i32_load8_u, 0, 4 ],
2447
+ Opcodes.i32_from_u
2448
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2449
+ [ Opcodes.local_tee, newValueTmp ],
2450
+
2451
+ ...number(0),
2452
+ [ Opcodes.f64_max ],
2453
+ ...number(255),
2454
+ [ Opcodes.f64_min ],
2455
+ Opcodes.i32_to_u,
2456
+ [ Opcodes.i32_store8, 0, 4 ]
2457
+ ],
2458
+ [TYPES.int8array]: [
2459
+ [ Opcodes.i32_add ],
2460
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2461
+
2462
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2463
+ [ Opcodes.local_get, pointerTmp ],
2464
+ [ Opcodes.i32_load8_s, 0, 4 ],
2465
+ Opcodes.i32_from
2466
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2467
+ [ Opcodes.local_tee, newValueTmp ],
2468
+
2469
+ Opcodes.i32_to,
2470
+ [ Opcodes.i32_store8, 0, 4 ]
2471
+ ],
2472
+ [TYPES.uint16array]: [
2473
+ ...number(2, Valtype.i32),
2474
+ [ Opcodes.i32_mul ],
2475
+ [ Opcodes.i32_add ],
2476
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2477
+
2478
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2479
+ [ Opcodes.local_get, pointerTmp ],
2480
+ [ Opcodes.i32_load16_u, 0, 4 ],
2481
+ Opcodes.i32_from_u
2482
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2483
+ [ Opcodes.local_tee, newValueTmp ],
2484
+
2485
+ Opcodes.i32_to_u,
2486
+ [ Opcodes.i32_store16, 0, 4 ]
2487
+ ],
2488
+ [TYPES.int16array]: [
2489
+ ...number(2, Valtype.i32),
2490
+ [ Opcodes.i32_mul ],
2491
+ [ Opcodes.i32_add ],
2492
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2493
+
2494
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2495
+ [ Opcodes.local_get, pointerTmp ],
2496
+ [ Opcodes.i32_load16_s, 0, 4 ],
2497
+ Opcodes.i32_from
2498
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2499
+ [ Opcodes.local_tee, newValueTmp ],
2500
+
2501
+ Opcodes.i32_to,
2502
+ [ Opcodes.i32_store16, 0, 4 ]
2503
+ ],
2504
+ [TYPES.uint32array]: [
2505
+ ...number(4, Valtype.i32),
2506
+ [ Opcodes.i32_mul ],
2507
+ [ Opcodes.i32_add ],
2508
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2509
+
2510
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2511
+ [ Opcodes.local_get, pointerTmp ],
2512
+ [ Opcodes.i32_load, 0, 4 ],
2513
+ Opcodes.i32_from_u
2514
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2515
+ [ Opcodes.local_tee, newValueTmp ],
2516
+
2517
+ Opcodes.i32_to_u,
2518
+ [ Opcodes.i32_store, 0, 4 ]
2519
+ ],
2520
+ [TYPES.int32array]: [
2521
+ ...number(4, Valtype.i32),
2522
+ [ Opcodes.i32_mul ],
2523
+ [ Opcodes.i32_add ],
2524
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2525
+
2526
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2527
+ [ Opcodes.local_get, pointerTmp ],
2528
+ [ Opcodes.i32_load, 0, 4 ],
2529
+ Opcodes.i32_from
2530
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2531
+ [ Opcodes.local_tee, newValueTmp ],
2532
+
2533
+ Opcodes.i32_to,
2534
+ [ Opcodes.i32_store, 0, 4 ]
2535
+ ],
2536
+ [TYPES.float32array]: [
2537
+ ...number(4, Valtype.i32),
2538
+ [ Opcodes.i32_mul ],
2539
+ [ Opcodes.i32_add ],
2540
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2541
+
2542
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2543
+ [ Opcodes.local_get, pointerTmp ],
2544
+ [ Opcodes.f32_load, 0, 4 ],
2545
+ [ Opcodes.f64_promote_f32 ]
2546
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2547
+ [ Opcodes.local_tee, newValueTmp ],
2548
+
2549
+ [ Opcodes.f32_demote_f64 ],
2550
+ [ Opcodes.f32_store, 0, 4 ]
2551
+ ],
2552
+ [TYPES.float64array]: [
2553
+ ...number(8, Valtype.i32),
2554
+ [ Opcodes.i32_mul ],
2555
+ [ Opcodes.i32_add ],
2556
+ ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2557
+
2558
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2559
+ [ Opcodes.local_get, pointerTmp ],
2560
+ [ Opcodes.f64_load, 0, 4 ]
2561
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
2562
+ [ Opcodes.local_tee, newValueTmp ],
2563
+
2564
+ [ Opcodes.f64_store, 0, 4 ]
2565
+ ],
2566
+ }, {
2567
+ prelude: [
2568
+ ...generate(scope, decl.left.object),
2569
+ Opcodes.i32_to_u,
2570
+ ...generate(scope, decl.left.property),
2571
+ Opcodes.i32_to_u,
2572
+ ],
2573
+ postlude: setLastType(scope, TYPES.number)
2574
+ }),
2575
+
2386
2576
  default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
2387
2577
  }, Blocktype.void),
2388
2578
 
@@ -2766,7 +2956,9 @@ const generateForOf = (scope, decl) => {
2766
2956
  // // todo: we should only do this for strings but we don't know at compile-time :(
2767
2957
  // hack: this is naughty and will break things!
2768
2958
  let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
2769
- if (pages.hasAnyString) {
2959
+
2960
+ const known = knownType(scope, getNodeType(scope, decl.right));
2961
+ if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
2770
2962
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
2771
2963
  0, [ newOut, newPointer ] = makeArray(scope, {
2772
2964
  rawElements: new Array(0)
@@ -2814,6 +3006,7 @@ const generateForOf = (scope, decl) => {
2814
3006
  [ Opcodes.end ],
2815
3007
  [ Opcodes.end ]
2816
3008
  ],
3009
+
2817
3010
  [TYPES.string]: [
2818
3011
  ...setType(scope, leftName, TYPES.string),
2819
3012
 
@@ -2922,6 +3115,7 @@ const generateForOf = (scope, decl) => {
2922
3115
  [ Opcodes.end ],
2923
3116
  [ Opcodes.end ]
2924
3117
  ],
3118
+
2925
3119
  [TYPES.set]: [
2926
3120
  [ Opcodes.loop, Blocktype.void ],
2927
3121
 
@@ -2960,6 +3154,106 @@ const generateForOf = (scope, decl) => {
2960
3154
  [ Opcodes.end ],
2961
3155
  [ Opcodes.end ]
2962
3156
  ],
3157
+
3158
+ ...wrapBC({
3159
+ [TYPES.uint8array]: [
3160
+ [ Opcodes.i32_add ],
3161
+
3162
+ [ Opcodes.i32_load8_u, 0, 4 ],
3163
+ Opcodes.i32_from_u
3164
+ ],
3165
+ [TYPES.uint8clampedarray]: [
3166
+ [ Opcodes.i32_add ],
3167
+
3168
+ [ Opcodes.i32_load8_u, 0, 4 ],
3169
+ Opcodes.i32_from_u
3170
+ ],
3171
+ [TYPES.int8array]: [
3172
+ [ Opcodes.i32_add ],
3173
+
3174
+ [ Opcodes.i32_load8_s, 0, 4 ],
3175
+ Opcodes.i32_from
3176
+ ],
3177
+ [TYPES.uint16array]: [
3178
+ ...number(2, Valtype.i32),
3179
+ [ Opcodes.i32_mul ],
3180
+ [ Opcodes.i32_add ],
3181
+
3182
+ [ Opcodes.i32_load16_u, 0, 4 ],
3183
+ Opcodes.i32_from_u
3184
+ ],
3185
+ [TYPES.int16array]: [
3186
+ ...number(2, Valtype.i32),
3187
+ [ Opcodes.i32_mul ],
3188
+ [ Opcodes.i32_add ],
3189
+
3190
+ [ Opcodes.i32_load16_s, 0, 4 ],
3191
+ Opcodes.i32_from
3192
+ ],
3193
+ [TYPES.uint32array]: [
3194
+ ...number(4, Valtype.i32),
3195
+ [ Opcodes.i32_mul ],
3196
+ [ Opcodes.i32_add ],
3197
+
3198
+ [ Opcodes.i32_load, 0, 4 ],
3199
+ Opcodes.i32_from_u
3200
+ ],
3201
+ [TYPES.int32array]: [
3202
+ ...number(4, Valtype.i32),
3203
+ [ Opcodes.i32_mul ],
3204
+ [ Opcodes.i32_add ],
3205
+
3206
+ [ Opcodes.i32_load, 0, 4 ],
3207
+ Opcodes.i32_from
3208
+ ],
3209
+ [TYPES.float32array]: [
3210
+ ...number(4, Valtype.i32),
3211
+ [ Opcodes.i32_mul ],
3212
+ [ Opcodes.i32_add ],
3213
+
3214
+ [ Opcodes.f32_load, 0, 4 ],
3215
+ [ Opcodes.f64_promote_f32 ]
3216
+ ],
3217
+ [TYPES.float64array]: [
3218
+ ...number(8, Valtype.i32),
3219
+ [ Opcodes.i32_mul ],
3220
+ [ Opcodes.i32_add ],
3221
+
3222
+ [ Opcodes.f64_load, 0, 4 ]
3223
+ ],
3224
+ }, {
3225
+ prelude: [
3226
+ ...setType(scope, leftName, TYPES.number),
3227
+
3228
+ [ Opcodes.loop, Blocktype.void ],
3229
+
3230
+ [ Opcodes.local_get, pointer ],
3231
+ [ Opcodes.local_get, counter ]
3232
+ ],
3233
+ postlude: [
3234
+ [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
3235
+
3236
+ [ Opcodes.block, Blocktype.void ],
3237
+ [ Opcodes.block, Blocktype.void ],
3238
+ ...generate(scope, decl.body),
3239
+ [ Opcodes.end ],
3240
+
3241
+ // increment counter by 1
3242
+ [ Opcodes.local_get, counter ],
3243
+ ...number(1, Valtype.i32),
3244
+ [ Opcodes.i32_add ],
3245
+ [ Opcodes.local_tee, counter ],
3246
+
3247
+ // loop if counter != length
3248
+ [ Opcodes.local_get, length ],
3249
+ [ Opcodes.i32_ne ],
3250
+ [ Opcodes.br_if, 1 ],
3251
+
3252
+ [ Opcodes.end ],
3253
+ [ Opcodes.end ]
3254
+ ]
3255
+ }),
3256
+
2963
3257
  default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
2964
3258
  }, Blocktype.void));
2965
3259
 
@@ -3048,13 +3342,14 @@ const generateThrow = (scope, decl) => {
3048
3342
  idx: tags.length
3049
3343
  });
3050
3344
 
3051
- let exceptId = exceptions.push({ constructor, message }) - 1;
3345
+ let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
3346
+ if (exceptId === -1) exceptId = exceptions.push({ constructor, message }) - 1;
3052
3347
 
3053
3348
  scope.exceptions ??= [];
3054
3349
  scope.exceptions.push(exceptId);
3055
3350
 
3056
3351
  return [
3057
- [ Opcodes.i32_const, signedLEB128(exceptId) ],
3352
+ ...number(exceptId, Valtype.i32),
3058
3353
  [ Opcodes.throw, tags[0].idx ]
3059
3354
  ];
3060
3355
  }
@@ -3121,7 +3416,7 @@ const generateThrow = (scope, decl) => {
3121
3416
  scope.exceptions.push(exceptId);
3122
3417
 
3123
3418
  return [
3124
- [ Opcodes.i32_const, signedLEB128(exceptId) ],
3419
+ ...number(exceptId, Valtype.i32),
3125
3420
  ...generate(scope, message),
3126
3421
  ...getNodeType(scope, message),
3127
3422
  [ Opcodes.throw, tags[0].idx ]
@@ -3479,6 +3774,19 @@ const withType = (scope, wasm, type) => [
3479
3774
  ...setLastType(scope, type)
3480
3775
  ];
3481
3776
 
3777
+ const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
3778
+ const out = {};
3779
+ for (const x in bc) {
3780
+ out[x] = [
3781
+ ...prelude,
3782
+ ...bc[x],
3783
+ ...postlude
3784
+ ];
3785
+ }
3786
+
3787
+ return out;
3788
+ };
3789
+
3482
3790
  const generateMember = (scope, decl, _global, _name) => {
3483
3791
  const name = decl.object.name;
3484
3792
 
@@ -3532,7 +3840,7 @@ const generateMember = (scope, decl, _global, _name) => {
3532
3840
  const type = getNodeType(scope, decl.object);
3533
3841
  const known = knownType(scope, type);
3534
3842
  if (known != null) {
3535
- if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
3843
+ if (typeHasFlag(known, TYPE_FLAGS.length)) return [
3536
3844
  ...generate(scope, decl.object),
3537
3845
  Opcodes.i32_to_u,
3538
3846
 
@@ -3544,7 +3852,9 @@ const generateMember = (scope, decl, _global, _name) => {
3544
3852
  }
3545
3853
 
3546
3854
  return [
3547
- ...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
3855
+ ...getNodeType(scope, decl.object),
3856
+ ...number(TYPE_FLAGS.length, Valtype.i32),
3857
+ [ Opcodes.i32_and ],
3548
3858
  [ Opcodes.if, valtypeBinary ],
3549
3859
  ...generate(scope, decl.object),
3550
3860
  Opcodes.i32_to_u,
@@ -3593,7 +3903,9 @@ const generateMember = (scope, decl, _global, _name) => {
3593
3903
  // // todo: we should only do this for strings but we don't know at compile-time :(
3594
3904
  // hack: this is naughty and will break things!
3595
3905
  let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
3596
- if (pages.hasAnyString && knownType(scope, getNodeType(scope, decl.object)) !== TYPES.array) {
3906
+
3907
+ const known = knownType(scope, getNodeType(scope, decl.object));
3908
+ if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
3597
3909
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
3598
3910
  0, [ newOut, newPointer ] = makeArray(scope, {
3599
3911
  rawElements: new Array(0)
@@ -3667,6 +3979,82 @@ const generateMember = (scope, decl, _global, _name) => {
3667
3979
  ...setLastType(scope, TYPES.bytestring)
3668
3980
  ],
3669
3981
 
3982
+ ...wrapBC({
3983
+ [TYPES.uint8array]: [
3984
+ [ Opcodes.i32_add ],
3985
+
3986
+ [ Opcodes.i32_load8_u, 0, 4 ],
3987
+ Opcodes.i32_from_u
3988
+ ],
3989
+ [TYPES.uint8clampedarray]: [
3990
+ [ Opcodes.i32_add ],
3991
+
3992
+ [ Opcodes.i32_load8_u, 0, 4 ],
3993
+ Opcodes.i32_from_u
3994
+ ],
3995
+ [TYPES.int8array]: [
3996
+ [ Opcodes.i32_add ],
3997
+
3998
+ [ Opcodes.i32_load8_s, 0, 4 ],
3999
+ Opcodes.i32_from
4000
+ ],
4001
+ [TYPES.uint16array]: [
4002
+ ...number(2, Valtype.i32),
4003
+ [ Opcodes.i32_mul ],
4004
+ [ Opcodes.i32_add ],
4005
+
4006
+ [ Opcodes.i32_load16_u, 0, 4 ],
4007
+ Opcodes.i32_from_u
4008
+ ],
4009
+ [TYPES.int16array]: [
4010
+ ...number(2, Valtype.i32),
4011
+ [ Opcodes.i32_mul ],
4012
+ [ Opcodes.i32_add ],
4013
+
4014
+ [ Opcodes.i32_load16_s, 0, 4 ],
4015
+ Opcodes.i32_from
4016
+ ],
4017
+ [TYPES.uint32array]: [
4018
+ ...number(4, Valtype.i32),
4019
+ [ Opcodes.i32_mul ],
4020
+ [ Opcodes.i32_add ],
4021
+
4022
+ [ Opcodes.i32_load, 0, 4 ],
4023
+ Opcodes.i32_from_u
4024
+ ],
4025
+ [TYPES.int32array]: [
4026
+ ...number(4, Valtype.i32),
4027
+ [ Opcodes.i32_mul ],
4028
+ [ Opcodes.i32_add ],
4029
+
4030
+ [ Opcodes.i32_load, 0, 4 ],
4031
+ Opcodes.i32_from
4032
+ ],
4033
+ [TYPES.float32array]: [
4034
+ ...number(4, Valtype.i32),
4035
+ [ Opcodes.i32_mul ],
4036
+ [ Opcodes.i32_add ],
4037
+
4038
+ [ Opcodes.f32_load, 0, 4 ],
4039
+ [ Opcodes.f64_promote_f32 ]
4040
+ ],
4041
+ [TYPES.float64array]: [
4042
+ ...number(8, Valtype.i32),
4043
+ [ Opcodes.i32_mul ],
4044
+ [ Opcodes.i32_add ],
4045
+
4046
+ [ Opcodes.f64_load, 0, 4 ]
4047
+ ],
4048
+ }, {
4049
+ prelude: [
4050
+ ...object,
4051
+ Opcodes.i32_to_u,
4052
+ ...property,
4053
+ Opcodes.i32_to_u
4054
+ ],
4055
+ postlude: setLastType(scope, TYPES.number)
4056
+ }),
4057
+
3670
4058
  default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
3671
4059
  });
3672
4060
  };