porffor 0.2.0-69d30a8 → 0.2.0-6bc63ef
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/CONTRIBUTING.md +256 -0
- package/README.md +64 -44
- package/asur/index.js +2 -2
- package/byg/index.js +3 -24
- package/compiler/2c.js +2 -53
- package/compiler/assemble.js +6 -7
- package/compiler/builtins/annexb_string.js +12 -12
- package/compiler/builtins/annexb_string.ts +5 -6
- package/compiler/builtins/array.ts +15 -15
- package/compiler/builtins/base64.ts +4 -79
- package/compiler/builtins/boolean.ts +18 -0
- package/compiler/builtins/crypto.ts +1 -1
- package/compiler/builtins/date.ts +2067 -0
- package/compiler/builtins/escape.ts +2 -2
- package/compiler/builtins/function.ts +5 -0
- package/compiler/builtins/int.ts +2 -4
- package/compiler/builtins/number.ts +11 -9
- package/compiler/builtins/object.ts +4 -0
- package/compiler/builtins/porffor.d.ts +28 -10
- package/compiler/builtins/set.ts +187 -0
- package/compiler/builtins/string.ts +47 -22
- package/compiler/builtins.js +19 -36
- package/compiler/codegen.js +239 -199
- package/compiler/decompile.js +2 -3
- package/compiler/embedding.js +2 -2
- package/compiler/encoding.js +0 -14
- package/compiler/expression.js +1 -1
- package/compiler/generated_builtins.js +1138 -208
- package/compiler/index.js +0 -2
- package/compiler/opt.js +7 -7
- package/compiler/parse.js +5 -5
- package/compiler/precompile.js +21 -24
- package/compiler/prefs.js +6 -5
- package/compiler/prototype.js +19 -19
- package/compiler/types.js +3 -2
- package/compiler/wasmSpec.js +1 -0
- package/compiler/wrap.js +70 -54
- package/package.json +1 -1
- package/rhemyn/compile.js +42 -25
- package/rhemyn/parse.js +4 -5
- package/runner/compare.js +0 -1
- package/runner/debug.js +1 -6
- package/runner/index.js +45 -4
- package/runner/profiler.js +15 -42
- package/runner/repl.js +3 -9
- package/runner/sizes.js +2 -2
- package/runner/version.js +3 -3
- package/.vscode/launch.json +0 -18
- package/compiler/builtins/tostring.ts +0 -45
- package/test262_changes_from_1afe9b87d2_to_04-09.md +0 -270
package/compiler/codegen.js
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from
|
2
|
-
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from
|
3
|
-
import { operatorOpcode } from
|
4
|
-
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from
|
5
|
-
import { PrototypeFuncs } from
|
6
|
-
import { number
|
7
|
-
import { log } from "./log.js";
|
8
|
-
import parse from "./parse.js";
|
9
|
-
import * as Rhemyn from "../rhemyn/compile.js";
|
10
|
-
import Prefs from './prefs.js';
|
1
|
+
import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from './wasmSpec.js';
|
2
|
+
import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from './encoding.js';
|
3
|
+
import { operatorOpcode } from './expression.js';
|
4
|
+
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
|
5
|
+
import { PrototypeFuncs } from './prototype.js';
|
6
|
+
import { number } from './embedding.js';
|
11
7
|
import { TYPES, TYPE_NAMES } from './types.js';
|
8
|
+
import * as Rhemyn from '../rhemyn/compile.js';
|
9
|
+
import parse from './parse.js';
|
10
|
+
import { log } from './log.js';
|
11
|
+
import Prefs from './prefs.js';
|
12
12
|
|
13
13
|
let globals = {};
|
14
14
|
let globalInd = 0;
|
@@ -19,24 +19,6 @@ let funcIndex = {};
|
|
19
19
|
let currentFuncIndex = importedFuncs.length;
|
20
20
|
let builtinFuncs = {}, builtinVars = {}, prototypeFuncs = {};
|
21
21
|
|
22
|
-
const debug = str => {
|
23
|
-
const code = [];
|
24
|
-
|
25
|
-
const logChar = n => {
|
26
|
-
code.push(...number(n));
|
27
|
-
|
28
|
-
code.push([ Opcodes.call, 0 ]);
|
29
|
-
};
|
30
|
-
|
31
|
-
for (let i = 0; i < str.length; i++) {
|
32
|
-
logChar(str.charCodeAt(i));
|
33
|
-
}
|
34
|
-
|
35
|
-
logChar(10); // new line
|
36
|
-
|
37
|
-
return code;
|
38
|
-
};
|
39
|
-
|
40
22
|
class TodoError extends Error {
|
41
23
|
constructor(message) {
|
42
24
|
super(message);
|
@@ -59,6 +41,10 @@ const todo = (scope, msg, expectsValue = undefined) => {
|
|
59
41
|
};
|
60
42
|
|
61
43
|
const isFuncType = type => type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
|
44
|
+
const hasFuncWithName = name => {
|
45
|
+
const func = funcs.find(x => x.name === name);
|
46
|
+
return !!(func || builtinFuncs[name] || importedFuncs[name] || internalConstrs[name]);
|
47
|
+
};
|
62
48
|
const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
|
63
49
|
switch (decl.type) {
|
64
50
|
case 'BinaryExpression':
|
@@ -167,11 +153,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
167
153
|
newFunc.export = true;
|
168
154
|
}
|
169
155
|
|
170
|
-
// if (funcsBefore === funcs.length) throw new Error('no new func added in export');
|
171
|
-
|
172
|
-
// const newFunc = funcs[funcs.length - 1];
|
173
|
-
// newFunc.export = true;
|
174
|
-
|
175
156
|
return [];
|
176
157
|
|
177
158
|
case 'TaggedTemplateExpression': {
|
@@ -201,7 +182,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
201
182
|
}
|
202
183
|
|
203
184
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
204
|
-
if (
|
185
|
+
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
205
186
|
|
206
187
|
if (!Array.isArray(inst)) inst = [ inst ];
|
207
188
|
const immediates = asm.slice(1).map(x => {
|
@@ -210,7 +191,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
210
191
|
return int;
|
211
192
|
});
|
212
193
|
|
213
|
-
out.push([ ...inst, ...immediates ]);
|
194
|
+
out.push([ ...inst, ...immediates.flatMap(x => signedLEB128(x)) ]);
|
214
195
|
}
|
215
196
|
|
216
197
|
return out;
|
@@ -219,8 +200,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
219
200
|
__Porffor_bs: str => [
|
220
201
|
...makeString(scope, str, global, name, true),
|
221
202
|
|
222
|
-
...(name ? setType(scope, name, TYPES.
|
223
|
-
...number(TYPES.
|
203
|
+
...(name ? setType(scope, name, TYPES.bytestring) : [
|
204
|
+
...number(TYPES.bytestring, Valtype.i32),
|
224
205
|
...setLastType(scope)
|
225
206
|
])
|
226
207
|
],
|
@@ -460,7 +441,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
460
441
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
461
442
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
462
443
|
|
463
|
-
if (assign) {
|
444
|
+
if (assign && Prefs.aotPointerOpt) {
|
464
445
|
const pointer = scope.arrays?.get(name ?? '$undeclared');
|
465
446
|
|
466
447
|
return [
|
@@ -723,7 +704,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
723
704
|
|
724
705
|
...typeSwitch(scope, type, {
|
725
706
|
// [TYPES.number]: def,
|
726
|
-
[TYPES.
|
707
|
+
[TYPES.array]: [
|
727
708
|
// arrays are always truthy
|
728
709
|
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
729
710
|
],
|
@@ -739,7 +720,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
739
720
|
[ Opcodes.i32_eqz ], */
|
740
721
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
741
722
|
],
|
742
|
-
[TYPES.
|
723
|
+
[TYPES.bytestring]: [ // duplicate of string
|
743
724
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
744
725
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
745
726
|
|
@@ -762,7 +743,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
762
743
|
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
763
744
|
|
764
745
|
...typeSwitch(scope, type, {
|
765
|
-
[TYPES.
|
746
|
+
[TYPES.array]: [
|
766
747
|
// arrays are always truthy
|
767
748
|
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
768
749
|
],
|
@@ -777,7 +758,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
777
758
|
[ Opcodes.i32_eqz ],
|
778
759
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
779
760
|
],
|
780
|
-
[TYPES.
|
761
|
+
[TYPES.bytestring]: [ // duplicate of string
|
781
762
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
782
763
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
783
764
|
|
@@ -854,31 +835,6 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
854
835
|
|
855
836
|
// if strict (in)equal check types match
|
856
837
|
if (strictOp) {
|
857
|
-
// startOut.push(
|
858
|
-
// ...leftType,
|
859
|
-
// ...rightType,
|
860
|
-
// [ Opcodes.i32_eq ]
|
861
|
-
// );
|
862
|
-
|
863
|
-
// endOut.push(
|
864
|
-
// [ Opcodes.i32_and ]
|
865
|
-
// );
|
866
|
-
|
867
|
-
// startOut.push(
|
868
|
-
// [ Opcodes.block, Valtype.i32 ],
|
869
|
-
// ...leftType,
|
870
|
-
// ...rightType,
|
871
|
-
// [ Opcodes.i32_ne ],
|
872
|
-
// [ Opcodes.if, Blocktype.void ],
|
873
|
-
// ...number(op === '===' ? 0 : 1, Valtype.i32),
|
874
|
-
// [ Opcodes.br, 1 ],
|
875
|
-
// [ Opcodes.end ]
|
876
|
-
// );
|
877
|
-
|
878
|
-
// endOut.push(
|
879
|
-
// [ Opcodes.end ]
|
880
|
-
// );
|
881
|
-
|
882
838
|
endOut.push(
|
883
839
|
...leftType,
|
884
840
|
...rightType,
|
@@ -922,7 +878,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
922
878
|
}
|
923
879
|
}
|
924
880
|
|
925
|
-
if (knownLeft === TYPES.
|
881
|
+
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
|
926
882
|
if (op === '+') {
|
927
883
|
// todo: this should be dynamic too but for now only static
|
928
884
|
// string concat (a + b)
|
@@ -1041,12 +997,12 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
1041
997
|
|
1042
998
|
// if left is bytestring
|
1043
999
|
...leftType,
|
1044
|
-
...number(TYPES.
|
1000
|
+
...number(TYPES.bytestring, Valtype.i32),
|
1045
1001
|
[ Opcodes.i32_eq ],
|
1046
1002
|
|
1047
1003
|
// if right is bytestring
|
1048
1004
|
...rightType,
|
1049
|
-
...number(TYPES.
|
1005
|
+
...number(TYPES.bytestring, Valtype.i32),
|
1050
1006
|
[ Opcodes.i32_eq ],
|
1051
1007
|
|
1052
1008
|
// if both are true
|
@@ -1085,7 +1041,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
1085
1041
|
|
1086
1042
|
const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals = [], returns = [], localInd = 0 }) => {
|
1087
1043
|
return func({ name, params, locals, returns, localInd }, {
|
1088
|
-
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage,
|
1044
|
+
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
|
1089
1045
|
builtin: name => {
|
1090
1046
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1091
1047
|
if (idx === undefined && builtinFuncs[name]) {
|
@@ -1177,7 +1133,6 @@ const generateLogicExp = (scope, decl) => {
|
|
1177
1133
|
// js type: 4 bits
|
1178
1134
|
// internal type: ? bits
|
1179
1135
|
// pointer: 32 bits
|
1180
|
-
|
1181
1136
|
// generic
|
1182
1137
|
// 1 23 4 5
|
1183
1138
|
// 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
|
@@ -1188,7 +1143,7 @@ const generateLogicExp = (scope, decl) => {
|
|
1188
1143
|
// 5: pointer
|
1189
1144
|
|
1190
1145
|
const isExistingProtoFunc = name => {
|
1191
|
-
if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.
|
1146
|
+
if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
|
1192
1147
|
if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
|
1193
1148
|
|
1194
1149
|
return false;
|
@@ -1245,11 +1200,11 @@ const setLastType = scope => {
|
|
1245
1200
|
};
|
1246
1201
|
|
1247
1202
|
const getNodeType = (scope, node) => {
|
1248
|
-
const
|
1203
|
+
const ret = (() => {
|
1249
1204
|
if (node.type === 'Literal') {
|
1250
|
-
if (node.regex) return TYPES.
|
1205
|
+
if (node.regex) return TYPES.regexp;
|
1251
1206
|
|
1252
|
-
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.
|
1207
|
+
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.bytestring;
|
1253
1208
|
|
1254
1209
|
return TYPES[typeof node.value];
|
1255
1210
|
}
|
@@ -1273,10 +1228,21 @@ const getNodeType = (scope, node) => {
|
|
1273
1228
|
return TYPES.number;
|
1274
1229
|
}
|
1275
1230
|
|
1231
|
+
if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
|
1232
|
+
if (builtinFuncs[name + '$constructor'].typedReturns) {
|
1233
|
+
if (scope.locals['#last_type']) return getLastType(scope);
|
1234
|
+
|
1235
|
+
// presume
|
1236
|
+
// todo: warn here?
|
1237
|
+
return TYPES.number;
|
1238
|
+
}
|
1239
|
+
|
1240
|
+
return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
|
1241
|
+
}
|
1242
|
+
|
1276
1243
|
const func = funcs.find(x => x.name === name);
|
1277
1244
|
|
1278
1245
|
if (func) {
|
1279
|
-
// console.log(scope, func, func.returnType);
|
1280
1246
|
if (func.returnType) return func.returnType;
|
1281
1247
|
}
|
1282
1248
|
|
@@ -1291,7 +1257,7 @@ const getNodeType = (scope, node) => {
|
|
1291
1257
|
const spl = name.slice(2).split('_');
|
1292
1258
|
|
1293
1259
|
const func = spl[spl.length - 1];
|
1294
|
-
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.
|
1260
|
+
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1295
1261
|
if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
|
1296
1262
|
}
|
1297
1263
|
|
@@ -1343,7 +1309,7 @@ const getNodeType = (scope, node) => {
|
|
1343
1309
|
}
|
1344
1310
|
|
1345
1311
|
if (node.type === 'ArrayExpression') {
|
1346
|
-
return TYPES.
|
1312
|
+
return TYPES.array;
|
1347
1313
|
}
|
1348
1314
|
|
1349
1315
|
if (node.type === 'BinaryExpression') {
|
@@ -1355,7 +1321,7 @@ const getNodeType = (scope, node) => {
|
|
1355
1321
|
|
1356
1322
|
// todo: this should be dynamic but for now only static
|
1357
1323
|
if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
|
1358
|
-
if (knownLeft === TYPES.
|
1324
|
+
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1359
1325
|
|
1360
1326
|
return TYPES.number;
|
1361
1327
|
|
@@ -1381,19 +1347,28 @@ const getNodeType = (scope, node) => {
|
|
1381
1347
|
if (node.operator === '!') return TYPES.boolean;
|
1382
1348
|
if (node.operator === 'void') return TYPES.undefined;
|
1383
1349
|
if (node.operator === 'delete') return TYPES.boolean;
|
1384
|
-
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.
|
1350
|
+
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.bytestring : TYPES.string;
|
1385
1351
|
|
1386
1352
|
return TYPES.number;
|
1387
1353
|
}
|
1388
1354
|
|
1389
1355
|
if (node.type === 'MemberExpression') {
|
1356
|
+
// hack: if something.name, string type
|
1357
|
+
if (node.property.name === 'name') {
|
1358
|
+
if (hasFuncWithName(node.object.name)) {
|
1359
|
+
return TYPES.bytestring;
|
1360
|
+
} else {
|
1361
|
+
return TYPES.undefined;
|
1362
|
+
}
|
1363
|
+
}
|
1364
|
+
|
1390
1365
|
// hack: if something.length, number type
|
1391
1366
|
if (node.property.name === 'length') return TYPES.number;
|
1392
1367
|
|
1393
1368
|
// ts hack
|
1394
1369
|
if (scope.locals[node.object.name]?.metadata?.type === TYPES.string) return TYPES.string;
|
1395
|
-
if (scope.locals[node.object.name]?.metadata?.type === TYPES.
|
1396
|
-
if (scope.locals[node.object.name]?.metadata?.type === TYPES.
|
1370
|
+
if (scope.locals[node.object.name]?.metadata?.type === TYPES.bytestring) return TYPES.bytestring;
|
1371
|
+
if (scope.locals[node.object.name]?.metadata?.type === TYPES.array) return TYPES.number;
|
1397
1372
|
|
1398
1373
|
if (scope.locals['#last_type']) return getLastType(scope);
|
1399
1374
|
|
@@ -1411,10 +1386,8 @@ const getNodeType = (scope, node) => {
|
|
1411
1386
|
// presume
|
1412
1387
|
// todo: warn here?
|
1413
1388
|
return TYPES.number;
|
1414
|
-
};
|
1389
|
+
})();
|
1415
1390
|
|
1416
|
-
const ret = inner();
|
1417
|
-
// console.trace(node, ret);
|
1418
1391
|
if (typeof ret === 'number') return number(ret, Valtype.i32);
|
1419
1392
|
return ret;
|
1420
1393
|
};
|
@@ -1460,16 +1433,23 @@ const countLeftover = wasm => {
|
|
1460
1433
|
if (depth === 0)
|
1461
1434
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1462
1435
|
else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x0a)) {}
|
1463
|
-
else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const].includes(inst[0])) count++;
|
1436
|
+
else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
|
1464
1437
|
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1465
1438
|
else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
|
1466
1439
|
else if (inst[0] === Opcodes.return) count = 0;
|
1467
1440
|
else if (inst[0] === Opcodes.call) {
|
1468
1441
|
let func = funcs.find(x => x.index === inst[1]);
|
1469
|
-
if (
|
1470
|
-
count
|
1471
|
-
} else
|
1472
|
-
|
1442
|
+
if (inst[1] === -1) {
|
1443
|
+
// todo: count for calling self
|
1444
|
+
} else if (!func && inst[1] < importedFuncs.length) {
|
1445
|
+
count -= importedFuncs[inst[1]].params;
|
1446
|
+
count += importedFuncs[inst[1]].returns;
|
1447
|
+
} else {
|
1448
|
+
if (func) {
|
1449
|
+
count -= func.params.length;
|
1450
|
+
} else count--;
|
1451
|
+
if (func) count += func.returns.length;
|
1452
|
+
}
|
1473
1453
|
} else count--;
|
1474
1454
|
|
1475
1455
|
// console.log(count, decompile([ inst ]).slice(0, -1));
|
@@ -1546,15 +1526,6 @@ const RTArrayUtil = {
|
|
1546
1526
|
};
|
1547
1527
|
|
1548
1528
|
const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
1549
|
-
/* const callee = decl.callee;
|
1550
|
-
const args = decl.arguments;
|
1551
|
-
|
1552
|
-
return [
|
1553
|
-
...generate(args),
|
1554
|
-
...generate(callee),
|
1555
|
-
Opcodes.call_indirect,
|
1556
|
-
]; */
|
1557
|
-
|
1558
1529
|
let name = mapName(decl.callee.name);
|
1559
1530
|
if (isFuncType(decl.callee.type)) { // iife
|
1560
1531
|
const func = generateFunc(scope, decl.callee);
|
@@ -1627,18 +1598,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1627
1598
|
// megahack for /regex/.func()
|
1628
1599
|
const funcName = decl.callee.property.name;
|
1629
1600
|
if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
|
1630
|
-
const
|
1601
|
+
const regex = decl.callee.object.regex.pattern;
|
1602
|
+
const rhemynName = `regex_${funcName}_${regex}`;
|
1603
|
+
|
1604
|
+
if (!funcIndex[rhemynName]) {
|
1605
|
+
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
1631
1606
|
|
1632
|
-
|
1633
|
-
|
1607
|
+
funcIndex[func.name] = func.index;
|
1608
|
+
funcs.push(func);
|
1609
|
+
}
|
1634
1610
|
|
1611
|
+
const idx = funcIndex[rhemynName];
|
1635
1612
|
return [
|
1636
1613
|
// make string arg
|
1637
1614
|
...generate(scope, decl.arguments[0]),
|
1615
|
+
Opcodes.i32_to_u,
|
1616
|
+
...getNodeType(scope, decl.arguments[0]),
|
1638
1617
|
|
1639
1618
|
// call regex func
|
1640
|
-
Opcodes.
|
1641
|
-
[ Opcodes.call, func.index ],
|
1619
|
+
[ Opcodes.call, idx ],
|
1642
1620
|
Opcodes.i32_from_u,
|
1643
1621
|
|
1644
1622
|
...number(TYPES.boolean, Valtype.i32),
|
@@ -1678,6 +1656,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1678
1656
|
|
1679
1657
|
protoBC[type] = generateCall(scope, {
|
1680
1658
|
callee: {
|
1659
|
+
type: 'Identifier',
|
1681
1660
|
name: x
|
1682
1661
|
},
|
1683
1662
|
arguments: [ target, ...decl.arguments ],
|
@@ -1720,8 +1699,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1720
1699
|
continue;
|
1721
1700
|
}
|
1722
1701
|
|
1723
|
-
// const protoLocal = protoFunc.local ? localTmp(scope, `__${TYPE_NAMES[x]}_${protoName}_tmp`, protoFunc.local) : -1;
|
1724
|
-
// const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${TYPE_NAMES[x]}_${protoName}_tmp2`, protoFunc.local2) : -1;
|
1725
1702
|
const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
|
1726
1703
|
const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
|
1727
1704
|
|
@@ -1798,22 +1775,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1798
1775
|
|
1799
1776
|
includeBuiltin(scope, name);
|
1800
1777
|
idx = funcIndex[name];
|
1801
|
-
|
1802
|
-
// infer arguments types from builtins params
|
1803
|
-
const func = funcs.find(x => x.name === name);
|
1804
|
-
for (let i = 0; i < decl.arguments.length; i++) {
|
1805
|
-
const arg = decl.arguments[i];
|
1806
|
-
if (!arg.name) continue;
|
1807
|
-
|
1808
|
-
const local = scope.locals[arg.name];
|
1809
|
-
if (!local) continue;
|
1810
|
-
|
1811
|
-
local.type = func.params[i];
|
1812
|
-
if (local.type === Valtype.v128) {
|
1813
|
-
// specify vec subtype inferred from last vec type in function name
|
1814
|
-
local.vecType = name.split('_').reverse().find(x => x.includes('x'));
|
1815
|
-
}
|
1816
|
-
}
|
1817
1778
|
}
|
1818
1779
|
|
1819
1780
|
if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
@@ -1826,28 +1787,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1826
1787
|
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1827
1788
|
const wasmOps = {
|
1828
1789
|
// pointer, align, offset
|
1829
|
-
i32_load: { imms: 2, args:
|
1790
|
+
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
1830
1791
|
// pointer, value, align, offset
|
1831
|
-
i32_store: { imms: 2, args:
|
1792
|
+
i32_store: { imms: 2, args: [ true, true ], returns: 0 },
|
1832
1793
|
// pointer, align, offset
|
1833
|
-
i32_load8_u: { imms: 2, args:
|
1794
|
+
i32_load8_u: { imms: 2, args: [ true ], returns: 1 },
|
1834
1795
|
// pointer, value, align, offset
|
1835
|
-
i32_store8: { imms: 2, args:
|
1796
|
+
i32_store8: { imms: 2, args: [ true, true ], returns: 0 },
|
1836
1797
|
// pointer, align, offset
|
1837
|
-
i32_load16_u: { imms: 2, args:
|
1798
|
+
i32_load16_u: { imms: 2, args: [ true ], returns: 1 },
|
1838
1799
|
// pointer, value, align, offset
|
1839
|
-
i32_store16: { imms: 2, args:
|
1800
|
+
i32_store16: { imms: 2, args: [ true, true ], returns: 0 },
|
1840
1801
|
|
1841
1802
|
// pointer, align, offset
|
1842
|
-
f64_load: { imms: 2, args:
|
1803
|
+
f64_load: { imms: 2, args: [ true ], returns: 0 }, // 0 due to not i32
|
1843
1804
|
// pointer, value, align, offset
|
1844
|
-
f64_store: { imms: 2, args:
|
1805
|
+
f64_store: { imms: 2, args: [ true, false ], returns: 0 },
|
1845
1806
|
|
1846
1807
|
// value
|
1847
|
-
i32_const: { imms: 1, args:
|
1848
|
-
|
1849
|
-
// a, b
|
1850
|
-
i32_or: { imms: 0, args: 2, returns: 1 },
|
1808
|
+
i32_const: { imms: 1, args: [], returns: 1 },
|
1851
1809
|
};
|
1852
1810
|
|
1853
1811
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -1856,13 +1814,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1856
1814
|
const op = wasmOps[opName];
|
1857
1815
|
|
1858
1816
|
const argOut = [];
|
1859
|
-
for (let i = 0; i < op.args; i++) argOut.push(
|
1817
|
+
for (let i = 0; i < op.args.length; i++) argOut.push(
|
1860
1818
|
...generate(scope, decl.arguments[i]),
|
1861
|
-
Opcodes.i32_to
|
1819
|
+
...(op.args[i] ? [ Opcodes.i32_to ] : [])
|
1862
1820
|
);
|
1863
1821
|
|
1864
1822
|
// literals only
|
1865
|
-
const imms = decl.arguments.slice(op.args).map(x => x.value);
|
1823
|
+
const imms = decl.arguments.slice(op.args.length).map(x => x.value);
|
1866
1824
|
|
1867
1825
|
return [
|
1868
1826
|
...argOut,
|
@@ -1937,7 +1895,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1937
1895
|
const generateNew = (scope, decl, _global, _name) => {
|
1938
1896
|
// hack: basically treat this as a normal call for builtins for now
|
1939
1897
|
const name = mapName(decl.callee.name);
|
1898
|
+
|
1940
1899
|
if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1900
|
+
|
1901
|
+
if (builtinFuncs[name + '$constructor']) {
|
1902
|
+
// custom ...$constructor override builtin func
|
1903
|
+
return generateCall(scope, {
|
1904
|
+
...decl,
|
1905
|
+
callee: {
|
1906
|
+
type: 'Identifier',
|
1907
|
+
name: name + '$constructor'
|
1908
|
+
}
|
1909
|
+
}, _global, _name);
|
1910
|
+
}
|
1911
|
+
|
1941
1912
|
if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet`); // return todo(scope, `new statement is not supported yet (new ${unhackName(name)})`);
|
1942
1913
|
|
1943
1914
|
return generateCall(scope, decl, _global, _name);
|
@@ -2055,7 +2026,7 @@ const brTable = (input, bc, returns) => {
|
|
2055
2026
|
};
|
2056
2027
|
|
2057
2028
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
2058
|
-
if (!Prefs.bytestring) delete bc[TYPES.
|
2029
|
+
if (!Prefs.bytestring) delete bc[TYPES.bytestring];
|
2059
2030
|
|
2060
2031
|
const known = knownType(scope, type);
|
2061
2032
|
if (known != null) {
|
@@ -2128,8 +2099,7 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
|
|
2128
2099
|
|
2129
2100
|
const typeAnnoToPorfType = x => {
|
2130
2101
|
if (!x) return null;
|
2131
|
-
if (TYPES[x] != null) return TYPES[x];
|
2132
|
-
if (TYPES['_' + x] != null) return TYPES['_' + x];
|
2102
|
+
if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
|
2133
2103
|
|
2134
2104
|
switch (x) {
|
2135
2105
|
case 'i32':
|
@@ -2158,7 +2128,7 @@ const extractTypeAnnotation = decl => {
|
|
2158
2128
|
const typeName = type;
|
2159
2129
|
type = typeAnnoToPorfType(type);
|
2160
2130
|
|
2161
|
-
if (type === TYPES.
|
2131
|
+
if (type === TYPES.bytestring && !Prefs.bytestring) type = TYPES.string;
|
2162
2132
|
|
2163
2133
|
// if (decl.name) console.log(decl.name, { type, elementType });
|
2164
2134
|
|
@@ -2170,8 +2140,8 @@ const generateVar = (scope, decl) => {
|
|
2170
2140
|
|
2171
2141
|
const topLevel = scope.name === 'main';
|
2172
2142
|
|
2173
|
-
// global variable if in top scope (main)
|
2174
|
-
const global = topLevel || decl._bare;
|
2143
|
+
// global variable if in top scope (main) or if internally wanted
|
2144
|
+
const global = topLevel || decl._bare;
|
2175
2145
|
|
2176
2146
|
for (const x of decl.declarations) {
|
2177
2147
|
const name = mapName(x.id.name);
|
@@ -2185,7 +2155,6 @@ const generateVar = (scope, decl) => {
|
|
2185
2155
|
continue;
|
2186
2156
|
}
|
2187
2157
|
|
2188
|
-
// console.log(name);
|
2189
2158
|
if (topLevel && builtinVars[name]) {
|
2190
2159
|
// cannot redeclare
|
2191
2160
|
if (decl.kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
|
@@ -2193,17 +2162,29 @@ const generateVar = (scope, decl) => {
|
|
2193
2162
|
continue; // always ignore
|
2194
2163
|
}
|
2195
2164
|
|
2165
|
+
// // generate init before allocating var
|
2166
|
+
// let generated;
|
2167
|
+
// if (x.init) generated = generate(scope, x.init, global, name);
|
2168
|
+
|
2196
2169
|
const typed = typedInput && x.id.typeAnnotation;
|
2197
|
-
let idx = allocVar(scope, name, global, !typed);
|
2170
|
+
let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
|
2198
2171
|
|
2199
2172
|
if (typed) {
|
2200
2173
|
addVarMetadata(scope, name, global, extractTypeAnnotation(x.id));
|
2201
2174
|
}
|
2202
2175
|
|
2203
2176
|
if (x.init) {
|
2204
|
-
|
2205
|
-
|
2206
|
-
|
2177
|
+
const generated = generate(scope, x.init, global, name);
|
2178
|
+
if (scope.arrays?.get(name) != null) {
|
2179
|
+
// hack to set local as pointer before
|
2180
|
+
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2181
|
+
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
2182
|
+
generated.pop();
|
2183
|
+
out = out.concat(generated);
|
2184
|
+
} else {
|
2185
|
+
out = out.concat(generated);
|
2186
|
+
out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2187
|
+
}
|
2207
2188
|
out.push(...setType(scope, name, getNodeType(scope, x.init)));
|
2208
2189
|
}
|
2209
2190
|
|
@@ -2230,6 +2211,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2230
2211
|
return [];
|
2231
2212
|
}
|
2232
2213
|
|
2214
|
+
const op = decl.operator.slice(0, -1) || '=';
|
2215
|
+
|
2233
2216
|
// hack: .length setter
|
2234
2217
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2235
2218
|
const name = decl.left.object.name;
|
@@ -2238,14 +2221,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2238
2221
|
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2239
2222
|
|
2240
2223
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2224
|
+
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2241
2225
|
|
2242
2226
|
return [
|
2243
2227
|
...(aotPointer ? number(0, Valtype.i32) : [
|
2244
2228
|
...generate(scope, decl.left.object),
|
2245
2229
|
Opcodes.i32_to_u
|
2246
2230
|
]),
|
2231
|
+
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2247
2232
|
|
2248
|
-
...generate(scope, decl.right),
|
2233
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2234
|
+
[ Opcodes.local_get, pointerTmp ],
|
2235
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2236
|
+
Opcodes.i32_from_u
|
2237
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
|
2249
2238
|
[ Opcodes.local_tee, newValueTmp ],
|
2250
2239
|
|
2251
2240
|
Opcodes.i32_to_u,
|
@@ -2255,8 +2244,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2255
2244
|
];
|
2256
2245
|
}
|
2257
2246
|
|
2258
|
-
const op = decl.operator.slice(0, -1) || '=';
|
2259
|
-
|
2260
2247
|
// arr[i]
|
2261
2248
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2262
2249
|
const name = decl.left.object.name;
|
@@ -2269,7 +2256,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2269
2256
|
|
2270
2257
|
return [
|
2271
2258
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2272
|
-
[TYPES.
|
2259
|
+
[TYPES.array]: [
|
2273
2260
|
...(aotPointer ? [] : [
|
2274
2261
|
...generate(scope, decl.left.object),
|
2275
2262
|
Opcodes.i32_to_u
|
@@ -2471,7 +2458,7 @@ const generateUnary = (scope, decl) => {
|
|
2471
2458
|
[TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
|
2472
2459
|
[TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
|
2473
2460
|
|
2474
|
-
[TYPES.
|
2461
|
+
[TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
|
2475
2462
|
|
2476
2463
|
// object and internal types
|
2477
2464
|
default: makeString(scope, 'object', false, '#typeof_result'),
|
@@ -2707,7 +2694,7 @@ const generateForOf = (scope, decl) => {
|
|
2707
2694
|
// set type for local
|
2708
2695
|
// todo: optimize away counter and use end pointer
|
2709
2696
|
out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
|
2710
|
-
[TYPES.
|
2697
|
+
[TYPES.array]: [
|
2711
2698
|
...setType(scope, leftName, TYPES.number),
|
2712
2699
|
|
2713
2700
|
[ Opcodes.loop, Blocktype.void ],
|
@@ -2790,8 +2777,8 @@ const generateForOf = (scope, decl) => {
|
|
2790
2777
|
[ Opcodes.end ],
|
2791
2778
|
[ Opcodes.end ]
|
2792
2779
|
],
|
2793
|
-
[TYPES.
|
2794
|
-
...setType(scope, leftName, TYPES.
|
2780
|
+
[TYPES.bytestring]: [
|
2781
|
+
...setType(scope, leftName, TYPES.bytestring),
|
2795
2782
|
|
2796
2783
|
[ Opcodes.loop, Blocktype.void ],
|
2797
2784
|
|
@@ -2968,13 +2955,6 @@ const generateEmpty = (scope, decl) => {
|
|
2968
2955
|
return [];
|
2969
2956
|
};
|
2970
2957
|
|
2971
|
-
const generateAssignPat = (scope, decl) => {
|
2972
|
-
// TODO
|
2973
|
-
// if identifier declared, use that
|
2974
|
-
// else, use default (right)
|
2975
|
-
return todo(scope, 'assignment pattern (optional arg)');
|
2976
|
-
};
|
2977
|
-
|
2978
2958
|
let pages = new Map();
|
2979
2959
|
const allocPage = (scope, reason, type) => {
|
2980
2960
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3060,12 +3040,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3060
3040
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3061
3041
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
3062
3042
|
|
3063
|
-
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${
|
3043
|
+
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
|
3064
3044
|
else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
|
3065
3045
|
}
|
3066
3046
|
|
3067
3047
|
const pointer = scope.arrays.get(name);
|
3068
3048
|
|
3049
|
+
const local = global ? globals[name] : scope.locals[name];
|
3050
|
+
|
3069
3051
|
const useRawElements = !!decl.rawElements;
|
3070
3052
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
3071
3053
|
|
@@ -3098,11 +3080,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3098
3080
|
return [ out, pointer ];
|
3099
3081
|
}
|
3100
3082
|
|
3083
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3084
|
+
if (pointerTmp != null) {
|
3085
|
+
out.push(
|
3086
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3087
|
+
Opcodes.i32_to_u,
|
3088
|
+
[ Opcodes.local_set, pointerTmp ]
|
3089
|
+
);
|
3090
|
+
}
|
3091
|
+
|
3092
|
+
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3093
|
+
|
3101
3094
|
// store length as 0th array
|
3102
3095
|
out.push(
|
3103
|
-
...
|
3096
|
+
...pointerWasm,
|
3104
3097
|
...number(length, Valtype.i32),
|
3105
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3098
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3106
3099
|
);
|
3107
3100
|
|
3108
3101
|
const storeOp = StoreOps[itemType];
|
@@ -3111,14 +3104,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3111
3104
|
if (elements[i] == null) continue;
|
3112
3105
|
|
3113
3106
|
out.push(
|
3114
|
-
...
|
3107
|
+
...pointerWasm,
|
3115
3108
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3116
|
-
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(
|
3109
|
+
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
|
3117
3110
|
);
|
3118
3111
|
}
|
3119
3112
|
|
3120
3113
|
// local value as pointer
|
3121
|
-
out.push(...
|
3114
|
+
out.push(...pointerWasm, Opcodes.i32_from_u);
|
3122
3115
|
|
3123
3116
|
return [ out, pointer ];
|
3124
3117
|
};
|
@@ -3160,6 +3153,20 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3160
3153
|
|
3161
3154
|
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
3162
3155
|
|
3156
|
+
// hack: .name
|
3157
|
+
if (decl.property.name === 'name') {
|
3158
|
+
if (hasFuncWithName(name)) {
|
3159
|
+
let nameProp = name;
|
3160
|
+
|
3161
|
+
// eg: __String_prototype_toLowerCase -> toLowerCase
|
3162
|
+
if (nameProp.startsWith('__')) nameProp = nameProp.split('_').pop();
|
3163
|
+
|
3164
|
+
return makeString(scope, nameProp, _global, _name, true);
|
3165
|
+
} else {
|
3166
|
+
return generate(scope, DEFAULT_VALUE);
|
3167
|
+
}
|
3168
|
+
}
|
3169
|
+
|
3163
3170
|
// hack: .length
|
3164
3171
|
if (decl.property.name === 'length') {
|
3165
3172
|
const func = funcs.find(x => x.name === name);
|
@@ -3169,6 +3176,16 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3169
3176
|
return number(typedParams ? func.params.length / 2 : func.params.length);
|
3170
3177
|
}
|
3171
3178
|
|
3179
|
+
if (builtinFuncs[name + '$constructor']) {
|
3180
|
+
const regularFunc = builtinFuncs[name];
|
3181
|
+
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3182
|
+
|
3183
|
+
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3184
|
+
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3185
|
+
|
3186
|
+
return number(Math.max(regularParams, constructorParams));
|
3187
|
+
}
|
3188
|
+
|
3172
3189
|
if (builtinFuncs[name]) return number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length);
|
3173
3190
|
if (importedFuncs[name]) return number(importedFuncs[name].params);
|
3174
3191
|
if (internalConstrs[name]) return number(internalConstrs[name].length ?? 0);
|
@@ -3197,7 +3214,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3197
3214
|
}
|
3198
3215
|
|
3199
3216
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3200
|
-
[TYPES.
|
3217
|
+
[TYPES.array]: [
|
3201
3218
|
// get index as valtype
|
3202
3219
|
...property,
|
3203
3220
|
|
@@ -3250,7 +3267,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3250
3267
|
...number(TYPES.string, Valtype.i32),
|
3251
3268
|
...setLastType(scope)
|
3252
3269
|
],
|
3253
|
-
[TYPES.
|
3270
|
+
[TYPES.bytestring]: [
|
3254
3271
|
// setup new/out array
|
3255
3272
|
...newOut,
|
3256
3273
|
[ Opcodes.drop ],
|
@@ -3275,7 +3292,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3275
3292
|
// return new string (page)
|
3276
3293
|
...number(newPointer),
|
3277
3294
|
|
3278
|
-
...number(TYPES.
|
3295
|
+
...number(TYPES.bytestring, Valtype.i32),
|
3279
3296
|
...setLastType(scope)
|
3280
3297
|
],
|
3281
3298
|
|
@@ -3300,8 +3317,8 @@ const objectHack = node => {
|
|
3300
3317
|
|
3301
3318
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3302
3319
|
|
3303
|
-
// if .length, give up (hack within a hack!)
|
3304
|
-
if (node.property.name
|
3320
|
+
// if .name or .length, give up (hack within a hack!)
|
3321
|
+
if (['name', 'length'].includes(node.property.name)) {
|
3305
3322
|
node.object = objectHack(node.object);
|
3306
3323
|
return;
|
3307
3324
|
}
|
@@ -3350,8 +3367,11 @@ const generateFunc = (scope, decl) => {
|
|
3350
3367
|
};
|
3351
3368
|
|
3352
3369
|
if (typedInput && decl.returnType) {
|
3353
|
-
|
3354
|
-
|
3370
|
+
const { type } = extractTypeAnnotation(decl.returnType);
|
3371
|
+
if (type != null) {
|
3372
|
+
innerScope.returnType = type;
|
3373
|
+
innerScope.returns = [ valtypeBinary ];
|
3374
|
+
}
|
3355
3375
|
}
|
3356
3376
|
|
3357
3377
|
for (let i = 0; i < params.length; i++) {
|
@@ -3393,7 +3413,7 @@ const generateFunc = (scope, decl) => {
|
|
3393
3413
|
if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
3394
3414
|
wasm.push(
|
3395
3415
|
...number(0),
|
3396
|
-
...number(TYPES.undefined, Valtype.i32),
|
3416
|
+
...(innerScope.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
|
3397
3417
|
[ Opcodes.return ]
|
3398
3418
|
);
|
3399
3419
|
}
|
@@ -3444,7 +3464,7 @@ const internalConstrs = {
|
|
3444
3464
|
...number(pointer)
|
3445
3465
|
];
|
3446
3466
|
},
|
3447
|
-
type: TYPES.
|
3467
|
+
type: TYPES.array,
|
3448
3468
|
length: 1
|
3449
3469
|
},
|
3450
3470
|
|
@@ -3456,7 +3476,7 @@ const internalConstrs = {
|
|
3456
3476
|
elements: decl.arguments
|
3457
3477
|
}, global, name);
|
3458
3478
|
},
|
3459
|
-
type: TYPES.
|
3479
|
+
type: TYPES.array,
|
3460
3480
|
notConstr: true,
|
3461
3481
|
length: 0
|
3462
3482
|
},
|
@@ -3473,6 +3493,8 @@ const internalConstrs = {
|
|
3473
3493
|
);
|
3474
3494
|
}
|
3475
3495
|
|
3496
|
+
out.push(Opcodes.i32_from_u);
|
3497
|
+
|
3476
3498
|
return out;
|
3477
3499
|
},
|
3478
3500
|
type: TYPES.boolean,
|
@@ -3491,6 +3513,8 @@ const internalConstrs = {
|
|
3491
3513
|
);
|
3492
3514
|
}
|
3493
3515
|
|
3516
|
+
out.push(Opcodes.i32_from_u);
|
3517
|
+
|
3494
3518
|
return out;
|
3495
3519
|
},
|
3496
3520
|
type: TYPES.boolean,
|
@@ -3545,25 +3569,41 @@ const internalConstrs = {
|
|
3545
3569
|
type: TYPES.number,
|
3546
3570
|
notConstr: true,
|
3547
3571
|
length: 2
|
3548
|
-
}
|
3549
|
-
|
3572
|
+
},
|
3573
|
+
|
3574
|
+
__console_log: {
|
3575
|
+
generate: (scope, decl) => {
|
3576
|
+
const out = [];
|
3550
3577
|
|
3551
|
-
|
3552
|
-
|
3553
|
-
|
3554
|
-
|
3555
|
-
|
3556
|
-
|
3557
|
-
|
3558
|
-
|
3559
|
-
|
3560
|
-
|
3561
|
-
//
|
3562
|
-
|
3563
|
-
|
3578
|
+
for (let i = 0; i < decl.arguments.length; i++) {
|
3579
|
+
out.push(
|
3580
|
+
...generateCall(scope, {
|
3581
|
+
callee: {
|
3582
|
+
type: 'Identifier',
|
3583
|
+
name: '__Porffor_print'
|
3584
|
+
},
|
3585
|
+
arguments: [ decl.arguments[i] ]
|
3586
|
+
}),
|
3587
|
+
|
3588
|
+
// print space
|
3589
|
+
...number(32),
|
3590
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3591
|
+
);
|
3592
|
+
}
|
3593
|
+
|
3594
|
+
// print newline
|
3595
|
+
out.push(
|
3596
|
+
...number(10),
|
3597
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3598
|
+
);
|
3564
3599
|
|
3565
|
-
|
3566
|
-
|
3600
|
+
return out;
|
3601
|
+
},
|
3602
|
+
type: TYPES.undefined,
|
3603
|
+
notConstr: true,
|
3604
|
+
length: 0
|
3605
|
+
}
|
3606
|
+
};
|
3567
3607
|
|
3568
3608
|
export default program => {
|
3569
3609
|
globals = {};
|
@@ -3579,7 +3619,7 @@ export default program => {
|
|
3579
3619
|
|
3580
3620
|
globalThis.valtype = 'f64';
|
3581
3621
|
|
3582
|
-
const valtypeOpt = process.argv.find(x => x.startsWith('
|
3622
|
+
const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
|
3583
3623
|
if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
|
3584
3624
|
|
3585
3625
|
globalThis.valtypeBinary = Valtype[valtype];
|
@@ -3587,7 +3627,7 @@ export default program => {
|
|
3587
3627
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3588
3628
|
|
3589
3629
|
globalThis.pageSize = PageSize;
|
3590
|
-
const pageSizeOpt = process.argv.find(x => x.startsWith('
|
3630
|
+
const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
|
3591
3631
|
if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
|
3592
3632
|
|
3593
3633
|
// set generic opcodes for current valtype
|