porffor 0.0.0-650350 → 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.
- package/compiler/codeGen.js +127 -29
- package/package.json +1 -1
- package/runner/repl.js +3 -3
package/compiler/codeGen.js
CHANGED
@@ -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
|
-
|
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
|
393
|
-
...
|
394
|
-
|
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 = '$
|
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
|
543
|
-
// todo: string
|
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
|
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
|
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
|
-
|
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
|
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
package/runner/repl.js
CHANGED
@@ -51,12 +51,12 @@ const memoryToString = mem => {
|
|
51
51
|
let prev = '';
|
52
52
|
const run = async (source, _context, _filename, callback, run = true) => {
|
53
53
|
let toRun = prev + source.trim();
|
54
|
-
prev = toRun + ';\n';
|
54
|
+
// prev = toRun + ';\n';
|
55
55
|
|
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,7 +64,7 @@ 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
|
-
|
67
|
+
if (source.includes(' = ') || source.includes('let ') || source.includes('var ') || source.includes('const ') || source.includes('function ')) prev = toRun + ';\n';
|
68
68
|
// prev = toRun + ';\n';
|
69
69
|
};
|
70
70
|
|