porffor 0.2.0-4035760 → 0.2.0-4b72c49
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 +62 -42
- package/compiler/2c.js +316 -71
- package/compiler/builtins/base64.ts +153 -0
- package/compiler/builtins/porffor.d.ts +23 -0
- package/compiler/builtins.js +85 -198
- package/compiler/codeGen.js +251 -131
- package/compiler/generated_builtins.js +15 -0
- package/compiler/index.js +22 -22
- package/compiler/opt.js +39 -26
- package/compiler/parse.js +4 -2
- package/compiler/precompile.js +129 -0
- package/compiler/prefs.js +26 -0
- package/compiler/prototype.js +11 -10
- package/compiler/sections.js +7 -6
- package/compiler/wasmSpec.js +10 -2
- package/compiler/wrap.js +2 -1
- package/demo.js +15 -0
- package/package.json +1 -1
- package/porf +2 -0
- package/rhemyn/compile.js +2 -1
- package/runner/index.js +20 -3
- package/compiler/builtins/base64.js +0 -92
- package/r.js +0 -45
package/compiler/codeGen.js
CHANGED
@@ -7,6 +7,7 @@ import { number, i32x4, enforceOneByte, enforceTwoBytes, enforceFourBytes, enfor
|
|
7
7
|
import { log } from "./log.js";
|
8
8
|
import parse from "./parse.js";
|
9
9
|
import * as Rhemyn from "../rhemyn/compile.js";
|
10
|
+
import Prefs from './prefs.js';
|
10
11
|
|
11
12
|
let globals = {};
|
12
13
|
let globalInd = 0;
|
@@ -160,7 +161,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
160
161
|
|
161
162
|
case 'TaggedTemplateExpression': {
|
162
163
|
const funcs = {
|
163
|
-
|
164
|
+
__Porffor_wasm: str => {
|
164
165
|
let out = [];
|
165
166
|
|
166
167
|
for (const line of str.split('\n')) {
|
@@ -168,8 +169,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
168
169
|
if (asm[0] === '') continue; // blank
|
169
170
|
|
170
171
|
if (asm[0] === 'local') {
|
171
|
-
const [ name,
|
172
|
-
scope.locals[name] = { idx:
|
172
|
+
const [ name, type ] = asm.slice(1);
|
173
|
+
scope.locals[name] = { idx: scope.localInd++, type: Valtype[type] };
|
173
174
|
continue;
|
174
175
|
}
|
175
176
|
|
@@ -179,7 +180,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
179
180
|
}
|
180
181
|
|
181
182
|
if (asm[0] === 'memory') {
|
182
|
-
allocPage('asm instrinsic');
|
183
|
+
allocPage(scope, 'asm instrinsic');
|
183
184
|
// todo: add to store/load offset insts
|
184
185
|
continue;
|
185
186
|
}
|
@@ -188,7 +189,11 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
188
189
|
if (!inst) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
189
190
|
|
190
191
|
if (!Array.isArray(inst)) inst = [ inst ];
|
191
|
-
const immediates = asm.slice(1).map(x =>
|
192
|
+
const immediates = asm.slice(1).map(x => {
|
193
|
+
const int = parseInt(x);
|
194
|
+
if (Number.isNaN(int)) return scope.locals[x]?.idx;
|
195
|
+
return int;
|
196
|
+
});
|
192
197
|
|
193
198
|
out.push([ ...inst, ...immediates ]);
|
194
199
|
}
|
@@ -196,31 +201,40 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
196
201
|
return out;
|
197
202
|
},
|
198
203
|
|
199
|
-
|
200
|
-
|
204
|
+
__Porffor_bs: str => [
|
205
|
+
...makeString(scope, str, undefined, undefined, true),
|
201
206
|
|
202
|
-
|
203
|
-
|
204
|
-
|
207
|
+
...number(TYPES._bytestring, Valtype.i32),
|
208
|
+
setLastType(scope)
|
209
|
+
],
|
210
|
+
__Porffor_s: str => [
|
211
|
+
...makeString(scope, str, undefined, undefined, false),
|
205
212
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
}
|
211
|
-
}
|
213
|
+
...number(TYPES.string, Valtype.i32),
|
214
|
+
setLastType(scope)
|
215
|
+
],
|
216
|
+
};
|
212
217
|
|
213
218
|
const name = decl.tag.name;
|
214
219
|
// hack for inline asm
|
215
220
|
if (!funcs[name]) return todo('tagged template expressions not implemented');
|
216
221
|
|
217
|
-
const
|
222
|
+
const { quasis, expressions } = decl.quasi;
|
223
|
+
let str = quasis[0].value.raw;
|
224
|
+
|
225
|
+
for (let i = 0; i < expressions.length; i++) {
|
226
|
+
const e = expressions[i];
|
227
|
+
str += lookupName(scope, e.name)[0].idx;
|
228
|
+
str += quasis[i + 1].value.raw;
|
229
|
+
}
|
230
|
+
|
218
231
|
return funcs[name](str);
|
219
232
|
}
|
220
233
|
|
221
234
|
default:
|
222
|
-
|
223
|
-
|
235
|
+
// ignore typescript nodes
|
236
|
+
if (decl.type.startsWith('TS') ||
|
237
|
+
decl.type === 'ImportDeclaration' && decl.importKind === 'type') {
|
224
238
|
return [];
|
225
239
|
}
|
226
240
|
|
@@ -274,25 +288,25 @@ const generateIdent = (scope, decl) => {
|
|
274
288
|
const name = mapName(rawName);
|
275
289
|
let local = scope.locals[rawName];
|
276
290
|
|
277
|
-
if (builtinVars
|
291
|
+
if (Object.hasOwn(builtinVars, name)) {
|
278
292
|
if (builtinVars[name].floatOnly && valtype[0] === 'i') throw new Error(`Cannot use ${unhackName(name)} with integer valtype`);
|
279
293
|
return builtinVars[name];
|
280
294
|
}
|
281
295
|
|
282
|
-
if (builtinFuncs
|
296
|
+
if (Object.hasOwn(builtinFuncs, name) || Object.hasOwn(internalConstrs, name)) {
|
283
297
|
// todo: return an actual something
|
284
298
|
return number(1);
|
285
299
|
}
|
286
300
|
|
287
|
-
if (local === undefined) {
|
301
|
+
if (local?.idx === undefined) {
|
288
302
|
// no local var with name
|
289
|
-
if (
|
290
|
-
if (funcIndex
|
303
|
+
if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name]);
|
304
|
+
if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name]);
|
291
305
|
|
292
|
-
if (globals
|
306
|
+
if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
|
293
307
|
}
|
294
308
|
|
295
|
-
if (local === undefined && rawName.startsWith('__')) {
|
309
|
+
if (local?.idx === undefined && rawName.startsWith('__')) {
|
296
310
|
// return undefined if unknown key in already known var
|
297
311
|
let parent = rawName.slice(2).split('_').slice(0, -1).join('_');
|
298
312
|
if (parent.includes('_')) parent = '__' + parent;
|
@@ -301,7 +315,7 @@ const generateIdent = (scope, decl) => {
|
|
301
315
|
if (!parentLookup[1]) return number(UNDEFINED);
|
302
316
|
}
|
303
317
|
|
304
|
-
if (local === undefined) return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
318
|
+
if (local?.idx === undefined) return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
305
319
|
|
306
320
|
return [ [ Opcodes.local_get, local.idx ] ];
|
307
321
|
};
|
@@ -409,9 +423,6 @@ const concatStrings = (scope, left, right, global, name, assign) => {
|
|
409
423
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
410
424
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
411
425
|
|
412
|
-
const aotWFA = process.argv.includes('-aot-well-formed-string-approximation');
|
413
|
-
if (aotWFA) addVarMeta(name, { wellFormed: undefined });
|
414
|
-
|
415
426
|
if (assign) {
|
416
427
|
const pointer = arrays.get(name ?? '$undeclared');
|
417
428
|
|
@@ -649,11 +660,12 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
649
660
|
...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
650
661
|
];
|
651
662
|
|
652
|
-
const
|
663
|
+
const useTmp = knownType(scope, type) == null;
|
664
|
+
const tmp = useTmp && localTmp(scope, `$logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
|
653
665
|
|
654
666
|
const def = [
|
655
667
|
// if value != 0
|
656
|
-
[ Opcodes.local_get, tmp ],
|
668
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
657
669
|
|
658
670
|
// ...(intIn ? [ [ Opcodes.i32_eqz ] ] : [ ...Opcodes.eqz ]),
|
659
671
|
...(!intOut || (intIn && intOut) ? [] : [ Opcodes.i32_to_u ]),
|
@@ -665,7 +677,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
665
677
|
|
666
678
|
return [
|
667
679
|
...wasm,
|
668
|
-
[ Opcodes.local_set, tmp ],
|
680
|
+
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
669
681
|
|
670
682
|
...typeSwitch(scope, type, {
|
671
683
|
// [TYPES.number]: def,
|
@@ -674,7 +686,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
674
686
|
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
675
687
|
],
|
676
688
|
[TYPES.string]: [
|
677
|
-
[ Opcodes.local_get, tmp ],
|
689
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
678
690
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
679
691
|
|
680
692
|
// get length
|
@@ -686,7 +698,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
686
698
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
687
699
|
],
|
688
700
|
[TYPES._bytestring]: [ // duplicate of string
|
689
|
-
|
701
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
690
702
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
691
703
|
|
692
704
|
// get length
|
@@ -700,10 +712,12 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
700
712
|
};
|
701
713
|
|
702
714
|
const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
703
|
-
const
|
715
|
+
const useTmp = knownType(scope, type) == null;
|
716
|
+
const tmp = useTmp && localTmp(scope, `$logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
|
717
|
+
|
704
718
|
return [
|
705
719
|
...wasm,
|
706
|
-
[ Opcodes.local_set, tmp ],
|
720
|
+
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
707
721
|
|
708
722
|
...typeSwitch(scope, type, {
|
709
723
|
[TYPES._array]: [
|
@@ -711,7 +725,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
711
725
|
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
712
726
|
],
|
713
727
|
[TYPES.string]: [
|
714
|
-
[ Opcodes.local_get, tmp ],
|
728
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
715
729
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
716
730
|
|
717
731
|
// get length
|
@@ -722,7 +736,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
722
736
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
723
737
|
],
|
724
738
|
[TYPES._bytestring]: [ // duplicate of string
|
725
|
-
[ Opcodes.local_get, tmp ],
|
739
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
726
740
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
727
741
|
|
728
742
|
// get length
|
@@ -734,7 +748,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
734
748
|
],
|
735
749
|
default: [
|
736
750
|
// if value == 0
|
737
|
-
[ Opcodes.local_get, tmp ],
|
751
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
738
752
|
|
739
753
|
...(intIn ? [ [ Opcodes.i32_eqz ] ] : [ ...Opcodes.eqz ]),
|
740
754
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
@@ -744,10 +758,12 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
744
758
|
};
|
745
759
|
|
746
760
|
const nullish = (scope, wasm, type, intIn = false, intOut = false) => {
|
747
|
-
const
|
761
|
+
const useTmp = knownType(scope, type) == null;
|
762
|
+
const tmp = useTmp && localTmp(scope, `$logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
|
763
|
+
|
748
764
|
return [
|
749
765
|
...wasm,
|
750
|
-
[ Opcodes.local_set, tmp ],
|
766
|
+
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
751
767
|
|
752
768
|
...typeSwitch(scope, type, {
|
753
769
|
[TYPES.undefined]: [
|
@@ -756,7 +772,7 @@ const nullish = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
756
772
|
],
|
757
773
|
[TYPES.object]: [
|
758
774
|
// object, null if == 0
|
759
|
-
[ Opcodes.local_get, tmp ],
|
775
|
+
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
760
776
|
|
761
777
|
...(intIn ? [ [ Opcodes.i32_eqz ] ] : [ ...Opcodes.eqz ]),
|
762
778
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
@@ -785,11 +801,14 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
785
801
|
return performLogicOp(scope, op, left, right, leftType, rightType);
|
786
802
|
}
|
787
803
|
|
804
|
+
const knownLeft = knownType(scope, leftType);
|
805
|
+
const knownRight = knownType(scope, rightType);
|
806
|
+
|
788
807
|
const eqOp = ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(op);
|
789
808
|
const strictOp = op === '===' || op === '!==';
|
790
809
|
|
791
810
|
const startOut = [], endOut = [];
|
792
|
-
const
|
811
|
+
const finalize = out => startOut.concat(out, endOut);
|
793
812
|
|
794
813
|
// if strict (in)equal check types match
|
795
814
|
if (strictOp) {
|
@@ -834,31 +853,32 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
834
853
|
// todo: if equality op and an operand is undefined, return false
|
835
854
|
// todo: niche null hell with 0
|
836
855
|
|
837
|
-
//
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
856
|
+
// todo: this should be dynamic but for now only static
|
857
|
+
if (knownLeft === TYPES.string || knownRight === TYPES.string) {
|
858
|
+
if (op === '+') {
|
859
|
+
// string concat (a + b)
|
860
|
+
return concatStrings(scope, left, right, _global, _name, assign);
|
861
|
+
}
|
862
|
+
|
863
|
+
// not an equality op, NaN
|
864
|
+
if (!eqOp) return number(NaN);
|
865
|
+
|
866
|
+
// else leave bool ops
|
867
|
+
// todo: convert string to number if string and number/bool
|
868
|
+
// todo: string (>|>=|<|<=) string
|
869
|
+
|
870
|
+
// string comparison
|
871
|
+
if (op === '===' || op === '==') {
|
872
|
+
return compareStrings(scope, left, right);
|
873
|
+
}
|
874
|
+
|
875
|
+
if (op === '!==' || op === '!=') {
|
876
|
+
return [
|
877
|
+
...compareStrings(scope, left, right),
|
878
|
+
[ Opcodes.i32_eqz ]
|
879
|
+
];
|
880
|
+
}
|
881
|
+
}
|
862
882
|
|
863
883
|
let ops = operatorOpcode[valtype][op];
|
864
884
|
|
@@ -868,7 +888,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
868
888
|
includeBuiltin(scope, builtinName);
|
869
889
|
const idx = funcIndex[builtinName];
|
870
890
|
|
871
|
-
return
|
891
|
+
return finalize([
|
872
892
|
...left,
|
873
893
|
...right,
|
874
894
|
[ Opcodes.call, idx ]
|
@@ -883,9 +903,6 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
883
903
|
let tmpLeft, tmpRight;
|
884
904
|
// if equal op, check if strings for compareStrings
|
885
905
|
if (op === '===' || op === '==' || op === '!==' || op === '!=') (() => {
|
886
|
-
const knownLeft = knownType(scope, leftType);
|
887
|
-
const knownRight = knownType(scope, rightType);
|
888
|
-
|
889
906
|
// todo: intelligent partial skip later
|
890
907
|
// if neither known are string, stop this madness
|
891
908
|
if ((knownLeft != null && knownLeft !== TYPES.string) && (knownRight != null && knownRight !== TYPES.string)) {
|
@@ -925,7 +942,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
925
942
|
[ Opcodes.i32_or ],
|
926
943
|
[ Opcodes.if, Blocktype.void ],
|
927
944
|
...number(0, Valtype.i32),
|
928
|
-
[ Opcodes.br,
|
945
|
+
[ Opcodes.br, 2 ],
|
929
946
|
[ Opcodes.end ],
|
930
947
|
|
931
948
|
...compareStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ]),
|
@@ -943,7 +960,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
943
960
|
// }
|
944
961
|
})();
|
945
962
|
|
946
|
-
return
|
963
|
+
return finalize([
|
947
964
|
...left,
|
948
965
|
...(tmpLeft != null ? stringOnly([ [ Opcodes.local_tee, tmpLeft ] ]) : []),
|
949
966
|
...right,
|
@@ -960,7 +977,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
960
977
|
return out;
|
961
978
|
};
|
962
979
|
|
963
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [] }) => {
|
980
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [] }) => {
|
964
981
|
const existing = funcs.find(x => x.name === name);
|
965
982
|
if (existing) return existing;
|
966
983
|
|
@@ -972,6 +989,12 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
972
989
|
locals[nameParam(i)] = { idx: i, type: allLocals[i] };
|
973
990
|
}
|
974
991
|
|
992
|
+
for (const x of _data) {
|
993
|
+
const copy = { ...x };
|
994
|
+
copy.offset += pages.size * pageSize;
|
995
|
+
data.push(copy);
|
996
|
+
}
|
997
|
+
|
975
998
|
if (typeof wasm === 'function') {
|
976
999
|
const scope = {
|
977
1000
|
name,
|
@@ -981,7 +1004,18 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
981
1004
|
localInd: allLocals.length,
|
982
1005
|
};
|
983
1006
|
|
984
|
-
wasm = wasm(scope, {
|
1007
|
+
wasm = wasm(scope, {
|
1008
|
+
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage,
|
1009
|
+
builtin: name => {
|
1010
|
+
let idx = funcIndex[name] ?? importedFuncs[name];
|
1011
|
+
if (idx === undefined && builtinFuncs[name]) {
|
1012
|
+
includeBuiltin(scope, name);
|
1013
|
+
idx = funcIndex[name];
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
return idx;
|
1017
|
+
}
|
1018
|
+
});
|
985
1019
|
}
|
986
1020
|
|
987
1021
|
let baseGlobalIdx, i = 0;
|
@@ -1086,7 +1120,10 @@ const TYPE_NAMES = {
|
|
1086
1120
|
const getType = (scope, _name) => {
|
1087
1121
|
const name = mapName(_name);
|
1088
1122
|
|
1123
|
+
if (typedInput && scope.locals[name]?.metadata?.type != null) return number(scope.locals[name].metadata.type, Valtype.i32);
|
1089
1124
|
if (scope.locals[name]) return [ [ Opcodes.local_get, scope.locals[name + '#type'].idx ] ];
|
1125
|
+
|
1126
|
+
if (typedInput && globals[name]?.metadata?.type != null) return number(globals[name].metadata.type, Valtype.i32);
|
1090
1127
|
if (globals[name]) return [ [ Opcodes.global_get, globals[name + '#type'].idx ] ];
|
1091
1128
|
|
1092
1129
|
let type = TYPES.undefined;
|
@@ -1164,7 +1201,7 @@ const getNodeType = (scope, node) => {
|
|
1164
1201
|
if (func.returnType) return func.returnType;
|
1165
1202
|
}
|
1166
1203
|
|
1167
|
-
if (builtinFuncs[name]) return TYPES[builtinFuncs[name].returnType ?? 'number'];
|
1204
|
+
if (builtinFuncs[name] && !builtinFuncs[name].typedReturns) return TYPES[builtinFuncs[name].returnType ?? 'number'];
|
1168
1205
|
if (internalConstrs[name]) return internalConstrs[name].type;
|
1169
1206
|
|
1170
1207
|
// check if this is a prototype function
|
@@ -1179,6 +1216,11 @@ const getNodeType = (scope, node) => {
|
|
1179
1216
|
if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
|
1180
1217
|
}
|
1181
1218
|
|
1219
|
+
if (name.startsWith('__Porffor_wasm_')) {
|
1220
|
+
// todo: return undefined for non-returning ops
|
1221
|
+
return TYPES.number;
|
1222
|
+
}
|
1223
|
+
|
1182
1224
|
if (scope.locals['#last_type']) return [ getLastType(scope) ];
|
1183
1225
|
|
1184
1226
|
// presume
|
@@ -1227,6 +1269,14 @@ const getNodeType = (scope, node) => {
|
|
1227
1269
|
|
1228
1270
|
if (node.type === 'BinaryExpression') {
|
1229
1271
|
if (['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(node.operator)) return TYPES.boolean;
|
1272
|
+
if (node.operator !== '+') return TYPES.number;
|
1273
|
+
|
1274
|
+
const knownLeft = knownType(scope, getNodeType(scope, node.left));
|
1275
|
+
const knownRight = knownType(scope, getNodeType(scope, node.right));
|
1276
|
+
|
1277
|
+
// todo: this should be dynamic but for now only static
|
1278
|
+
if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
|
1279
|
+
|
1230
1280
|
return TYPES.number;
|
1231
1281
|
|
1232
1282
|
// todo: string concat types
|
@@ -1251,7 +1301,7 @@ const getNodeType = (scope, node) => {
|
|
1251
1301
|
if (node.operator === '!') return TYPES.boolean;
|
1252
1302
|
if (node.operator === 'void') return TYPES.undefined;
|
1253
1303
|
if (node.operator === 'delete') return TYPES.boolean;
|
1254
|
-
if (node.operator === 'typeof') return
|
1304
|
+
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES._bytestring : TYPES.string;
|
1255
1305
|
|
1256
1306
|
return TYPES.number;
|
1257
1307
|
}
|
@@ -1286,8 +1336,8 @@ const getNodeType = (scope, node) => {
|
|
1286
1336
|
const generateLiteral = (scope, decl, global, name) => {
|
1287
1337
|
if (decl.value === null) return number(NULL);
|
1288
1338
|
|
1339
|
+
// hack: just return 1 for regex literals
|
1289
1340
|
if (decl.regex) {
|
1290
|
-
scope.regex[name] = decl.regex;
|
1291
1341
|
return number(1);
|
1292
1342
|
}
|
1293
1343
|
|
@@ -1473,8 +1523,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1473
1523
|
// literal.func()
|
1474
1524
|
if (!name && decl.callee.type === 'MemberExpression') {
|
1475
1525
|
// megahack for /regex/.func()
|
1476
|
-
|
1477
|
-
|
1526
|
+
const funcName = decl.callee.property.name;
|
1527
|
+
if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
|
1478
1528
|
const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
|
1479
1529
|
|
1480
1530
|
funcIndex[func.name] = func.index;
|
@@ -1645,6 +1695,32 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1645
1695
|
idx = -1;
|
1646
1696
|
}
|
1647
1697
|
|
1698
|
+
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1699
|
+
const wasmOps = {
|
1700
|
+
// pointer, align, offset
|
1701
|
+
i32_load8_u: { imms: 2, args: 1 },
|
1702
|
+
// pointer, value, align, offset
|
1703
|
+
i32_store8: { imms: 2, args: 2 },
|
1704
|
+
};
|
1705
|
+
|
1706
|
+
const opName = name.slice('__Porffor_wasm_'.length);
|
1707
|
+
|
1708
|
+
if (wasmOps[opName]) {
|
1709
|
+
const op = wasmOps[opName];
|
1710
|
+
|
1711
|
+
const argOut = [];
|
1712
|
+
for (let i = 0; i < op.args; i++) argOut.push(...generate(scope, decl.arguments[i]));
|
1713
|
+
|
1714
|
+
// literals only
|
1715
|
+
const imms = decl.arguments.slice(op.args).map(x => x.value);
|
1716
|
+
|
1717
|
+
return [
|
1718
|
+
...argOut,
|
1719
|
+
[ Opcodes[opName], ...imms ]
|
1720
|
+
];
|
1721
|
+
}
|
1722
|
+
}
|
1723
|
+
|
1648
1724
|
if (idx === undefined) {
|
1649
1725
|
if (scope.locals[name] !== undefined || globals[name] !== undefined || builtinVars[name] !== undefined) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`);
|
1650
1726
|
return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`);
|
@@ -1654,7 +1730,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1654
1730
|
|
1655
1731
|
const userFunc = (funcIndex[name] && !importedFuncs[name] && !builtinFuncs[name] && !internalConstrs[name]) || idx === -1;
|
1656
1732
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1657
|
-
const
|
1733
|
+
const typedReturns = userFunc || builtinFuncs[name]?.typedReturns;
|
1658
1734
|
const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
|
1659
1735
|
|
1660
1736
|
let args = decl.arguments;
|
@@ -1671,14 +1747,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1671
1747
|
if (func && func.throws) scope.throws = true;
|
1672
1748
|
|
1673
1749
|
let out = [];
|
1674
|
-
for (
|
1750
|
+
for (let i = 0; i < args.length; i++) {
|
1751
|
+
const arg = args[i];
|
1675
1752
|
out = out.concat(generate(scope, arg));
|
1753
|
+
|
1754
|
+
if (builtinFuncs[name] && builtinFuncs[name].params[i] === Valtype.i32 && valtypeBinary !== Valtype.i32) {
|
1755
|
+
out.push(Opcodes.i32_to);
|
1756
|
+
}
|
1757
|
+
|
1676
1758
|
if (typedParams) out = out.concat(getNodeType(scope, arg));
|
1677
1759
|
}
|
1678
1760
|
|
1679
1761
|
out.push([ Opcodes.call, idx ]);
|
1680
1762
|
|
1681
|
-
if (!
|
1763
|
+
if (!typedReturns) {
|
1682
1764
|
// let type;
|
1683
1765
|
// if (builtinFuncs[name]) type = TYPES[builtinFuncs[name].returnType ?? 'number'];
|
1684
1766
|
// if (internalConstrs[name]) type = internalConstrs[name].type;
|
@@ -1690,6 +1772,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1690
1772
|
// );
|
1691
1773
|
} else out.push(setLastType(scope));
|
1692
1774
|
|
1775
|
+
if (builtinFuncs[name] && builtinFuncs[name].returns[0] === Valtype.i32 && valtypeBinary !== Valtype.i32) {
|
1776
|
+
out.push(Opcodes.i32_from);
|
1777
|
+
}
|
1778
|
+
|
1693
1779
|
return out;
|
1694
1780
|
};
|
1695
1781
|
|
@@ -1814,14 +1900,14 @@ const brTable = (input, bc, returns) => {
|
|
1814
1900
|
};
|
1815
1901
|
|
1816
1902
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
1817
|
-
if (!
|
1903
|
+
if (!Prefs.bytestring) delete bc[TYPES._bytestring];
|
1818
1904
|
|
1819
1905
|
const known = knownType(scope, type);
|
1820
1906
|
if (known != null) {
|
1821
1907
|
return bc[known] ?? bc.default;
|
1822
1908
|
}
|
1823
1909
|
|
1824
|
-
if (
|
1910
|
+
if (Prefs.typeswitchUseBrtable)
|
1825
1911
|
return brTable(type, bc, returns);
|
1826
1912
|
|
1827
1913
|
const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
|
@@ -1856,7 +1942,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
1856
1942
|
return out;
|
1857
1943
|
};
|
1858
1944
|
|
1859
|
-
const allocVar = (scope, name, global = false) => {
|
1945
|
+
const allocVar = (scope, name, global = false, type = true) => {
|
1860
1946
|
const target = global ? globals : scope.locals;
|
1861
1947
|
|
1862
1948
|
// already declared
|
@@ -1870,8 +1956,10 @@ const allocVar = (scope, name, global = false) => {
|
|
1870
1956
|
let idx = global ? globalInd++ : scope.localInd++;
|
1871
1957
|
target[name] = { idx, type: valtypeBinary };
|
1872
1958
|
|
1873
|
-
|
1874
|
-
|
1959
|
+
if (type) {
|
1960
|
+
let typeIdx = global ? globalInd++ : scope.localInd++;
|
1961
|
+
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32 };
|
1962
|
+
}
|
1875
1963
|
|
1876
1964
|
return idx;
|
1877
1965
|
};
|
@@ -1891,6 +1979,7 @@ const typeAnnoToPorfType = x => {
|
|
1891
1979
|
|
1892
1980
|
switch (x) {
|
1893
1981
|
case 'i32':
|
1982
|
+
case 'i64':
|
1894
1983
|
return TYPES.number;
|
1895
1984
|
}
|
1896
1985
|
|
@@ -1914,7 +2003,7 @@ const extractTypeAnnotation = decl => {
|
|
1914
2003
|
const typeName = type;
|
1915
2004
|
type = typeAnnoToPorfType(type);
|
1916
2005
|
|
1917
|
-
if (type === TYPES._bytestring && !
|
2006
|
+
if (type === TYPES._bytestring && !Prefs.bytestring) type = TYPES.string;
|
1918
2007
|
|
1919
2008
|
// if (decl.name) console.log(decl.name, { type, elementType });
|
1920
2009
|
|
@@ -1932,6 +2021,8 @@ const generateVar = (scope, decl) => {
|
|
1932
2021
|
for (const x of decl.declarations) {
|
1933
2022
|
const name = mapName(x.id.name);
|
1934
2023
|
|
2024
|
+
if (!name) return todo('destructuring is not supported yet');
|
2025
|
+
|
1935
2026
|
if (x.init && isFuncType(x.init.type)) {
|
1936
2027
|
// hack for let a = function () { ... }
|
1937
2028
|
x.init.id = { name };
|
@@ -1947,7 +2038,7 @@ const generateVar = (scope, decl) => {
|
|
1947
2038
|
continue; // always ignore
|
1948
2039
|
}
|
1949
2040
|
|
1950
|
-
let idx = allocVar(scope, name, global);
|
2041
|
+
let idx = allocVar(scope, name, global, !x.id.typeAnnotation);
|
1951
2042
|
|
1952
2043
|
if (typedInput && x.id.typeAnnotation) {
|
1953
2044
|
addVarMetadata(scope, name, global, extractTypeAnnotation(x.id));
|
@@ -2070,6 +2161,8 @@ const generateAssign = (scope, decl) => {
|
|
2070
2161
|
];
|
2071
2162
|
}
|
2072
2163
|
|
2164
|
+
if (!name) return todo('destructuring is not supported yet');
|
2165
|
+
|
2073
2166
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2074
2167
|
|
2075
2168
|
if (local === undefined) {
|
@@ -2116,9 +2209,7 @@ const generateAssign = (scope, decl) => {
|
|
2116
2209
|
], getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
|
2117
2210
|
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2118
2211
|
|
2119
|
-
getLastType(scope)
|
2120
|
-
// hack: type is idx+1
|
2121
|
-
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx + 1 ],
|
2212
|
+
...setType(scope, name, getLastType(scope))
|
2122
2213
|
];
|
2123
2214
|
}
|
2124
2215
|
|
@@ -2129,9 +2220,7 @@ const generateAssign = (scope, decl) => {
|
|
2129
2220
|
|
2130
2221
|
// todo: string concat types
|
2131
2222
|
|
2132
|
-
|
2133
|
-
...number(TYPES.number, Valtype.i32),
|
2134
|
-
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx + 1 ],
|
2223
|
+
...setType(scope, name, TYPES.number)
|
2135
2224
|
];
|
2136
2225
|
};
|
2137
2226
|
|
@@ -2315,8 +2404,10 @@ const generateFor = (scope, decl) => {
|
|
2315
2404
|
out.push([ Opcodes.loop, Blocktype.void ]);
|
2316
2405
|
depth.push('for');
|
2317
2406
|
|
2318
|
-
out.push(...generate(scope, decl.test));
|
2319
|
-
|
2407
|
+
if (decl.test) out.push(...generate(scope, decl.test), Opcodes.i32_to);
|
2408
|
+
else out.push(...number(1, Valtype.i32));
|
2409
|
+
|
2410
|
+
out.push([ Opcodes.if, Blocktype.void ]);
|
2320
2411
|
depth.push('if');
|
2321
2412
|
|
2322
2413
|
out.push([ Opcodes.block, Blocktype.void ]);
|
@@ -2324,8 +2415,7 @@ const generateFor = (scope, decl) => {
|
|
2324
2415
|
out.push(...generate(scope, decl.body));
|
2325
2416
|
out.push([ Opcodes.end ]);
|
2326
2417
|
|
2327
|
-
out.push(...generate(scope, decl.update));
|
2328
|
-
depth.pop();
|
2418
|
+
if (decl.update) out.push(...generate(scope, decl.update));
|
2329
2419
|
|
2330
2420
|
out.push([ Opcodes.br, 1 ]);
|
2331
2421
|
out.push([ Opcodes.end ], [ Opcodes.end ]);
|
@@ -2382,7 +2472,13 @@ const generateForOf = (scope, decl) => {
|
|
2382
2472
|
// setup local for left
|
2383
2473
|
generate(scope, decl.left);
|
2384
2474
|
|
2385
|
-
|
2475
|
+
let leftName = decl.left.declarations?.[0]?.id?.name;
|
2476
|
+
if (!leftName && decl.left.name) {
|
2477
|
+
leftName = decl.left.name;
|
2478
|
+
|
2479
|
+
generateVar(scope, { kind: 'var', _bare: true, declarations: [ { id: { name: leftName } } ] })
|
2480
|
+
}
|
2481
|
+
|
2386
2482
|
const [ local, isGlobal ] = lookupName(scope, leftName);
|
2387
2483
|
|
2388
2484
|
depth.push('block');
|
@@ -2535,6 +2631,9 @@ const generateThrow = (scope, decl) => {
|
|
2535
2631
|
let exceptId = exceptions.push({ constructor, message }) - 1;
|
2536
2632
|
let tagIdx = tags[0].idx;
|
2537
2633
|
|
2634
|
+
scope.exceptions ??= [];
|
2635
|
+
scope.exceptions.push(exceptId);
|
2636
|
+
|
2538
2637
|
// todo: write a description of how this works lol
|
2539
2638
|
|
2540
2639
|
return [
|
@@ -2579,7 +2678,7 @@ const generateAssignPat = (scope, decl) => {
|
|
2579
2678
|
};
|
2580
2679
|
|
2581
2680
|
let pages = new Map();
|
2582
|
-
const allocPage = (reason, type) => {
|
2681
|
+
const allocPage = (scope, reason, type) => {
|
2583
2682
|
if (pages.has(reason)) return pages.get(reason).ind;
|
2584
2683
|
|
2585
2684
|
if (reason.startsWith('array:')) pages.hasArray = true;
|
@@ -2590,16 +2689,20 @@ const allocPage = (reason, type) => {
|
|
2590
2689
|
const ind = pages.size;
|
2591
2690
|
pages.set(reason, { ind, type });
|
2592
2691
|
|
2593
|
-
|
2692
|
+
scope.pages ??= new Map();
|
2693
|
+
scope.pages.set(reason, { ind, type });
|
2694
|
+
|
2695
|
+
if (Prefs.allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
|
2594
2696
|
|
2595
2697
|
return ind;
|
2596
2698
|
};
|
2597
2699
|
|
2700
|
+
// todo: add scope.pages
|
2598
2701
|
const freePage = reason => {
|
2599
2702
|
const { ind } = pages.get(reason);
|
2600
2703
|
pages.delete(reason);
|
2601
2704
|
|
2602
|
-
if (allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
2705
|
+
if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
|
2603
2706
|
|
2604
2707
|
return ind;
|
2605
2708
|
};
|
@@ -2625,15 +2728,14 @@ const StoreOps = {
|
|
2625
2728
|
|
2626
2729
|
let data = [];
|
2627
2730
|
|
2628
|
-
const compileBytes = (val, itemType
|
2731
|
+
const compileBytes = (val, itemType) => {
|
2629
2732
|
// todo: this is a mess and needs confirming / ????
|
2630
2733
|
switch (itemType) {
|
2631
2734
|
case 'i8': return [ val % 256 ];
|
2632
|
-
case 'i16': return [ val % 256,
|
2633
|
-
|
2634
|
-
case 'i32':
|
2635
|
-
|
2636
|
-
return enforceFourBytes(signedLEB128(val));
|
2735
|
+
case 'i16': return [ val % 256, (val / 256 | 0) % 256 ];
|
2736
|
+
case 'i16': return [ val % 256, (val / 256 | 0) % 256 ];
|
2737
|
+
case 'i32': return [...new Uint8Array(new Int32Array([ val ]).buffer)];
|
2738
|
+
// todo: i64
|
2637
2739
|
|
2638
2740
|
case 'f64': return ieee754_binary64(val);
|
2639
2741
|
}
|
@@ -2657,7 +2759,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2657
2759
|
|
2658
2760
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
2659
2761
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
2660
|
-
arrays.set(name, allocPage(`${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
|
2762
|
+
arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
|
2661
2763
|
}
|
2662
2764
|
|
2663
2765
|
const pointer = arrays.get(name);
|
@@ -2668,19 +2770,25 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2668
2770
|
const valtype = itemTypeToValtype[itemType];
|
2669
2771
|
const length = elements.length;
|
2670
2772
|
|
2671
|
-
if (firstAssign && useRawElements) {
|
2672
|
-
|
2773
|
+
if (firstAssign && useRawElements && !Prefs.noData) {
|
2774
|
+
// if length is 0 memory/data will just be 0000... anyway
|
2775
|
+
if (length !== 0) {
|
2776
|
+
let bytes = compileBytes(length, 'i32');
|
2673
2777
|
|
2674
|
-
|
2675
|
-
|
2778
|
+
if (!initEmpty) for (let i = 0; i < length; i++) {
|
2779
|
+
if (elements[i] == null) continue;
|
2676
2780
|
|
2677
|
-
|
2678
|
-
|
2781
|
+
bytes.push(...compileBytes(elements[i], itemType));
|
2782
|
+
}
|
2679
2783
|
|
2680
|
-
|
2681
|
-
|
2682
|
-
|
2683
|
-
|
2784
|
+
const ind = data.push({
|
2785
|
+
offset: pointer,
|
2786
|
+
bytes
|
2787
|
+
}) - 1;
|
2788
|
+
|
2789
|
+
scope.data ??= [];
|
2790
|
+
scope.data.push(ind);
|
2791
|
+
}
|
2684
2792
|
|
2685
2793
|
// local value as pointer
|
2686
2794
|
out.push(...number(pointer));
|
@@ -2714,7 +2822,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2714
2822
|
};
|
2715
2823
|
|
2716
2824
|
const byteStringable = str => {
|
2717
|
-
if (!
|
2825
|
+
if (!Prefs.bytestring) return false;
|
2718
2826
|
|
2719
2827
|
for (let i = 0; i < str.length; i++) {
|
2720
2828
|
if (str.charCodeAt(i) > 0xFF) return false;
|
@@ -2723,9 +2831,9 @@ const byteStringable = str => {
|
|
2723
2831
|
return true;
|
2724
2832
|
};
|
2725
2833
|
|
2726
|
-
const makeString = (scope, str, global = false, name = '$undeclared') => {
|
2834
|
+
const makeString = (scope, str, global = false, name = '$undeclared', forceBytestring = undefined) => {
|
2727
2835
|
const rawElements = new Array(str.length);
|
2728
|
-
let byteStringable =
|
2836
|
+
let byteStringable = Prefs.bytestring;
|
2729
2837
|
for (let i = 0; i < str.length; i++) {
|
2730
2838
|
const c = str.charCodeAt(i);
|
2731
2839
|
rawElements[i] = c;
|
@@ -2733,6 +2841,8 @@ const makeString = (scope, str, global = false, name = '$undeclared') => {
|
|
2733
2841
|
if (byteStringable && c > 0xFF) byteStringable = false;
|
2734
2842
|
}
|
2735
2843
|
|
2844
|
+
if (byteStringable && forceBytestring === false) byteStringable = false;
|
2845
|
+
|
2736
2846
|
return makeArray(scope, {
|
2737
2847
|
rawElements
|
2738
2848
|
}, global, name, false, byteStringable ? 'i8' : 'i16')[0];
|
@@ -2766,8 +2876,6 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2766
2876
|
const object = generate(scope, decl.object);
|
2767
2877
|
const property = generate(scope, decl.property);
|
2768
2878
|
|
2769
|
-
console.log(decl.property, property);
|
2770
|
-
|
2771
2879
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2772
2880
|
// hack: this is naughty and will break things!
|
2773
2881
|
let newOut = number(0, valtypeBinary), newPointer = -1;
|
@@ -2860,7 +2968,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2860
2968
|
setLastType(scope)
|
2861
2969
|
],
|
2862
2970
|
|
2863
|
-
default:
|
2971
|
+
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet')
|
2864
2972
|
});
|
2865
2973
|
};
|
2866
2974
|
|
@@ -2886,7 +2994,7 @@ const objectHack = node => {
|
|
2886
2994
|
if (!objectName) return node;
|
2887
2995
|
|
2888
2996
|
const name = '__' + objectName + '_' + node.property.name;
|
2889
|
-
if (codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
|
2997
|
+
if (Prefs.codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
|
2890
2998
|
|
2891
2999
|
return {
|
2892
3000
|
type: 'Identifier',
|
@@ -2948,6 +3056,8 @@ const generateFunc = (scope, decl) => {
|
|
2948
3056
|
};
|
2949
3057
|
funcIndex[name] = func.index;
|
2950
3058
|
|
3059
|
+
if (name === 'main') func.gotLastType = true;
|
3060
|
+
|
2951
3061
|
// quick hack fixes
|
2952
3062
|
for (const inst of wasm) {
|
2953
3063
|
if (inst[0] === Opcodes.call && inst[1] === -1) {
|
@@ -2982,6 +3092,16 @@ const generateCode = (scope, decl) => {
|
|
2982
3092
|
};
|
2983
3093
|
|
2984
3094
|
const internalConstrs = {
|
3095
|
+
Boolean: {
|
3096
|
+
generate: (scope, decl) => {
|
3097
|
+
if (decl.arguments.length === 0) return number(0);
|
3098
|
+
|
3099
|
+
// should generate/run all args
|
3100
|
+
return truthy(scope, generate(scope, decl.arguments[0]), getNodeType(scope, decl.arguments[0]), false, false);
|
3101
|
+
},
|
3102
|
+
type: TYPES.boolean
|
3103
|
+
},
|
3104
|
+
|
2985
3105
|
Array: {
|
2986
3106
|
generate: (scope, decl, global, name) => {
|
2987
3107
|
// new Array(i0, i1, ...)
|
@@ -3103,7 +3223,7 @@ export default program => {
|
|
3103
3223
|
body: program.body
|
3104
3224
|
};
|
3105
3225
|
|
3106
|
-
if (
|
3226
|
+
if (Prefs.astLog) console.log(program.body.body);
|
3107
3227
|
|
3108
3228
|
generateFunc(scope, program);
|
3109
3229
|
|