porffor 0.0.0-758fed5 → 0.0.0-7d5ae9c
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 +29 -15
- 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 +465 -112
- package/compiler/decompile.js +1 -1
- package/compiler/embedding.js +9 -5
- package/compiler/index.js +47 -5
- package/compiler/opt.js +15 -19
- package/compiler/parse.js +1 -0
- package/compiler/prototype.js +170 -30
- package/compiler/sections.js +20 -4
- package/compiler/wrap.js +12 -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 -52
- package/runner/info.js +37 -2
- package/runner/transform.js +2 -1
- package/tmp.c +58 -0
package/compiler/codeGen.js
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from "./wasmSpec.js";
|
2
|
-
import { signedLEB128, unsignedLEB128 } from "./encoding.js";
|
2
|
+
import { ieee754_binary64, signedLEB128, unsignedLEB128 } from "./encoding.js";
|
3
3
|
import { operatorOpcode } from "./expression.js";
|
4
4
|
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from "./builtins.js";
|
5
5
|
import { PrototypeFuncs } from "./prototype.js";
|
6
|
-
import { number, i32x4 } from "./embedding.js";
|
6
|
+
import { number, i32x4, enforceOneByte, enforceTwoBytes, enforceFourBytes, enforceEightBytes } 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;
|
@@ -108,8 +109,8 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
108
109
|
case 'WhileStatement':
|
109
110
|
return generateWhile(scope, decl);
|
110
111
|
|
111
|
-
|
112
|
-
return generateForOf(scope, decl);
|
112
|
+
case 'ForOfStatement':
|
113
|
+
return generateForOf(scope, decl);
|
113
114
|
|
114
115
|
case 'BreakStatement':
|
115
116
|
return generateBreak(scope, decl);
|
@@ -151,44 +152,65 @@ const generate = (scope, decl, global = false, name = undefined) => {
|
|
151
152
|
|
152
153
|
return [];
|
153
154
|
|
154
|
-
case 'TaggedTemplateExpression':
|
155
|
-
|
156
|
-
|
155
|
+
case 'TaggedTemplateExpression': {
|
156
|
+
const funcs = {
|
157
|
+
asm: str => {
|
158
|
+
let out = [];
|
157
159
|
|
158
|
-
|
159
|
-
|
160
|
+
for (const line of str.split('\n')) {
|
161
|
+
const asm = line.trim().split(';;')[0].split(' ');
|
162
|
+
if (asm[0] === '') continue; // blank
|
160
163
|
|
161
|
-
|
162
|
-
|
163
|
-
|
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
|
+
}
|
164
169
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
}
|
170
|
+
if (asm[0] === 'returns') {
|
171
|
+
scope.returns = asm.slice(1).map(x => Valtype[x]);
|
172
|
+
continue;
|
173
|
+
}
|
170
174
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
+
if (asm[0] === 'memory') {
|
176
|
+
allocPage('asm instrinsic');
|
177
|
+
// todo: add to store/load offset insts
|
178
|
+
continue;
|
179
|
+
}
|
175
180
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
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));
|
181
186
|
|
182
|
-
|
183
|
-
|
187
|
+
out.push([ ...inst, ...immediates ]);
|
188
|
+
}
|
184
189
|
|
185
|
-
|
186
|
-
|
190
|
+
return out;
|
191
|
+
},
|
187
192
|
|
188
|
-
|
193
|
+
__internal_print_type: str => {
|
194
|
+
const type = getType(scope, str) - TYPES.number;
|
195
|
+
|
196
|
+
return [
|
197
|
+
...number(type),
|
198
|
+
[ Opcodes.call, importedFuncs.print ],
|
199
|
+
|
200
|
+
// newline
|
201
|
+
...number(10),
|
202
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
203
|
+
];
|
204
|
+
}
|
189
205
|
}
|
190
206
|
|
191
|
-
|
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
|
+
}
|
192
214
|
|
193
215
|
default:
|
194
216
|
return todo(`no generation for ${decl.type}!`);
|
@@ -304,6 +326,8 @@ const localTmp = (scope, name, type = valtypeBinary) => {
|
|
304
326
|
return idx;
|
305
327
|
};
|
306
328
|
|
329
|
+
const isIntOp = op => op[0] >= 0xb7 && op[0] <= 0xba;
|
330
|
+
|
307
331
|
const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
308
332
|
const checks = {
|
309
333
|
'||': falsy,
|
@@ -316,6 +340,32 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
|
316
340
|
// generic structure for {a} OP {b}
|
317
341
|
// -->
|
318
342
|
// _ = {a}; if (OP_CHECK) {b} else _
|
343
|
+
|
344
|
+
// if we can, use int tmp and convert at the end to help prevent unneeded conversions
|
345
|
+
// (like if we are in an if condition - very common)
|
346
|
+
const leftIsInt = isIntOp(left[left.length - 1]);
|
347
|
+
const rightIsInt = isIntOp(right[right.length - 1]);
|
348
|
+
|
349
|
+
const canInt = leftIsInt && rightIsInt;
|
350
|
+
|
351
|
+
if (canInt) {
|
352
|
+
// remove int -> float conversions from left and right
|
353
|
+
left.pop();
|
354
|
+
right.pop();
|
355
|
+
|
356
|
+
return [
|
357
|
+
...left,
|
358
|
+
[ Opcodes.local_tee, localTmp(scope, 'logictmpi', Valtype.i32) ],
|
359
|
+
...checks[op](scope, [], leftType, true),
|
360
|
+
[ Opcodes.if, Valtype.i32 ],
|
361
|
+
...right,
|
362
|
+
[ Opcodes.else ],
|
363
|
+
[ Opcodes.local_get, localTmp(scope, 'logictmpi', Valtype.i32) ],
|
364
|
+
[ Opcodes.end ],
|
365
|
+
Opcodes.i32_from
|
366
|
+
];
|
367
|
+
}
|
368
|
+
|
319
369
|
return [
|
320
370
|
...left,
|
321
371
|
[ Opcodes.local_tee, localTmp(scope, 'logictmp') ],
|
@@ -339,6 +389,9 @@ const concatStrings = (scope, left, right, global, name, assign) => {
|
|
339
389
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
340
390
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
341
391
|
|
392
|
+
const aotWFA = process.argv.includes('-aot-well-formed-string-approximation');
|
393
|
+
if (aotWFA) addVarMeta(name, { wellFormed: undefined });
|
394
|
+
|
342
395
|
if (assign) {
|
343
396
|
const pointer = arrays.get(name ?? '$undeclared');
|
344
397
|
|
@@ -566,12 +619,12 @@ const compareStrings = (scope, left, right) => {
|
|
566
619
|
];
|
567
620
|
};
|
568
621
|
|
569
|
-
const truthy = (scope, wasm, type) => {
|
622
|
+
const truthy = (scope, wasm, type, int = false) => {
|
570
623
|
// arrays are always truthy
|
571
624
|
if (type === TYPES._array) return [
|
572
625
|
...wasm,
|
573
626
|
[ Opcodes.drop ],
|
574
|
-
...number(1)
|
627
|
+
...number(1, int ? Valtype.i32 : valtypeBinary)
|
575
628
|
];
|
576
629
|
|
577
630
|
if (type === TYPES.string) {
|
@@ -587,8 +640,8 @@ const truthy = (scope, wasm, type) => {
|
|
587
640
|
// if length != 0
|
588
641
|
/* [ Opcodes.i32_eqz ],
|
589
642
|
[ Opcodes.i32_eqz ], */
|
590
|
-
Opcodes.i32_from_u
|
591
|
-
]
|
643
|
+
...(int ? [] : [ Opcodes.i32_from_u ])
|
644
|
+
];
|
592
645
|
}
|
593
646
|
|
594
647
|
// if != 0
|
@@ -601,12 +654,12 @@ const truthy = (scope, wasm, type) => {
|
|
601
654
|
];
|
602
655
|
};
|
603
656
|
|
604
|
-
const falsy = (scope, wasm, type) => {
|
657
|
+
const falsy = (scope, wasm, type, int = false) => {
|
605
658
|
// arrays are always truthy
|
606
659
|
if (type === TYPES._array) return [
|
607
660
|
...wasm,
|
608
661
|
[ Opcodes.drop ],
|
609
|
-
...number(0)
|
662
|
+
...number(0, int ? Valtype.i32 : valtypeBinary)
|
610
663
|
];
|
611
664
|
|
612
665
|
if (type === TYPES.string) {
|
@@ -621,7 +674,7 @@ const falsy = (scope, wasm, type) => {
|
|
621
674
|
|
622
675
|
// if length == 0
|
623
676
|
[ Opcodes.i32_eqz ],
|
624
|
-
Opcodes.i32_from_u
|
677
|
+
...(int ? [] : [ Opcodes.i32_from_u ])
|
625
678
|
]
|
626
679
|
}
|
627
680
|
|
@@ -629,31 +682,29 @@ const falsy = (scope, wasm, type) => {
|
|
629
682
|
return [
|
630
683
|
...wasm,
|
631
684
|
|
632
|
-
...Opcodes.eqz,
|
633
|
-
Opcodes.i32_from_u
|
685
|
+
...(int ? [ [ Opcodes.i32_eqz ] ] : [ ...Opcodes.eqz, Opcodes.i32_from_u ])
|
634
686
|
];
|
635
687
|
};
|
636
688
|
|
637
|
-
const nullish = (scope, wasm, type) => {
|
689
|
+
const nullish = (scope, wasm, type, int = false) => {
|
638
690
|
// undefined
|
639
691
|
if (type === TYPES.undefined) return [
|
640
692
|
...wasm,
|
641
693
|
[ Opcodes.drop ],
|
642
|
-
...number(1)
|
694
|
+
...number(1, int ? Valtype.i32 : valtypeBinary)
|
643
695
|
];
|
644
696
|
|
645
697
|
// null (if object and = "0")
|
646
698
|
if (type === TYPES.object) return [
|
647
699
|
...wasm,
|
648
|
-
...Opcodes.eqz,
|
649
|
-
Opcodes.i32_from_u
|
700
|
+
...(int ? [ [ Opcodes.i32_eqz ] ] : [ ...Opcodes.eqz, Opcodes.i32_from_u ])
|
650
701
|
];
|
651
702
|
|
652
703
|
// not
|
653
704
|
return [
|
654
705
|
...wasm,
|
655
706
|
[ Opcodes.drop ],
|
656
|
-
...number(0)
|
707
|
+
...number(0, int ? Valtype.i32 : valtypeBinary)
|
657
708
|
];
|
658
709
|
};
|
659
710
|
|
@@ -664,29 +715,44 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
664
715
|
|
665
716
|
if (codeLog && (!leftType || !rightType)) log('codegen', 'untracked type in op', op, _name, '\n' + new Error().stack.split('\n').slice(1).join('\n'));
|
666
717
|
|
667
|
-
|
668
|
-
|
718
|
+
const eqOp = ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(op);
|
719
|
+
|
720
|
+
if (leftType && rightType && (
|
721
|
+
// if strict (in)equal and known types mismatch, return false (===)/true (!==)
|
722
|
+
((op === '===' || op === '!==') && leftType !== rightType) ||
|
723
|
+
|
724
|
+
// if equality op and an operand is undefined, return false
|
725
|
+
(eqOp && leftType === TYPES.undefined ^ rightType === TYPES.undefined)
|
726
|
+
)) {
|
727
|
+
// undefined == null
|
728
|
+
if (((leftType === TYPES.undefined && rightType === TYPES.object) || (leftType === TYPES.object && rightType === TYPES.undefined)) && (op === '==' || op === '!=')) return [
|
729
|
+
...(leftType === TYPES.object ? left : right),
|
730
|
+
...Opcodes.eqz,
|
731
|
+
...(op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
|
732
|
+
];
|
733
|
+
|
669
734
|
return [
|
670
735
|
...left,
|
671
|
-
...right,
|
672
|
-
|
673
|
-
// drop values
|
674
736
|
[ Opcodes.drop ],
|
737
|
+
|
738
|
+
...right,
|
675
739
|
[ Opcodes.drop ],
|
676
740
|
|
677
|
-
// return
|
678
|
-
...number(op === '===' ?
|
741
|
+
// return true (!=/!==) or false (else)
|
742
|
+
...number(op === '!=' || op === '!==' ? 1 : 0, Valtype.i32)
|
679
743
|
];
|
680
744
|
}
|
681
745
|
|
746
|
+
// todo: niche null hell with 0
|
747
|
+
|
682
748
|
if (leftType === TYPES.string || rightType === TYPES.string) {
|
683
749
|
if (op === '+') {
|
684
750
|
// string concat (a + b)
|
685
751
|
return concatStrings(scope, left, right, _global, _name, assign);
|
686
752
|
}
|
687
753
|
|
688
|
-
//
|
689
|
-
if (!
|
754
|
+
// not an equality op, NaN
|
755
|
+
if (!eqOp) return number(NaN);
|
690
756
|
|
691
757
|
// else leave bool ops
|
692
758
|
// todo: convert string to number if string and number/bool
|
@@ -731,21 +797,15 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
731
797
|
];
|
732
798
|
};
|
733
799
|
|
734
|
-
let binaryExpDepth = 0;
|
735
800
|
const generateBinaryExp = (scope, decl, _global, _name) => {
|
736
|
-
|
737
|
-
|
738
|
-
const out = [
|
739
|
-
...performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name)
|
740
|
-
];
|
801
|
+
const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
|
741
802
|
|
742
803
|
if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
|
743
804
|
|
744
|
-
binaryExpDepth--;
|
745
805
|
return out;
|
746
806
|
};
|
747
807
|
|
748
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType,
|
808
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [] }) => {
|
749
809
|
const existing = funcs.find(x => x.name === name);
|
750
810
|
if (existing) return existing;
|
751
811
|
|
@@ -781,7 +841,6 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
781
841
|
returns,
|
782
842
|
returnType: TYPES[returnType ?? 'number'],
|
783
843
|
wasm,
|
784
|
-
memory,
|
785
844
|
internal: true,
|
786
845
|
index: currentFuncIndex++
|
787
846
|
};
|
@@ -814,7 +873,8 @@ const TYPES = {
|
|
814
873
|
bigint: 0xffffffffffff7,
|
815
874
|
|
816
875
|
// these are not "typeof" types but tracked internally
|
817
|
-
_array:
|
876
|
+
_array: 0xfffffffffff0f,
|
877
|
+
_regexp: 0xfffffffffff1f
|
818
878
|
};
|
819
879
|
|
820
880
|
const TYPE_NAMES = {
|
@@ -849,6 +909,8 @@ const getType = (scope, _name) => {
|
|
849
909
|
const getNodeType = (scope, node) => {
|
850
910
|
if (node.type === 'Literal') {
|
851
911
|
if (['number', 'boolean', 'string', 'undefined', 'object', 'function', 'symbol', 'bigint'].includes(node.value)) return TYPES.number;
|
912
|
+
if (node.regex) return TYPES._regexp;
|
913
|
+
|
852
914
|
return TYPES[typeof node.value];
|
853
915
|
}
|
854
916
|
|
@@ -882,6 +944,11 @@ const getNodeType = (scope, node) => {
|
|
882
944
|
|
883
945
|
// literal.func()
|
884
946
|
if (!name && node.callee.type === 'MemberExpression') {
|
947
|
+
if (node.callee.object.regex) {
|
948
|
+
const funcName = node.callee.property.name;
|
949
|
+
return Rhemyn[funcName] ? TYPES.boolean : TYPES.undefined;
|
950
|
+
}
|
951
|
+
|
885
952
|
const baseType = getNodeType(scope, node.callee.object);
|
886
953
|
|
887
954
|
const func = node.callee.property.name;
|
@@ -925,6 +992,11 @@ const getNodeType = (scope, node) => {
|
|
925
992
|
const generateLiteral = (scope, decl, global, name) => {
|
926
993
|
if (decl.value === null) return number(NULL);
|
927
994
|
|
995
|
+
if (decl.regex) {
|
996
|
+
scope.regex[name] = decl.regex;
|
997
|
+
return number(1);
|
998
|
+
}
|
999
|
+
|
928
1000
|
switch (typeof decl.value) {
|
929
1001
|
case 'number':
|
930
1002
|
return number(decl.value);
|
@@ -946,12 +1018,38 @@ const generateLiteral = (scope, decl, global, name) => {
|
|
946
1018
|
case 'bigint': return number(TYPES.bigint);
|
947
1019
|
}
|
948
1020
|
|
1021
|
+
const aotWFA = process.argv.includes('-aot-well-formed-string-approximation');
|
1022
|
+
let wellFormed = aotWFA ? true : undefined;
|
1023
|
+
|
949
1024
|
const str = decl.value;
|
950
1025
|
const rawElements = new Array(str.length);
|
1026
|
+
let j = 0;
|
951
1027
|
for (let i = 0; i < str.length; i++) {
|
952
1028
|
rawElements[i] = str.charCodeAt(i);
|
1029
|
+
|
1030
|
+
if (wellFormed) {
|
1031
|
+
// check if surrogate
|
1032
|
+
if ((str.charCodeAt(j) & 0xF800) === 0xD800) {
|
1033
|
+
// unpaired trailing surrogate
|
1034
|
+
if (str.charCodeAt(j) >= 0xDC00) {
|
1035
|
+
wellFormed = false;
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
// unpaired leading surrogate
|
1039
|
+
// if (++j >= str.length || (str.charCodeAt(j) & 0xFC00) != 0xDC00) {
|
1040
|
+
if ((str.charCodeAt(++j) & 0xFC00) != 0xDC00) {
|
1041
|
+
wellFormed = false;
|
1042
|
+
}
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
j++;
|
1046
|
+
}
|
953
1047
|
}
|
954
1048
|
|
1049
|
+
// console.log(wellFormed, str);
|
1050
|
+
|
1051
|
+
if (aotWFA) addVarMeta(name, { wellFormed });
|
1052
|
+
|
955
1053
|
return makeArray(scope, {
|
956
1054
|
rawElements
|
957
1055
|
}, global, name, false, 'i16')[0];
|
@@ -986,6 +1084,8 @@ const countLeftover = wasm => {
|
|
986
1084
|
} else count--;
|
987
1085
|
if (func) count += func.returns.length;
|
988
1086
|
} else count--;
|
1087
|
+
|
1088
|
+
// console.log(count, decompile([ inst ]).slice(0, -1));
|
989
1089
|
}
|
990
1090
|
|
991
1091
|
return count;
|
@@ -1084,6 +1184,25 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1084
1184
|
|
1085
1185
|
// literal.func()
|
1086
1186
|
if (!name && decl.callee.type === 'MemberExpression') {
|
1187
|
+
// megahack for /regex/.func()
|
1188
|
+
if (decl.callee.object.regex) {
|
1189
|
+
const funcName = decl.callee.property.name;
|
1190
|
+
const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
|
1191
|
+
|
1192
|
+
funcIndex[func.name] = func.index;
|
1193
|
+
funcs.push(func);
|
1194
|
+
|
1195
|
+
return [
|
1196
|
+
// make string arg
|
1197
|
+
...generate(scope, decl.arguments[0]),
|
1198
|
+
|
1199
|
+
// call regex func
|
1200
|
+
Opcodes.i32_to_u,
|
1201
|
+
[ Opcodes.call, func.index ],
|
1202
|
+
Opcodes.i32_from
|
1203
|
+
];
|
1204
|
+
}
|
1205
|
+
|
1087
1206
|
baseType = getNodeType(scope, decl.callee.object);
|
1088
1207
|
|
1089
1208
|
const func = decl.callee.property.name;
|
@@ -1096,6 +1215,31 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1096
1215
|
baseName = [...arrays.keys()].pop();
|
1097
1216
|
}
|
1098
1217
|
|
1218
|
+
if (protoName && baseType === TYPES.string && Rhemyn[protoName]) {
|
1219
|
+
const func = Rhemyn[protoName](decl.arguments[0].regex.pattern, currentFuncIndex++);
|
1220
|
+
|
1221
|
+
funcIndex[func.name] = func.index;
|
1222
|
+
funcs.push(func);
|
1223
|
+
|
1224
|
+
const pointer = arrays.get(baseName);
|
1225
|
+
const [ local, isGlobal ] = lookupName(scope, baseName);
|
1226
|
+
|
1227
|
+
return [
|
1228
|
+
...out,
|
1229
|
+
|
1230
|
+
...(pointer == null ? [
|
1231
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1232
|
+
Opcodes.i32_to_u,
|
1233
|
+
] : [
|
1234
|
+
...number(pointer, Valtype.i32)
|
1235
|
+
]),
|
1236
|
+
|
1237
|
+
// call regex func
|
1238
|
+
[ Opcodes.call, func.index ],
|
1239
|
+
Opcodes.i32_from
|
1240
|
+
];
|
1241
|
+
}
|
1242
|
+
|
1099
1243
|
if (protoFunc) {
|
1100
1244
|
let pointer = arrays.get(baseName);
|
1101
1245
|
|
@@ -1124,28 +1268,39 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1124
1268
|
if (protoFunc.noArgRetLength && decl.arguments.length === 0) return arrayUtil.getLength(pointer)
|
1125
1269
|
|
1126
1270
|
let protoLocal = protoFunc.local ? localTmp(scope, `__${TYPE_NAMES[baseType]}_${protoName}_tmp`, protoFunc.local) : -1;
|
1271
|
+
let protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${TYPE_NAMES[baseType]}_${protoName}_tmp2`, protoFunc.local2) : -1;
|
1127
1272
|
|
1128
1273
|
// use local for cached i32 length as commonly used
|
1129
1274
|
let lengthLocal = localTmp(scope, '__proto_length_cache', Valtype.i32);
|
1130
1275
|
|
1276
|
+
let lengthI32CacheUsed = false;
|
1277
|
+
|
1278
|
+
const protoOut = protoFunc(pointer, {
|
1279
|
+
getCachedI32: () => {
|
1280
|
+
lengthI32CacheUsed = true;
|
1281
|
+
return [ [ Opcodes.local_get, lengthLocal ] ]
|
1282
|
+
},
|
1283
|
+
setCachedI32: () => [ [ Opcodes.local_set, lengthLocal ] ],
|
1284
|
+
get: () => arrayUtil.getLength(pointer),
|
1285
|
+
getI32: () => arrayUtil.getLengthI32(pointer),
|
1286
|
+
set: value => arrayUtil.setLength(pointer, value),
|
1287
|
+
setI32: value => arrayUtil.setLengthI32(pointer, value)
|
1288
|
+
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1289
|
+
return makeArray(scope, {
|
1290
|
+
rawElements: new Array(length)
|
1291
|
+
}, _global, _name, true, itemType);
|
1292
|
+
}, varMetadata.get(baseName));
|
1293
|
+
|
1131
1294
|
return [
|
1132
1295
|
...out,
|
1133
1296
|
|
1134
|
-
...
|
1135
|
-
|
1297
|
+
...(!lengthI32CacheUsed ? [] : [
|
1298
|
+
...arrayUtil.getLengthI32(pointer),
|
1299
|
+
[ Opcodes.local_set, lengthLocal ],
|
1300
|
+
]),
|
1136
1301
|
|
1137
1302
|
[ Opcodes.block, valtypeBinary ],
|
1138
|
-
...
|
1139
|
-
cachedI32: [ [ Opcodes.local_get, lengthLocal ] ],
|
1140
|
-
get: arrayUtil.getLength(pointer),
|
1141
|
-
getI32: arrayUtil.getLengthI32(pointer),
|
1142
|
-
set: value => arrayUtil.setLength(pointer, value),
|
1143
|
-
setI32: value => arrayUtil.setLengthI32(pointer, value)
|
1144
|
-
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, (length, itemType) => {
|
1145
|
-
return makeArray(scope, {
|
1146
|
-
rawElements: new Array(length)
|
1147
|
-
}, _global, _name, true, itemType);
|
1148
|
-
}),
|
1303
|
+
...protoOut,
|
1149
1304
|
[ Opcodes.end ]
|
1150
1305
|
];
|
1151
1306
|
}
|
@@ -1205,7 +1360,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1205
1360
|
if (func && func.throws) scope.throws = true;
|
1206
1361
|
|
1207
1362
|
for (const arg of args) {
|
1208
|
-
out.
|
1363
|
+
out = out.concat(generate(scope, arg));
|
1209
1364
|
}
|
1210
1365
|
|
1211
1366
|
out.push([ Opcodes.call, idx ]);
|
@@ -1216,7 +1371,7 @@ const generateCall = (scope, decl, _global, _name) => {
|
|
1216
1371
|
const generateNew = (scope, decl, _global, _name) => {
|
1217
1372
|
// hack: basically treat this as a normal call for builtins for now
|
1218
1373
|
const name = mapName(decl.callee.name);
|
1219
|
-
if (internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1374
|
+
if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1220
1375
|
if (!builtinFuncs[name]) return todo(`new statement is not supported yet`); // return todo(`new statement is not supported yet (new ${unhackName(name)})`);
|
1221
1376
|
|
1222
1377
|
return generateCall(scope, decl, _global, _name);
|
@@ -1234,12 +1389,12 @@ const unhackName = name => {
|
|
1234
1389
|
};
|
1235
1390
|
|
1236
1391
|
const generateVar = (scope, decl) => {
|
1237
|
-
|
1392
|
+
let out = [];
|
1238
1393
|
|
1239
1394
|
const topLevel = scope.name === 'main';
|
1240
1395
|
|
1241
1396
|
// global variable if in top scope (main) and var ..., or if wanted
|
1242
|
-
const global = decl.kind === 'var';
|
1397
|
+
const global = topLevel || decl._bare; // decl.kind === 'var';
|
1243
1398
|
const target = global ? globals : scope.locals;
|
1244
1399
|
|
1245
1400
|
for (const x of decl.declarations) {
|
@@ -1276,7 +1431,7 @@ const generateVar = (scope, decl) => {
|
|
1276
1431
|
|
1277
1432
|
// x.init ??= DEFAULT_VALUE;
|
1278
1433
|
if (x.init) {
|
1279
|
-
out.
|
1434
|
+
out = out.concat(generate(scope, x.init, global, name));
|
1280
1435
|
|
1281
1436
|
// if our value is the result of a function, infer the type from that func's return value
|
1282
1437
|
if (out[out.length - 1][0] === Opcodes.call) {
|
@@ -1345,13 +1500,60 @@ const generateAssign = (scope, decl) => {
|
|
1345
1500
|
];
|
1346
1501
|
}
|
1347
1502
|
|
1503
|
+
const op = decl.operator.slice(0, -1) || '=';
|
1504
|
+
|
1505
|
+
// arr[i] | str[i]
|
1506
|
+
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
1507
|
+
const name = decl.left.object.name;
|
1508
|
+
const pointer = arrays.get(name);
|
1509
|
+
|
1510
|
+
const aotPointer = pointer != null;
|
1511
|
+
|
1512
|
+
const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
|
1513
|
+
const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
1514
|
+
|
1515
|
+
const parentType = getNodeType(scope, decl.left.object);
|
1516
|
+
|
1517
|
+
return [
|
1518
|
+
...(aotPointer ? [] : [
|
1519
|
+
...generate(scope, decl.left.object),
|
1520
|
+
Opcodes.i32_to_u
|
1521
|
+
]),
|
1522
|
+
|
1523
|
+
// get index as valtype
|
1524
|
+
...generate(scope, decl.left.property),
|
1525
|
+
|
1526
|
+
// convert to i32 and turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
1527
|
+
Opcodes.i32_to_u,
|
1528
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
1529
|
+
[ Opcodes.i32_mul ],
|
1530
|
+
...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
1531
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
1532
|
+
|
1533
|
+
...(op === '=' ? generate(scope, decl.right, false, name) : performOp(scope, op, [
|
1534
|
+
[ Opcodes.local_get, pointerTmp ],
|
1535
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1536
|
+
], generate(scope, decl.right), parentType === TYPES._array ? TYPES.number : TYPES.string, getNodeType(scope, decl.right), false, name, true)),
|
1537
|
+
[ Opcodes.local_tee, newValueTmp ],
|
1538
|
+
|
1539
|
+
...(parentType === TYPES._array ? [
|
1540
|
+
[ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1541
|
+
] : [
|
1542
|
+
Opcodes.i32_to_u,
|
1543
|
+
[ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
1544
|
+
]),
|
1545
|
+
|
1546
|
+
[ Opcodes.local_get, newValueTmp ]
|
1547
|
+
];
|
1548
|
+
}
|
1549
|
+
|
1348
1550
|
const [ local, isGlobal ] = lookupName(scope, name);
|
1349
1551
|
|
1350
1552
|
if (local === undefined) {
|
1351
|
-
// todo: this should be a
|
1553
|
+
// todo: this should be a sloppy mode only thing
|
1352
1554
|
|
1353
1555
|
// only allow = for this
|
1354
|
-
if (
|
1556
|
+
if (op !== '=') return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`);
|
1355
1557
|
|
1356
1558
|
if (builtinVars[name]) {
|
1357
1559
|
// just return rhs (eg `NaN = 2`)
|
@@ -1360,13 +1562,15 @@ const generateAssign = (scope, decl) => {
|
|
1360
1562
|
|
1361
1563
|
// set global and return (eg a = 2)
|
1362
1564
|
return [
|
1363
|
-
...generateVar(scope, { kind: 'var', declarations: [ { id: { name }, init: decl.right } ] }),
|
1565
|
+
...generateVar(scope, { kind: 'var', _bare: true, declarations: [ { id: { name }, init: decl.right } ] }),
|
1364
1566
|
[ Opcodes.global_get, globals[name].idx ]
|
1365
1567
|
];
|
1366
1568
|
}
|
1367
1569
|
|
1368
|
-
|
1369
|
-
|
1570
|
+
typeStates[name] = getNodeType(scope, decl.right);
|
1571
|
+
|
1572
|
+
if (op === '=') {
|
1573
|
+
// typeStates[name] = getNodeType(scope, decl.right);
|
1370
1574
|
|
1371
1575
|
return [
|
1372
1576
|
...generate(scope, decl.right, isGlobal, name),
|
@@ -1375,7 +1579,6 @@ const generateAssign = (scope, decl) => {
|
|
1375
1579
|
];
|
1376
1580
|
}
|
1377
1581
|
|
1378
|
-
const op = decl.operator.slice(0, -1);
|
1379
1582
|
if (op === '||' || op === '&&' || op === '??') {
|
1380
1583
|
// todo: is this needed?
|
1381
1584
|
// for logical assignment ops, it is not left @= right ~= left = left @ right
|
@@ -1510,7 +1713,7 @@ const generateUpdate = (scope, decl) => {
|
|
1510
1713
|
};
|
1511
1714
|
|
1512
1715
|
const generateIf = (scope, decl) => {
|
1513
|
-
const out = truthy(scope, generate(scope, decl.test), decl.test);
|
1716
|
+
const out = truthy(scope, generate(scope, decl.test), getNodeType(scope, decl.test));
|
1514
1717
|
|
1515
1718
|
out.push(Opcodes.i32_to, [ Opcodes.if, Blocktype.void ]);
|
1516
1719
|
depth.push('if');
|
@@ -1603,18 +1806,106 @@ const generateWhile = (scope, decl) => {
|
|
1603
1806
|
const generateForOf = (scope, decl) => {
|
1604
1807
|
const out = [];
|
1605
1808
|
|
1809
|
+
const rightType = getNodeType(scope, decl.right);
|
1810
|
+
const valtypeSize = rightType === TYPES._array ? ValtypeSize[valtype] : ValtypeSize.i16; // presume array (:()
|
1811
|
+
|
1812
|
+
// todo: for of inside for of might fuck up?
|
1813
|
+
const pointer = localTmp(scope, 'forof_base_pointer', Valtype.i32);
|
1814
|
+
const length = localTmp(scope, 'forof_length', Valtype.i32);
|
1815
|
+
const counter = localTmp(scope, 'forof_counter', Valtype.i32);
|
1816
|
+
|
1817
|
+
out.push(
|
1818
|
+
// set pointer as right
|
1819
|
+
...generate(scope, decl.right),
|
1820
|
+
Opcodes.i32_to_u,
|
1821
|
+
[ Opcodes.local_set, pointer ],
|
1822
|
+
|
1823
|
+
// get length
|
1824
|
+
[ Opcodes.local_get, pointer ],
|
1825
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
1826
|
+
[ Opcodes.local_set, length ]
|
1827
|
+
);
|
1828
|
+
|
1606
1829
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
1607
|
-
depth.push('
|
1830
|
+
depth.push('forof');
|
1608
1831
|
|
1609
|
-
|
1610
|
-
|
1611
|
-
depth.push('if');
|
1832
|
+
// setup local for left
|
1833
|
+
generate(scope, decl.left);
|
1612
1834
|
|
1613
|
-
|
1835
|
+
const leftName = decl.left.declarations[0].id.name;
|
1614
1836
|
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1837
|
+
// set type for local
|
1838
|
+
typeStates[leftName] = rightType === TYPES._array ? TYPES.number : TYPES.string;
|
1839
|
+
|
1840
|
+
const [ local, isGlobal ] = lookupName(scope, leftName);
|
1841
|
+
|
1842
|
+
if (rightType === TYPES._array) { // array
|
1843
|
+
out.push(
|
1844
|
+
[ Opcodes.local_get, pointer ],
|
1845
|
+
[ Opcodes.load, Math.log2(valtypeSize) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
|
1846
|
+
);
|
1847
|
+
} else { // string
|
1848
|
+
const [ newOut, newPointer ] = makeArray(scope, {
|
1849
|
+
rawElements: new Array(1)
|
1850
|
+
}, isGlobal, leftName, true, 'i16');
|
1851
|
+
|
1852
|
+
out.push(
|
1853
|
+
// setup new/out array
|
1854
|
+
...newOut,
|
1855
|
+
[ Opcodes.drop ],
|
1856
|
+
|
1857
|
+
...number(0, Valtype.i32), // base 0 for store after
|
1858
|
+
|
1859
|
+
// load current string ind {arg}
|
1860
|
+
[ Opcodes.local_get, pointer ],
|
1861
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
1862
|
+
|
1863
|
+
// store to new string ind 0
|
1864
|
+
[ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
1865
|
+
|
1866
|
+
// return new string (page)
|
1867
|
+
...number(newPointer)
|
1868
|
+
);
|
1869
|
+
}
|
1870
|
+
|
1871
|
+
// set left value
|
1872
|
+
out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ]);
|
1873
|
+
|
1874
|
+
out.push(
|
1875
|
+
[ Opcodes.block, Blocktype.void ],
|
1876
|
+
[ Opcodes.block, Blocktype.void ]
|
1877
|
+
);
|
1878
|
+
depth.push('block');
|
1879
|
+
depth.push('block');
|
1880
|
+
|
1881
|
+
out.push(
|
1882
|
+
...generate(scope, decl.body),
|
1883
|
+
[ Opcodes.end ]
|
1884
|
+
);
|
1885
|
+
depth.pop();
|
1886
|
+
|
1887
|
+
out.push(
|
1888
|
+
// increment iter pointer by valtype size
|
1889
|
+
[ Opcodes.local_get, pointer ],
|
1890
|
+
...number(valtypeSize, Valtype.i32),
|
1891
|
+
[ Opcodes.i32_add ],
|
1892
|
+
[ Opcodes.local_set, pointer ],
|
1893
|
+
|
1894
|
+
// increment counter by 1
|
1895
|
+
[ Opcodes.local_get, counter ],
|
1896
|
+
...number(1, Valtype.i32),
|
1897
|
+
[ Opcodes.i32_add ],
|
1898
|
+
[ Opcodes.local_tee, counter ],
|
1899
|
+
|
1900
|
+
// loop if counter != length
|
1901
|
+
[ Opcodes.local_get, length ],
|
1902
|
+
[ Opcodes.i32_ne ],
|
1903
|
+
[ Opcodes.br_if, 1 ],
|
1904
|
+
|
1905
|
+
[ Opcodes.end ], [ Opcodes.end ]
|
1906
|
+
);
|
1907
|
+
depth.pop();
|
1908
|
+
depth.pop();
|
1618
1909
|
|
1619
1910
|
return out;
|
1620
1911
|
};
|
@@ -1705,19 +1996,19 @@ const generateAssignPat = (scope, decl) => {
|
|
1705
1996
|
};
|
1706
1997
|
|
1707
1998
|
let pages = new Map();
|
1708
|
-
const allocPage = reason => {
|
1709
|
-
if (pages.has(reason)) return pages.get(reason);
|
1999
|
+
const allocPage = (reason, type) => {
|
2000
|
+
if (pages.has(reason)) return pages.get(reason).ind;
|
1710
2001
|
|
1711
|
-
|
1712
|
-
pages.set(reason, ind);
|
2002
|
+
const ind = pages.size;
|
2003
|
+
pages.set(reason, { ind, type });
|
1713
2004
|
|
1714
|
-
if (allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason}`);
|
2005
|
+
if (allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
|
1715
2006
|
|
1716
2007
|
return ind;
|
1717
2008
|
};
|
1718
2009
|
|
1719
2010
|
const freePage = reason => {
|
1720
|
-
|
2011
|
+
const { ind } = pages.get(reason);
|
1721
2012
|
pages.delete(reason);
|
1722
2013
|
|
1723
2014
|
if (allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
@@ -1734,7 +2025,7 @@ const itemTypeToValtype = {
|
|
1734
2025
|
i16: 'i32'
|
1735
2026
|
};
|
1736
2027
|
|
1737
|
-
const
|
2028
|
+
const StoreOps = {
|
1738
2029
|
i32: Opcodes.i32_store,
|
1739
2030
|
i64: Opcodes.i64_store,
|
1740
2031
|
f64: Opcodes.f64_store,
|
@@ -1743,13 +2034,31 @@ const storeOps = {
|
|
1743
2034
|
i16: Opcodes.i32_store16
|
1744
2035
|
};
|
1745
2036
|
|
2037
|
+
let data = [];
|
2038
|
+
|
2039
|
+
const compileBytes = (val, itemType, signed = true) => {
|
2040
|
+
switch (itemType) {
|
2041
|
+
case 'i8': return [ val % 256 ];
|
2042
|
+
case 'i16': return [ val % 256, Math.floor(val / 256) ];
|
2043
|
+
|
2044
|
+
case 'i32':
|
2045
|
+
case 'i64':
|
2046
|
+
return enforceFourBytes(signedLEB128(val));
|
2047
|
+
|
2048
|
+
case 'f64': return ieee754_binary64(val);
|
2049
|
+
}
|
2050
|
+
};
|
2051
|
+
|
1746
2052
|
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype) => {
|
1747
2053
|
const out = [];
|
1748
2054
|
|
2055
|
+
let firstAssign = false;
|
1749
2056
|
if (!arrays.has(name) || name === '$undeclared') {
|
2057
|
+
firstAssign = true;
|
2058
|
+
|
1750
2059
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
1751
2060
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
1752
|
-
arrays.set(name, allocPage(`${itemType === 'i16' ? 'string' : 'array'}: ${uniqueName}
|
2061
|
+
arrays.set(name, allocPage(`${itemType === 'i16' ? 'string' : 'array'}: ${uniqueName}`, itemType) * pageSize);
|
1753
2062
|
}
|
1754
2063
|
|
1755
2064
|
const pointer = arrays.get(name);
|
@@ -1757,8 +2066,29 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
1757
2066
|
const useRawElements = !!decl.rawElements;
|
1758
2067
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
1759
2068
|
|
2069
|
+
const valtype = itemTypeToValtype[itemType];
|
1760
2070
|
const length = elements.length;
|
1761
2071
|
|
2072
|
+
if (firstAssign && useRawElements) {
|
2073
|
+
let bytes = compileBytes(length, 'i32');
|
2074
|
+
|
2075
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
2076
|
+
if (elements[i] == null) continue;
|
2077
|
+
|
2078
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
2079
|
+
}
|
2080
|
+
|
2081
|
+
data.push({
|
2082
|
+
offset: pointer,
|
2083
|
+
bytes
|
2084
|
+
});
|
2085
|
+
|
2086
|
+
// local value as pointer
|
2087
|
+
out.push(...number(pointer));
|
2088
|
+
|
2089
|
+
return [ out, pointer ];
|
2090
|
+
}
|
2091
|
+
|
1762
2092
|
// store length as 0th array
|
1763
2093
|
out.push(
|
1764
2094
|
...number(0, Valtype.i32),
|
@@ -1766,8 +2096,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
1766
2096
|
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
|
1767
2097
|
);
|
1768
2098
|
|
1769
|
-
const storeOp =
|
1770
|
-
const valtype = itemTypeToValtype[itemType];
|
2099
|
+
const storeOp = StoreOps[itemType];
|
1771
2100
|
|
1772
2101
|
if (!initEmpty) for (let i = 0; i < length; i++) {
|
1773
2102
|
if (elements[i] == null) continue;
|
@@ -1790,6 +2119,17 @@ const generateArray = (scope, decl, global = false, name = '$undeclared', initEm
|
|
1790
2119
|
return makeArray(scope, decl, global, name, initEmpty, valtype)[0];
|
1791
2120
|
};
|
1792
2121
|
|
2122
|
+
let varMetadata = new Map();
|
2123
|
+
const addVarMeta = (_name, obj) => {
|
2124
|
+
const name = _name ?? '$undeclared';
|
2125
|
+
if (!varMetadata.has(name)) varMetadata.set(name, {});
|
2126
|
+
|
2127
|
+
const meta = varMetadata.get(name);
|
2128
|
+
for (const k in obj) {
|
2129
|
+
meta[k] = obj[k];
|
2130
|
+
}
|
2131
|
+
};
|
2132
|
+
|
1793
2133
|
export const generateMember = (scope, decl, _global, _name) => {
|
1794
2134
|
const type = getNodeType(scope, decl.object);
|
1795
2135
|
|
@@ -1929,7 +2269,6 @@ const generateFunc = (scope, decl) => {
|
|
1929
2269
|
localInd: 0,
|
1930
2270
|
returns: [ valtypeBinary ],
|
1931
2271
|
returnType: null,
|
1932
|
-
memory: false,
|
1933
2272
|
throws: false,
|
1934
2273
|
name
|
1935
2274
|
};
|
@@ -2092,10 +2431,10 @@ const generateFunc = (scope, decl) => {
|
|
2092
2431
|
};
|
2093
2432
|
|
2094
2433
|
const generateCode = (scope, decl) => {
|
2095
|
-
|
2434
|
+
let out = [];
|
2096
2435
|
|
2097
2436
|
for (const x of decl.body) {
|
2098
|
-
out.
|
2437
|
+
out = out.concat(generate(scope, x));
|
2099
2438
|
}
|
2100
2439
|
|
2101
2440
|
return out;
|
@@ -2131,6 +2470,18 @@ const internalConstrs = {
|
|
2131
2470
|
];
|
2132
2471
|
},
|
2133
2472
|
type: TYPES._array
|
2473
|
+
},
|
2474
|
+
|
2475
|
+
__Array_of: {
|
2476
|
+
// this is not a constructor but best fits internal structure here
|
2477
|
+
generate: (scope, decl, global, name) => {
|
2478
|
+
// Array.of(i0, i1, ...)
|
2479
|
+
return generateArray(scope, {
|
2480
|
+
elements: decl.arguments
|
2481
|
+
}, global, name);
|
2482
|
+
},
|
2483
|
+
type: TYPES._array,
|
2484
|
+
notConstr: true
|
2134
2485
|
}
|
2135
2486
|
};
|
2136
2487
|
|
@@ -2144,7 +2495,9 @@ export default program => {
|
|
2144
2495
|
depth = [];
|
2145
2496
|
typeStates = {};
|
2146
2497
|
arrays = new Map();
|
2498
|
+
varMetadata = new Map();
|
2147
2499
|
pages = new Map();
|
2500
|
+
data = [];
|
2148
2501
|
currentFuncIndex = importedFuncs.length;
|
2149
2502
|
|
2150
2503
|
globalThis.valtype = 'f64';
|
@@ -2221,5 +2574,5 @@ export default program => {
|
|
2221
2574
|
// if blank main func and other exports, remove it
|
2222
2575
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(funcs.length - 1, 1);
|
2223
2576
|
|
2224
|
-
return { funcs, globals, tags, exceptions, pages };
|
2577
|
+
return { funcs, globals, tags, exceptions, pages, data };
|
2225
2578
|
};
|