porffor 0.35.0 → 0.35.2

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.
@@ -183,6 +183,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
183
183
  case 'AwaitExpression':
184
184
  return cacheAst(decl, generateAwait(scope, decl));
185
185
 
186
+ case 'TemplateLiteral':
187
+ return cacheAst(decl, generateTemplate(scope, decl));
188
+
186
189
  case 'ExportNamedDeclaration':
187
190
  if (!decl.declaration) return todo(scope, 'unsupported export declaration');
188
191
 
@@ -499,126 +502,19 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
499
502
  ];
500
503
  };
501
504
 
502
- const concatStrings = (scope, left, right, leftType, rightType, allBytestrings = false, skipTypeCheck = false) => {
503
- // todo: this should be rewritten into a built-in/func: String.prototype.concat
504
- // todo: convert left and right to strings if not
505
- // todo: optimize by looking up names in arrays and using that if exists?
506
- // todo: optimize this if using literals/known lengths?
507
-
508
- const rightPointer = localTmp(scope, 'concat_right_pointer', Valtype.i32);
509
- const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
510
- const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
511
-
512
- const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
513
-
514
- // alloc/assign array
515
- const out = localTmp(scope, 'concat_out_pointer', Valtype.i32);
516
-
517
- if (!skipTypeCheck && !allBytestrings) includeBuiltin(scope, '__Porffor_bytestringToString');
505
+ const concatStrings = (scope, left, right, leftType, rightType) => {
518
506
  return [
519
- // setup pointers
520
- ...(left.length === 0 ? [
521
- Opcodes.i32_to_u,
522
- [ Opcodes.local_set, rightPointer ],
523
-
524
- Opcodes.i32_to_u,
525
- [ Opcodes.local_set, leftPointer ],
526
- ] : [
527
- ...left,
528
- Opcodes.i32_to_u,
529
- [ Opcodes.local_set, leftPointer ],
530
-
531
- ...right,
532
- Opcodes.i32_to_u,
533
- [ Opcodes.local_set, rightPointer ],
534
- ]),
535
-
536
- // setup out
537
- [ Opcodes.i32_const, 1 ],
538
- [ Opcodes.memory_grow, 0 ],
539
- [ Opcodes.i32_const, ...signedLEB128(65536) ],
540
- [ Opcodes.i32_mul ],
541
- [ Opcodes.local_tee, out ],
542
-
543
- // calculate length
544
- [ Opcodes.local_get, leftPointer ],
545
- [ Opcodes.i32_load, 0, 0 ],
546
- [ Opcodes.local_tee, leftLength ],
547
-
548
- [ Opcodes.local_get, rightPointer ],
549
- [ Opcodes.i32_load, 0, 0 ],
550
- [ Opcodes.local_tee, rightLength ],
551
-
552
- [ Opcodes.i32_add ],
553
-
554
- // store length
555
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
556
-
557
- ...(skipTypeCheck || allBytestrings ? [] : [
558
- ...leftType,
559
- ...number(TYPES.bytestring, Valtype.i32),
560
- [ Opcodes.i32_eq ],
561
- [ Opcodes.if, Blocktype.void ],
562
- [ Opcodes.local_get, leftPointer ],
563
- [ Opcodes.local_get, leftLength ],
564
- [ Opcodes.call, funcIndex.__Porffor_bytestringToString ],
565
- [ Opcodes.local_set, leftPointer ],
566
- [ Opcodes.end ],
567
-
568
- ...rightType,
569
- ...number(TYPES.bytestring, Valtype.i32),
570
- [ Opcodes.i32_eq ],
571
- [ Opcodes.if, Blocktype.void ],
572
- [ Opcodes.local_get, rightPointer ],
573
- [ Opcodes.local_get, rightLength ],
574
- [ Opcodes.call, funcIndex.__Porffor_bytestringToString ],
575
- [ Opcodes.local_set, rightPointer ],
576
- [ Opcodes.end ]
577
- ]),
578
-
579
- // copy left
580
- // dst = out pointer + length size
581
- [ Opcodes.local_get, out ],
582
- ...number(ValtypeSize.i32, Valtype.i32),
583
- [ Opcodes.i32_add ],
584
-
585
- // src = left pointer + length size
586
- [ Opcodes.local_get, leftPointer ],
587
- ...number(ValtypeSize.i32, Valtype.i32),
588
- [ Opcodes.i32_add ],
589
-
590
- // size = PageSize - length size. we do not need to calculate length as init value
591
- ...number(pageSize - ValtypeSize.i32, Valtype.i32),
592
- [ ...Opcodes.memory_copy, 0x00, 0x00 ],
593
-
594
- // copy right
595
- // dst = out pointer + length size + left length * sizeof valtype
596
- [ Opcodes.local_get, out ],
597
- ...number(ValtypeSize.i32, Valtype.i32),
598
- [ Opcodes.i32_add ],
599
-
600
- [ Opcodes.local_get, leftLength ],
601
- ...number(allBytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
602
- [ Opcodes.i32_mul ],
603
- [ Opcodes.i32_add ],
604
-
605
- // src = right pointer + length size
606
- [ Opcodes.local_get, rightPointer ],
607
- ...number(ValtypeSize.i32, Valtype.i32),
608
- [ Opcodes.i32_add ],
609
-
610
- // size = right length * sizeof valtype
611
- [ Opcodes.local_get, rightLength ],
612
- ...number(allBytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
613
- [ Opcodes.i32_mul ],
614
-
615
- [ ...Opcodes.memory_copy, 0x00, 0x00 ],
507
+ ...left,
508
+ ...(valtypeBinary === Valtype.i32 ? [ [ Opcodes.f64_convert_i32_s ] ] : []),
509
+ ...leftType,
616
510
 
617
- ...setLastType(scope, allBytestrings ? TYPES.bytestring : TYPES.string),
511
+ ...right,
512
+ ...(valtypeBinary === Valtype.i32 ? [ [ Opcodes.f64_convert_i32_s ] ] : []),
513
+ ...rightType,
618
514
 
619
- // return new string (page)
620
- [ Opcodes.local_get, out ],
621
- Opcodes.i32_from_u
515
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_concatStrings').index ],
516
+ ...setLastType(scope),
517
+ ...(valtypeBinary === Valtype.i32 ? [ Opcodes.i32_trunc_sat_f64_u ] : []),
622
518
  ];
623
519
  };
624
520
 
@@ -829,8 +725,8 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
829
725
  return performLogicOp(scope, op, left, right, leftType, rightType);
830
726
  }
831
727
 
832
- const knownLeft = knownType(scope, leftType);
833
- const knownRight = knownType(scope, rightType);
728
+ const knownLeft = knownTypeWithGuess(scope, leftType);
729
+ const knownRight = knownTypeWithGuess(scope, rightType);
834
730
 
835
731
  const eqOp = ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(op);
836
732
  const strictOp = op === '===' || op === '!==';
@@ -860,23 +756,16 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
860
756
  // todo: if equality op and an operand is undefined, return false
861
757
  // todo: niche null hell with 0
862
758
 
863
- if (knownLeft === TYPES.string || knownRight === TYPES.string) {
759
+ if ((knownLeft === TYPES.string || knownRight === TYPES.string) ||
760
+ (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)) {
864
761
  if (op === '+') {
865
762
  // string concat (a + b)
866
- return [
867
- ...left,
868
- ...right,
869
- ...concatStrings(scope, [], [], leftType, rightType, false, knownLeft === TYPES.string && knownRight === TYPES.string)
870
- ];
763
+ return concatStrings(scope, left, right, leftType, rightType);
871
764
  }
872
765
 
873
766
  // not an equality op, NaN
874
767
  if (!eqOp) return number(NaN);
875
768
 
876
- // else leave bool ops
877
- // todo: convert string to number if string and number/bool
878
- // todo: string (>|>=|<|<=) string
879
-
880
769
  // string comparison
881
770
  if (op === '===' || op === '==' || op === '!==' || op === '!=') {
882
771
  return [
@@ -884,32 +773,8 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
884
773
  ...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
885
774
  ];
886
775
  }
887
- }
888
-
889
- if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
890
- if (op === '+') {
891
- // string concat (a + b)
892
- return [
893
- ...left,
894
- ...right,
895
- ...concatStrings(scope, [], [], leftType, rightType, knownLeft === TYPES.bytestring && knownRight === TYPES.bytestring)
896
- ];
897
- }
898
-
899
- // not an equality op, NaN
900
- if (!eqOp) return number(NaN);
901
-
902
- // else leave bool ops
903
- // todo: convert string to number if string and number/bool
904
- // todo: string (>|>=|<|<=) string
905
776
 
906
- // string comparison
907
- if (op === '===' || op === '==' || op === '!==' || op === '!=') {
908
- return [
909
- ...compareStrings(scope, left, right, leftType, rightType),
910
- ...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
911
- ];
912
- }
777
+ // todo: proper >|>=|<|<=
913
778
  }
914
779
 
915
780
  let ops = operatorOpcode[valtype][op];
@@ -943,39 +808,19 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
943
808
  tmpRight = localTmp(scope, '__tmpop_right');
944
809
 
945
810
  ops.unshift(...stringOnly([
946
- // if left is bytestring
947
- ...leftType,
948
- ...number(TYPES.bytestring, Valtype.i32),
949
- [ Opcodes.i32_eq ],
950
-
951
- // if right is bytestring
952
- ...rightType,
953
- ...number(TYPES.bytestring, Valtype.i32),
954
- [ Opcodes.i32_eq ],
955
-
956
- // if both are true
957
- [ Opcodes.i32_and ],
958
- [ Opcodes.if, Blocktype.void ],
959
- ...concatStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ], leftType, rightType, true),
960
- ...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : []),
961
- [ Opcodes.br, 1 ],
962
- [ Opcodes.end ],
963
-
964
- // if left is string or bytestring
811
+ // if left or right are string or bytestring
965
812
  ...leftType,
966
813
  ...number(TYPE_FLAGS.parity, Valtype.i32),
967
814
  [ Opcodes.i32_or ],
968
815
  ...number(TYPES.bytestring, Valtype.i32),
969
816
  [ Opcodes.i32_eq ],
970
817
 
971
- // if right is string or bytestring
972
818
  ...rightType,
973
819
  ...number(TYPE_FLAGS.parity, Valtype.i32),
974
820
  [ Opcodes.i32_or ],
975
821
  ...number(TYPES.bytestring, Valtype.i32),
976
822
  [ Opcodes.i32_eq ],
977
823
 
978
- // if either
979
824
  [ Opcodes.i32_or ],
980
825
  [ Opcodes.if, Blocktype.void ],
981
826
  ...concatStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ], leftType, rightType),
