porffor 0.2.0-9928127 → 0.2.0-9f58210
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 +63 -44
- package/asur/index.js +1 -1
- package/compiler/assemble.js +1 -1
- 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 +20 -0
- package/compiler/builtins/crypto.ts +1 -1
- package/compiler/builtins/date.ts +799 -99
- 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 +177 -88
- package/compiler/decompile.js +0 -1
- package/compiler/generated_builtins.js +429 -174
- package/compiler/parse.js +4 -2
- package/compiler/precompile.js +7 -2
- package/compiler/prefs.js +6 -5
- package/compiler/prototype.js +14 -14
- package/compiler/types.js +1 -1
- package/compiler/wrap.js +3 -3
- 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/compiler/codegen.js
CHANGED
@@ -59,6 +59,10 @@ const todo = (scope, msg, expectsValue = undefined) => {
|
|
59
59
|
};
|
60
60
|
|
61
61
|
const isFuncType = type => type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
|
62
|
+
const hasFuncWithName = name => {
|
63
|
+
const func = funcs.find(x => x.name === name);
|
64
|
+
return !!(func || builtinFuncs[name] || importedFuncs[name] || internalConstrs[name]);
|
65
|
+
};
|
62
66
|
const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
|
63
67
|
switch (decl.type) {
|
64
68
|
case 'BinaryExpression':
|
@@ -201,7 +205,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
201
205
|
}
|
202
206
|
|
203
207
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
204
|
-
if (
|
208
|
+
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
205
209
|
|
206
210
|
if (!Array.isArray(inst)) inst = [ inst ];
|
207
211
|
const immediates = asm.slice(1).map(x => {
|
@@ -219,8 +223,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
219
223
|
__Porffor_bs: str => [
|
220
224
|
...makeString(scope, str, global, name, true),
|
221
225
|
|
222
|
-
...(name ? setType(scope, name, TYPES.
|
223
|
-
...number(TYPES.
|
226
|
+
...(name ? setType(scope, name, TYPES.bytestring) : [
|
227
|
+
...number(TYPES.bytestring, Valtype.i32),
|
224
228
|
...setLastType(scope)
|
225
229
|
])
|
226
230
|
],
|
@@ -460,7 +464,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
460
464
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
461
465
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
462
466
|
|
463
|
-
if (assign) {
|
467
|
+
if (assign && Prefs.aotPointerOpt) {
|
464
468
|
const pointer = scope.arrays?.get(name ?? '$undeclared');
|
465
469
|
|
466
470
|
return [
|
@@ -723,7 +727,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
723
727
|
|
724
728
|
...typeSwitch(scope, type, {
|
725
729
|
// [TYPES.number]: def,
|
726
|
-
[TYPES.
|
730
|
+
[TYPES.array]: [
|
727
731
|
// arrays are always truthy
|
728
732
|
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
729
733
|
],
|
@@ -739,7 +743,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
739
743
|
[ Opcodes.i32_eqz ], */
|
740
744
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
741
745
|
],
|
742
|
-
[TYPES.
|
746
|
+
[TYPES.bytestring]: [ // duplicate of string
|
743
747
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
744
748
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
745
749
|
|
@@ -762,7 +766,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
762
766
|
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
763
767
|
|
764
768
|
...typeSwitch(scope, type, {
|
765
|
-
[TYPES.
|
769
|
+
[TYPES.array]: [
|
766
770
|
// arrays are always truthy
|
767
771
|
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
768
772
|
],
|
@@ -777,7 +781,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
777
781
|
[ Opcodes.i32_eqz ],
|
778
782
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
779
783
|
],
|
780
|
-
[TYPES.
|
784
|
+
[TYPES.bytestring]: [ // duplicate of string
|
781
785
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
782
786
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
783
787
|
|
@@ -922,7 +926,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
922
926
|
}
|
923
927
|
}
|
924
928
|
|
925
|
-
if (knownLeft === TYPES.
|
929
|
+
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
|
926
930
|
if (op === '+') {
|
927
931
|
// todo: this should be dynamic too but for now only static
|
928
932
|
// string concat (a + b)
|
@@ -1041,12 +1045,12 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
1041
1045
|
|
1042
1046
|
// if left is bytestring
|
1043
1047
|
...leftType,
|
1044
|
-
...number(TYPES.
|
1048
|
+
...number(TYPES.bytestring, Valtype.i32),
|
1045
1049
|
[ Opcodes.i32_eq ],
|
1046
1050
|
|
1047
1051
|
// if right is bytestring
|
1048
1052
|
...rightType,
|
1049
|
-
...number(TYPES.
|
1053
|
+
...number(TYPES.bytestring, Valtype.i32),
|
1050
1054
|
[ Opcodes.i32_eq ],
|
1051
1055
|
|
1052
1056
|
// if both are true
|
@@ -1177,7 +1181,6 @@ const generateLogicExp = (scope, decl) => {
|
|
1177
1181
|
// js type: 4 bits
|
1178
1182
|
// internal type: ? bits
|
1179
1183
|
// pointer: 32 bits
|
1180
|
-
|
1181
1184
|
// generic
|
1182
1185
|
// 1 23 4 5
|
1183
1186
|
// 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
|
@@ -1188,7 +1191,7 @@ const generateLogicExp = (scope, decl) => {
|
|
1188
1191
|
// 5: pointer
|
1189
1192
|
|
1190
1193
|
const isExistingProtoFunc = name => {
|
1191
|
-
if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.
|
1194
|
+
if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
|
1192
1195
|
if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
|
1193
1196
|
|
1194
1197
|
return false;
|
@@ -1247,9 +1250,9 @@ const setLastType = scope => {
|
|
1247
1250
|
const getNodeType = (scope, node) => {
|
1248
1251
|
const inner = () => {
|
1249
1252
|
if (node.type === 'Literal') {
|
1250
|
-
if (node.regex) return TYPES.
|
1253
|
+
if (node.regex) return TYPES.regexp;
|
1251
1254
|
|
1252
|
-
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.
|
1255
|
+
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.bytestring;
|
1253
1256
|
|
1254
1257
|
return TYPES[typeof node.value];
|
1255
1258
|
}
|
@@ -1303,7 +1306,7 @@ const getNodeType = (scope, node) => {
|
|
1303
1306
|
const spl = name.slice(2).split('_');
|
1304
1307
|
|
1305
1308
|
const func = spl[spl.length - 1];
|
1306
|
-
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.
|
1309
|
+
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1307
1310
|
if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
|
1308
1311
|
}
|
1309
1312
|
|
@@ -1355,7 +1358,7 @@ const getNodeType = (scope, node) => {
|
|
1355
1358
|
}
|
1356
1359
|
|
1357
1360
|
if (node.type === 'ArrayExpression') {
|
1358
|
-
return TYPES.
|
1361
|
+
return TYPES.array;
|
1359
1362
|
}
|
1360
1363
|
|
1361
1364
|
if (node.type === 'BinaryExpression') {
|
@@ -1367,7 +1370,7 @@ const getNodeType = (scope, node) => {
|
|
1367
1370
|
|
1368
1371
|
// todo: this should be dynamic but for now only static
|
1369
1372
|
if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
|
1370
|
-
if (knownLeft === TYPES.
|
1373
|
+
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1371
1374
|
|
1372
1375
|
return TYPES.number;
|
1373
1376
|
|
@@ -1393,19 +1396,28 @@ const getNodeType = (scope, node) => {
|
|
1393
1396
|
if (node.operator === '!') return TYPES.boolean;
|
1394
1397
|
if (node.operator === 'void') return TYPES.undefined;
|
1395
1398
|
if (node.operator === 'delete') return TYPES.boolean;
|
1396
|
-
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.
|
1399
|
+
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.bytestring : TYPES.string;
|
1397
1400
|
|
1398
1401
|
return TYPES.number;
|
1399
1402
|
}
|
1400
1403
|
|
1401
1404
|
if (node.type === 'MemberExpression') {
|
1405
|
+
// hack: if something.name, string type
|
1406
|
+
if (node.property.name === 'name') {
|
1407
|
+
if (hasFuncWithName(node.object.name)) {
|
1408
|
+
return TYPES.bytestring;
|
1409
|
+
} else {
|
1410
|
+
return TYPES.undefined;
|
1411
|
+
}
|
1412
|
+
}
|
1413
|
+
|
1402
1414
|
// hack: if something.length, number type
|
1403
1415
|
if (node.property.name === 'length') return TYPES.number;
|
1404
1416
|
|
1405
1417
|
// ts hack
|
1406
1418
|
if (scope.locals[node.object.name]?.metadata?.type === TYPES.string) return TYPES.string;
|
1407
|
-
if (scope.locals[node.object.name]?.metadata?.type === TYPES.
|
1408
|
-
if (scope.locals[node.object.name]?.metadata?.type === TYPES.
|
1419
|
+
if (scope.locals[node.object.name]?.metadata?.type === TYPES.bytestring) return TYPES.bytestring;
|
1420
|
+
if (scope.locals[node.object.name]?.metadata?.type === TYPES.array) return TYPES.number;
|
1409
1421
|
|
1410
1422
|
if (scope.locals['#last_type']) return getLastType(scope);
|
1411
1423
|
|
@@ -1646,18 +1658,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1646
1658
|
// megahack for /regex/.func()
|
1647
1659
|
const funcName = decl.callee.property.name;
|
1648
1660
|
if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
|
1649
|
-
const
|
1661
|
+
const regex = decl.callee.object.regex.pattern;
|
1662
|
+
const rhemynName = `regex_${funcName}_${regex}`;
|
1663
|
+
|
1664
|
+
if (!funcIndex[rhemynName]) {
|
1665
|
+
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
1650
1666
|
|
1651
|
-
|
1652
|
-
|
1667
|
+
funcIndex[func.name] = func.index;
|
1668
|
+
funcs.push(func);
|
1669
|
+
}
|
1653
1670
|
|
1671
|
+
const idx = funcIndex[rhemynName];
|
1654
1672
|
return [
|
1655
1673
|
// make string arg
|
1656
1674
|
...generate(scope, decl.arguments[0]),
|
1675
|
+
Opcodes.i32_to_u,
|
1676
|
+
...getNodeType(scope, decl.arguments[0]),
|
1657
1677
|
|
1658
1678
|
// call regex func
|
1659
|
-
Opcodes.
|
1660
|
-
[ Opcodes.call, func.index ],
|
1679
|
+
[ Opcodes.call, idx ],
|
1661
1680
|
Opcodes.i32_from_u,
|
1662
1681
|
|
1663
1682
|
...number(TYPES.boolean, Valtype.i32),
|
@@ -1697,6 +1716,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1697
1716
|
|
1698
1717
|
protoBC[type] = generateCall(scope, {
|
1699
1718
|
callee: {
|
1719
|
+
type: 'Identifier',
|
1700
1720
|
name: x
|
1701
1721
|
},
|
1702
1722
|
arguments: [ target, ...decl.arguments ],
|
@@ -1819,20 +1839,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1819
1839
|
idx = funcIndex[name];
|
1820
1840
|
|
1821
1841
|
// infer arguments types from builtins params
|
1822
|
-
const func = funcs.find(x => x.name === name);
|
1823
|
-
for (let i = 0; i < decl.arguments.length; i++) {
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
}
|
1842
|
+
// const func = funcs.find(x => x.name === name);
|
1843
|
+
// for (let i = 0; i < decl.arguments.length; i++) {
|
1844
|
+
// const arg = decl.arguments[i];
|
1845
|
+
// if (!arg.name) continue;
|
1846
|
+
|
1847
|
+
// const local = scope.locals[arg.name];
|
1848
|
+
// if (!local) continue;
|
1849
|
+
|
1850
|
+
// local.type = func.params[i];
|
1851
|
+
// if (local.type === Valtype.v128) {
|
1852
|
+
// // specify vec subtype inferred from last vec type in function name
|
1853
|
+
// local.vecType = name.split('_').reverse().find(x => x.includes('x'));
|
1854
|
+
// }
|
1855
|
+
// }
|
1836
1856
|
}
|
1837
1857
|
|
1838
1858
|
if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
@@ -1864,9 +1884,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1864
1884
|
|
1865
1885
|
// value
|
1866
1886
|
i32_const: { imms: 1, args: [], returns: 1 },
|
1867
|
-
|
1868
|
-
// a, b
|
1869
|
-
i32_or: { imms: 0, args: [ true, true ], returns: 1 },
|
1870
1887
|
};
|
1871
1888
|
|
1872
1889
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -2087,7 +2104,7 @@ const brTable = (input, bc, returns) => {
|
|
2087
2104
|
};
|
2088
2105
|
|
2089
2106
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
2090
|
-
if (!Prefs.bytestring) delete bc[TYPES.
|
2107
|
+
if (!Prefs.bytestring) delete bc[TYPES.bytestring];
|
2091
2108
|
|
2092
2109
|
const known = knownType(scope, type);
|
2093
2110
|
if (known != null) {
|
@@ -2190,7 +2207,7 @@ const extractTypeAnnotation = decl => {
|
|
2190
2207
|
const typeName = type;
|
2191
2208
|
type = typeAnnoToPorfType(type);
|
2192
2209
|
|
2193
|
-
if (type === TYPES.
|
2210
|
+
if (type === TYPES.bytestring && !Prefs.bytestring) type = TYPES.string;
|
2194
2211
|
|
2195
2212
|
// if (decl.name) console.log(decl.name, { type, elementType });
|
2196
2213
|
|
@@ -2204,6 +2221,7 @@ const generateVar = (scope, decl) => {
|
|
2204
2221
|
|
2205
2222
|
// global variable if in top scope (main) and var ..., or if wanted
|
2206
2223
|
const global = topLevel || decl._bare; // decl.kind === 'var';
|
2224
|
+
const target = global ? globals : scope.locals;
|
2207
2225
|
|
2208
2226
|
for (const x of decl.declarations) {
|
2209
2227
|
const name = mapName(x.id.name);
|
@@ -2225,6 +2243,10 @@ const generateVar = (scope, decl) => {
|
|
2225
2243
|
continue; // always ignore
|
2226
2244
|
}
|
2227
2245
|
|
2246
|
+
// // generate init before allocating var
|
2247
|
+
// let generated;
|
2248
|
+
// if (x.init) generated = generate(scope, x.init, global, name);
|
2249
|
+
|
2228
2250
|
const typed = typedInput && x.id.typeAnnotation;
|
2229
2251
|
let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
|
2230
2252
|
|
@@ -2233,9 +2255,17 @@ const generateVar = (scope, decl) => {
|
|
2233
2255
|
}
|
2234
2256
|
|
2235
2257
|
if (x.init) {
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2258
|
+
const generated = generate(scope, x.init, global, name);
|
2259
|
+
if (scope.arrays?.get(name) != null) {
|
2260
|
+
// hack to set local as pointer before
|
2261
|
+
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2262
|
+
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
2263
|
+
generated.pop();
|
2264
|
+
out = out.concat(generated);
|
2265
|
+
} else {
|
2266
|
+
out = out.concat(generated);
|
2267
|
+
out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2268
|
+
}
|
2239
2269
|
out.push(...setType(scope, name, getNodeType(scope, x.init)));
|
2240
2270
|
}
|
2241
2271
|
|
@@ -2262,6 +2292,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2262
2292
|
return [];
|
2263
2293
|
}
|
2264
2294
|
|
2295
|
+
const op = decl.operator.slice(0, -1) || '=';
|
2296
|
+
|
2265
2297
|
// hack: .length setter
|
2266
2298
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2267
2299
|
const name = decl.left.object.name;
|
@@ -2270,14 +2302,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2270
2302
|
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2271
2303
|
|
2272
2304
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2305
|
+
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2273
2306
|
|
2274
2307
|
return [
|
2275
2308
|
...(aotPointer ? number(0, Valtype.i32) : [
|
2276
2309
|
...generate(scope, decl.left.object),
|
2277
2310
|
Opcodes.i32_to_u
|
2278
2311
|
]),
|
2312
|
+
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2279
2313
|
|
2280
|
-
...generate(scope, decl.right),
|
2314
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2315
|
+
[ Opcodes.local_get, pointerTmp ],
|
2316
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2317
|
+
Opcodes.i32_from_u
|
2318
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
|
2281
2319
|
[ Opcodes.local_tee, newValueTmp ],
|
2282
2320
|
|
2283
2321
|
Opcodes.i32_to_u,
|
@@ -2287,8 +2325,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2287
2325
|
];
|
2288
2326
|
}
|
2289
2327
|
|
2290
|
-
const op = decl.operator.slice(0, -1) || '=';
|
2291
|
-
|
2292
2328
|
// arr[i]
|
2293
2329
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2294
2330
|
const name = decl.left.object.name;
|
@@ -2301,7 +2337,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2301
2337
|
|
2302
2338
|
return [
|
2303
2339
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2304
|
-
[TYPES.
|
2340
|
+
[TYPES.array]: [
|
2305
2341
|
...(aotPointer ? [] : [
|
2306
2342
|
...generate(scope, decl.left.object),
|
2307
2343
|
Opcodes.i32_to_u
|
@@ -2503,7 +2539,7 @@ const generateUnary = (scope, decl) => {
|
|
2503
2539
|
[TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
|
2504
2540
|
[TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
|
2505
2541
|
|
2506
|
-
[TYPES.
|
2542
|
+
[TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
|
2507
2543
|
|
2508
2544
|
// object and internal types
|
2509
2545
|
default: makeString(scope, 'object', false, '#typeof_result'),
|
@@ -2739,7 +2775,7 @@ const generateForOf = (scope, decl) => {
|
|
2739
2775
|
// set type for local
|
2740
2776
|
// todo: optimize away counter and use end pointer
|
2741
2777
|
out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
|
2742
|
-
[TYPES.
|
2778
|
+
[TYPES.array]: [
|
2743
2779
|
...setType(scope, leftName, TYPES.number),
|
2744
2780
|
|
2745
2781
|
[ Opcodes.loop, Blocktype.void ],
|
@@ -2822,8 +2858,8 @@ const generateForOf = (scope, decl) => {
|
|
2822
2858
|
[ Opcodes.end ],
|
2823
2859
|
[ Opcodes.end ]
|
2824
2860
|
],
|
2825
|
-
[TYPES.
|
2826
|
-
...setType(scope, leftName, TYPES.
|
2861
|
+
[TYPES.bytestring]: [
|
2862
|
+
...setType(scope, leftName, TYPES.bytestring),
|
2827
2863
|
|
2828
2864
|
[ Opcodes.loop, Blocktype.void ],
|
2829
2865
|
|
@@ -3092,12 +3128,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3092
3128
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3093
3129
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
3094
3130
|
|
3095
|
-
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${
|
3131
|
+
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
|
3096
3132
|
else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
|
3097
3133
|
}
|
3098
3134
|
|
3099
3135
|
const pointer = scope.arrays.get(name);
|
3100
3136
|
|
3137
|
+
const local = global ? globals[name] : scope.locals[name];
|
3138
|
+
|
3101
3139
|
const useRawElements = !!decl.rawElements;
|
3102
3140
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
3103
3141
|
|
@@ -3130,11 +3168,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3130
3168
|
return [ out, pointer ];
|
3131
3169
|
}
|
3132
3170
|
|
3171
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3172
|
+
if (pointerTmp != null) {
|
3173
|
+
out.push(
|
3174
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3175
|
+
Opcodes.i32_to_u,
|
3176
|
+
[ Opcodes.local_set, pointerTmp ]
|
3177
|
+
);
|
3178
|
+
}
|
3179
|
+
|
3180
|
+
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3181
|
+
|
3133
3182
|
// store length as 0th array
|
3134
3183
|
out.push(
|
3135
|
-
...
|
3184
|
+
...pointerWasm,
|
3136
3185
|
...number(length, Valtype.i32),
|
3137
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3186
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3138
3187
|
);
|
3139
3188
|
|
3140
3189
|
const storeOp = StoreOps[itemType];
|
@@ -3143,14 +3192,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3143
3192
|
if (elements[i] == null) continue;
|
3144
3193
|
|
3145
3194
|
out.push(
|
3146
|
-
...
|
3195
|
+
...pointerWasm,
|
3147
3196
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3148
|
-
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(
|
3197
|
+
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
|
3149
3198
|
);
|
3150
3199
|
}
|
3151
3200
|
|
3152
3201
|
// local value as pointer
|
3153
|
-
out.push(...
|
3202
|
+
out.push(...pointerWasm, Opcodes.i32_from_u);
|
3154
3203
|
|
3155
3204
|
return [ out, pointer ];
|
3156
3205
|
};
|
@@ -3192,6 +3241,20 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3192
3241
|
|
3193
3242
|
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
3194
3243
|
|
3244
|
+
// hack: .name
|
3245
|
+
if (decl.property.name === 'name') {
|
3246
|
+
if (hasFuncWithName(name)) {
|
3247
|
+
let nameProp = name;
|
3248
|
+
|
3249
|
+
// eg: __String_prototype_toLowerCase -> toLowerCase
|
3250
|
+
if (nameProp.startsWith('__')) nameProp = nameProp.split('_').pop();
|
3251
|
+
|
3252
|
+
return makeString(scope, nameProp, _global, _name, true);
|
3253
|
+
} else {
|
3254
|
+
return generate(scope, DEFAULT_VALUE);
|
3255
|
+
}
|
3256
|
+
}
|
3257
|
+
|
3195
3258
|
// hack: .length
|
3196
3259
|
if (decl.property.name === 'length') {
|
3197
3260
|
const func = funcs.find(x => x.name === name);
|
@@ -3201,6 +3264,16 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3201
3264
|
return number(typedParams ? func.params.length / 2 : func.params.length);
|
3202
3265
|
}
|
3203
3266
|
|
3267
|
+
if (builtinFuncs[name + '$constructor']) {
|
3268
|
+
const regularFunc = builtinFuncs[name];
|
3269
|
+
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3270
|
+
|
3271
|
+
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3272
|
+
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3273
|
+
|
3274
|
+
return number(Math.max(regularParams, constructorParams));
|
3275
|
+
}
|
3276
|
+
|
3204
3277
|
if (builtinFuncs[name]) return number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length);
|
3205
3278
|
if (importedFuncs[name]) return number(importedFuncs[name].params);
|
3206
3279
|
if (internalConstrs[name]) return number(internalConstrs[name].length ?? 0);
|
@@ -3229,7 +3302,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3229
3302
|
}
|
3230
3303
|
|
3231
3304
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3232
|
-
[TYPES.
|
3305
|
+
[TYPES.array]: [
|
3233
3306
|
// get index as valtype
|
3234
3307
|
...property,
|
3235
3308
|
|
@@ -3282,7 +3355,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3282
3355
|
...number(TYPES.string, Valtype.i32),
|
3283
3356
|
...setLastType(scope)
|
3284
3357
|
],
|
3285
|
-
[TYPES.
|
3358
|
+
[TYPES.bytestring]: [
|
3286
3359
|
// setup new/out array
|
3287
3360
|
...newOut,
|
3288
3361
|
[ Opcodes.drop ],
|
@@ -3307,7 +3380,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3307
3380
|
// return new string (page)
|
3308
3381
|
...number(newPointer),
|
3309
3382
|
|
3310
|
-
...number(TYPES.
|
3383
|
+
...number(TYPES.bytestring, Valtype.i32),
|
3311
3384
|
...setLastType(scope)
|
3312
3385
|
],
|
3313
3386
|
|
@@ -3332,8 +3405,8 @@ const objectHack = node => {
|
|
3332
3405
|
|
3333
3406
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3334
3407
|
|
3335
|
-
// if .length, give up (hack within a hack!)
|
3336
|
-
if (node.property.name
|
3408
|
+
// if .name or .length, give up (hack within a hack!)
|
3409
|
+
if (['name', 'length'].includes(node.property.name)) {
|
3337
3410
|
node.object = objectHack(node.object);
|
3338
3411
|
return;
|
3339
3412
|
}
|
@@ -3476,7 +3549,7 @@ const internalConstrs = {
|
|
3476
3549
|
...number(pointer)
|
3477
3550
|
];
|
3478
3551
|
},
|
3479
|
-
type: TYPES.
|
3552
|
+
type: TYPES.array,
|
3480
3553
|
length: 1
|
3481
3554
|
},
|
3482
3555
|
|
@@ -3488,7 +3561,7 @@ const internalConstrs = {
|
|
3488
3561
|
elements: decl.arguments
|
3489
3562
|
}, global, name);
|
3490
3563
|
},
|
3491
|
-
type: TYPES.
|
3564
|
+
type: TYPES.array,
|
3492
3565
|
notConstr: true,
|
3493
3566
|
length: 0
|
3494
3567
|
},
|
@@ -3581,25 +3654,41 @@ const internalConstrs = {
|
|
3581
3654
|
type: TYPES.number,
|
3582
3655
|
notConstr: true,
|
3583
3656
|
length: 2
|
3584
|
-
}
|
3585
|
-
};
|
3657
|
+
},
|
3586
3658
|
|
3587
|
-
|
3588
|
-
|
3589
|
-
|
3590
|
-
|
3591
|
-
|
3592
|
-
|
3593
|
-
|
3594
|
-
|
3595
|
-
|
3596
|
-
|
3597
|
-
|
3598
|
-
|
3599
|
-
|
3659
|
+
__console_log: {
|
3660
|
+
generate: (scope, decl) => {
|
3661
|
+
const out = [];
|
3662
|
+
|
3663
|
+
for (let i = 0; i < decl.arguments.length; i++) {
|
3664
|
+
out.push(
|
3665
|
+
...generateCall(scope, {
|
3666
|
+
callee: {
|
3667
|
+
type: 'Identifier',
|
3668
|
+
name: '__Porffor_print'
|
3669
|
+
},
|
3670
|
+
arguments: [ decl.arguments[i] ]
|
3671
|
+
}),
|
3672
|
+
|
3673
|
+
// print space
|
3674
|
+
...number(32),
|
3675
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3676
|
+
);
|
3677
|
+
}
|
3678
|
+
|
3679
|
+
// print newline
|
3680
|
+
out.push(
|
3681
|
+
...number(10),
|
3682
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3683
|
+
);
|
3600
3684
|
|
3601
|
-
|
3602
|
-
|
3685
|
+
return out;
|
3686
|
+
},
|
3687
|
+
type: TYPES.undefined,
|
3688
|
+
notConstr: true,
|
3689
|
+
length: 0
|
3690
|
+
}
|
3691
|
+
};
|
3603
3692
|
|
3604
3693
|
export default program => {
|
3605
3694
|
globals = {};
|
@@ -3615,7 +3704,7 @@ export default program => {
|
|
3615
3704
|
|
3616
3705
|
globalThis.valtype = 'f64';
|
3617
3706
|
|
3618
|
-
const valtypeOpt = process.argv.find(x => x.startsWith('
|
3707
|
+
const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
|
3619
3708
|
if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
|
3620
3709
|
|
3621
3710
|
globalThis.valtypeBinary = Valtype[valtype];
|
@@ -3623,7 +3712,7 @@ export default program => {
|
|
3623
3712
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3624
3713
|
|
3625
3714
|
globalThis.pageSize = PageSize;
|
3626
|
-
const pageSizeOpt = process.argv.find(x => x.startsWith('
|
3715
|
+
const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
|
3627
3716
|
if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
|
3628
3717
|
|
3629
3718
|
// set generic opcodes for current valtype
|