porffor 0.42.6 → 0.42.8

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.
@@ -279,7 +279,7 @@ export const __Math_cbrt = (y: number): number => {
279
279
  if (!Number.isFinite(y)) return y;
280
280
 
281
281
  // Babylonian method
282
- let x = Math.abs(y);
282
+ let x:number = Math.abs(y);
283
283
 
284
284
  let prev: number;
285
285
 
@@ -1780,9 +1780,9 @@ params:[124,127],typedParams:1,returns:[124,127],typedReturns:1,
1780
1780
  locals:[124,124],localNames:["y","y#type","x","prev"],
1781
1781
  }
1782
1782
  this.__Math_cbrt = {
1783
- wasm:(_,{builtin})=>[[32,0],[68,0],[97],[4,64],[68,0],[65,1],[15],[11],[32,0],[16,builtin('__Number_isFinite')],[68,0],[97],[4,64],[32,0],[65,1],[15],[11],[32,0],[16,builtin('__Math_abs')],[33,2],[65,1],[33,3],[3,64],[2,64],[32,2],[33,4],[68,2],[32,2],[162],[32,0],[32,2],[32,2],[162],[163],[160],[68,3],[163],[34,2],[65,1],[33,3],[26],[32,4],[32,2],[161],[16,builtin('__Math_abs')],[68,1e-15],[100],[13,1],[11],[11],[32,0],[68,0],[99],[4,124],[32,2],[154],[65,1],[33,5],[5],[32,2],[32,3],[33,5],[11],[32,5],[15]],
1783
+ wasm:(_,{builtin})=>[[32,0],[68,0],[97],[4,64],[68,0],[65,1],[15],[11],[32,0],[16,builtin('__Number_isFinite')],[68,0],[97],[4,64],[32,0],[65,1],[15],[11],[32,0],[16,builtin('__Math_abs')],[33,2],[3,64],[2,64],[32,2],[33,3],[68,2],[32,2],[162],[32,0],[32,2],[32,2],[162],[163],[160],[68,3],[163],[33,2],[32,3],[32,2],[161],[16,builtin('__Math_abs')],[68,1e-15],[100],[13,1],[11],[11],[32,0],[68,0],[99],[4,124],[32,2],[154],[65,1],[33,4],[5],[32,2],[65,1],[33,4],[11],[32,4],[15]],
1784
1784
  params:[124,127],typedParams:1,returns:[124,127],typedReturns:1,
1785
- locals:[124,127,124,127],localNames:["y","y#type","x","x#type","prev","#last_type"],
1785
+ locals:[124,124,127],localNames:["y","y#type","x","prev","#last_type"],
1786
1786
  }