@@ -1371,6 +1216,7 @@ const setLastType = (scope, type = []) => [
1371
1216
  ];
1372
1217
 
1373
1218
  const getNodeType = (scope, node) => {
1219
+ let guess = null;
1374
1220
  const ret = (() => {
1375
1221
  if (node._type) return node._type;
1376
1222
  if (node.type === 'Literal') {
@@ -1476,6 +1322,7 @@ const getNodeType = (scope, node) => {
1476
1322
  if (node.type === 'AssignmentExpression') {
1477
1323
  const op = node.operator.slice(0, -1) || '=';
1478
1324
  if (op === '=') return getNodeType(scope, node.right);
1325
+ // if (op === '=') return getNodeType(scope, node.left);
1479
1326
 
1480
1327
  return getNodeType(scope, {
1481
1328
  type: ['||', '&&', '??'].includes(op) ? 'LogicalExpression' : 'BinaryExpression',
@@ -1495,14 +1342,20 @@ const getNodeType = (scope, node) => {
1495
1342
 
1496
1343
  const leftType = getNodeType(scope, node.left);
1497
1344
  const rightType = getNodeType(scope, node.right);
1498
- const knownLeft = knownType(scope, leftType);
1499
- const knownRight = knownType(scope, rightType);
1345
+ const knownLeft = knownTypeWithGuess(scope, leftType);
1346
+ const knownRight = knownTypeWithGuess(scope, rightType);
1500
1347
 
1501
- if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
1502
- if (knownLeft === TYPES.bytestring && knownRight === TYPES.bytestring) return TYPES.bytestring;
1503
- if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.string;
1348
+ if ((knownLeft != null || knownRight != null) && !(
1349
+ (knownLeft === TYPES.string || knownRight === TYPES.string) ||
1350
+ (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
1351
+ )) return TYPES.number;
1504
1352
 
1505
- if (knownLeft != null || knownRight != null) return TYPES.number;
1353
+ if (knownLeft === TYPES.string || knownRight === TYPES.string)
1354
+ return TYPES.string;
1355
+
1356
+ // guess bytestring, could really be bytestring or string
1357
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
1358
+ guess = TYPES.bytestring;
1506
1359
 
1507
1360
  if (scope.locals['#last_type']) return getLastType(scope);
1508
1361
 
@@ -1580,8 +1433,10 @@ const getNodeType = (scope, node) => {
1580
1433
  return TYPES.number;
1581
1434
  })();
1582
1435
 
1583
- if (typeof ret === 'number') return number(ret, Valtype.i32);
1584
- return ret;
1436
+ const out = typeof ret === 'number' ? number(ret, Valtype.i32) : ret;
1437
+ if (guess != null) out.guess = typeof guess === 'number' ? number(guess, Valtype.i32) : guess;
1438
+
1439
+ return out;
1585
1440
  };
1586
1441
 
1587
1442
  const generateLiteral = (scope, decl, global, name) => {
@@ -2232,6 +2087,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2232
2087
 
2233
2088
  // value
2234
2089
  i32_const: { imms: 1, args: [], returns: 0 },
2090
+
2091
+ // dst, src, size, _, _
2092
+ memory_copy: { imms: 2, args: [ true, true, true ], returns: 0 }
2235
2093
  };
2236
2094
 
2237
2095
  const opName = name.slice('__Porffor_wasm_'.length);
@@ -2254,9 +2112,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2254
2112
  // literals only
2255
2113
  const imms = decl.arguments.slice(op.args.length).map(x => x.value);
2256
2114
 
2115
+ let opcode = Opcodes[opName];
2116
+ if (!Array.isArray(opcode)) opcode = [ opcode ];
2117
+
2257
2118
  return [
2258
2119
  ...argOut,
2259
- [ Opcodes[opName], ...imms ],
2120
+ [ ...opcode, ...imms ],
2260
2121
  ...(new Array(op.returns).fill(Opcodes.i32_from))
2261
2122
  ];
2262
2123
  }
@@ -2705,6 +2566,13 @@ const knownType = (scope, type) => {
2705
2566
 
2706
2567
  return null;
2707
2568
  };
2569
+ const knownTypeWithGuess = (scope, type) => {
2570
+ let known = knownType(scope, type);
2571
+ if (known != null) return known;
2572
+
2573
+ if (type.guess != null) return knownType(scope, type.guess);
2574
+ return known;
2575
+ };
2708
2576
 
2709
2577
  const brTable = (input, bc, returns) => {
2710
2578
  const out = [];
@@ -2975,8 +2843,10 @@ const setLocalWithType = (scope, name, isGlobal, decl, tee = false, overrideType
2975
2843
  // todo: detect last type then i32 conversion op
2976
2844
  const lastOp = out.at(-1);
2977
2845
  if (lastOp[0] === Opcodes.local_set && lastOp[1] === scope.locals['#last_type']?.idx) {
2978
- out.pop();
2846
+ // set last type -> tee last type
2847
+ lastOp[0] = Opcodes.local_tee;
2979
2848
 
2849
+ // still set last type due to side effects or type of decl gotten later
2980
2850
  const setOut = setType(scope, name, []);
2981
2851
  out.push(
2982
2852
  // drop if setType is empty
@@ -5809,6 +5679,38 @@ const generateClass = (scope, decl) => {
5809
5679
  return out;
5810
5680
  };
5811
5681
 
5682
+ export const generateTemplate = (scope, decl) => {
5683
+ let current = null;
5684
+ const append = val => {
5685
+ // console.log(val);
5686
+ if (!current) {
5687
+ current = val;
5688
+ return;
5689
+ }
5690
+
5691
+ current = {
5692
+ type: 'BinaryExpression',
5693
+ operator: '+',
5694
+ left: current,
5695
+ right: val
5696
+ };
5697
+ };
5698
+
5699
+ const { expressions, quasis } = decl;
5700
+ for (let i = 0; i < quasis.length; i++) {
5701
+ append({
5702
+ type: 'Literal',
5703
+ value: quasis[i].value.cooked
5704
+ });
5705
+
5706
+ if (i < expressions.length) {
5707
+ append(expressions[i]);
5708
+ }
5709
+ }
5710
+
5711
+ return generate(scope, current);
5712
+ };
5713
+
5812
5714
  globalThis._uniqId = 0;
5813
5715
  const uniqId = () => '_' + globalThis._uniqId++;
5814
5716
 
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.35.0+8b2f7cee3",
4
+ "version": "0.35.2+e15887a34",
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.35.0+8b2f7cee3';
3
+ globalThis.version = '0.35.2+e15887a34';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
package/runner/repl.js CHANGED
@@ -61,7 +61,10 @@ const memoryToString = mem => {
61
61
  out += ` \x1B[34m${name}${' '.repeat(longestName - name.length)} \x1B[90m│\x1B[0m \x1B[36m${type}${' '.repeat(longestType - type.length)} \x1B[90m│\x1B[0m `;
62
62
  }
63
63
 
64
- for (let j = 0; j < 40; j++) {
64
+ let j = 0;
65
+ if (i === 0) j = 16;
66
+ const end = j + 40;
67
+ for (; j < end; j++) {
65
68
  const val = buf[i * pageSize + j];
66
69
  // if (val === 0) out += '\x1B[2m';
67
70
  if (val === 0) out += '\x1B[90m';