porffor 0.0.0-579ef36 → 0.0.0-745e995

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.
@@ -327,13 +327,13 @@ const concatStrings = (scope, left, right, global, name, assign) => {
327
327
 
328
328
  scope.memory = true;
329
329
 
330
- const pointer = arrays.get(name ?? '$undeclared');
331
-
332
330
  const rightPointer = localTmp(scope, 'concat_right_pointer', Valtype.i32);
333
331
  const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
334
332
  const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
335
333
 
336
334
  if (assign) {
335
+ const pointer = arrays.get(name ?? '$undeclared');
336
+
337
337
  return [
338
338
  // setup right
339
339
  ...right,
@@ -384,15 +384,96 @@ const concatStrings = (scope, left, right, global, name, assign) => {
384
384
 
385
385
  const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
386
386
 
387
- const newOut = makeArray(scope, {
387
+ // alloc/assign array
388
+ const [ , pointer ] = makeArray(scope, {
388
389
  rawElements: new Array(0)
389
390
  }, global, name, true, 'i16');
390
391
 
391
392
  return [
392
- // setup new/out array
393
- ...newOut,
394
- [ Opcodes.drop ],
393
+ // setup left
394
+ ...left,
395
+ Opcodes.i32_to_u,
396
+ [ Opcodes.local_set, leftPointer ],
397
+
398
+ // setup right
399
+ ...right,
400
+ Opcodes.i32_to_u,
401
+ [ Opcodes.local_set, rightPointer ],
402
+
403
+ // calculate length
404
+ ...number(0, Valtype.i32), // base 0 for store later
395
405
 
406
+ [ Opcodes.local_get, leftPointer ],
407
+ [ Opcodes.i32_load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(0) ],
408
+ [ Opcodes.local_tee, leftLength ],
409
+
410
+ [ Opcodes.local_get, rightPointer ],
411
+ [ Opcodes.i32_load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(0) ],
412
+ [ Opcodes.local_tee, rightLength ],
413
+
414
+ [ Opcodes.i32_add ],
415
+
416
+ // store length
417
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
418
+
419
+ // copy left
420
+ // dst = out pointer + length size
421
+ ...number(pointer + ValtypeSize.i32, Valtype.i32),
422
+
423
+ // src = left pointer + length size
424
+ [ Opcodes.local_get, leftPointer ],
425
+ ...number(ValtypeSize.i32, Valtype.i32),
426
+ [ Opcodes.i32_add ],
427
+
428
+ // size = PageSize - length size. we do not need to calculate length as init value
429
+ ...number(pageSize - ValtypeSize.i32, Valtype.i32),
430
+ [ ...Opcodes.memory_copy, 0x00, 0x00 ],
431
+
432
+ // copy right
433
+ // dst = out pointer + length size + left length * i16 size
434
+ ...number(pointer + ValtypeSize.i32, Valtype.i32),
435
+
436
+ [ Opcodes.local_get, leftLength ],
437
+ ...number(ValtypeSize.i16, Valtype.i32),
438
+ [ Opcodes.i32_mul ],
439
+ [ Opcodes.i32_add ],
440
+
441
+ // src = right pointer + length size
442
+ [ Opcodes.local_get, rightPointer ],
443
+ ...number(ValtypeSize.i32, Valtype.i32),
444
+ [ Opcodes.i32_add ],
445
+
446
+ // size = right length * i16 size
447
+ [ Opcodes.local_get, rightLength ],
448
+ ...number(ValtypeSize.i16, Valtype.i32),
449
+ [ Opcodes.i32_mul ],
450
+
451
+ [ ...Opcodes.memory_copy, 0x00, 0x00 ],
452
+
453
+ // return new string (page)
454
+ ...number(pointer)
455
+ ];
456
+ };
457
+
458
+ const compareStrings = (scope, left, right, global, name) => {
459
+ // todo: this should be rewritten into a built-in/func: String.prototype.concat
460
+ // todo: convert left and right to strings if not
461
+ // todo: optimize by looking up names in arrays and using that if exists?
462
+ // todo: optimize this if using literals/known lengths?
463
+
464
+ scope.memory = true;
465
+
466
+ const rightPointer = localTmp(scope, 'concat_right_pointer', Valtype.i32);
467
+ const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
468
+ const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
469
+ const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
470
+
471
+ // alloc/assign array
472
+ const [ , pointer ] = makeArray(scope, {
473
+ rawElements: new Array(0)
474
+ }, global, name, true, 'i16');
475
+
476
+ return [
396
477
  // setup left
397
478
  ...left,
398
479
  Opcodes.i32_to_u,
@@ -524,11 +605,28 @@ const truthy = (scope, wasm, type) => {
524
605
  ];
525
606
  };
526
607
 
527
- const performOp = (scope, op, left, right, leftType, rightType, _global = false, _name = '$unspecified', assign = false) => {
608
+ const performOp = (scope, op, left, right, leftType, rightType, _global = false, _name = '$undeclared', assign = false) => {
528
609
  if (op === '||' || op === '&&' || op === '??') {
529
610
  return performLogicOp(scope, op, left, right);
530
611
  }
531
612
 
613
+ if (codeLog && (!leftType || !rightType)) log('codegen', 'untracked type in op', op, _name, '\n' + new Error().stack.split('\n').slice(1).join('\n'));
614
+
615
+ // if strict (in)equal and known types mismatch, return false (===)/true (!==)
616
+ if ((op === '===' || op === '!==') && leftType && rightType && leftType !== rightType) {
617
+ return [
618
+ ...left,
619
+ ...right,
620
+
621
+ // drop values
622
+ [ Opcodes.drop ],
623
+ [ Opcodes.drop ],
624
+
625
+ // return false (===)/true (!==)
626
+ ...number(op === '===' ? 0 : 1, Valtype.i32)
627
+ ];
628
+ }
629
+
532
630
  if (leftType === TYPES.string || rightType === TYPES.string) {
533
631
  if (op === '+') {
534
632
  // string concat (a + b)
@@ -539,8 +637,13 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
539
637
  if (!['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(op)) return number(NaN);
540
638
 
541
639
  // else leave bool ops
542
- // todo: convert string to number if string and number or le/ge op
543
- // todo: string equality
640
+ // todo: convert string to number if string and number/bool
641
+ // todo: string (>|>=|<|<=) string
642
+
643
+ // string equality
644
+ if (op === '===') {
645
+
646
+ }
544
647
  }
545
648
 
546
649
  let ops = operatorOpcode[valtype][op];
@@ -569,13 +672,17 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
569
672
  ];
570
673
  };
571
674
 
675
+ let binaryExpDepth = 0;
572
676
  const generateBinaryExp = (scope, decl, _global, _name) => {
677
+ binaryExpDepth++;
678
+
573
679
  const out = [
574
680
  ...performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name)
575
681
  ];
576
682
 
577
683
  if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
578
684
 
685
+ binaryExpDepth--;
579
686
  return out;
580
687
  };
581
688
 
@@ -696,7 +803,7 @@ const getNodeType = (scope, node) => {
696
803
  if (node.type === 'CallExpression' || node.type === 'NewExpression') {
697
804
  const name = node.callee.name;
698
805
  const func = funcs.find(x => x.name === name);
699
- if (func) return func.returnType ?? TYPES.number;
806
+ if (func) return func.returnType;
700
807
 
701
808
  if (builtinFuncs[name]) return TYPES[builtinFuncs[name].returnType ?? 'number'];
702
809
  if (internalConstrs[name]) return internalConstrs[name].type;
@@ -721,9 +828,7 @@ const getNodeType = (scope, node) => {
721
828
  protoFunc = prototypeFuncs[baseType]?.[func];
722
829
  }
723
830
 
724
- if (protoFunc) return protoFunc.returnType ?? TYPES.number;
725
-
726
- return TYPES.number;
831
+ if (protoFunc) return protoFunc.returnType;
727
832
  }
728
833
 
729
834
  if (node.type === 'ExpressionStatement') {
@@ -755,9 +860,6 @@ const getNodeType = (scope, node) => {
755
860
 
756
861
  if (objectType === TYPES.string && node.computed) return TYPES.string;
757
862
  }
758
-
759
- // default to number
760
- return TYPES.number;
761
863
  };
762
864
 
763
865
  const generateLiteral = (scope, decl, global, name) => {
@@ -792,7 +894,7 @@ const generateLiteral = (scope, decl, global, name) => {
792
894
 
793
895
  return makeArray(scope, {
794
896
  rawElements
795
- }, global, name, false, 'i16');
897
+ }, global, name, false, 'i16')[0];
796
898
 
797
899
  default:
798
900
  return todo(`cannot generate literal of type ${typeof decl.value}`);
@@ -941,10 +1043,9 @@ const generateCall = (scope, decl, _global, _name) => {
941
1043
  if (codeLog) log('codegen', 'cloning unknown dynamic pointer');
942
1044
 
943
1045
  // register array
944
- makeArray(scope, {
1046
+ const [ , pointer ] = makeArray(scope, {
945
1047
  rawElements: new Array(0)
946
1048
  }, _global, baseName, true, baseType === TYPES.string ? 'i16' : valtype);
947
- pointer = arrays.get(baseName);
948
1049
 
949
1050
  const [ local, isGlobal ] = lookupName(scope, baseName);
950
1051
 
@@ -980,10 +1081,9 @@ const generateCall = (scope, decl, _global, _name) => {
980
1081
  set: value => arrayUtil.setLength(pointer, value),
981
1082
  setI32: value => arrayUtil.setLengthI32(pointer, value)
982
1083
  }, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, (length, itemType) => {
983
- const out = makeArray(scope, {
1084
+ return makeArray(scope, {
984
1085
  rawElements: new Array(length)
985
1086
  }, _global, _name, true, itemType);
986
- return [ out, arrays.get(_name ?? '$undeclared') ];
987
1087
  }),
988
1088
  [ Opcodes.end ]
989
1089
  ];
@@ -1289,7 +1389,7 @@ const generateUnary = (scope, decl) => {
1289
1389
  return out;
1290
1390
 
1291
1391
  case 'typeof':
1292
- const type = getNodeType(scope, decl.argument);
1392
+ const type = getNodeType(scope, decl.argument) ?? TYPES.number;
1293
1393
 
1294
1394
  // for custom types, just return object
1295
1395
  if (type > 0xffffffffffff7) return number(TYPES.object);
@@ -1578,12 +1678,12 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
1578
1678
 
1579
1679
  scope.memory = true;
1580
1680
 
1581
- return out;
1681
+ return [ out, pointer ];
1582
1682
  };
1583
1683
 
1584
1684
  let arrays = new Map();
1585
1685
  const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
1586
- return makeArray(scope, decl, global, name, initEmpty, valtype);
1686
+ return makeArray(scope, decl, global, name, initEmpty, valtype)[0];
1587
1687
  };
1588
1688
 
1589
1689
  export const generateMember = (scope, decl, _global, _name) => {
@@ -1644,10 +1744,9 @@ export const generateMember = (scope, decl, _global, _name) => {
1644
1744
 
1645
1745
  // string
1646
1746
 
1647
- const newOut = makeArray(scope, {
1747
+ const [ newOut, newPointer ] = makeArray(scope, {
1648
1748
  rawElements: new Array(1)
1649
1749
  }, _global, _name, true, 'i16');
1650
- const newPointer = arrays.get(_name ?? '$undeclared');
1651
1750
 
1652
1751
  return [
1653
1752
  // setup new/out array
@@ -1753,7 +1852,7 @@ const generateFunc = (scope, decl) => {
1753
1852
  name,
1754
1853
  params: Object.values(innerScope.locals).slice(0, params.length).map(x => x.type),
1755
1854
  returns: innerScope.returns,
1756
- returnType: innerScope.returnType ?? TYPES.number,
1855
+ returnType: innerScope.returnType,
1757
1856
  locals: innerScope.locals,
1758
1857
  memory: innerScope.memory,
1759
1858
  throws: innerScope.throws,
@@ -1912,10 +2011,9 @@ const internalConstrs = {
1912
2011
 
1913
2012
  // new Array(n)
1914
2013
 
1915
- makeArray(scope, {
2014
+ const [ , pointer ] = makeArray(scope, {
1916
2015
  rawElements: new Array(0)
1917
2016
  }, global, name, true);
1918
- const pointer = arrays.get(name ?? '$undeclared');
1919
2017
 
1920
2018
  const arg = decl.arguments[0] ?? DEFAULT_VALUE;
1921
2019
 
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.0.0-579ef36",
4
+ "version": "0.0.0-745e995",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "dependencies": {
package/runner/repl.js CHANGED
@@ -56,7 +56,7 @@ const run = async (source, _context, _filename, callback, run = true) => {
56
56
  const { exports, wasm, pages } = await compile(toRun, []);
57
57
  fs.writeFileSync('out.wasm', Buffer.from(wasm));
58
58
 
59
- if (exports.$) {
59
+ if (run && exports.$) {
60
60
  lastMemory = exports.$;
61
61
  lastPages = [...pages.keys()];
62
62
  }
@@ -64,8 +64,8 @@ const run = async (source, _context, _filename, callback, run = true) => {
64
64
  const ret = run ? exports.main() : undefined;
65
65
  callback(null, ret);
66
66
 
67
- // if (source.includes(' = ') || source.includes('let ') || source.includes('var ') || source.includes('const ')) prev += source + ';\n';
68
- prev = toRun + ';\n';
67
+ if (source.includes(' = ') || source.includes('let ') || source.includes('var ') || source.includes('const ') || source.includes('function ')) prev = toRun + ';\n';
68
+ // prev = toRun + ';\n';
69
69
  };
70
70
 
71
71
  const replServer = repl.start({ prompt: '> ', eval: run });