porffor 0.2.0-c87ffeb → 0.2.0-c908b46
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 +1 -1
- package/compiler/assemble.js +2 -2
- package/compiler/builtins/annexb_string.js +2 -2
- package/compiler/builtins/annexb_string.ts +5 -6
- package/compiler/builtins/array.ts +10 -10
- package/compiler/builtins/base64.ts +4 -79
- package/compiler/builtins/boolean.ts +21 -0
- package/compiler/builtins/crypto.ts +1 -1
- package/compiler/builtins/date.ts +2065 -2
- package/compiler/builtins/escape.ts +2 -2
- package/compiler/builtins/int.ts +3 -3
- package/compiler/builtins/number.ts +9 -2
- package/compiler/builtins/porffor.d.ts +21 -4
- package/compiler/builtins/string.ts +37 -22
- package/compiler/builtins/tostring.ts +4 -12
- package/compiler/builtins.js +6 -30
- package/compiler/codegen.js +181 -103
- package/compiler/decompile.js +0 -1
- package/compiler/generated_builtins.js +956 -134
- package/compiler/parse.js +4 -2
- package/compiler/precompile.js +8 -3
- package/compiler/prefs.js +6 -5
- package/compiler/prototype.js +14 -14
- package/compiler/types.js +1 -1
- package/compiler/wasmSpec.js +1 -0
- package/compiler/wrap.js +10 -8
- package/package.json +1 -1
- package/rhemyn/compile.js +42 -25
- package/rhemyn/parse.js +4 -5
- package/runner/index.js +45 -4
- package/runner/repl.js +2 -2
- package/runner/sizes.js +1 -1
- package/.vscode/launch.json +0 -18
- package/test262_changes_from_1afe9b87d2_to_04-09.md +0 -270
package/compiler/codegen.js
CHANGED
@@ -201,7 +201,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
201
201
|
}
|
202
202
|
|
203
203
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
204
|
-
if (
|
204
|
+
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
205
205
|
|
206
206
|
if (!Array.isArray(inst)) inst = [ inst ];
|
207
207
|
const immediates = asm.slice(1).map(x => {
|
@@ -210,7 +210,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
210
210
|
return int;
|
211
211
|
});
|
212
212
|
|
213
|
-
out.push([ ...inst, ...immediates ]);
|
213
|
+
out.push([ ...inst, ...immediates.flatMap(x => signedLEB128(x)) ]);
|
214
214
|
}
|
215
215
|
|
216
216
|
return out;
|
@@ -219,8 +219,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
219
219
|
__Porffor_bs: str => [
|
220
220
|
...makeString(scope, str, global, name, true),
|
221
221
|
|
222
|
-
...(name ? setType(scope, name, TYPES.
|
223
|
-
...number(TYPES.
|
222
|
+
...(name ? setType(scope, name, TYPES.bytestring) : [
|
223
|
+
...number(TYPES.bytestring, Valtype.i32),
|
224
224
|
...setLastType(scope)
|
225
225
|
])
|
226
226
|
],
|
@@ -460,7 +460,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
460
460
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
461
461
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
462
462
|
|
463
|
-
if (assign) {
|
463
|
+
if (assign && Prefs.aotPointerOpt) {
|
464
464
|
const pointer = scope.arrays?.get(name ?? '$undeclared');
|
465
465
|
|
466
466
|
return [
|
@@ -723,7 +723,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
723
723
|
|
724
724
|
...typeSwitch(scope, type, {
|
725
725
|
// [TYPES.number]: def,
|
726
|
-
[TYPES.
|
726
|
+
[TYPES.array]: [
|
727
727
|
// arrays are always truthy
|
728
728
|
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
729
729
|
],
|
@@ -739,7 +739,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
739
739
|
[ Opcodes.i32_eqz ], */
|
740
740
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
741
741
|
],
|
742
|
-
[TYPES.
|
742
|
+
[TYPES.bytestring]: [ // duplicate of string
|
743
743
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
744
744
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
745
745
|
|
@@ -762,7 +762,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
762
762
|
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
763
763
|
|
764
764
|
...typeSwitch(scope, type, {
|
765
|
-
[TYPES.
|
765
|
+
[TYPES.array]: [
|
766
766
|
// arrays are always truthy
|
767
767
|
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
768
768
|
],
|
@@ -777,7 +777,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
777
777
|
[ Opcodes.i32_eqz ],
|
778
778
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
779
779
|
],
|
780
|
-
[TYPES.
|
780
|
+
[TYPES.bytestring]: [ // duplicate of string
|
781
781
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
782
782
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
783
783
|
|
@@ -922,7 +922,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
922
922
|
}
|
923
923
|
}
|
924
924
|
|
925
|
-
if (knownLeft === TYPES.
|
925
|
+
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
|
926
926
|
if (op === '+') {
|
927
927
|
// todo: this should be dynamic too but for now only static
|
928
928
|
// string concat (a + b)
|
@@ -1041,12 +1041,12 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
1041
1041
|
|
1042
1042
|
// if left is bytestring
|
1043
1043
|
...leftType,
|
1044
|
-
...number(TYPES.
|
1044
|
+
...number(TYPES.bytestring, Valtype.i32),
|
1045
1045
|
[ Opcodes.i32_eq ],
|
1046
1046
|
|
1047
1047
|
// if right is bytestring
|
1048
1048
|
...rightType,
|
1049
|
-
...number(TYPES.
|
1049
|
+
...number(TYPES.bytestring, Valtype.i32),
|
1050
1050
|
[ Opcodes.i32_eq ],
|
1051
1051
|
|
1052
1052
|
// if both are true
|
@@ -1177,7 +1177,6 @@ const generateLogicExp = (scope, decl) => {
|
|
1177
1177
|
// js type: 4 bits
|
1178
1178
|
// internal type: ? bits
|
1179
1179
|
// pointer: 32 bits
|
1180
|
-
|
1181
1180
|
// generic
|
1182
1181
|
// 1 23 4 5
|
1183
1182
|
// 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
|
@@ -1188,7 +1187,7 @@ const generateLogicExp = (scope, decl) => {
|
|
1188
1187
|
// 5: pointer
|
1189
1188
|
|
1190
1189
|
const isExistingProtoFunc = name => {
|
1191
|
-
if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.
|
1190
|
+
if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
|
1192
1191
|
if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
|
1193
1192
|
|
1194
1193
|
return false;
|
@@ -1247,9 +1246,9 @@ const setLastType = scope => {
|
|
1247
1246
|
const getNodeType = (scope, node) => {
|
1248
1247
|
const inner = () => {
|
1249
1248
|
if (node.type === 'Literal') {
|
1250
|
-
if (node.regex) return TYPES.
|
1249
|
+
if (node.regex) return TYPES.regexp;
|
1251
1250
|
|
1252
|
-
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.
|
1251
|
+
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.bytestring;
|
1253
1252
|
|
1254
1253
|
return TYPES[typeof node.value];
|
1255
1254
|
}
|
@@ -1273,6 +1272,18 @@ const getNodeType = (scope, node) => {
|
|
1273
1272
|
return TYPES.number;
|
1274
1273
|
}
|
1275
1274
|
|
1275
|
+
if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
|
1276
|
+
if (builtinFuncs[name + '$constructor'].typedReturns) {
|
1277
|
+
if (scope.locals['#last_type']) return getLastType(scope);
|
1278
|
+
|
1279
|
+
// presume
|
1280
|
+
// todo: warn here?
|
1281
|
+
return TYPES.number;
|
1282
|
+
}
|
1283
|
+
|
1284
|
+
return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
|
1285
|
+
}
|
1286
|
+
|
1276
1287
|
const func = funcs.find(x => x.name === name);
|
1277
1288
|
|
1278
1289
|
if (func) {
|
@@ -1291,7 +1302,7 @@ const getNodeType = (scope, node) => {
|
|
1291
1302
|
const spl = name.slice(2).split('_');
|
1292
1303
|
|
1293
1304
|
const func = spl[spl.length - 1];
|
1294
|
-
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.
|
1305
|
+
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1295
1306
|
if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
|
1296
1307
|
}
|
1297
1308
|
|
@@ -1343,7 +1354,7 @@ const getNodeType = (scope, node) => {
|
|
1343
1354
|
}
|
1344
1355
|
|
1345
1356
|
if (node.type === 'ArrayExpression') {
|
1346
|
-
return TYPES.
|
1357
|
+
return TYPES.array;
|
1347
1358
|
}
|
1348
1359
|
|
1349
1360
|
if (node.type === 'BinaryExpression') {
|
@@ -1355,7 +1366,7 @@ const getNodeType = (scope, node) => {
|
|
1355
1366
|
|
1356
1367
|
// todo: this should be dynamic but for now only static
|
1357
1368
|
if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
|
1358
|
-
if (knownLeft === TYPES.
|
1369
|
+
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1359
1370
|
|
1360
1371
|
return TYPES.number;
|
1361
1372
|
|
@@ -1381,7 +1392,7 @@ const getNodeType = (scope, node) => {
|
|
1381
1392
|
if (node.operator === '!') return TYPES.boolean;
|
1382
1393
|
if (node.operator === 'void') return TYPES.undefined;
|
1383
1394
|
if (node.operator === 'delete') return TYPES.boolean;
|
1384
|
-
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.
|
1395
|
+
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.bytestring : TYPES.string;
|
1385
1396
|
|
1386
1397
|
return TYPES.number;
|
1387
1398
|
}
|
@@ -1392,8 +1403,8 @@ const getNodeType = (scope, node) => {
|
|
1392
1403
|
|
1393
1404
|
// ts hack
|
1394
1405
|
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.
|
1406
|
+
if (scope.locals[node.object.name]?.metadata?.type === TYPES.bytestring) return TYPES.bytestring;
|
1407
|
+
if (scope.locals[node.object.name]?.metadata?.type === TYPES.array) return TYPES.number;
|
1397
1408
|
|
1398
1409
|
if (scope.locals['#last_type']) return getLastType(scope);
|
1399
1410
|
|
@@ -1460,7 +1471,7 @@ const countLeftover = wasm => {
|
|
1460
1471
|
if (depth === 0)
|
1461
1472
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1462
1473
|
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++;
|
1474
|
+
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
1475
|
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1465
1476
|
else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
|
1466
1477
|
else if (inst[0] === Opcodes.return) count = 0;
|
@@ -1634,18 +1645,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1634
1645
|
// megahack for /regex/.func()
|
1635
1646
|
const funcName = decl.callee.property.name;
|
1636
1647
|
if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
|
1637
|
-
const
|
1648
|
+
const regex = decl.callee.object.regex.pattern;
|
1649
|
+
const rhemynName = `regex_${funcName}_${regex}`;
|
1638
1650
|
|
1639
|
-
funcIndex[
|
1640
|
-
|
1651
|
+
if (!funcIndex[rhemynName]) {
|
1652
|
+
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
1653
|
+
|
1654
|
+
funcIndex[func.name] = func.index;
|
1655
|
+
funcs.push(func);
|
1656
|
+
}
|
1641
1657
|
|
1658
|
+
const idx = funcIndex[rhemynName];
|
1642
1659
|
return [
|
1643
1660
|
// make string arg
|
1644
1661
|
...generate(scope, decl.arguments[0]),
|
1662
|
+
Opcodes.i32_to_u,
|
1663
|
+
...getNodeType(scope, decl.arguments[0]),
|
1645
1664
|
|
1646
1665
|
// call regex func
|
1647
|
-
Opcodes.
|
1648
|
-
[ Opcodes.call, func.index ],
|
1666
|
+
[ Opcodes.call, idx ],
|
1649
1667
|
Opcodes.i32_from_u,
|
1650
1668
|
|
1651
1669
|
...number(TYPES.boolean, Valtype.i32),
|
@@ -1685,6 +1703,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1685
1703
|
|
1686
1704
|
protoBC[type] = generateCall(scope, {
|
1687
1705
|
callee: {
|
1706
|
+
type: 'Identifier',
|
1688
1707
|
name: x
|
1689
1708
|
},
|
1690
1709
|
arguments: [ target, ...decl.arguments ],
|
@@ -1807,20 +1826,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1807
1826
|
idx = funcIndex[name];
|
1808
1827
|
|
1809
1828
|
// infer arguments types from builtins params
|
1810
|
-
const func = funcs.find(x => x.name === name);
|
1811
|
-
for (let i = 0; i < decl.arguments.length; i++) {
|
1812
|
-
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
}
|
1829
|
+
// const func = funcs.find(x => x.name === name);
|
1830
|
+
// for (let i = 0; i < decl.arguments.length; i++) {
|
1831
|
+
// const arg = decl.arguments[i];
|
1832
|
+
// if (!arg.name) continue;
|
1833
|
+
|
1834
|
+
// const local = scope.locals[arg.name];
|
1835
|
+
// if (!local) continue;
|
1836
|
+
|
1837
|
+
// local.type = func.params[i];
|
1838
|
+
// if (local.type === Valtype.v128) {
|
1839
|
+
// // specify vec subtype inferred from last vec type in function name
|
1840
|
+
// local.vecType = name.split('_').reverse().find(x => x.includes('x'));
|
1841
|
+
// }
|
1842
|
+
// }
|
1824
1843
|
}
|
1825
1844
|
|
1826
1845
|
if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
@@ -1833,28 +1852,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1833
1852
|
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1834
1853
|
const wasmOps = {
|
1835
1854
|
// pointer, align, offset
|
1836
|
-
i32_load: { imms: 2, args:
|
1855
|
+
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
1837
1856
|
// pointer, value, align, offset
|
1838
|
-
i32_store: { imms: 2, args:
|
1857
|
+
i32_store: { imms: 2, args: [ true, true ], returns: 0 },
|
1839
1858
|
// pointer, align, offset
|
1840
|
-
i32_load8_u: { imms: 2, args:
|
1859
|
+
i32_load8_u: { imms: 2, args: [ true ], returns: 1 },
|
1841
1860
|
// pointer, value, align, offset
|
1842
|
-
i32_store8: { imms: 2, args:
|
1861
|
+
i32_store8: { imms: 2, args: [ true, true ], returns: 0 },
|
1843
1862
|
// pointer, align, offset
|
1844
|
-
i32_load16_u: { imms: 2, args:
|
1863
|
+
i32_load16_u: { imms: 2, args: [ true ], returns: 1 },
|
1845
1864
|
// pointer, value, align, offset
|
1846
|
-
i32_store16: { imms: 2, args:
|
1865
|
+
i32_store16: { imms: 2, args: [ true, true ], returns: 0 },
|
1847
1866
|
|
1848
1867
|
// pointer, align, offset
|
1849
|
-
f64_load: { imms: 2, args:
|
1868
|
+
f64_load: { imms: 2, args: [ true ], returns: 0 }, // 0 due to not i32
|
1850
1869
|
// pointer, value, align, offset
|
1851
|
-
f64_store: { imms: 2, args:
|
1870
|
+
f64_store: { imms: 2, args: [ true, false ], returns: 0 },
|
1852
1871
|
|
1853
1872
|
// value
|
1854
|
-
i32_const: { imms: 1, args:
|
1855
|
-
|
1856
|
-
// a, b
|
1857
|
-
i32_or: { imms: 0, args: 2, returns: 1 },
|
1873
|
+
i32_const: { imms: 1, args: [], returns: 1 },
|
1858
1874
|
};
|
1859
1875
|
|
1860
1876
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -1863,13 +1879,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1863
1879
|
const op = wasmOps[opName];
|
1864
1880
|
|
1865
1881
|
const argOut = [];
|
1866
|
-
for (let i = 0; i < op.args; i++) argOut.push(
|
1882
|
+
for (let i = 0; i < op.args.length; i++) argOut.push(
|
1867
1883
|
...generate(scope, decl.arguments[i]),
|
1868
|
-
Opcodes.i32_to
|
1884
|
+
...(op.args[i] ? [ Opcodes.i32_to ] : [])
|
1869
1885
|
);
|
1870
1886
|
|
1871
1887
|
// literals only
|
1872
|
-
const imms = decl.arguments.slice(op.args).map(x => x.value);
|
1888
|
+
const imms = decl.arguments.slice(op.args.length).map(x => x.value);
|
1873
1889
|
|
1874
1890
|
return [
|
1875
1891
|
...argOut,
|
@@ -2075,7 +2091,7 @@ const brTable = (input, bc, returns) => {
|
|
2075
2091
|
};
|
2076
2092
|
|
2077
2093
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
2078
|
-
if (!Prefs.bytestring) delete bc[TYPES.
|
2094
|
+
if (!Prefs.bytestring) delete bc[TYPES.bytestring];
|
2079
2095
|
|
2080
2096
|
const known = knownType(scope, type);
|
2081
2097
|
if (known != null) {
|
@@ -2148,8 +2164,8 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
|
|
2148
2164
|
|
2149
2165
|
const typeAnnoToPorfType = x => {
|
2150
2166
|
if (!x) return null;
|
2151
|
-
if (TYPES[x] != null) return TYPES[x];
|
2152
|
-
if (TYPES['_' + x] != null) return TYPES['_' + x];
|
2167
|
+
if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
|
2168
|
+
if (TYPES['_' + x.toLowerCase()] != null) return TYPES['_' + x.toLowerCase()];
|
2153
2169
|
|
2154
2170
|
switch (x) {
|
2155
2171
|
case 'i32':
|
@@ -2178,7 +2194,7 @@ const extractTypeAnnotation = decl => {
|
|
2178
2194
|
const typeName = type;
|
2179
2195
|
type = typeAnnoToPorfType(type);
|
2180
2196
|
|
2181
|
-
if (type === TYPES.
|
2197
|
+
if (type === TYPES.bytestring && !Prefs.bytestring) type = TYPES.string;
|
2182
2198
|
|
2183
2199
|
// if (decl.name) console.log(decl.name, { type, elementType });
|
2184
2200
|
|
@@ -2192,6 +2208,7 @@ const generateVar = (scope, decl) => {
|
|
2192
2208
|
|
2193
2209
|
// global variable if in top scope (main) and var ..., or if wanted
|
2194
2210
|
const global = topLevel || decl._bare; // decl.kind === 'var';
|
2211
|
+
const target = global ? globals : scope.locals;
|
2195
2212
|
|
2196
2213
|
for (const x of decl.declarations) {
|
2197
2214
|
const name = mapName(x.id.name);
|
@@ -2213,17 +2230,29 @@ const generateVar = (scope, decl) => {
|
|
2213
2230
|
continue; // always ignore
|
2214
2231
|
}
|
2215
2232
|
|
2233
|
+
// // generate init before allocating var
|
2234
|
+
// let generated;
|
2235
|
+
// if (x.init) generated = generate(scope, x.init, global, name);
|
2236
|
+
|
2216
2237
|
const typed = typedInput && x.id.typeAnnotation;
|
2217
|
-
let idx = allocVar(scope, name, global, !typed);
|
2238
|
+
let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
|
2218
2239
|
|
2219
2240
|
if (typed) {
|
2220
2241
|
addVarMetadata(scope, name, global, extractTypeAnnotation(x.id));
|
2221
2242
|
}
|
2222
2243
|
|
2223
2244
|
if (x.init) {
|
2224
|
-
|
2225
|
-
|
2226
|
-
|
2245
|
+
const generated = generate(scope, x.init, global, name);
|
2246
|
+
if (scope.arrays?.get(name) != null) {
|
2247
|
+
// hack to set local as pointer before
|
2248
|
+
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2249
|
+
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
2250
|
+
generated.pop();
|
2251
|
+
out = out.concat(generated);
|
2252
|
+
} else {
|
2253
|
+
out = out.concat(generated);
|
2254
|
+
out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2255
|
+
}
|
2227
2256
|
out.push(...setType(scope, name, getNodeType(scope, x.init)));
|
2228
2257
|
}
|
2229
2258
|
|
@@ -2250,6 +2279,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2250
2279
|
return [];
|
2251
2280
|
}
|
2252
2281
|
|
2282
|
+
const op = decl.operator.slice(0, -1) || '=';
|
2283
|
+
|
2253
2284
|
// hack: .length setter
|
2254
2285
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2255
2286
|
const name = decl.left.object.name;
|
@@ -2258,14 +2289,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2258
2289
|
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2259
2290
|
|
2260
2291
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2292
|
+
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2261
2293
|
|
2262
2294
|
return [
|
2263
2295
|
...(aotPointer ? number(0, Valtype.i32) : [
|
2264
2296
|
...generate(scope, decl.left.object),
|
2265
2297
|
Opcodes.i32_to_u
|
2266
2298
|
]),
|
2299
|
+
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2267
2300
|
|
2268
|
-
...generate(scope, decl.right),
|
2301
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2302
|
+
[ Opcodes.local_get, pointerTmp ],
|
2303
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2304
|
+
Opcodes.i32_from_u
|
2305
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
|
2269
2306
|
[ Opcodes.local_tee, newValueTmp ],
|
2270
2307
|
|
2271
2308
|
Opcodes.i32_to_u,
|
@@ -2275,8 +2312,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2275
2312
|
];
|
2276
2313
|
}
|
2277
2314
|
|
2278
|
-
const op = decl.operator.slice(0, -1) || '=';
|
2279
|
-
|
2280
2315
|
// arr[i]
|
2281
2316
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2282
2317
|
const name = decl.left.object.name;
|
@@ -2289,7 +2324,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2289
2324
|
|
2290
2325
|
return [
|
2291
2326
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2292
|
-
[TYPES.
|
2327
|
+
[TYPES.array]: [
|
2293
2328
|
...(aotPointer ? [] : [
|
2294
2329
|
...generate(scope, decl.left.object),
|
2295
2330
|
Opcodes.i32_to_u
|
@@ -2491,7 +2526,7 @@ const generateUnary = (scope, decl) => {
|
|
2491
2526
|
[TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
|
2492
2527
|
[TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
|
2493
2528
|
|
2494
|
-
[TYPES.
|
2529
|
+
[TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
|
2495
2530
|
|
2496
2531
|
// object and internal types
|
2497
2532
|
default: makeString(scope, 'object', false, '#typeof_result'),
|
@@ -2727,7 +2762,7 @@ const generateForOf = (scope, decl) => {
|
|
2727
2762
|
// set type for local
|
2728
2763
|
// todo: optimize away counter and use end pointer
|
2729
2764
|
out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
|
2730
|
-
[TYPES.
|
2765
|
+
[TYPES.array]: [
|
2731
2766
|
...setType(scope, leftName, TYPES.number),
|
2732
2767
|
|
2733
2768
|
[ Opcodes.loop, Blocktype.void ],
|
@@ -2810,8 +2845,8 @@ const generateForOf = (scope, decl) => {
|
|
2810
2845
|
[ Opcodes.end ],
|
2811
2846
|
[ Opcodes.end ]
|
2812
2847
|
],
|
2813
|
-
[TYPES.
|
2814
|
-
...setType(scope, leftName, TYPES.
|
2848
|
+
[TYPES.bytestring]: [
|
2849
|
+
...setType(scope, leftName, TYPES.bytestring),
|
2815
2850
|
|
2816
2851
|
[ Opcodes.loop, Blocktype.void ],
|
2817
2852
|
|
@@ -3080,12 +3115,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3080
3115
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3081
3116
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
3082
3117
|
|
3083
|
-
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${
|
3118
|
+
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
|
3084
3119
|
else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
|
3085
3120
|
}
|
3086
3121
|
|
3087
3122
|
const pointer = scope.arrays.get(name);
|
3088
3123
|
|
3124
|
+
const local = global ? globals[name] : scope.locals[name];
|
3125
|
+
|
3089
3126
|
const useRawElements = !!decl.rawElements;
|
3090
3127
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
3091
3128
|
|
@@ -3118,11 +3155,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3118
3155
|
return [ out, pointer ];
|
3119
3156
|
}
|
3120
3157
|
|
3158
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3159
|
+
if (pointerTmp != null) {
|
3160
|
+
out.push(
|
3161
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3162
|
+
Opcodes.i32_to_u,
|
3163
|
+
[ Opcodes.local_set, pointerTmp ]
|
3164
|
+
);
|
3165
|
+
}
|
3166
|
+
|
3167
|
+
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3168
|
+
|
3121
3169
|
// store length as 0th array
|
3122
3170
|
out.push(
|
3123
|
-
...
|
3171
|
+
...pointerWasm,
|
3124
3172
|
...number(length, Valtype.i32),
|
3125
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3173
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3126
3174
|
);
|
3127
3175
|
|
3128
3176
|
const storeOp = StoreOps[itemType];
|
@@ -3131,14 +3179,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3131
3179
|
if (elements[i] == null) continue;
|
3132
3180
|
|
3133
3181
|
out.push(
|
3134
|
-
...
|
3182
|
+
...pointerWasm,
|
3135
3183
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3136
|
-
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(
|
3184
|
+
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
|
3137
3185
|
);
|
3138
3186
|
}
|
3139
3187
|
|
3140
3188
|
// local value as pointer
|
3141
|
-
out.push(...
|
3189
|
+
out.push(...pointerWasm, Opcodes.i32_from_u);
|
3142
3190
|
|
3143
3191
|
return [ out, pointer ];
|
3144
3192
|
};
|
@@ -3189,6 +3237,16 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3189
3237
|
return number(typedParams ? func.params.length / 2 : func.params.length);
|
3190
3238
|
}
|
3191
3239
|
|
3240
|
+
if (builtinFuncs[name + '$constructor']) {
|
3241
|
+
const regularFunc = builtinFuncs[name];
|
3242
|
+
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3243
|
+
|
3244
|
+
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3245
|
+
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3246
|
+
|
3247
|
+
return number(Math.max(regularParams, constructorParams));
|
3248
|
+
}
|
3249
|
+
|
3192
3250
|
if (builtinFuncs[name]) return number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length);
|
3193
3251
|
if (importedFuncs[name]) return number(importedFuncs[name].params);
|
3194
3252
|
if (internalConstrs[name]) return number(internalConstrs[name].length ?? 0);
|
@@ -3217,7 +3275,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3217
3275
|
}
|
3218
3276
|
|
3219
3277
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3220
|
-
[TYPES.
|
3278
|
+
[TYPES.array]: [
|
3221
3279
|
// get index as valtype
|
3222
3280
|
...property,
|
3223
3281
|
|
@@ -3270,7 +3328,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3270
3328
|
...number(TYPES.string, Valtype.i32),
|
3271
3329
|
...setLastType(scope)
|
3272
3330
|
],
|
3273
|
-
[TYPES.
|
3331
|
+
[TYPES.bytestring]: [
|
3274
3332
|
// setup new/out array
|
3275
3333
|
...newOut,
|
3276
3334
|
[ Opcodes.drop ],
|
@@ -3295,7 +3353,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3295
3353
|
// return new string (page)
|
3296
3354
|
...number(newPointer),
|
3297
3355
|
|
3298
|
-
...number(TYPES.
|
3356
|
+
...number(TYPES.bytestring, Valtype.i32),
|
3299
3357
|
...setLastType(scope)
|
3300
3358
|
],
|
3301
3359
|
|
@@ -3464,7 +3522,7 @@ const internalConstrs = {
|
|
3464
3522
|
...number(pointer)
|
3465
3523
|
];
|
3466
3524
|
},
|
3467
|
-
type: TYPES.
|
3525
|
+
type: TYPES.array,
|
3468
3526
|
length: 1
|
3469
3527
|
},
|
3470
3528
|
|
@@ -3476,7 +3534,7 @@ const internalConstrs = {
|
|
3476
3534
|
elements: decl.arguments
|
3477
3535
|
}, global, name);
|
3478
3536
|
},
|
3479
|
-
type: TYPES.
|
3537
|
+
type: TYPES.array,
|
3480
3538
|
notConstr: true,
|
3481
3539
|
length: 0
|
3482
3540
|
},
|
@@ -3493,6 +3551,8 @@ const internalConstrs = {
|
|
3493
3551
|
);
|
3494
3552
|
}
|
3495
3553
|
|
3554
|
+
out.push(Opcodes.i32_from_u);
|
3555
|
+
|
3496
3556
|
return out;
|
3497
3557
|
},
|
3498
3558
|
type: TYPES.boolean,
|
@@ -3511,6 +3571,8 @@ const internalConstrs = {
|
|
3511
3571
|
);
|
3512
3572
|
}
|
3513
3573
|
|
3574
|
+
out.push(Opcodes.i32_from_u);
|
3575
|
+
|
3514
3576
|
return out;
|
3515
3577
|
},
|
3516
3578
|
type: TYPES.boolean,
|
@@ -3565,25 +3627,41 @@ const internalConstrs = {
|
|
3565
3627
|
type: TYPES.number,
|
3566
3628
|
notConstr: true,
|
3567
3629
|
length: 2
|
3568
|
-
}
|
3569
|
-
|
3630
|
+
},
|
3631
|
+
|
3632
|
+
__console_log: {
|
3633
|
+
generate: (scope, decl) => {
|
3634
|
+
const out = [];
|
3570
3635
|
|
3571
|
-
|
3572
|
-
|
3573
|
-
|
3574
|
-
|
3575
|
-
|
3576
|
-
|
3577
|
-
|
3578
|
-
|
3579
|
-
|
3580
|
-
|
3581
|
-
//
|
3582
|
-
|
3583
|
-
|
3636
|
+
for (let i = 0; i < decl.arguments.length; i++) {
|
3637
|
+
out.push(
|
3638
|
+
...generateCall(scope, {
|
3639
|
+
callee: {
|
3640
|
+
type: 'Identifier',
|
3641
|
+
name: '__Porffor_print'
|
3642
|
+
},
|
3643
|
+
arguments: [ decl.arguments[i] ]
|
3644
|
+
}),
|
3645
|
+
|
3646
|
+
// print space
|
3647
|
+
...number(32),
|
3648
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3649
|
+
);
|
3650
|
+
}
|
3584
3651
|
|
3585
|
-
//
|
3586
|
-
|
3652
|
+
// print newline
|
3653
|
+
out.push(
|
3654
|
+
...number(10),
|
3655
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3656
|
+
);
|
3657
|
+
|
3658
|
+
return out;
|
3659
|
+
},
|
3660
|
+
type: TYPES.undefined,
|
3661
|
+
notConstr: true,
|
3662
|
+
length: 0
|
3663
|
+
}
|
3664
|
+
};
|
3587
3665
|
|
3588
3666
|
export default program => {
|
3589
3667
|
globals = {};
|
@@ -3599,7 +3677,7 @@ export default program => {
|
|
3599
3677
|
|
3600
3678
|
globalThis.valtype = 'f64';
|
3601
3679
|
|
3602
|
-
const valtypeOpt = process.argv.find(x => x.startsWith('
|
3680
|
+
const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
|
3603
3681
|
if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
|
3604
3682
|
|
3605
3683
|
globalThis.valtypeBinary = Valtype[valtype];
|
@@ -3607,7 +3685,7 @@ export default program => {
|
|
3607
3685
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3608
3686
|
|
3609
3687
|
globalThis.pageSize = PageSize;
|
3610
|
-
const pageSizeOpt = process.argv.find(x => x.startsWith('
|
3688
|
+
const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
|
3611
3689
|
if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
|
3612
3690
|
|
3613
3691
|
// set generic opcodes for current valtype
|