porffor 0.35.0 → 0.35.1
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/__internal_string.ts +74 -0
- package/compiler/builtins/_internal_string.ts +21 -0
- package/compiler/builtins/string.ts +28 -18
- package/compiler/builtins_precompiled.js +291 -281
- package/compiler/codegen.js +33 -179
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -499,126 +499,19 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
|
499
499
|
];
|
500
500
|
};
|
501
501
|
|
502
|
-
const concatStrings = (scope, left, right, leftType, rightType
|
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');
|
502
|
+
const concatStrings = (scope, left, right, leftType, rightType) => {
|
518
503
|
return [
|
519
|
-
|
520
|
-
...(
|
521
|
-
|
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 ],
|
504
|
+
...left,
|
505
|
+
...(valtypeBinary === Valtype.i32 ? [ [ Opcodes.f64_convert_i32_s ] ] : []),
|
506
|
+
...leftType,
|
616
507
|
|
617
|
-
...
|
508
|
+
...right,
|
509
|
+
...(valtypeBinary === Valtype.i32 ? [ [ Opcodes.f64_convert_i32_s ] ] : []),
|
510
|
+
...rightType,
|
618
511
|
|
619
|
-
|
620
|
-
|
621
|
-
Opcodes.
|
512
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_concatStrings').index ],
|
513
|
+
...setLastType(scope),
|
514
|
+
...(valtypeBinary === Valtype.i32 ? [ Opcodes.i32_trunc_sat_f64_u ] : []),
|
622
515
|
];
|
623
516
|
};
|
624
517
|
|
@@ -860,23 +753,16 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
860
753
|
// todo: if equality op and an operand is undefined, return false
|
861
754
|
// todo: niche null hell with 0
|
862
755
|
|
863
|
-
if (knownLeft === TYPES.string || knownRight === TYPES.string)
|
756
|
+
if ((knownLeft === TYPES.string || knownRight === TYPES.string) ||
|
757
|
+
(knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)) {
|
864
758
|
if (op === '+') {
|
865
759
|
// string concat (a + b)
|
866
|
-
return
|
867
|
-
...left,
|
868
|
-
...right,
|
869
|
-
...concatStrings(scope, [], [], leftType, rightType, false, knownLeft === TYPES.string && knownRight === TYPES.string)
|
870
|
-
];
|
760
|
+
return concatStrings(scope, left, right, leftType, rightType);
|
871
761
|
}
|
872
762
|
|
873
763
|
// not an equality op, NaN
|
874
764
|
if (!eqOp) return number(NaN);
|
875
765
|
|
876
|
-
// else leave bool ops
|
877
|
-
// todo: convert string to number if string and number/bool
|
878
|
-
// todo: string (>|>=|<|<=) string
|
879
|
-
|
880
766
|
// string comparison
|
881
767
|
if (op === '===' || op === '==' || op === '!==' || op === '!=') {
|
882
768
|
return [
|
@@ -884,32 +770,8 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
884
770
|
...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
|
885
771
|
];
|
886
772
|
}
|
887
|
-
}
|
888
773
|
|
889
|
-
|
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
|
-
|
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
|
-
}
|
774
|
+
// todo: proper >|>=|<|<=
|
913
775
|
}
|
914
776
|
|
915
777
|
let ops = operatorOpcode[valtype][op];
|
@@ -943,39 +805,19 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
943
805
|
tmpRight = localTmp(scope, '__tmpop_right');
|
944
806
|
|
945
807
|
ops.unshift(...stringOnly([
|
946
|
-
// if left
|
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
|
808
|
+
// if left or right are string or bytestring
|
965
809
|
...leftType,
|
966
810
|
...number(TYPE_FLAGS.parity, Valtype.i32),
|
967
811
|
[ Opcodes.i32_or ],
|
968
812
|
...number(TYPES.bytestring, Valtype.i32),
|
969
813
|
[ Opcodes.i32_eq ],
|
970
814
|
|
971
|
-
// if right is string or bytestring
|
972
815
|
...rightType,
|
973
816
|
...number(TYPE_FLAGS.parity, Valtype.i32),
|
974
817
|
[ Opcodes.i32_or ],
|
975
818
|
...number(TYPES.bytestring, Valtype.i32),
|
976
819
|
[ Opcodes.i32_eq ],
|
977
820
|
|
978
|
-
// if either
|
979
821
|
[ Opcodes.i32_or ],
|
980
822
|
[ Opcodes.if, Blocktype.void ],
|
981
823
|
...concatStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ], leftType, rightType),
|
@@ -1476,6 +1318,7 @@ const getNodeType = (scope, node) => {
|
|
1476
1318
|
if (node.type === 'AssignmentExpression') {
|
1477
1319
|
const op = node.operator.slice(0, -1) || '=';
|
1478
1320
|
if (op === '=') return getNodeType(scope, node.right);
|
1321
|
+
// if (op === '=') return getNodeType(scope, node.left);
|
1479
1322
|
|
1480
1323
|
return getNodeType(scope, {
|
1481
1324
|
type: ['||', '&&', '??'].includes(op) ? 'LogicalExpression' : 'BinaryExpression',
|
@@ -1498,11 +1341,14 @@ const getNodeType = (scope, node) => {
|
|
1498
1341
|
const knownLeft = knownType(scope, leftType);
|
1499
1342
|
const knownRight = knownType(scope, rightType);
|
1500
1343
|
|
1501
|
-
if (knownLeft
|
1502
|
-
|
1503
|
-
|
1344
|
+
if ((knownLeft != null || knownRight != null) && !(
|
1345
|
+
(knownLeft === TYPES.string || knownRight === TYPES.string) ||
|
1346
|
+
(knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
|
1347
|
+
)) return TYPES.number;
|
1504
1348
|
|
1505
|
-
if (knownLeft
|
1349
|
+
// if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
|
1350
|
+
// if (knownLeft === TYPES.bytestring && knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1351
|
+
// if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.string;
|
1506
1352
|
|
1507
1353
|
if (scope.locals['#last_type']) return getLastType(scope);
|
1508
1354
|
|
@@ -2232,6 +2078,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2232
2078
|
|
2233
2079
|
// value
|
2234
2080
|
i32_const: { imms: 1, args: [], returns: 0 },
|
2081
|
+
|
2082
|
+
// dst, src, size, _, _
|
2083
|
+
memory_copy: { imms: 2, args: [ true, true, true ], returns: 0 }
|
2235
2084
|
};
|
2236
2085
|
|
2237
2086
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -2254,9 +2103,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2254
2103
|
// literals only
|
2255
2104
|
const imms = decl.arguments.slice(op.args.length).map(x => x.value);
|
2256
2105
|
|
2106
|
+
let opcode = Opcodes[opName];
|
2107
|
+
if (!Array.isArray(opcode)) opcode = [ opcode ];
|
2108
|
+
|
2257
2109
|
return [
|
2258
2110
|
...argOut,
|
2259
|
-
[
|
2111
|
+
[ ...opcode, ...imms ],
|
2260
2112
|
...(new Array(op.returns).fill(Opcodes.i32_from))
|
2261
2113
|
];
|
2262
2114
|
}
|
@@ -2975,8 +2827,10 @@ const setLocalWithType = (scope, name, isGlobal, decl, tee = false, overrideType
|
|
2975
2827
|
// todo: detect last type then i32 conversion op
|
2976
2828
|
const lastOp = out.at(-1);
|
2977
2829
|
if (lastOp[0] === Opcodes.local_set && lastOp[1] === scope.locals['#last_type']?.idx) {
|
2978
|
-
|
2830
|
+
// set last type -> tee last type
|
2831
|
+
lastOp[0] = Opcodes.local_tee;
|
2979
2832
|
|
2833
|
+
// still set last type due to side effects or type of decl gotten later
|
2980
2834
|
const setOut = setType(scope, name, []);
|
2981
2835
|
out.push(
|
2982
2836
|
// drop if setType is empty
|
package/package.json
CHANGED