porffor 0.0.0-1989c22 → 0.0.0-1b0a5c6
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/README.md +46 -13
- package/c +0 -0
- package/c.exe +0 -0
- package/compiler/2c.js +350 -0
- package/compiler/builtins.js +6 -1
- package/compiler/codeGen.js +442 -138
- package/compiler/decompile.js +3 -3
- package/compiler/encoding.js +4 -2
- package/compiler/index.js +53 -2
- package/compiler/opt.js +49 -23
- package/compiler/parse.js +1 -0
- package/compiler/prototype.js +94 -33
- package/compiler/sections.js +28 -2
- package/compiler/wrap.js +21 -3
- package/cool.exe +0 -0
- package/g +0 -0
- package/g.exe +0 -0
- package/hi.c +37 -0
- package/out +0 -0
- package/out.exe +0 -0
- package/package.json +1 -1
- package/r.js +39 -0
- package/rhemyn/README.md +37 -0
- package/rhemyn/compile.js +214 -0
- package/rhemyn/parse.js +321 -0
- package/rhemyn/test/parse.js +59 -0
- package/runner/index.js +54 -34
- package/runner/info.js +37 -2
- package/runner/repl.js +6 -11
- package/runner/transform.js +2 -1
- package/runner/version.js +10 -0
- package/tmp.c +58 -0
package/compiler/codeGen.js
CHANGED
@@ -5,6 +5,7 @@ import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from "./bui
|
|
5
5
|
import { PrototypeFuncs } from "./prototype.js";
|
6
6
|
import { number, i32x4 } from "./embedding.js";
|
7
7
|
import parse from "./parse.js";
|
8
|
+
import * as Rhemyn from "../rhemyn/compile.js";
|
8
9
|
|
9
10
|
let globals = {};
|
10
11
|
let globalInd = 0;
|
@@ -35,7 +36,14 @@ const debug = str => {
|
|
35
36
|
};
|
36
37
|
|
37
38
|
const todo = msg => {
|
38
|
-
|
39
|
+
class TodoError extends Error {
|
40
|
+
constructor(message) {
|
41
|
+
super(message);
|
42
|
+
this.name = 'TodoError';
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
throw new TodoError(`todo: ${msg}`);
|
39
47
|
|
40
48
|
const code = [];
|
41
49
|
|
@@ -101,6 +109,9 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
101
109
|
case 'WhileStatement':
|
102
110
|
return generateWhile(scope, decl);
|
103
111
|
|
112
|
+
case 'ForOfStatement':
|
113
|
+
return generateForOf(scope, decl);
|
114
|
+
|
104
115
|
case 'BreakStatement':
|
105
116
|
return generateBreak(scope, decl);
|
106
117
|
|
@@ -141,45 +152,65 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
141
152
|
|
142
153
|
return [];
|
143
154
|
|
144
|
-
case 'TaggedTemplateExpression':
|
145
|
-
|
146
|
-
|
155
|
+
case 'TaggedTemplateExpression': {
|
156
|
+
const funcs = {
|
157
|
+
asm: str => {
|
158
|
+
let out = [];
|
147
159
|
|
148
|
-
|
149
|
-
|
160
|
+
for (const line of str.split('\n')) {
|
161
|
+
const asm = line.trim().split(';;')[0].split(' ');
|
162
|
+
if (asm[0] === '') continue; // blank
|
150
163
|
|
151
|
-
|
152
|
-
|
153
|
-
|
164
|
+
if (asm[0] === 'local') {
|
165
|
+
const [ name, idx, type ] = asm.slice(1);
|
166
|
+
scope.locals[name] = { idx: parseInt(idx), type: Valtype[type] };
|
167
|
+
continue;
|
168
|
+
}
|
154
169
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
}
|
170
|
+
if (asm[0] === 'returns') {
|
171
|
+
scope.returns = asm.slice(1).map(x => Valtype[x]);
|
172
|
+
continue;
|
173
|
+
}
|
160
174
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
175
|
+
if (asm[0] === 'memory') {
|
176
|
+
allocPage('asm instrinsic');
|
177
|
+
// todo: add to store/load offset insts
|
178
|
+
continue;
|
179
|
+
}
|
165
180
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
181
|
+
let inst = Opcodes[asm[0].replace('.', '_')];
|
182
|
+
if (!inst) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
183
|
+
|
184
|
+
if (!Array.isArray(inst)) inst = [ inst ];
|
185
|
+
const immediates = asm.slice(1).map(x => parseInt(x));
|
186
|
+
|
187
|
+
out.push([ ...inst, ...immediates ]);
|
188
|
+
}
|
172
189
|
|
173
|
-
|
174
|
-
|
190
|
+
return out;
|
191
|
+
},
|
175
192
|
|
176
|
-
|
177
|
-
|
193
|
+
__internal_print_type: str => {
|
194
|
+
const type = getType(scope, str) - TYPES.number;
|
178
195
|
|
179
|
-
|
196
|
+
return [
|
197
|
+
...number(type),
|
198
|
+
[ Opcodes.call, importedFuncs.print ],
|
199
|
+
|
200
|
+
// newline
|
201
|
+
...number(10),
|
202
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
203
|
+
];
|
204
|
+
}
|
180
205
|
}
|
181
206
|
|
182
|
-
|
207
|
+
const name = decl.tag.name;
|
208
|
+
// hack for inline asm
|
209
|
+
if (!funcs[name]) return todo('tagged template expressions not implemented');
|
210
|
+
|
211
|
+
const str = decl.quasi.quasis[0].value.raw;
|
212
|
+
return funcs[name](str);
|
213
|
+
}
|
183
214
|
|
184
215
|
default:
|
185
216
|
return todo(`no generation for ${decl.type}!`);
|
@@ -278,7 +309,7 @@ const generateReturn = (scope, decl) => {
|
|
278
309
|
];
|
279
310
|
}
|
280
311
|
|
281
|
-
|
312
|
+
scope.returnType = getNodeType(scope, decl.argument);
|
282
313
|
|
283
314
|
return [
|
284
315
|
...generate(scope, decl.argument),
|
@@ -295,11 +326,11 @@ const localTmp = (scope, name, type = valtypeBinary) => {
|
|
295
326
|
return idx;
|
296
327
|
};
|
297
328
|
|
298
|
-
const performLogicOp = (scope, op, left, right) => {
|
329
|
+
const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
299
330
|
const checks = {
|
300
|
-
'||':
|
301
|
-
'&&':
|
302
|
-
|
331
|
+
'||': falsy,
|
332
|
+
'&&': truthy,
|
333
|
+
'??': nullish
|
303
334
|
};
|
304
335
|
|
305
336
|
if (!checks[op]) return todo(`logic operator ${op} not implemented yet`);
|
@@ -310,7 +341,8 @@ const performLogicOp = (scope, op, left, right) => {
|
|
310
341
|
return [
|
311
342
|
...left,
|
312
343
|
[ Opcodes.local_tee, localTmp(scope, 'logictmp') ],
|
313
|
-
...checks[op],
|
344
|
+
...checks[op](scope, [], leftType),
|
345
|
+
Opcodes.i32_to,
|
314
346
|
[ Opcodes.if, valtypeBinary ],
|
315
347
|
...right,
|
316
348
|
[ Opcodes.else ],
|
@@ -325,8 +357,6 @@ const concatStrings = (scope, left, right, global, name, assign) => {
|
|
325
357
|
// todo: optimize by looking up names in arrays and using that if exists?
|
326
358
|
// todo: optimize this if using literals/known lengths?
|
327
359
|
|
328
|
-
scope.memory = true;
|
329
|
-
|
330
360
|
const rightPointer = localTmp(scope, 'concat_right_pointer', Valtype.i32);
|
331
361
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
332
362
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
@@ -461,8 +491,6 @@ const compareStrings = (scope, left, right) => {
|
|
461
491
|
// todo: optimize by looking up names in arrays and using that if exists?
|
462
492
|
// todo: optimize this if using literals/known lengths?
|
463
493
|
|
464
|
-
scope.memory = true;
|
465
|
-
|
466
494
|
const leftPointer = localTmp(scope, 'compare_left_pointer', Valtype.i32);
|
467
495
|
const leftLength = localTmp(scope, 'compare_left_length', Valtype.i32);
|
468
496
|
const rightPointer = localTmp(scope, 'compare_right_pointer', Valtype.i32);
|
@@ -472,9 +500,6 @@ const compareStrings = (scope, left, right) => {
|
|
472
500
|
const indexEnd = localTmp(scope, 'compare_index_end', Valtype.i32);
|
473
501
|
|
474
502
|
return [
|
475
|
-
// use block to "return" a value early
|
476
|
-
[ Opcodes.block, Valtype.i32 ],
|
477
|
-
|
478
503
|
// setup left
|
479
504
|
...left,
|
480
505
|
Opcodes.i32_to_u,
|
@@ -486,11 +511,9 @@ const compareStrings = (scope, left, right) => {
|
|
486
511
|
[ Opcodes.local_tee, rightPointer ],
|
487
512
|
|
488
513
|
// fast path: check leftPointer == rightPointer
|
489
|
-
|
490
|
-
[ Opcodes.
|
491
|
-
|
492
|
-
[ Opcodes.br, 1 ],
|
493
|
-
[ Opcodes.end ],
|
514
|
+
// use if (block) for everything after to "return" a value early
|
515
|
+
[ Opcodes.i32_ne ],
|
516
|
+
[ Opcodes.if, Valtype.i32 ],
|
494
517
|
|
495
518
|
// get lengths
|
496
519
|
[ Opcodes.local_get, leftPointer ],
|
@@ -553,6 +576,10 @@ const compareStrings = (scope, left, right) => {
|
|
553
576
|
|
554
577
|
// no failed checks, so true!
|
555
578
|
...number(1, Valtype.i32),
|
579
|
+
|
580
|
+
// pointers match, so true
|
581
|
+
[ Opcodes.else ],
|
582
|
+
...number(1, Valtype.i32),
|
556
583
|
[ Opcodes.end ],
|
557
584
|
|
558
585
|
// convert i32 result to valtype
|
@@ -561,102 +588,142 @@ const compareStrings = (scope, left, right) => {
|
|
561
588
|
];
|
562
589
|
};
|
563
590
|
|
564
|
-
const
|
591
|
+
const truthy = (scope, wasm, type) => {
|
565
592
|
// arrays are always truthy
|
566
593
|
if (type === TYPES._array) return [
|
567
594
|
...wasm,
|
568
595
|
[ Opcodes.drop ],
|
569
|
-
number(
|
596
|
+
...number(1)
|
570
597
|
];
|
571
598
|
|
572
599
|
if (type === TYPES.string) {
|
573
|
-
// if "" (length = 0)
|
600
|
+
// if not "" (length = 0)
|
574
601
|
return [
|
575
602
|
// pointer
|
576
603
|
...wasm,
|
604
|
+
Opcodes.i32_to_u,
|
577
605
|
|
578
606
|
// get length
|
579
607
|
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
580
608
|
|
581
|
-
// if length
|
582
|
-
[ Opcodes.i32_eqz ],
|
609
|
+
// if length != 0
|
610
|
+
/* [ Opcodes.i32_eqz ],
|
611
|
+
[ Opcodes.i32_eqz ], */
|
583
612
|
Opcodes.i32_from_u
|
584
613
|
]
|
585
614
|
}
|
586
615
|
|
587
|
-
// if
|
616
|
+
// if != 0
|
588
617
|
return [
|
589
618
|
...wasm,
|
590
619
|
|
591
|
-
|
592
|
-
Opcodes.
|
620
|
+
/* Opcodes.eqz,
|
621
|
+
[ Opcodes.i32_eqz ],
|
622
|
+
Opcodes.i32_from */
|
593
623
|
];
|
594
624
|
};
|
595
625
|
|
596
|
-
const
|
626
|
+
const falsy = (scope, wasm, type) => {
|
597
627
|
// arrays are always truthy
|
598
628
|
if (type === TYPES._array) return [
|
599
629
|
...wasm,
|
600
630
|
[ Opcodes.drop ],
|
601
|
-
number(
|
631
|
+
...number(0)
|
602
632
|
];
|
603
633
|
|
604
634
|
if (type === TYPES.string) {
|
605
|
-
// if
|
635
|
+
// if "" (length = 0)
|
606
636
|
return [
|
607
637
|
// pointer
|
608
638
|
...wasm,
|
639
|
+
Opcodes.i32_to_u,
|
609
640
|
|
610
641
|
// get length
|
611
642
|
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
612
643
|
|
613
|
-
// if length
|
614
|
-
|
615
|
-
[ Opcodes.i32_eqz ], */
|
644
|
+
// if length == 0
|
645
|
+
[ Opcodes.i32_eqz ],
|
616
646
|
Opcodes.i32_from_u
|
617
647
|
]
|
618
648
|
}
|
619
649
|
|
620
|
-
// if
|
650
|
+
// if = 0
|
621
651
|
return [
|
622
652
|
...wasm,
|
623
653
|
|
624
|
-
|
625
|
-
|
626
|
-
|
654
|
+
...Opcodes.eqz,
|
655
|
+
Opcodes.i32_from_u
|
656
|
+
];
|
657
|
+
};
|
658
|
+
|
659
|
+
const nullish = (scope, wasm, type) => {
|
660
|
+
// undefined
|
661
|
+
if (type === TYPES.undefined) return [
|
662
|
+
...wasm,
|
663
|
+
[ Opcodes.drop ],
|
664
|
+
...number(1)
|
665
|
+
];
|
666
|
+
|
667
|
+
// null (if object and = "0")
|
668
|
+
if (type === TYPES.object) return [
|
669
|
+
...wasm,
|
670
|
+
...Opcodes.eqz,
|
671
|
+
Opcodes.i32_from_u
|
672
|
+
];
|
673
|
+
|
674
|
+
// not
|
675
|
+
return [
|
676
|
+
...wasm,
|
677
|
+
[ Opcodes.drop ],
|
678
|
+
...number(0)
|
627
679
|
];
|
628
680
|
};
|
629
681
|
|
630
682
|
const performOp = (scope, op, left, right, leftType, rightType, _global = false, _name = '$undeclared', assign = false) => {
|
631
683
|
if (op === '||' || op === '&&' || op === '??') {
|
632
|
-
return performLogicOp(scope, op, left, right);
|
684
|
+
return performLogicOp(scope, op, left, right, leftType, rightType);
|
633
685
|
}
|
634
686
|
|
635
687
|
if (codeLog && (!leftType || !rightType)) log('codegen', 'untracked type in op', op, _name, '\n' + new Error().stack.split('\n').slice(1).join('\n'));
|
636
688
|
|
637
|
-
|
638
|
-
|
689
|
+
const eqOp = ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(op);
|
690
|
+
|
691
|
+
if (leftType && rightType && (
|
692
|
+
// if strict (in)equal and known types mismatch, return false (===)/true (!==)
|
693
|
+
((op === '===' || op === '!==') && leftType !== rightType) ||
|
694
|
+
|
695
|
+
// if equality op and an operand is undefined, return false
|
696
|
+
(eqOp && leftType === TYPES.undefined ^ rightType === TYPES.undefined)
|
697
|
+
)) {
|
698
|
+
// undefined == null
|
699
|
+
if (((leftType === TYPES.undefined && rightType === TYPES.object) || (leftType === TYPES.object && rightType === TYPES.undefined)) && (op === '==' || op === '!=')) return [
|
700
|
+
...(leftType === TYPES.object ? left : right),
|
701
|
+
...Opcodes.eqz,
|
702
|
+
...(op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
|
703
|
+
];
|
704
|
+
|
639
705
|
return [
|
640
706
|
...left,
|
641
|
-
...right,
|
642
|
-
|
643
|
-
// drop values
|
644
707
|
[ Opcodes.drop ],
|
708
|
+
|
709
|
+
...right,
|
645
710
|
[ Opcodes.drop ],
|
646
711
|
|
647
|
-
// return
|
648
|
-
...number(op === '===' ?
|
712
|
+
// return true (!=/!==) or false (else)
|
713
|
+
...number(op === '!=' || op === '!==' ? 1 : 0, Valtype.i32)
|
649
714
|
];
|
650
715
|
}
|
651
716
|
|
717
|
+
// todo: niche null hell with 0
|
718
|
+
|
652
719
|
if (leftType === TYPES.string || rightType === TYPES.string) {
|
653
720
|
if (op === '+') {
|
654
721
|
// string concat (a + b)
|
655
722
|
return concatStrings(scope, left, right, _global, _name, assign);
|
656
723
|
}
|
657
724
|
|
658
|
-
//
|
659
|
-
if (!
|
725
|
+
// not an equality op, NaN
|
726
|
+
if (!eqOp) return number(NaN);
|
660
727
|
|
661
728
|
// else leave bool ops
|
662
729
|
// todo: convert string to number if string and number/bool
|
@@ -701,21 +768,15 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
701
768
|
];
|
702
769
|
};
|
703
770
|
|
704
|
-
let binaryExpDepth = 0;
|
705
771
|
const generateBinaryExp = (scope, decl, _global, _name) => {
|
706
|
-
|
707
|
-
|
708
|
-
const out = [
|
709
|
-
...performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name)
|
710
|
-
];
|
772
|
+
const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
|
711
773
|
|
712
774
|
if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
|
713
775
|
|
714
|
-
binaryExpDepth--;
|
715
776
|
return out;
|
716
777
|
};
|
717
778
|
|
718
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType,
|
779
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [] }) => {
|
719
780
|
const existing = funcs.find(x => x.name === name);
|
720
781
|
if (existing) return existing;
|
721
782
|
|
@@ -751,7 +812,6 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
751
812
|
returns,
|
752
813
|
returnType: TYPES[returnType ?? 'number'],
|
753
814
|
wasm,
|
754
|
-
memory,
|
755
815
|
internal: true,
|
756
816
|
index: currentFuncIndex++
|
757
817
|
};
|
@@ -770,7 +830,7 @@ const includeBuiltin = (scope, builtin) => {
|
|
770
830
|
};
|
771
831
|
|
772
832
|
const generateLogicExp = (scope, decl) => {
|
773
|
-
return performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right));
|
833
|
+
return performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right));
|
774
834
|
};
|
775
835
|
|
776
836
|
const TYPES = {
|
@@ -784,7 +844,8 @@ const TYPES = {
|
|
784
844
|
bigint: 0xffffffffffff7,
|
785
845
|
|
786
846
|
// these are not "typeof" types but tracked internally
|
787
|
-
_array:
|
847
|
+
_array: 0xfffffffffff0f,
|
848
|
+
_regexp: 0xfffffffffff1f
|
788
849
|
};
|
789
850
|
|
790
851
|
const TYPE_NAMES = {
|
@@ -819,6 +880,8 @@ const getType = (scope, _name) => {
|
|
819
880
|
const getNodeType = (scope, node) => {
|
820
881
|
if (node.type === 'Literal') {
|
821
882
|
if (['number', 'boolean', 'string', 'undefined', 'object', 'function', 'symbol', 'bigint'].includes(node.value)) return TYPES.number;
|
883
|
+
if (node.regex) return TYPES._regexp;
|
884
|
+
|
822
885
|
return TYPES[typeof node.value];
|
823
886
|
}
|
824
887
|
|
@@ -852,6 +915,11 @@ const getNodeType = (scope, node) => {
|
|
852
915
|
|
853
916
|
// literal.func()
|
854
917
|
if (!name && node.callee.type === 'MemberExpression') {
|
918
|
+
if (node.callee.object.regex) {
|
919
|
+
const funcName = node.callee.property.name;
|
920
|
+
return Rhemyn[funcName] ? TYPES.boolean : TYPES.undefined;
|
921
|
+
}
|
922
|
+
|
855
923
|
const baseType = getNodeType(scope, node.callee.object);
|
856
924
|
|
857
925
|
const func = node.callee.property.name;
|
@@ -895,6 +963,11 @@ const getNodeType = (scope, node) => {
|
|
895
963
|
const generateLiteral = (scope, decl, global, name) => {
|
896
964
|
if (decl.value === null) return number(NULL);
|
897
965
|
|
966
|
+
if (decl.regex) {
|
967
|
+
scope.regex[name] = decl.regex;
|
968
|
+
return number(1);
|
969
|
+
}
|
970
|
+
|
898
971
|
switch (typeof decl.value) {
|
899
972
|
case 'number':
|
900
973
|
return number(decl.value);
|
@@ -934,7 +1007,8 @@ const generateLiteral = (scope, decl, global, name) => {
|
|
934
1007
|
const countLeftover = wasm => {
|
935
1008
|
let count = 0, depth = 0;
|
936
1009
|
|
937
|
-
for (
|
1010
|
+
for (let i = 0; i < wasm.length; i++) {
|
1011
|
+
const inst = wasm[i];
|
938
1012
|
if (depth === 0 && (inst[0] === Opcodes.if || inst[0] === Opcodes.block || inst[0] === Opcodes.loop)) {
|
939
1013
|
if (inst[0] === Opcodes.if) count--;
|
940
1014
|
if (inst[1] !== Blocktype.void) count++;
|
@@ -955,6 +1029,8 @@ const countLeftover = wasm => {
|
|
955
1029
|
} else count--;
|
956
1030
|
if (func) count += func.returns.length;
|
957
1031
|
} else count--;
|
1032
|
+
|
1033
|
+
// console.log(count, decompile([ inst ]).slice(0, -1));
|
958
1034
|
}
|
959
1035
|
|
960
1036
|
return count;
|
@@ -1038,7 +1114,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1038
1114
|
}
|
1039
1115
|
|
1040
1116
|
let out = [];
|
1041
|
-
let protoFunc, protoName, baseType, baseName
|
1117
|
+
let protoFunc, protoName, baseType, baseName;
|
1042
1118
|
// ident.func()
|
1043
1119
|
if (name && name.startsWith('__')) {
|
1044
1120
|
const spl = name.slice(2).split('_');
|
@@ -1053,6 +1129,25 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1053
1129
|
|
1054
1130
|
// literal.func()
|
1055
1131
|
if (!name && decl.callee.type === 'MemberExpression') {
|
1132
|
+
// megahack for /regex/.func()
|
1133
|
+
if (decl.callee.object.regex) {
|
1134
|
+
const funcName = decl.callee.property.name;
|
1135
|
+
const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
|
1136
|
+
|
1137
|
+
funcIndex[func.name] = func.index;
|
1138
|
+
funcs.push(func);
|
1139
|
+
|
1140
|
+
return [
|
1141
|
+
// make string arg
|
1142
|
+
...generate(scope, decl.arguments[0]),
|
1143
|
+
|
1144
|
+
// call regex func
|
1145
|
+
Opcodes.i32_to_u,
|
1146
|
+
[ Opcodes.call, func.index ],
|
1147
|
+
Opcodes.i32_from
|
1148
|
+
];
|
1149
|
+
}
|
1150
|
+
|
1056
1151
|
baseType = getNodeType(scope, decl.callee.object);
|
1057
1152
|
|
1058
1153
|
const func = decl.callee.property.name;
|
@@ -1061,11 +1156,36 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1061
1156
|
|
1062
1157
|
out = generate(scope, decl.callee.object);
|
1063
1158
|
out.push([ Opcodes.drop ]);
|
1159
|
+
|
1160
|
+
baseName = [...arrays.keys()].pop();
|
1064
1161
|
}
|
1065
1162
|
|
1066
|
-
if (
|
1067
|
-
|
1163
|
+
if (protoName && baseType === TYPES.string && Rhemyn[protoName]) {
|
1164
|
+
const func = Rhemyn[protoName](decl.arguments[0].regex.pattern, currentFuncIndex++);
|
1165
|
+
|
1166
|
+
funcIndex[func.name] = func.index;
|
1167
|
+
funcs.push(func);
|
1168
|
+
|
1169
|
+
const pointer = arrays.get(baseName);
|
1170
|
+
const [ local, isGlobal ] = lookupName(scope, baseName);
|
1171
|
+
|
1172
|
+
return [
|
1173
|
+
...out,
|
1174
|
+
|
1175
|
+
...(pointer == null ? [
|
1176
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1177
|
+
Opcodes.i32_to_u,
|
1178
|
+
] : [
|
1179
|
+
...number(pointer, Valtype.i32)
|
1180
|
+
]),
|
1068
1181
|
|
1182
|
+
// call regex func
|
1183
|
+
[ Opcodes.call, func.index ],
|
1184
|
+
Opcodes.i32_from
|
1185
|
+
];
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
if (protoFunc) {
|
1069
1189
|
let pointer = arrays.get(baseName);
|
1070
1190
|
|
1071
1191
|
if (pointer == null) {
|
@@ -1073,7 +1193,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1073
1193
|
if (codeLog) log('codegen', 'cloning unknown dynamic pointer');
|
1074
1194
|
|
1075
1195
|
// register array
|
1076
|
-
|
1196
|
+
0, [ , pointer ] = makeArray(scope, {
|
1077
1197
|
rawElements: new Array(0)
|
1078
1198
|
}, _global, baseName, true, baseType === TYPES.string ? 'i16' : valtype);
|
1079
1199
|
|
@@ -1097,24 +1217,34 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1097
1217
|
// use local for cached i32 length as commonly used
|
1098
1218
|
let lengthLocal = localTmp(scope, '__proto_length_cache', Valtype.i32);
|
1099
1219
|
|
1220
|
+
let lengthI32CacheUsed = false;
|
1221
|
+
|
1222
|
+
const protoOut = protoFunc(pointer, {
|
1223
|
+
getCachedI32: () => {
|
1224
|
+
lengthI32CacheUsed = true;
|
1225
|
+
return [ [ Opcodes.local_get, lengthLocal ] ]
|
1226
|
+
},
|
1227
|
+
setCachedI32: () => [ [ Opcodes.local_set, lengthLocal ] ],
|
1228
|
+
get: () => arrayUtil.getLength(pointer),
|
1229
|
+
getI32: () => arrayUtil.getLengthI32(pointer),
|
1230
|
+
set: value => arrayUtil.setLength(pointer, value),
|
1231
|
+
setI32: value => arrayUtil.setLengthI32(pointer, value)
|
1232
|
+
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, (length, itemType) => {
|
1233
|
+
return makeArray(scope, {
|
1234
|
+
rawElements: new Array(length)
|
1235
|
+
}, _global, _name, true, itemType);
|
1236
|
+
});
|
1237
|
+
|
1100
1238
|
return [
|
1101
1239
|
...out,
|
1102
1240
|
|
1103
|
-
...
|
1104
|
-
|
1241
|
+
...(!lengthI32CacheUsed ? [] : [
|
1242
|
+
...arrayUtil.getLengthI32(pointer),
|
1243
|
+
[ Opcodes.local_set, lengthLocal ],
|
1244
|
+
]),
|
1105
1245
|
|
1106
1246
|
[ Opcodes.block, valtypeBinary ],
|
1107
|
-
...
|
1108
|
-
cachedI32: [ [ Opcodes.local_get, lengthLocal ] ],
|
1109
|
-
get: arrayUtil.getLength(pointer),
|
1110
|
-
getI32: arrayUtil.getLengthI32(pointer),
|
1111
|
-
set: value => arrayUtil.setLength(pointer, value),
|
1112
|
-
setI32: value => arrayUtil.setLengthI32(pointer, value)
|
1113
|
-
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, (length, itemType) => {
|
1114
|
-
return makeArray(scope, {
|
1115
|
-
rawElements: new Array(length)
|
1116
|
-
}, _global, _name, true, itemType);
|
1117
|
-
}),
|
1247
|
+
...protoOut,
|
1118
1248
|
[ Opcodes.end ]
|
1119
1249
|
];
|
1120
1250
|
}
|
@@ -1171,11 +1301,10 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1171
1301
|
args = args.slice(0, func.params.length);
|
1172
1302
|
}
|
1173
1303
|
|
1174
|
-
if (func && func.memory) scope.memory = true;
|
1175
1304
|
if (func && func.throws) scope.throws = true;
|
1176
1305
|
|
1177
1306
|
for (const arg of args) {
|
1178
|
-
out.
|
1307
|
+
out = out.concat(generate(scope, arg));
|
1179
1308
|
}
|
1180
1309
|
|
1181
1310
|
out.push([ Opcodes.call, idx ]);
|
@@ -1187,7 +1316,7 @@ const generateNew = (scope, decl, _global, _name) => {
|
|
1187
1316
|
// hack: basically treat this as a normal call for builtins for now
|
1188
1317
|
const name = mapName(decl.callee.name);
|
1189
1318
|
if (internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1190
|
-
if (!builtinFuncs[name]) return todo(`new statement is not supported yet (new ${unhackName(name)})`);
|
1319
|
+
if (!builtinFuncs[name]) return todo(`new statement is not supported yet`); // return todo(`new statement is not supported yet (new ${unhackName(name)})`);
|
1191
1320
|
|
1192
1321
|
return generateCall(scope, decl, _global, _name);
|
1193
1322
|
};
|
@@ -1295,8 +1424,6 @@ const generateAssign = (scope, decl) => {
|
|
1295
1424
|
const name = decl.left.object.name;
|
1296
1425
|
const pointer = arrays.get(name);
|
1297
1426
|
|
1298
|
-
scope.memory = true;
|
1299
|
-
|
1300
1427
|
const aotPointer = pointer != null;
|
1301
1428
|
|
1302
1429
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
@@ -1317,13 +1444,60 @@ const generateAssign = (scope, decl) => {
|
|
1317
1444
|
];
|
1318
1445
|
}
|
1319
1446
|
|
1447
|
+
const op = decl.operator.slice(0, -1) || '=';
|
1448
|
+
|
1449
|
+
// arr[i] | str[i]
|
1450
|
+
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
1451
|
+
const name = decl.left.object.name;
|
1452
|
+
const pointer = arrays.get(name);
|
1453
|
+
|
1454
|
+
const aotPointer = pointer != null;
|
1455
|
+
|
1456
|
+
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
1457
|
+
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
1458
|
+
|
1459
|
+
const parentType = getNodeType(scope, decl.left.object);
|
1460
|
+
|
1461
|
+
return [
|
1462
|
+
...(aotPointer ? [] : [
|
1463
|
+
...generate(scope, decl.left.object),
|
1464
|
+
Opcodes.i32_to_u
|
1465
|
+
]),
|
1466
|
+
|
1467
|
+
// get index as valtype
|
1468
|
+
...generate(scope, decl.left.property),
|
1469
|
+
|
1470
|
+
// convert to i32 and turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
1471
|
+
Opcodes.i32_to_u,
|
1472
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
1473
|
+
[ Opcodes.i32_mul ],
|
1474
|
+
...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
1475
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
1476
|
+
|
1477
|
+
...(op === '=' ? generate(scope, decl.right, false, name) : performOp(scope, op, [
|
1478
|
+
[ Opcodes.local_get, pointerTmp ],
|
1479
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1480
|
+
], generate(scope, decl.right), parentType === TYPES._array ? TYPES.number : TYPES.string, getNodeType(scope, decl.right), false, name, true)),
|
1481
|
+
[ Opcodes.local_tee, newValueTmp ],
|
1482
|
+
|
1483
|
+
...(parentType === TYPES._array ? [
|
1484
|
+
[ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1485
|
+
] : [
|
1486
|
+
Opcodes.i32_to_u,
|
1487
|
+
[ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1488
|
+
]),
|
1489
|
+
|
1490
|
+
[ Opcodes.local_get, newValueTmp ]
|
1491
|
+
];
|
1492
|
+
}
|
1493
|
+
|
1320
1494
|
const [ local, isGlobal ] = lookupName(scope, name);
|
1321
1495
|
|
1322
1496
|
if (local === undefined) {
|
1323
1497
|
// todo: this should be a devtools/repl/??? only thing
|
1324
1498
|
|
1325
1499
|
// only allow = for this
|
1326
|
-
if (
|
1500
|
+
if (op !== '=') return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`);
|
1327
1501
|
|
1328
1502
|
if (builtinVars[name]) {
|
1329
1503
|
// just return rhs (eg `NaN = 2`)
|
@@ -1337,8 +1511,10 @@ const generateAssign = (scope, decl) => {
|
|
1337
1511
|
];
|
1338
1512
|
}
|
1339
1513
|
|
1340
|
-
|
1341
|
-
|
1514
|
+
typeStates[name] = getNodeType(scope, decl.right);
|
1515
|
+
|
1516
|
+
if (op === '=') {
|
1517
|
+
// typeStates[name] = getNodeType(scope, decl.right);
|
1342
1518
|
|
1343
1519
|
return [
|
1344
1520
|
...generate(scope, decl.right, isGlobal, name),
|
@@ -1347,8 +1523,26 @@ const generateAssign = (scope, decl) => {
|
|
1347
1523
|
];
|
1348
1524
|
}
|
1349
1525
|
|
1526
|
+
if (op === '||' || op === '&&' || op === '??') {
|
1527
|
+
// todo: is this needed?
|
1528
|
+
// for logical assignment ops, it is not left @= right ~= left = left @ right
|
1529
|
+
// instead, left @ (left = right)
|
1530
|
+
// eg, x &&= y ~= x && (x = y)
|
1531
|
+
|
1532
|
+
return [
|
1533
|
+
...performOp(scope, op, [
|
1534
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
1535
|
+
], [
|
1536
|
+
...generate(scope, decl.right),
|
1537
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
1538
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
1539
|
+
], getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
1540
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
1541
|
+
];
|
1542
|
+
}
|
1543
|
+
|
1350
1544
|
return [
|
1351
|
-
...performOp(scope,
|
1545
|
+
...performOp(scope, op, [ [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ] ], generate(scope, decl.right), getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
1352
1546
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
1353
1547
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
|
1354
1548
|
];
|
@@ -1375,13 +1569,14 @@ const generateUnary = (scope, decl) => {
|
|
1375
1569
|
|
1376
1570
|
case '!':
|
1377
1571
|
// !=
|
1378
|
-
return falsy(scope, generate(scope, decl.argument));
|
1572
|
+
return falsy(scope, generate(scope, decl.argument), getNodeType(scope, decl.argument));
|
1379
1573
|
|
1380
1574
|
case '~':
|
1575
|
+
// todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
|
1381
1576
|
return [
|
1382
1577
|
...generate(scope, decl.argument),
|
1383
1578
|
Opcodes.i32_to,
|
1384
|
-
[ Opcodes.i32_const, signedLEB128(-1) ],
|
1579
|
+
[ Opcodes.i32_const, ...signedLEB128(-1) ],
|
1385
1580
|
[ Opcodes.i32_xor ],
|
1386
1581
|
Opcodes.i32_from
|
1387
1582
|
];
|
@@ -1462,7 +1657,7 @@ const generateUpdate = (scope, decl) => {
|
|
1462
1657
|
};
|
1463
1658
|
|
1464
1659
|
const generateIf = (scope, decl) => {
|
1465
|
-
const out = truthy(scope, generate(scope, decl.test), decl.test);
|
1660
|
+
const out = truthy(scope, generate(scope, decl.test), getNodeType(scope, decl.test));
|
1466
1661
|
|
1467
1662
|
out.push(Opcodes.i32_to, [ Opcodes.if, Blocktype.void ]);
|
1468
1663
|
depth.push('if');
|
@@ -1552,6 +1747,113 @@ const generateWhile = (scope, decl) => {
|
|
1552
1747
|
return out;
|
1553
1748
|
};
|
1554
1749
|
|
1750
|
+
const generateForOf = (scope, decl) => {
|
1751
|
+
const out = [];
|
1752
|
+
|
1753
|
+
const rightType = getNodeType(scope, decl.right);
|
1754
|
+
const valtypeSize = rightType === TYPES._array ? ValtypeSize[valtype] : ValtypeSize.i16; // presume array (:()
|
1755
|
+
|
1756
|
+
// todo: for of inside for of might fuck up?
|
1757
|
+
const pointer = localTmp(scope, 'forof_base_pointer', Valtype.i32);
|
1758
|
+
const length = localTmp(scope, 'forof_length', Valtype.i32);
|
1759
|
+
const counter = localTmp(scope, 'forof_counter', Valtype.i32);
|
1760
|
+
|
1761
|
+
out.push(
|
1762
|
+
// set pointer as right
|
1763
|
+
...generate(scope, decl.right),
|
1764
|
+
Opcodes.i32_to_u,
|
1765
|
+
[ Opcodes.local_set, pointer ],
|
1766
|
+
|
1767
|
+
// get length
|
1768
|
+
[ Opcodes.local_get, pointer ],
|
1769
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
1770
|
+
[ Opcodes.local_set, length ]
|
1771
|
+
);
|
1772
|
+
|
1773
|
+
out.push([ Opcodes.loop, Blocktype.void ]);
|
1774
|
+
depth.push('forof');
|
1775
|
+
|
1776
|
+
// setup local for left
|
1777
|
+
generate(scope, decl.left);
|
1778
|
+
|
1779
|
+
const leftName = decl.left.declarations[0].id.name;
|
1780
|
+
|
1781
|
+
// set type for local
|
1782
|
+
typeStates[leftName] = rightType === TYPES._array ? TYPES.number : TYPES.string;
|
1783
|
+
|
1784
|
+
const [ local, isGlobal ] = lookupName(scope, leftName);
|
1785
|
+
|
1786
|
+
if (rightType === TYPES._array) { // array
|
1787
|
+
out.push(
|
1788
|
+
[ Opcodes.local_get, pointer ],
|
1789
|
+
[ Opcodes.load, Math.log2(valtypeSize) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
|
1790
|
+
);
|
1791
|
+
} else { // string
|
1792
|
+
const [ newOut, newPointer ] = makeArray(scope, {
|
1793
|
+
rawElements: new Array(1)
|
1794
|
+
}, isGlobal, leftName, true, 'i16');
|
1795
|
+
|
1796
|
+
out.push(
|
1797
|
+
// setup new/out array
|
1798
|
+
...newOut,
|
1799
|
+
[ Opcodes.drop ],
|
1800
|
+
|
1801
|
+
...number(0, Valtype.i32), // base 0 for store after
|
1802
|
+
|
1803
|
+
// load current string ind {arg}
|
1804
|
+
[ Opcodes.local_get, pointer ],
|
1805
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
1806
|
+
|
1807
|
+
// store to new string ind 0
|
1808
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
1809
|
+
|
1810
|
+
// return new string (page)
|
1811
|
+
...number(newPointer)
|
1812
|
+
);
|
1813
|
+
}
|
1814
|
+
|
1815
|
+
// set left value
|
1816
|
+
out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ]);
|
1817
|
+
|
1818
|
+
out.push(
|
1819
|
+
[ Opcodes.block, Blocktype.void ],
|
1820
|
+
[ Opcodes.block, Blocktype.void ]
|
1821
|
+
);
|
1822
|
+
depth.push('block');
|
1823
|
+
depth.push('block');
|
1824
|
+
|
1825
|
+
out.push(
|
1826
|
+
...generate(scope, decl.body),
|
1827
|
+
[ Opcodes.end ]
|
1828
|
+
);
|
1829
|
+
depth.pop();
|
1830
|
+
|
1831
|
+
out.push(
|
1832
|
+
// increment iter pointer by valtype size
|
1833
|
+
[ Opcodes.local_get, pointer ],
|
1834
|
+
...number(valtypeSize, Valtype.i32),
|
1835
|
+
[ Opcodes.i32_add ],
|
1836
|
+
[ Opcodes.local_set, pointer ],
|
1837
|
+
|
1838
|
+
// increment counter by 1
|
1839
|
+
[ Opcodes.local_get, counter ],
|
1840
|
+
...number(1, Valtype.i32),
|
1841
|
+
[ Opcodes.i32_add ],
|
1842
|
+
[ Opcodes.local_tee, counter ],
|
1843
|
+
|
1844
|
+
// loop if counter != length
|
1845
|
+
[ Opcodes.local_get, length ],
|
1846
|
+
[ Opcodes.i32_ne ],
|
1847
|
+
[ Opcodes.br_if, 1 ],
|
1848
|
+
|
1849
|
+
[ Opcodes.end ], [ Opcodes.end ]
|
1850
|
+
);
|
1851
|
+
depth.pop();
|
1852
|
+
depth.pop();
|
1853
|
+
|
1854
|
+
return out;
|
1855
|
+
};
|
1856
|
+
|
1555
1857
|
const getNearestLoop = () => {
|
1556
1858
|
for (let i = depth.length - 1; i >= 0; i--) {
|
1557
1859
|
if (depth[i] === 'while' || depth[i] === 'for' || depth[i] === 'forof') return i;
|
@@ -1638,13 +1940,22 @@ const generateAssignPat = (scope, decl) => {
|
|
1638
1940
|
};
|
1639
1941
|
|
1640
1942
|
let pages = new Map();
|
1641
|
-
const allocPage = reason => {
|
1642
|
-
if (pages.has(reason)) return pages.get(reason);
|
1943
|
+
const allocPage = (reason, type) => {
|
1944
|
+
if (pages.has(reason)) return pages.get(reason).ind;
|
1945
|
+
|
1946
|
+
const ind = pages.size;
|
1947
|
+
pages.set(reason, { ind, type });
|
1948
|
+
|
1949
|
+
if (allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
|
1950
|
+
|
1951
|
+
return ind;
|
1952
|
+
};
|
1643
1953
|
|
1644
|
-
|
1645
|
-
pages.
|
1954
|
+
const freePage = reason => {
|
1955
|
+
const { ind } = pages.get(reason);
|
1956
|
+
pages.delete(reason);
|
1646
1957
|
|
1647
|
-
if (
|
1958
|
+
if (allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
1648
1959
|
|
1649
1960
|
return ind;
|
1650
1961
|
};
|
@@ -1658,7 +1969,7 @@ const itemTypeToValtype = {
|
|
1658
1969
|
i16: 'i32'
|
1659
1970
|
};
|
1660
1971
|
|
1661
|
-
const
|
1972
|
+
const StoreOps = {
|
1662
1973
|
i32: Opcodes.i32_store,
|
1663
1974
|
i64: Opcodes.i64_store,
|
1664
1975
|
f64: Opcodes.f64_store,
|
@@ -1673,7 +1984,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
1673
1984
|
if (!arrays.has(name) || name === '$undeclared') {
|
1674
1985
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
1675
1986
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
1676
|
-
arrays.set(name, allocPage(`${itemType === 'i16' ? 'string' : 'array'}: ${uniqueName}
|
1987
|
+
arrays.set(name, allocPage(`${itemType === 'i16' ? 'string' : 'array'}: ${uniqueName}`, itemType) * pageSize);
|
1677
1988
|
}
|
1678
1989
|
|
1679
1990
|
const pointer = arrays.get(name);
|
@@ -1690,7 +2001,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
1690
2001
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
|
1691
2002
|
);
|
1692
2003
|
|
1693
|
-
const storeOp =
|
2004
|
+
const storeOp = StoreOps[itemType];
|
1694
2005
|
const valtype = itemTypeToValtype[itemType];
|
1695
2006
|
|
1696
2007
|
if (!initEmpty) for (let i = 0; i < length; i++) {
|
@@ -1706,8 +2017,6 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
1706
2017
|
// local value as pointer
|
1707
2018
|
out.push(...number(pointer));
|
1708
2019
|
|
1709
|
-
scope.memory = true;
|
1710
|
-
|
1711
2020
|
return [ out, pointer ];
|
1712
2021
|
};
|
1713
2022
|
|
@@ -1726,8 +2035,6 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
1726
2035
|
const name = decl.object.name;
|
1727
2036
|
const pointer = arrays.get(name);
|
1728
2037
|
|
1729
|
-
scope.memory = true;
|
1730
|
-
|
1731
2038
|
const aotPointer = pointer != null;
|
1732
2039
|
|
1733
2040
|
return [
|
@@ -1747,8 +2054,6 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
1747
2054
|
const name = decl.object.name;
|
1748
2055
|
const pointer = arrays.get(name);
|
1749
2056
|
|
1750
|
-
scope.memory = true;
|
1751
|
-
|
1752
2057
|
const aotPointer = pointer != null;
|
1753
2058
|
|
1754
2059
|
if (type === TYPES._array) {
|
@@ -1858,7 +2163,7 @@ const generateFunc = (scope, decl) => {
|
|
1858
2163
|
locals: {},
|
1859
2164
|
localInd: 0,
|
1860
2165
|
returns: [ valtypeBinary ],
|
1861
|
-
|
2166
|
+
returnType: null,
|
1862
2167
|
throws: false,
|
1863
2168
|
name
|
1864
2169
|
};
|
@@ -1884,7 +2189,6 @@ const generateFunc = (scope, decl) => {
|
|
1884
2189
|
returns: innerScope.returns,
|
1885
2190
|
returnType: innerScope.returnType,
|
1886
2191
|
locals: innerScope.locals,
|
1887
|
-
memory: innerScope.memory,
|
1888
2192
|
throws: innerScope.throws,
|
1889
2193
|
index: currentFuncIndex++
|
1890
2194
|
};
|
@@ -1899,6 +2203,8 @@ const generateFunc = (scope, decl) => {
|
|
1899
2203
|
|
1900
2204
|
if (name !== 'main' && func.returns.length !== 0 && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
1901
2205
|
wasm.push(...number(0), [ Opcodes.return ]);
|
2206
|
+
|
2207
|
+
if (func.returnType === null) func.returnType = TYPES.undefined;
|
1902
2208
|
}
|
1903
2209
|
|
1904
2210
|
// change v128 params into many <type> (i32x4 -> i32/etc) instead as unsupported param valtype
|
@@ -1909,9 +2215,7 @@ const generateFunc = (scope, decl) => {
|
|
1909
2215
|
if (local.type === Valtype.v128) {
|
1910
2216
|
vecParams++;
|
1911
2217
|
|
1912
|
-
/*
|
1913
|
-
|
1914
|
-
wasm.unshift( // add v128 load for param
|
2218
|
+
/* wasm.unshift( // add v128 load for param
|
1915
2219
|
[ Opcodes.i32_const, 0 ],
|
1916
2220
|
[ ...Opcodes.v128_load, 0, i * 16 ],
|
1917
2221
|
[ Opcodes.local_set, local.idx ]
|
@@ -2022,10 +2326,10 @@ const generateFunc = (scope, decl) => {
|
|
2022
2326
|
};
|
2023
2327
|
|
2024
2328
|
const generateCode = (scope, decl) => {
|
2025
|
-
|
2329
|
+
let out = [];
|
2026
2330
|
|
2027
2331
|
for (const x of decl.body) {
|
2028
|
-
out.
|
2332
|
+
out = out.concat(generate(scope, x));
|
2029
2333
|
}
|
2030
2334
|
|
2031
2335
|
return out;
|