porffor 0.2.0-a6c01f5 → 0.2.0-a88bbe6
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 +17 -30
- package/asur/index.js +1 -1
- package/compiler/assemble.js +1 -1
- 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 +797 -100
- 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 +22 -4
- package/compiler/builtins/set.ts +188 -0
- package/compiler/builtins/string.ts +47 -22
- package/compiler/builtins.js +4 -25
- package/compiler/codegen.js +139 -108
- package/compiler/decompile.js +0 -1
- package/compiler/generated_builtins.js +667 -304
- package/compiler/opt.js +3 -3
- package/compiler/parse.js +4 -2
- package/compiler/precompile.js +20 -23
- package/compiler/prefs.js +6 -5
- package/compiler/prototype.js +14 -14
- package/compiler/types.js +3 -2
- package/compiler/wrap.js +67 -54
- package/package.json +1 -1
- package/rhemyn/compile.js +42 -25
- package/rhemyn/parse.js +4 -5
- package/runner/index.js +22 -6
- package/runner/repl.js +2 -2
- package/runner/sizes.js +1 -1
- package/compiler/builtins/tostring.ts +0 -45
- package/fib.js +0 -7
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':
|
@@ -167,11 +171,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
167
171
|
newFunc.export = true;
|
168
172
|
}
|
169
173
|
|
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
174
|
return [];
|
176
175
|
|
177
176
|
case 'TaggedTemplateExpression': {
|
@@ -201,7 +200,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
201
200
|
}
|
202
201
|
|
203
202
|
let inst = Opcodes[asm[0].replace('.', '_')];
|
204
|
-
if (
|
203
|
+
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
205
204
|
|
206
205
|
if (!Array.isArray(inst)) inst = [ inst ];
|
207
206
|
const immediates = asm.slice(1).map(x => {
|
@@ -219,8 +218,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
219
218
|
__Porffor_bs: str => [
|
220
219
|
...makeString(scope, str, global, name, true),
|
221
220
|
|
222
|
-
...(name ? setType(scope, name, TYPES.
|
223
|
-
...number(TYPES.
|
221
|
+
...(name ? setType(scope, name, TYPES.bytestring) : [
|
222
|
+
...number(TYPES.bytestring, Valtype.i32),
|
224
223
|
...setLastType(scope)
|
225
224
|
])
|
226
225
|
],
|
@@ -460,7 +459,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
460
459
|
const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
|
461
460
|
const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
|
462
461
|
|
463
|
-
if (assign) {
|
462
|
+
if (assign && Prefs.aotPointerOpt) {
|
464
463
|
const pointer = scope.arrays?.get(name ?? '$undeclared');
|
465
464
|
|
466
465
|
return [
|
@@ -723,7 +722,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
723
722
|
|
724
723
|
...typeSwitch(scope, type, {
|
725
724
|
// [TYPES.number]: def,
|
726
|
-
[TYPES.
|
725
|
+
[TYPES.array]: [
|
727
726
|
// arrays are always truthy
|
728
727
|
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
729
728
|
],
|
@@ -739,7 +738,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
739
738
|
[ Opcodes.i32_eqz ], */
|
740
739
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
741
740
|
],
|
742
|
-
[TYPES.
|
741
|
+
[TYPES.bytestring]: [ // duplicate of string
|
743
742
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
744
743
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
745
744
|
|
@@ -762,7 +761,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
762
761
|
...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
|
763
762
|
|
764
763
|
...typeSwitch(scope, type, {
|
765
|
-
[TYPES.
|
764
|
+
[TYPES.array]: [
|
766
765
|
// arrays are always truthy
|
767
766
|
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
768
767
|
],
|
@@ -777,7 +776,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
777
776
|
[ Opcodes.i32_eqz ],
|
778
777
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
779
778
|
],
|
780
|
-
[TYPES.
|
779
|
+
[TYPES.bytestring]: [ // duplicate of string
|
781
780
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
782
781
|
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
783
782
|
|
@@ -922,7 +921,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
922
921
|
}
|
923
922
|
}
|
924
923
|
|
925
|
-
if (knownLeft === TYPES.
|
924
|
+
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
|
926
925
|
if (op === '+') {
|
927
926
|
// todo: this should be dynamic too but for now only static
|
928
927
|
// string concat (a + b)
|
@@ -1041,12 +1040,12 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
1041
1040
|
|
1042
1041
|
// if left is bytestring
|
1043
1042
|
...leftType,
|
1044
|
-
...number(TYPES.
|
1043
|
+
...number(TYPES.bytestring, Valtype.i32),
|
1045
1044
|
[ Opcodes.i32_eq ],
|
1046
1045
|
|
1047
1046
|
// if right is bytestring
|
1048
1047
|
...rightType,
|
1049
|
-
...number(TYPES.
|
1048
|
+
...number(TYPES.bytestring, Valtype.i32),
|
1050
1049
|
[ Opcodes.i32_eq ],
|
1051
1050
|
|
1052
1051
|
// if both are true
|
@@ -1085,7 +1084,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
1085
1084
|
|
1086
1085
|
const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals = [], returns = [], localInd = 0 }) => {
|
1087
1086
|
return func({ name, params, locals, returns, localInd }, {
|
1088
|
-
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage,
|
1087
|
+
TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
|
1089
1088
|
builtin: name => {
|
1090
1089
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1091
1090
|
if (idx === undefined && builtinFuncs[name]) {
|
@@ -1177,7 +1176,6 @@ const generateLogicExp = (scope, decl) => {
|
|
1177
1176
|
// js type: 4 bits
|
1178
1177
|
// internal type: ? bits
|
1179
1178
|
// pointer: 32 bits
|
1180
|
-
|
1181
1179
|
// generic
|
1182
1180
|
// 1 23 4 5
|
1183
1181
|
// 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
|
@@ -1188,7 +1186,7 @@ const generateLogicExp = (scope, decl) => {
|
|
1188
1186
|
// 5: pointer
|
1189
1187
|
|
1190
1188
|
const isExistingProtoFunc = name => {
|
1191
|
-
if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.
|
1189
|
+
if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
|
1192
1190
|
if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
|
1193
1191
|
|
1194
1192
|
return false;
|
@@ -1245,11 +1243,11 @@ const setLastType = scope => {
|
|
1245
1243
|
};
|
1246
1244
|
|
1247
1245
|
const getNodeType = (scope, node) => {
|
1248
|
-
const
|
1246
|
+
const ret = (() => {
|
1249
1247
|
if (node.type === 'Literal') {
|
1250
|
-
if (node.regex) return TYPES.
|
1248
|
+
if (node.regex) return TYPES.regexp;
|
1251
1249
|
|
1252
|
-
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.
|
1250
|
+
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.bytestring;
|
1253
1251
|
|
1254
1252
|
return TYPES[typeof node.value];
|
1255
1253
|
}
|
@@ -1288,7 +1286,6 @@ const getNodeType = (scope, node) => {
|
|
1288
1286
|
const func = funcs.find(x => x.name === name);
|
1289
1287
|
|
1290
1288
|
if (func) {
|
1291
|
-
// console.log(scope, func, func.returnType);
|
1292
1289
|
if (func.returnType) return func.returnType;
|
1293
1290
|
}
|
1294
1291
|
|
@@ -1303,7 +1300,7 @@ const getNodeType = (scope, node) => {
|
|
1303
1300
|
const spl = name.slice(2).split('_');
|
1304
1301
|
|
1305
1302
|
const func = spl[spl.length - 1];
|
1306
|
-
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.
|
1303
|
+
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1307
1304
|
if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
|
1308
1305
|
}
|
1309
1306
|
|
@@ -1355,7 +1352,7 @@ const getNodeType = (scope, node) => {
|
|
1355
1352
|
}
|
1356
1353
|
|
1357
1354
|
if (node.type === 'ArrayExpression') {
|
1358
|
-
return TYPES.
|
1355
|
+
return TYPES.array;
|
1359
1356
|
}
|
1360
1357
|
|
1361
1358
|
if (node.type === 'BinaryExpression') {
|
@@ -1367,7 +1364,7 @@ const getNodeType = (scope, node) => {
|
|
1367
1364
|
|
1368
1365
|
// todo: this should be dynamic but for now only static
|
1369
1366
|
if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
|
1370
|
-
if (knownLeft === TYPES.
|
1367
|
+
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1371
1368
|
|
1372
1369
|
return TYPES.number;
|
1373
1370
|
|
@@ -1393,19 +1390,28 @@ const getNodeType = (scope, node) => {
|
|
1393
1390
|
if (node.operator === '!') return TYPES.boolean;
|
1394
1391
|
if (node.operator === 'void') return TYPES.undefined;
|
1395
1392
|
if (node.operator === 'delete') return TYPES.boolean;
|
1396
|
-
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.
|
1393
|
+
if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.bytestring : TYPES.string;
|
1397
1394
|
|
1398
1395
|
return TYPES.number;
|
1399
1396
|
}
|
1400
1397
|
|
1401
1398
|
if (node.type === 'MemberExpression') {
|
1399
|
+
// hack: if something.name, string type
|
1400
|
+
if (node.property.name === 'name') {
|
1401
|
+
if (hasFuncWithName(node.object.name)) {
|
1402
|
+
return TYPES.bytestring;
|
1403
|
+
} else {
|
1404
|
+
return TYPES.undefined;
|
1405
|
+
}
|
1406
|
+
}
|
1407
|
+
|
1402
1408
|
// hack: if something.length, number type
|
1403
1409
|
if (node.property.name === 'length') return TYPES.number;
|
1404
1410
|
|
1405
1411
|
// ts hack
|
1406
1412
|
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.
|
1413
|
+
if (scope.locals[node.object.name]?.metadata?.type === TYPES.bytestring) return TYPES.bytestring;
|
1414
|
+
if (scope.locals[node.object.name]?.metadata?.type === TYPES.array) return TYPES.number;
|
1409
1415
|
|
1410
1416
|
if (scope.locals['#last_type']) return getLastType(scope);
|
1411
1417
|
|
@@ -1423,10 +1429,8 @@ const getNodeType = (scope, node) => {
|
|
1423
1429
|
// presume
|
1424
1430
|
// todo: warn here?
|
1425
1431
|
return TYPES.number;
|
1426
|
-
};
|
1432
|
+
})();
|
1427
1433
|
|
1428
|
-
const ret = inner();
|
1429
|
-
// console.trace(node, ret);
|
1430
1434
|
if (typeof ret === 'number') return number(ret, Valtype.i32);
|
1431
1435
|
return ret;
|
1432
1436
|
};
|
@@ -1646,18 +1650,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1646
1650
|
// megahack for /regex/.func()
|
1647
1651
|
const funcName = decl.callee.property.name;
|
1648
1652
|
if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
|
1649
|
-
const
|
1653
|
+
const regex = decl.callee.object.regex.pattern;
|
1654
|
+
const rhemynName = `regex_${funcName}_${regex}`;
|
1655
|
+
|
1656
|
+
if (!funcIndex[rhemynName]) {
|
1657
|
+
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
1650
1658
|
|
1651
|
-
|
1652
|
-
|
1659
|
+
funcIndex[func.name] = func.index;
|
1660
|
+
funcs.push(func);
|
1661
|
+
}
|
1653
1662
|
|
1663
|
+
const idx = funcIndex[rhemynName];
|
1654
1664
|
return [
|
1655
1665
|
// make string arg
|
1656
1666
|
...generate(scope, decl.arguments[0]),
|
1667
|
+
Opcodes.i32_to_u,
|
1668
|
+
...getNodeType(scope, decl.arguments[0]),
|
1657
1669
|
|
1658
1670
|
// call regex func
|
1659
|
-
Opcodes.
|
1660
|
-
[ Opcodes.call, func.index ],
|
1671
|
+
[ Opcodes.call, idx ],
|
1661
1672
|
Opcodes.i32_from_u,
|
1662
1673
|
|
1663
1674
|
...number(TYPES.boolean, Valtype.i32),
|
@@ -1818,22 +1829,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1818
1829
|
|
1819
1830
|
includeBuiltin(scope, name);
|
1820
1831
|
idx = funcIndex[name];
|
1821
|
-
|
1822
|
-
// infer arguments types from builtins params
|
1823
|
-
const func = funcs.find(x => x.name === name);
|
1824
|
-
for (let i = 0; i < decl.arguments.length; i++) {
|
1825
|
-
const arg = decl.arguments[i];
|
1826
|
-
if (!arg.name) continue;
|
1827
|
-
|
1828
|
-
const local = scope.locals[arg.name];
|
1829
|
-
if (!local) continue;
|
1830
|
-
|
1831
|
-
local.type = func.params[i];
|
1832
|
-
if (local.type === Valtype.v128) {
|
1833
|
-
// specify vec subtype inferred from last vec type in function name
|
1834
|
-
local.vecType = name.split('_').reverse().find(x => x.includes('x'));
|
1835
|
-
}
|
1836
|
-
}
|
1837
1832
|
}
|
1838
1833
|
|
1839
1834
|
if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
|
@@ -1865,9 +1860,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1865
1860
|
|
1866
1861
|
// value
|
1867
1862
|
i32_const: { imms: 1, args: [], returns: 1 },
|
1868
|
-
|
1869
|
-
// a, b
|
1870
|
-
i32_or: { imms: 0, args: [ true, true ], returns: 1 },
|
1871
1863
|
};
|
1872
1864
|
|
1873
1865
|
const opName = name.slice('__Porffor_wasm_'.length);
|
@@ -2088,7 +2080,7 @@ const brTable = (input, bc, returns) => {
|
|
2088
2080
|
};
|
2089
2081
|
|
2090
2082
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
2091
|
-
if (!Prefs.bytestring) delete bc[TYPES.
|
2083
|
+
if (!Prefs.bytestring) delete bc[TYPES.bytestring];
|
2092
2084
|
|
2093
2085
|
const known = knownType(scope, type);
|
2094
2086
|
if (known != null) {
|
@@ -2162,7 +2154,6 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
|
|
2162
2154
|
const typeAnnoToPorfType = x => {
|
2163
2155
|
if (!x) return null;
|
2164
2156
|
if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
|
2165
|
-
if (TYPES['_' + x.toLowerCase()] != null) return TYPES['_' + x.toLowerCase()];
|
2166
2157
|
|
2167
2158
|
switch (x) {
|
2168
2159
|
case 'i32':
|
@@ -2191,7 +2182,7 @@ const extractTypeAnnotation = decl => {
|
|
2191
2182
|
const typeName = type;
|
2192
2183
|
type = typeAnnoToPorfType(type);
|
2193
2184
|
|
2194
|
-
if (type === TYPES.
|
2185
|
+
if (type === TYPES.bytestring && !Prefs.bytestring) type = TYPES.string;
|
2195
2186
|
|
2196
2187
|
// if (decl.name) console.log(decl.name, { type, elementType });
|
2197
2188
|
|
@@ -2203,8 +2194,8 @@ const generateVar = (scope, decl) => {
|
|
2203
2194
|
|
2204
2195
|
const topLevel = scope.name === 'main';
|
2205
2196
|
|
2206
|
-
// global variable if in top scope (main)
|
2207
|
-
const global = topLevel || decl._bare;
|
2197
|
+
// global variable if in top scope (main) or if internally wanted
|
2198
|
+
const global = topLevel || decl._bare;
|
2208
2199
|
|
2209
2200
|
for (const x of decl.declarations) {
|
2210
2201
|
const name = mapName(x.id.name);
|
@@ -2218,7 +2209,6 @@ const generateVar = (scope, decl) => {
|
|
2218
2209
|
continue;
|
2219
2210
|
}
|
2220
2211
|
|
2221
|
-
// console.log(name);
|
2222
2212
|
if (topLevel && builtinVars[name]) {
|
2223
2213
|
// cannot redeclare
|
2224
2214
|
if (decl.kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
|
@@ -2226,6 +2216,10 @@ const generateVar = (scope, decl) => {
|
|
2226
2216
|
continue; // always ignore
|
2227
2217
|
}
|
2228
2218
|
|
2219
|
+
// // generate init before allocating var
|
2220
|
+
// let generated;
|
2221
|
+
// if (x.init) generated = generate(scope, x.init, global, name);
|
2222
|
+
|
2229
2223
|
const typed = typedInput && x.id.typeAnnotation;
|
2230
2224
|
let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
|
2231
2225
|
|
@@ -2234,9 +2228,17 @@ const generateVar = (scope, decl) => {
|
|
2234
2228
|
}
|
2235
2229
|
|
2236
2230
|
if (x.init) {
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2231
|
+
const generated = generate(scope, x.init, global, name);
|
2232
|
+
if (scope.arrays?.get(name) != null) {
|
2233
|
+
// hack to set local as pointer before
|
2234
|
+
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2235
|
+
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
2236
|
+
generated.pop();
|
2237
|
+
out = out.concat(generated);
|
2238
|
+
} else {
|
2239
|
+
out = out.concat(generated);
|
2240
|
+
out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2241
|
+
}
|
2240
2242
|
out.push(...setType(scope, name, getNodeType(scope, x.init)));
|
2241
2243
|
}
|
2242
2244
|
|
@@ -2263,6 +2265,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2263
2265
|
return [];
|
2264
2266
|
}
|
2265
2267
|
|
2268
|
+
const op = decl.operator.slice(0, -1) || '=';
|
2269
|
+
|
2266
2270
|
// hack: .length setter
|
2267
2271
|
if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
|
2268
2272
|
const name = decl.left.object.name;
|
@@ -2271,14 +2275,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2271
2275
|
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
2272
2276
|
|
2273
2277
|
const newValueTmp = localTmp(scope, '__length_setter_tmp');
|
2278
|
+
const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
|
2274
2279
|
|
2275
2280
|
return [
|
2276
2281
|
...(aotPointer ? number(0, Valtype.i32) : [
|
2277
2282
|
...generate(scope, decl.left.object),
|
2278
2283
|
Opcodes.i32_to_u
|
2279
2284
|
]),
|
2285
|
+
...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2280
2286
|
|
2281
|
-
...generate(scope, decl.right),
|
2287
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2288
|
+
[ Opcodes.local_get, pointerTmp ],
|
2289
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
2290
|
+
Opcodes.i32_from_u
|
2291
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
|
2282
2292
|
[ Opcodes.local_tee, newValueTmp ],
|
2283
2293
|
|
2284
2294
|
Opcodes.i32_to_u,
|
@@ -2288,8 +2298,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2288
2298
|
];
|
2289
2299
|
}
|
2290
2300
|
|
2291
|
-
const op = decl.operator.slice(0, -1) || '=';
|
2292
|
-
|
2293
2301
|
// arr[i]
|
2294
2302
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2295
2303
|
const name = decl.left.object.name;
|
@@ -2302,7 +2310,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2302
2310
|
|
2303
2311
|
return [
|
2304
2312
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
2305
|
-
[TYPES.
|
2313
|
+
[TYPES.array]: [
|
2306
2314
|
...(aotPointer ? [] : [
|
2307
2315
|
...generate(scope, decl.left.object),
|
2308
2316
|
Opcodes.i32_to_u
|
@@ -2504,7 +2512,7 @@ const generateUnary = (scope, decl) => {
|
|
2504
2512
|
[TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
|
2505
2513
|
[TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
|
2506
2514
|
|
2507
|
-
[TYPES.
|
2515
|
+
[TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
|
2508
2516
|
|
2509
2517
|
// object and internal types
|
2510
2518
|
default: makeString(scope, 'object', false, '#typeof_result'),
|
@@ -2740,7 +2748,7 @@ const generateForOf = (scope, decl) => {
|
|
2740
2748
|
// set type for local
|
2741
2749
|
// todo: optimize away counter and use end pointer
|
2742
2750
|
out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
|
2743
|
-
[TYPES.
|
2751
|
+
[TYPES.array]: [
|
2744
2752
|
...setType(scope, leftName, TYPES.number),
|
2745
2753
|
|
2746
2754
|
[ Opcodes.loop, Blocktype.void ],
|
@@ -2823,8 +2831,8 @@ const generateForOf = (scope, decl) => {
|
|
2823
2831
|
[ Opcodes.end ],
|
2824
2832
|
[ Opcodes.end ]
|
2825
2833
|
],
|
2826
|
-
[TYPES.
|
2827
|
-
...setType(scope, leftName, TYPES.
|
2834
|
+
[TYPES.bytestring]: [
|
2835
|
+
...setType(scope, leftName, TYPES.bytestring),
|
2828
2836
|
|
2829
2837
|
[ Opcodes.loop, Blocktype.void ],
|
2830
2838
|
|
@@ -3093,12 +3101,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3093
3101
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
3094
3102
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
3095
3103
|
|
3096
|
-
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${
|
3104
|
+
if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
|
3097
3105
|
else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
|
3098
3106
|
}
|
3099
3107
|
|
3100
3108
|
const pointer = scope.arrays.get(name);
|
3101
3109
|
|
3110
|
+
const local = global ? globals[name] : scope.locals[name];
|
3111
|
+
|
3102
3112
|
const useRawElements = !!decl.rawElements;
|
3103
3113
|
const elements = useRawElements ? decl.rawElements : decl.elements;
|
3104
3114
|
|
@@ -3131,11 +3141,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3131
3141
|
return [ out, pointer ];
|
3132
3142
|
}
|
3133
3143
|
|
3144
|
+
const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
|
3145
|
+
if (pointerTmp != null) {
|
3146
|
+
out.push(
|
3147
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
3148
|
+
Opcodes.i32_to_u,
|
3149
|
+
[ Opcodes.local_set, pointerTmp ]
|
3150
|
+
);
|
3151
|
+
}
|
3152
|
+
|
3153
|
+
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3154
|
+
|
3134
3155
|
// store length as 0th array
|
3135
3156
|
out.push(
|
3136
|
-
...
|
3157
|
+
...pointerWasm,
|
3137
3158
|
...number(length, Valtype.i32),
|
3138
|
-
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1,
|
3159
|
+
[ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
|
3139
3160
|
);
|
3140
3161
|
|
3141
3162
|
const storeOp = StoreOps[itemType];
|
@@ -3144,14 +3165,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3144
3165
|
if (elements[i] == null) continue;
|
3145
3166
|
|
3146
3167
|
out.push(
|
3147
|
-
...
|
3168
|
+
...pointerWasm,
|
3148
3169
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3149
|
-
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(
|
3170
|
+
[ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
|
3150
3171
|
);
|
3151
3172
|
}
|
3152
3173
|
|
3153
3174
|
// local value as pointer
|
3154
|
-
out.push(...
|
3175
|
+
out.push(...pointerWasm, Opcodes.i32_from_u);
|
3155
3176
|
|
3156
3177
|
return [ out, pointer ];
|
3157
3178
|
};
|
@@ -3193,6 +3214,20 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3193
3214
|
|
3194
3215
|
const aotPointer = Prefs.aotPointerOpt && pointer != null;
|
3195
3216
|
|
3217
|
+
// hack: .name
|
3218
|
+
if (decl.property.name === 'name') {
|
3219
|
+
if (hasFuncWithName(name)) {
|
3220
|
+
let nameProp = name;
|
3221
|
+
|
3222
|
+
// eg: __String_prototype_toLowerCase -> toLowerCase
|
3223
|
+
if (nameProp.startsWith('__')) nameProp = nameProp.split('_').pop();
|
3224
|
+
|
3225
|
+
return makeString(scope, nameProp, _global, _name, true);
|
3226
|
+
} else {
|
3227
|
+
return generate(scope, DEFAULT_VALUE);
|
3228
|
+
}
|
3229
|
+
}
|
3230
|
+
|
3196
3231
|
// hack: .length
|
3197
3232
|
if (decl.property.name === 'length') {
|
3198
3233
|
const func = funcs.find(x => x.name === name);
|
@@ -3202,6 +3237,16 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3202
3237
|
return number(typedParams ? func.params.length / 2 : func.params.length);
|
3203
3238
|
}
|
3204
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
|
+
|
3205
3250
|
if (builtinFuncs[name]) return number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length);
|
3206
3251
|
if (importedFuncs[name]) return number(importedFuncs[name].params);
|
3207
3252
|
if (internalConstrs[name]) return number(internalConstrs[name].length ?? 0);
|
@@ -3230,7 +3275,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3230
3275
|
}
|
3231
3276
|
|
3232
3277
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3233
|
-
[TYPES.
|
3278
|
+
[TYPES.array]: [
|
3234
3279
|
// get index as valtype
|
3235
3280
|
...property,
|
3236
3281
|
|
@@ -3283,7 +3328,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3283
3328
|
...number(TYPES.string, Valtype.i32),
|
3284
3329
|
...setLastType(scope)
|
3285
3330
|
],
|
3286
|
-
[TYPES.
|
3331
|
+
[TYPES.bytestring]: [
|
3287
3332
|
// setup new/out array
|
3288
3333
|
...newOut,
|
3289
3334
|
[ Opcodes.drop ],
|
@@ -3308,7 +3353,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3308
3353
|
// return new string (page)
|
3309
3354
|
...number(newPointer),
|
3310
3355
|
|
3311
|
-
...number(TYPES.
|
3356
|
+
...number(TYPES.bytestring, Valtype.i32),
|
3312
3357
|
...setLastType(scope)
|
3313
3358
|
],
|
3314
3359
|
|
@@ -3333,8 +3378,8 @@ const objectHack = node => {
|
|
3333
3378
|
|
3334
3379
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3335
3380
|
|
3336
|
-
// if .length, give up (hack within a hack!)
|
3337
|
-
if (node.property.name
|
3381
|
+
// if .name or .length, give up (hack within a hack!)
|
3382
|
+
if (['name', 'length'].includes(node.property.name)) {
|
3338
3383
|
node.object = objectHack(node.object);
|
3339
3384
|
return;
|
3340
3385
|
}
|
@@ -3383,8 +3428,11 @@ const generateFunc = (scope, decl) => {
|
|
3383
3428
|
};
|
3384
3429
|
|
3385
3430
|
if (typedInput && decl.returnType) {
|
3386
|
-
|
3387
|
-
|
3431
|
+
const { type } = extractTypeAnnotation(decl.returnType);
|
3432
|
+
if (type != null) {
|
3433
|
+
innerScope.returnType = type;
|
3434
|
+
innerScope.returns = [ valtypeBinary ];
|
3435
|
+
}
|
3388
3436
|
}
|
3389
3437
|
|
3390
3438
|
for (let i = 0; i < params.length; i++) {
|
@@ -3426,7 +3474,7 @@ const generateFunc = (scope, decl) => {
|
|
3426
3474
|
if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
3427
3475
|
wasm.push(
|
3428
3476
|
...number(0),
|
3429
|
-
...number(TYPES.undefined, Valtype.i32),
|
3477
|
+
...(innerScope.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
|
3430
3478
|
[ Opcodes.return ]
|
3431
3479
|
);
|
3432
3480
|
}
|
@@ -3477,7 +3525,7 @@ const internalConstrs = {
|
|
3477
3525
|
...number(pointer)
|
3478
3526
|
];
|
3479
3527
|
},
|
3480
|
-
type: TYPES.
|
3528
|
+
type: TYPES.array,
|
3481
3529
|
length: 1
|
3482
3530
|
},
|
3483
3531
|
|
@@ -3489,7 +3537,7 @@ const internalConstrs = {
|
|
3489
3537
|
elements: decl.arguments
|
3490
3538
|
}, global, name);
|
3491
3539
|
},
|
3492
|
-
type: TYPES.
|
3540
|
+
type: TYPES.array,
|
3493
3541
|
notConstr: true,
|
3494
3542
|
length: 0
|
3495
3543
|
},
|
@@ -3618,23 +3666,6 @@ const internalConstrs = {
|
|
3618
3666
|
}
|
3619
3667
|
};
|
3620
3668
|
|
3621
|
-
// const _ = Array.prototype.push;
|
3622
|
-
// Array.prototype.push = function (a) {
|
3623
|
-
// const check = arr => {
|
3624
|
-
// for (const x of arr) {
|
3625
|
-
// if (x === undefined) {
|
3626
|
-
// console.trace(arr);
|
3627
|
-
// process.exit();
|
3628
|
-
// }
|
3629
|
-
// if (Array.isArray(x)) check(x);
|
3630
|
-
// }
|
3631
|
-
// };
|
3632
|
-
// if (Array.isArray(a) && !new Error().stack.includes('node:')) check(a);
|
3633
|
-
// // if (Array.isArray(a)) check(a);
|
3634
|
-
|
3635
|
-
// return _.apply(this, arguments);
|
3636
|
-
// };
|
3637
|
-
|
3638
3669
|
export default program => {
|
3639
3670
|
globals = {};
|
3640
3671
|
globalInd = 0;
|
@@ -3649,7 +3680,7 @@ export default program => {
|
|
3649
3680
|
|
3650
3681
|
globalThis.valtype = 'f64';
|
3651
3682
|
|
3652
|
-
const valtypeOpt = process.argv.find(x => x.startsWith('
|
3683
|
+
const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
|
3653
3684
|
if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
|
3654
3685
|
|
3655
3686
|
globalThis.valtypeBinary = Valtype[valtype];
|
@@ -3657,7 +3688,7 @@ export default program => {
|
|
3657
3688
|
const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
|
3658
3689
|
|
3659
3690
|
globalThis.pageSize = PageSize;
|
3660
|
-
const pageSizeOpt = process.argv.find(x => x.startsWith('
|
3691
|
+
const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
|
3661
3692
|
if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
|
3662
3693
|
|
3663
3694
|
// set generic opcodes for current valtype
|