1787
1787
  this.__Math_hypot = {
1788
1788
  wasm:(_,{builtin})=>[[32,0],[32,0],[162],[32,2],[32,2],[162],[160],[65,1],[16,builtin('__Math_sqrt')],[34,4],[15]],
@@ -399,9 +399,19 @@ const generateIdent = (scope, decl) => {
399
399
 
400
400
  if (local?.idx === undefined) {
401
401
  if (name === 'arguments' && scope.name !== 'main' && !scope.arrow) {
402
- // todo: stub arguments as [] for now :)
402
+ // todo: not compliant
403
+ let len = countLength(scope);
404
+ const names = new Array(len);
405
+ const off = scope.constr ? 4 : 0;
406
+ for (const x in scope.locals) {
407
+ const i = scope.locals[x].idx - off;
408
+ if (i >= 0 && i % 2 === 0 && i < len * 2) {
409
+ names[i / 2] = x;
410
+ }
411
+ }
412
+
403
413
  return generateArray(scope, {
404
- elements: []
414
+ elements: names.map(x => ({ type: 'Identifier', name: x }))
405
415
  }, false, '#arguments');
406
416
  }
407
417
 
@@ -1340,8 +1350,12 @@ const setType = (scope, name, type) => {
1340
1350
  };
1341
1351
 
1342
1352
  const getLastType = scope => {
1353
+ if (!scope.locals['#last_type']) return number(TYPES.number, Valtype.i32);
1354
+
1343
1355
  scope.gotLastType = true;
1344
- return [ [ Opcodes.local_get, localTmp(scope, '#last_type', Valtype.i32) ] ];
1356
+ return [
1357
+ [ Opcodes.local_get, localTmp(scope, '#last_type', Valtype.i32) ]
1358
+ ];
1345
1359
  };
1346
1360
 
1347
1361
  const setLastType = (scope, type = []) => {
@@ -1388,11 +1402,7 @@ const getNodeType = (scope, node) => {
1388
1402
 
1389
1403
  if (name == null) {
1390
1404
  // iife
1391
- if (scope.locals['#last_type']) return getLastType(scope);
1392
-
1393
- // presume
1394
- if (Prefs.warnAssumedType) console.warn(`Indirect call assumed to be number`);
1395
- return TYPES.number;
1405
+ return getLastType(scope);
1396
1406
  }
1397
1407
 
1398
1408
  const func = funcByName(name);
@@ -1426,38 +1436,7 @@ const getNodeType = (scope, node) => {
1426
1436
  return TYPES.number;
1427
1437
  }
1428
1438
 
1429
- if (scope.locals['#last_type']) return getLastType(scope);
1430
-
1431
- // presume
1432
- if (Prefs.warnAssumedType) console.warn(`Call to ${name} assumed to be number`);
1433
- return TYPES.number;
1434
-
1435
- // let protoFunc;
1436
- // // ident.func()
1437
- // if (name && name.startsWith('__')) {
1438
- // const spl = name.slice(2).split('_');
1439
-
1440
- // const baseName = spl.slice(0, -1).join('_');
1441
- // const baseType = getType(scope, baseName);
1442
-
1443
- // const func = spl[spl.length - 1];
1444
- // protoFunc = prototypeFuncs[baseType]?.[func];
1445
- // }
1446
-
1447
- // // literal.func()
1448
- // if (!name && node.callee.type === 'MemberExpression') {
1449
- // if (node.callee.object.regex) {
1450
- // const funcName = node.callee.property.name;
1451
- // return Rhemyn[funcName] ? TYPES.boolean : TYPES.undefined;
1452
- // }
1453
-
1454
- // const baseType = getNodeType(scope, node.callee.object);
1455
-
1456
- // const func = node.callee.property.name;
1457
- // protoFunc = prototypeFuncs[baseType]?.[func];
1458
- // }
1459
-
1460
- // if (protoFunc) return protoFunc.returnType;
1439
+ return getLastType(scope);
1461
1440
  }
1462
1441
 
1463
1442
  if (node.type === 'ExpressionStatement') {
@@ -1505,10 +1484,7 @@ const getNodeType = (scope, node) => {
1505
1484
  if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
1506
1485
  guess = TYPES.bytestring;
1507
1486
 
1508
- if (scope.locals['#last_type']) return getLastType(scope);
1509
-
1510
- // presume
1511
- return TYPES.number;
1487
+ return getLastType(scope);
1512
1488
  }
1513
1489
 
1514
1490
  if (node.type === 'UnaryExpression') {
@@ -1542,11 +1518,7 @@ const getNodeType = (scope, node) => {
1542
1518
  }
1543
1519
  }
1544
1520
 
1545
- if (scope.locals['#last_type']) return getLastType(scope);
1546
-
1547
- // presume
1548
- if (Prefs.warnAssumedType) console.warn(`Member access to field .${name} assumed to be number`);
1549
- return TYPES.number;
1521
+ return getLastType(scope);
1550
1522
  }
1551
1523
 
1552
1524
  if (node.type === 'TemplateLiteral') {
@@ -1579,11 +1551,7 @@ const getNodeType = (scope, node) => {
1579
1551
  }
1580
1552
  }
1581
1553
 
1582
- if (scope.locals['#last_type']) return getLastType(scope);
1583
-
1584
- // presume
1585
- if (Prefs.warnAssumedType) console.warn(`AST node ${node.type} assumed to be number`);
1586
- return TYPES.number;
1554
+ return getLastType(scope);
1587
1555
  })();
1588
1556
 
1589
1557
  const out = typeof ret === 'number' ? number(ret, Valtype.i32) : ret;
@@ -2447,6 +2415,31 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2447
2415
  paramOffset += 4;
2448
2416
  }
2449
2417
 
2418
+ if (args.at(-1)?.type === 'SpreadElement') {
2419
+ // hack: support spread element if last by doing essentially:
2420
+ // const foo = (a, b, c, d) => ...
2421
+ // foo(a, b, ...c) -> _ = c; foo(a, b, _[0], _[1])
2422
+ const arg = args.at(-1).argument;
2423
+ out.push(
2424
+ ...generate(scope, arg),
2425
+ [ Opcodes.local_set, localTmp(scope, '#spread') ],
2426
+ ...getNodeType(scope, arg),
2427
+ [ Opcodes.local_set, localTmp(scope, '#spread#type', Valtype.i32) ]
2428
+ );
2429
+
2430
+ args.pop();
2431
+ const leftover = paramCount - args.length;
2432
+ for (let i = 0; i < leftover; i++) {
2433
+ args.push({
2434
+ type: 'MemberExpression',
2435
+ object: { type: 'Identifier', name: '#spread' },
2436
+ property: { type: 'Literal', value: i },
2437
+ computed: true,
2438
+ optional: false
2439
+ });
2440
+ }
2441
+ }
2442
+
2450
2443
  if (func && args.length < paramCount) {
2451
2444
  // too little args, push undefineds
2452
2445
  args = args.concat(new Array(paramCount - (func.hasRestArgument ? 1 : 0) - args.length).fill(DEFAULT_VALUE()));
@@ -3689,7 +3682,10 @@ const ifIdentifierErrors = (scope, decl) => {
3689
3682
  const generateUnary = (scope, decl) => {
3690
3683
  switch (decl.operator) {
3691
3684
  case '+':
3692
- // todo/opt: skip ToNumber if already known number type
3685
+ // opt: skip ToNumber if already known as number type
3686
+ generate(scope, decl.argument); // hack: fix last type not being defined for getNodeType before generation
3687
+ const known = knownType(scope, getNodeType(scope, decl.argument));
3688
+ if (known === TYPES.number) return generate(scope, decl.argument);
3693
3689
 
3694
3690
  // 13.5.4 Unary + Operator, 13.5.4.1 Runtime Semantics: Evaluation
3695
3691
  // https://tc39.es/ecma262/#sec-unary-plus-operator-runtime-semantics-evaluation
@@ -3707,7 +3703,7 @@ const generateUnary = (scope, decl) => {
3707
3703
  });
3708
3704
 
3709
3705
  case '-':
3710
- // * -1
3706
+ // +x * -1
3711
3707
 
3712
3708
  if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
3713
3709
  // if -n, just return that as a const
@@ -3715,7 +3711,12 @@ const generateUnary = (scope, decl) => {
3715
3711
  }
3716
3712
 
3717
3713
  return [
3718
- ...generate(scope, decl.argument),
3714
+ ...generate(scope, {
3715
+ type: 'UnaryExpression',
3716
+ operator: '+',
3717
+ prefix: true,
3718
+ argument: decl.argument
3719
+ }),
3719
3720
  ...(valtype === 'f64' ? [ [ Opcodes.f64_neg ] ] : [ ...number(-1), [ Opcodes.mul ] ])
3720
3721
  ];
3721
3722
 
@@ -3731,7 +3732,12 @@ const generateUnary = (scope, decl) => {
3731
3732
 
3732
3733
  case '~':
3733
3734
  return [
3734
- ...generate(scope, decl.argument),
3735
+ ...generate(scope, {
3736
+ type: 'UnaryExpression',
3737
+ operator: '+',
3738
+ prefix: true,
3739
+ argument: decl.argument
3740
+ }),
3735
3741
  Opcodes.i32_to,
3736
3742
  [ Opcodes.i32_const, ...signedLEB128(-1) ],
3737
3743
  [ Opcodes.i32_xor ],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
4
- "version": "0.42.6+d8f9d3f11",
4
+ "version": "0.42.8+06fc0f2c7",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {},
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.42.6+d8f9d3f11';
3
+ globalThis.version = '0.42.8+06fc0f2c7';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
package/runner/repl.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { TYPE_NAMES } from '../compiler/types.js';
2
2
  import compile from '../compiler/wrap.js';
3
+ import parse from '../compiler/parse.js';
3
4
 
4
5
  import util from 'node:util';
5
6
 
@@ -83,7 +84,13 @@ const run = (source, _context, _filename, callback, run = true) => {
83
84
  // hack: print "secret" before latest code ran to only enable printing for new code
84
85
 
85
86
  source = source.trim();
86
- if (source.startsWith('{') && source.endsWith('}')) source = '(' + source + ')';
87
+ if (source.startsWith('{') && source.endsWith('}')) {
88
+ const wrapped = '(' + source + ')';
89
+ try {
90
+ parse(wrapped);
91
+ source = wrapped;
92
+ } catch {}
93
+ }
87
94
 
88
95
  let toRun = (prev ? (prev + `;\nprint(-0x1337);\n`) : '') + source;
89
96