porffor 0.14.0-3c0ba31cd → 0.14.0-3fa90b5d2
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/compiler/builtins/array.ts +6 -4
- package/compiler/builtins/set.ts +5 -6
- package/compiler/builtins/symbol.ts +1 -1
- package/compiler/builtins.js +9 -4
- package/compiler/codegen.js +266 -126
- package/compiler/generated_builtins.js +32 -32
- package/compiler/precompile.js +1 -1
- package/compiler/prefs.js +1 -1
- package/compiler/prototype.js +180 -157
- package/compiler/wrap.js +66 -37
- package/package.json +1 -1
- package/runner/index.js +1 -1
- package/runner/repl.js +18 -2
package/compiler/codegen.js
CHANGED
@@ -140,6 +140,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
140
140
|
case 'ArrayExpression':
|
141
141
|
return generateArray(scope, decl, global, name);
|
142
142
|
|
143
|
+
case 'ObjectExpression':
|
144
|
+
return generateObject(scope, decl, global, name);
|
145
|
+
|
143
146
|
case 'MemberExpression':
|
144
147
|
return generateMember(scope, decl, global, name);
|
145
148
|
|
@@ -200,19 +203,11 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
200
203
|
|
201
204
|
__Porffor_bs: str => [
|
202
205
|
...makeString(scope, str, global, name, true),
|
203
|
-
|
204
|
-
...(name ? setType(scope, name, TYPES.bytestring) : [
|
205
|
-
...number(TYPES.bytestring, Valtype.i32),
|
206
|
-
...setLastType(scope)
|
207
|
-
])
|
206
|
+
...(name ? setType(scope, name, TYPES.bytestring) : setLastType(scope, TYPES.bytestring))
|
208
207
|
],
|
209
208
|
__Porffor_s: str => [
|
210
209
|
...makeString(scope, str, global, name, false),
|
211
|
-
|
212
|
-
...(name ? setType(scope, name, TYPES.string) : [
|
213
|
-
...number(TYPES.string, Valtype.i32),
|
214
|
-
...setLastType(scope)
|
215
|
-
])
|
210
|
+
...(name ? setType(scope, name, TYPES.string) : setLastType(scope, TYPES.string))
|
216
211
|
],
|
217
212
|
};
|
218
213
|
|
@@ -400,13 +395,11 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
|
400
395
|
[ Opcodes.if, Valtype.i32 ],
|
401
396
|
...right,
|
402
397
|
// note type
|
403
|
-
...rightType,
|
404
|
-
...setLastType(scope),
|
398
|
+
...setLastType(scope, rightType),
|
405
399
|
[ Opcodes.else ],
|
406
400
|
[ Opcodes.local_get, localTmp(scope, 'logictmpi', Valtype.i32) ],
|
407
401
|
// note type
|
408
|
-
...leftType,
|
409
|
-
...setLastType(scope),
|
402
|
+
...setLastType(scope, leftType),
|
410
403
|
[ Opcodes.end ],
|
411
404
|
Opcodes.i32_from
|
412
405
|
];
|
@@ -419,13 +412,11 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
|
419
412
|
[ Opcodes.if, valtypeBinary ],
|
420
413
|
...right,
|
421
414
|
// note type
|
422
|
-
...rightType,
|
423
|
-
...setLastType(scope),
|
415
|
+
...setLastType(scope, rightType),
|
424
416
|
[ Opcodes.else ],
|
425
417
|
[ Opcodes.local_get, localTmp(scope, 'logictmp') ],
|
426
418
|
// note type
|
427
|
-
...leftType,
|
428
|
-
...setLastType(scope),
|
419
|
+
...setLastType(scope, leftType),
|
429
420
|
[ Opcodes.end ]
|
430
421
|
];
|
431
422
|
};
|
@@ -453,11 +444,11 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
453
444
|
...number(0, Valtype.i32), // base 0 for store later
|
454
445
|
|
455
446
|
...number(pointer, Valtype.i32),
|
456
|
-
[ Opcodes.i32_load,
|
447
|
+
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
457
448
|
[ Opcodes.local_tee, leftLength ],
|
458
449
|
|
459
450
|
[ Opcodes.local_get, rightPointer ],
|
460
|
-
[ Opcodes.i32_load,
|
451
|
+
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
461
452
|
[ Opcodes.local_tee, rightLength ],
|
462
453
|
|
463
454
|
[ Opcodes.i32_add ],
|
@@ -513,11 +504,11 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
|
|
513
504
|
...number(0, Valtype.i32), // base 0 for store later
|
514
505
|
|
515
506
|
[ Opcodes.local_get, leftPointer ],
|
516
|
-
[ Opcodes.i32_load,
|
507
|
+
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
517
508
|
[ Opcodes.local_tee, leftLength ],
|
518
509
|
|
519
510
|
[ Opcodes.local_get, rightPointer ],
|
520
|
-
[ Opcodes.i32_load,
|
511
|
+
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
521
512
|
[ Opcodes.local_tee, rightLength ],
|
522
513
|
|
523
514
|
[ Opcodes.i32_add ],
|
@@ -595,11 +586,11 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
595
586
|
|
596
587
|
// get lengths
|
597
588
|
[ Opcodes.local_get, leftPointer ],
|
598
|
-
[ Opcodes.i32_load,
|
589
|
+
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
599
590
|
[ Opcodes.local_tee, leftLength ],
|
600
591
|
|
601
592
|
[ Opcodes.local_get, rightPointer ],
|
602
|
-
[ Opcodes.i32_load,
|
593
|
+
[ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
|
603
594
|
|
604
595
|
// fast path: check leftLength != rightLength
|
605
596
|
[ Opcodes.i32_ne ],
|
@@ -1053,7 +1044,7 @@ const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals =
|
|
1053
1044
|
});
|
1054
1045
|
};
|
1055
1046
|
|
1056
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [] }) => {
|
1047
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], callsSelf = false }) => {
|
1057
1048
|
const existing = funcs.find(x => x.name === name);
|
1058
1049
|
if (existing) return existing;
|
1059
1050
|
|
@@ -1101,6 +1092,12 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1101
1092
|
index: currentFuncIndex++
|
1102
1093
|
};
|
1103
1094
|
|
1095
|
+
if (callsSelf) for (const inst of wasm) {
|
1096
|
+
if (inst[0] === Opcodes.call && inst[1] === -1) {
|
1097
|
+
inst[1] = func.index;
|
1098
|
+
}
|
1099
|
+
}
|
1100
|
+
|
1104
1101
|
funcs.push(func);
|
1105
1102
|
funcIndex[name] = func.index;
|
1106
1103
|
|
@@ -1194,9 +1191,10 @@ const getLastType = scope => {
|
|
1194
1191
|
return [ [ Opcodes.local_get, localTmp(scope, '#last_type', Valtype.i32) ] ];
|
1195
1192
|
};
|
1196
1193
|
|
1197
|
-
const setLastType = scope =>
|
1198
|
-
|
1199
|
-
|
1194
|
+
const setLastType = (scope, type = []) => [
|
1195
|
+
...(typeof type === 'number' ? number(type, Valtype.i32) : type),
|
1196
|
+
[ Opcodes.local_set, localTmp(scope, '#last_type', Valtype.i32) ]
|
1197
|
+
];
|
1200
1198
|
|
1201
1199
|
const getNodeType = (scope, node) => {
|
1202
1200
|
const ret = (() => {
|
@@ -1257,7 +1255,17 @@ const getNodeType = (scope, node) => {
|
|
1257
1255
|
|
1258
1256
|
const func = spl[spl.length - 1];
|
1259
1257
|
const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
|
1260
|
-
if (protoFuncs.length === 1)
|
1258
|
+
if (protoFuncs.length === 1) {
|
1259
|
+
if (protoFuncs[0].returnType) return protoFuncs[0].returnType;
|
1260
|
+
}
|
1261
|
+
|
1262
|
+
if (protoFuncs.length > 0) {
|
1263
|
+
if (scope.locals['#last_type']) return getLastType(scope);
|
1264
|
+
|
1265
|
+
// presume
|
1266
|
+
// todo: warn here?
|
1267
|
+
return TYPES.number;
|
1268
|
+
}
|
1261
1269
|
}
|
1262
1270
|
|
1263
1271
|
if (name.startsWith('__Porffor_wasm_')) {
|
@@ -1352,22 +1360,27 @@ const getNodeType = (scope, node) => {
|
|
1352
1360
|
}
|
1353
1361
|
|
1354
1362
|
if (node.type === 'MemberExpression') {
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
return TYPES.undefined;
|
1361
|
-
}
|
1363
|
+
const name = node.property.name;
|
1364
|
+
|
1365
|
+
if (name === 'length') {
|
1366
|
+
if (hasFuncWithName(node.object.name)) return TYPES.number;
|
1367
|
+
if (Prefs.fastLength) return TYPES.number;
|
1362
1368
|
}
|
1363
1369
|
|
1364
|
-
// hack: if something.length, number type
|
1365
|
-
if (node.property.name === 'length') return TYPES.number;
|
1366
1370
|
|
1367
|
-
|
1368
|
-
if (
|
1369
|
-
|
1370
|
-
|
1371
|
+
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1372
|
+
if (objectKnownType != null) {
|
1373
|
+
if (name === 'length') {
|
1374
|
+
if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(objectKnownType)) return TYPES.number;
|
1375
|
+
else return TYPES.undefined;
|
1376
|
+
}
|
1377
|
+
|
1378
|
+
if (node.computed) {
|
1379
|
+
if (objectKnownType === TYPES.string) return TYPES.string;
|
1380
|
+
if (objectKnownType === TYPES.bytestring) return TYPES.bytestring;
|
1381
|
+
if (objectKnownType === TYPES.array) return TYPES.number;
|
1382
|
+
}
|
1383
|
+
}
|
1371
1384
|
|
1372
1385
|
if (scope.locals['#last_type']) return getLastType(scope);
|
1373
1386
|
|
@@ -1470,7 +1483,7 @@ const disposeLeftover = wasm => {
|
|
1470
1483
|
const generateExp = (scope, decl) => {
|
1471
1484
|
const expression = decl.expression;
|
1472
1485
|
|
1473
|
-
const out = generate(scope, expression, undefined, undefined,
|
1486
|
+
const out = generate(scope, expression, undefined, undefined, Prefs.optUnused);
|
1474
1487
|
disposeLeftover(out);
|
1475
1488
|
|
1476
1489
|
return out;
|
@@ -1561,16 +1574,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1561
1574
|
out.splice(out.length - 1, 1);
|
1562
1575
|
|
1563
1576
|
const finalStatement = parsed.body[parsed.body.length - 1];
|
1564
|
-
out.push(
|
1565
|
-
...getNodeType(scope, finalStatement),
|
1566
|
-
...setLastType(scope)
|
1567
|
-
);
|
1577
|
+
out.push(...setLastType(scope, getNodeType(scope, finalStatement)));
|
1568
1578
|
} else if (countLeftover(out) === 0) {
|
1569
1579
|
out.push(...number(UNDEFINED));
|
1570
|
-
out.push(
|
1571
|
-
...number(TYPES.undefined, Valtype.i32),
|
1572
|
-
...setLastType(scope)
|
1573
|
-
);
|
1580
|
+
out.push(...setLastType(scope, TYPES.undefined));
|
1574
1581
|
}
|
1575
1582
|
|
1576
1583
|
// if (lastInst && lastInst[0] === Opcodes.drop) {
|
@@ -1622,8 +1629,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1622
1629
|
[ Opcodes.call, idx ],
|
1623
1630
|
Opcodes.i32_from_u,
|
1624
1631
|
|
1625
|
-
...
|
1626
|
-
...setLastType(scope)
|
1632
|
+
...setLastType(scope, TYPES.boolean)
|
1627
1633
|
];
|
1628
1634
|
}
|
1629
1635
|
|
@@ -1695,9 +1701,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1695
1701
|
if (protoFunc.noArgRetLength && decl.arguments.length === 0) {
|
1696
1702
|
protoBC[x] = [
|
1697
1703
|
...RTArrayUtil.getLength(getPointer),
|
1698
|
-
|
1699
|
-
...number(TYPES.number, Valtype.i32),
|
1700
|
-
...setLastType(scope)
|
1704
|
+
...setLastType(scope, TYPES.number)
|
1701
1705
|
];
|
1702
1706
|
continue;
|
1703
1707
|
}
|
@@ -1716,7 +1720,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1716
1720
|
getI32: () => RTArrayUtil.getLengthI32(getPointer),
|
1717
1721
|
set: value => RTArrayUtil.setLength(getPointer, value),
|
1718
1722
|
setI32: value => RTArrayUtil.setLengthI32(getPointer, value)
|
1719
|
-
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1723
|
+
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
1720
1724
|
return makeArray(scope, {
|
1721
1725
|
rawElements: new Array(length)
|
1722
1726
|
}, _global, _name, true, itemType);
|
@@ -1730,9 +1734,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1730
1734
|
protoBC[x] = [
|
1731
1735
|
[ Opcodes.block, unusedValue && optUnused ? Blocktype.void : valtypeBinary ],
|
1732
1736
|
...protoOut,
|
1733
|
-
|
1734
|
-
...number(protoFunc.returnType ?? TYPES.number, Valtype.i32),
|
1735
|
-
...setLastType(scope),
|
1737
|
+
...(unusedValue && optUnused ? [] : (protoFunc.returnType != null ? setLastType(scope, protoFunc.returnType) : setLastType(scope))),
|
1736
1738
|
[ Opcodes.end ]
|
1737
1739
|
];
|
1738
1740
|
}
|
@@ -1901,6 +1903,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1901
1903
|
const arg = args[i];
|
1902
1904
|
out = out.concat(generate(scope, arg));
|
1903
1905
|
|
1906
|
+
// todo: this should be used instead of the too many args thing above (by removing that)
|
1904
1907
|
if (i >= paramCount) {
|
1905
1908
|
// over param count of func, drop arg
|
1906
1909
|
out.push([ Opcodes.drop ]);
|
@@ -1985,8 +1988,11 @@ const knownType = (scope, type) => {
|
|
1985
1988
|
const idx = type[0][1];
|
1986
1989
|
|
1987
1990
|
// type idx = var idx + 1
|
1988
|
-
const
|
1989
|
-
if (
|
1991
|
+
const name = Object.values(scope.locals).find(x => x.idx === idx)?.name;
|
1992
|
+
if (name) {
|
1993
|
+
const local = scope.locals[name];
|
1994
|
+
if (local.metadata?.type != null) return v.metadata.type;
|
1995
|
+
}
|
1990
1996
|
}
|
1991
1997
|
|
1992
1998
|
return null;
|
@@ -2117,6 +2123,17 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
|
2117
2123
|
return out;
|
2118
2124
|
};
|
2119
2125
|
|
2126
|
+
const typeIsOneOf = (type, types, valtype = Valtype.i32) => {
|
2127
|
+
const out = [];
|
2128
|
+
|
2129
|
+
for (let i = 0; i < types.length; i++) {
|
2130
|
+
out.push(...type, ...number(types[i], valtype), valtype === Valtype.f64 ? [ Opcodes.f64_eq ] : [ Opcodes.i32_eq ]);
|
2131
|
+
if (i !== 0) out.push([ Opcodes.i32_or ]);
|
2132
|
+
}
|
2133
|
+
|
2134
|
+
return out;
|
2135
|
+
};
|
2136
|
+
|
2120
2137
|
const allocVar = (scope, name, global = false, type = true) => {
|
2121
2138
|
const target = global ? globals : scope.locals;
|
2122
2139
|
|
@@ -2133,7 +2150,7 @@ const allocVar = (scope, name, global = false, type = true) => {
|
|
2133
2150
|
|
2134
2151
|
if (type) {
|
2135
2152
|
let typeIdx = global ? globalInd++ : scope.localInd++;
|
2136
|
-
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32 };
|
2153
|
+
target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
|
2137
2154
|
}
|
2138
2155
|
|
2139
2156
|
return idx;
|
@@ -2346,18 +2363,21 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2346
2363
|
Opcodes.i32_to_u,
|
2347
2364
|
|
2348
2365
|
// turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2349
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
2366
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2350
2367
|
[ Opcodes.i32_mul ],
|
2351
2368
|
...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
|
2352
2369
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2353
2370
|
|
2354
2371
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2355
2372
|
[ Opcodes.local_get, pointerTmp ],
|
2356
|
-
[ Opcodes.load,
|
2357
|
-
], generate(scope, decl.right),
|
2373
|
+
[ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2374
|
+
], generate(scope, decl.right), [
|
2375
|
+
[ Opcodes.local_get, pointerTmp ],
|
2376
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
2377
|
+
], getNodeType(scope, decl.right), false, name, true)),
|
2358
2378
|
[ Opcodes.local_tee, newValueTmp ],
|
2359
2379
|
|
2360
|
-
[ Opcodes.store,
|
2380
|
+
[ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
|
2361
2381
|
],
|
2362
2382
|
|
2363
2383
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
@@ -2611,21 +2631,16 @@ const generateConditional = (scope, decl) => {
|
|
2611
2631
|
out.push([ Opcodes.if, valtypeBinary ]);
|
2612
2632
|
depth.push('if');
|
2613
2633
|
|
2614
|
-
out.push(...generate(scope, decl.consequent));
|
2615
|
-
|
2616
|
-
// note type
|
2617
2634
|
out.push(
|
2618
|
-
...
|
2619
|
-
...setLastType(scope)
|
2635
|
+
...generate(scope, decl.consequent),
|
2636
|
+
...setLastType(scope, getNodeType(scope, decl.consequent))
|
2620
2637
|
);
|
2621
2638
|
|
2622
2639
|
out.push([ Opcodes.else ]);
|
2623
|
-
out.push(...generate(scope, decl.alternate));
|
2624
2640
|
|
2625
|
-
// note type
|
2626
2641
|
out.push(
|
2627
|
-
...
|
2628
|
-
...setLastType(scope)
|
2642
|
+
...generate(scope, decl.alternate),
|
2643
|
+
...setLastType(scope, getNodeType(scope, decl.alternate))
|
2629
2644
|
);
|
2630
2645
|
|
2631
2646
|
out.push([ Opcodes.end ]);
|
@@ -2773,12 +2788,15 @@ const generateForOf = (scope, decl) => {
|
|
2773
2788
|
// todo: optimize away counter and use end pointer
|
2774
2789
|
out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
|
2775
2790
|
[TYPES.array]: [
|
2776
|
-
...setType(scope, leftName, TYPES.number),
|
2777
|
-
|
2778
2791
|
[ Opcodes.loop, Blocktype.void ],
|
2779
2792
|
|
2780
2793
|
[ Opcodes.local_get, pointer ],
|
2781
|
-
[ Opcodes.load,
|
2794
|
+
[ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
2795
|
+
|
2796
|
+
...setType(scope, leftName, [
|
2797
|
+
[ Opcodes.local_get, pointer ],
|
2798
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
|
2799
|
+
]),
|
2782
2800
|
|
2783
2801
|
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2784
2802
|
|
@@ -2787,9 +2805,9 @@ const generateForOf = (scope, decl) => {
|
|
2787
2805
|
...generate(scope, decl.body),
|
2788
2806
|
[ Opcodes.end ],
|
2789
2807
|
|
2790
|
-
// increment iter pointer by valtype size
|
2808
|
+
// increment iter pointer by valtype size + 1
|
2791
2809
|
[ Opcodes.local_get, pointer ],
|
2792
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
2810
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2793
2811
|
[ Opcodes.i32_add ],
|
2794
2812
|
[ Opcodes.local_set, pointer ],
|
2795
2813
|
|
@@ -3106,7 +3124,7 @@ const getAllocType = itemType => {
|
|
3106
3124
|
}
|
3107
3125
|
};
|
3108
3126
|
|
3109
|
-
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype) => {
|
3127
|
+
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
|
3110
3128
|
const out = [];
|
3111
3129
|
|
3112
3130
|
scope.arrays ??= new Map();
|
@@ -3169,7 +3187,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3169
3187
|
|
3170
3188
|
const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
|
3171
3189
|
|
3172
|
-
// store length
|
3190
|
+
// store length
|
3173
3191
|
out.push(
|
3174
3192
|
...pointerWasm,
|
3175
3193
|
...number(length, Valtype.i32),
|
@@ -3177,14 +3195,20 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3177
3195
|
);
|
3178
3196
|
|
3179
3197
|
const storeOp = StoreOps[itemType];
|
3180
|
-
|
3198
|
+
const sizePerEl = ValtypeSize[itemType] + (typed ? 1 : 0);
|
3181
3199
|
if (!initEmpty) for (let i = 0; i < length; i++) {
|
3182
3200
|
if (elements[i] == null) continue;
|
3183
3201
|
|
3202
|
+
const offset = ValtypeSize.i32 + i * sizePerEl;
|
3184
3203
|
out.push(
|
3185
3204
|
...pointerWasm,
|
3186
3205
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
3187
|
-
[ storeOp,
|
3206
|
+
[ storeOp, 0, ...unsignedLEB128(offset) ],
|
3207
|
+
...(!typed ? [] : [ // typed presumes !useRawElements
|
3208
|
+
...pointerWasm,
|
3209
|
+
...getNodeType(scope, elements[i]),
|
3210
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
|
3211
|
+
])
|
3188
3212
|
);
|
3189
3213
|
}
|
3190
3214
|
|
@@ -3194,6 +3218,65 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
3194
3218
|
return [ out, pointer ];
|
3195
3219
|
};
|
3196
3220
|
|
3221
|
+
const storeArray = (scope, array, index, element, aotPointer = null) => {
|
3222
|
+
if (!Array.isArray(element)) element = generate(scope, element);
|
3223
|
+
if (typeof index === 'number') index = number(index);
|
3224
|
+
|
3225
|
+
const offset = localTmp(scope, '#storeArray_offset', Valtype.i32);
|
3226
|
+
|
3227
|
+
return [
|
3228
|
+
// calculate offset
|
3229
|
+
...index,
|
3230
|
+
Opcodes.i32_to_u,
|
3231
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3232
|
+
[ Opcodes.i32_mul ],
|
3233
|
+
...(aotPointer ? [] : [
|
3234
|
+
...array,
|
3235
|
+
Opcodes.i32_to_u,
|
3236
|
+
[ Opcodes.i32_add ],
|
3237
|
+
]),
|
3238
|
+
[ Opcodes.local_set, offset ],
|
3239
|
+
|
3240
|
+
// store value
|
3241
|
+
[ Opcodes.local_get, offset ],
|
3242
|
+
...generate(scope, element),
|
3243
|
+
[ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
3244
|
+
|
3245
|
+
// store type
|
3246
|
+
[ Opcodes.local_get, offset ],
|
3247
|
+
...getNodeType(scope, element),
|
3248
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
3249
|
+
];
|
3250
|
+
};
|
3251
|
+
|
3252
|
+
const loadArray = (scope, array, index, aotPointer = null) => {
|
3253
|
+
if (typeof index === 'number') index = number(index);
|
3254
|
+
|
3255
|
+
const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
|
3256
|
+
|
3257
|
+
return [
|
3258
|
+
// calculate offset
|
3259
|
+
...index,
|
3260
|
+
Opcodes.i32_to_u,
|
3261
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
3262
|
+
[ Opcodes.i32_mul ],
|
3263
|
+
...(aotPointer ? [] : [
|
3264
|
+
...array,
|
3265
|
+
Opcodes.i32_to_u,
|
3266
|
+
[ Opcodes.i32_add ],
|
3267
|
+
]),
|
3268
|
+
[ Opcodes.local_set, offset ],
|
3269
|
+
|
3270
|
+
// load value
|
3271
|
+
[ Opcodes.local_get, offset ],
|
3272
|
+
[ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
3273
|
+
|
3274
|
+
// load type
|
3275
|
+
[ Opcodes.local_get, offset ],
|
3276
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
3277
|
+
];
|
3278
|
+
};
|
3279
|
+
|
3197
3280
|
const byteStringable = str => {
|
3198
3281
|
if (!Prefs.bytestring) return false;
|
3199
3282
|
|
@@ -3222,14 +3305,28 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
|
|
3222
3305
|
};
|
3223
3306
|
|
3224
3307
|
const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
|
3225
|
-
return makeArray(scope, decl, global, name, initEmpty, valtype)[0];
|
3308
|
+
return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
|
3226
3309
|
};
|
3227
3310
|
|
3228
|
-
|
3311
|
+
const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
3312
|
+
if (decl.properties.length > 0) return todo(scope, 'objects are not supported yet', true);
|
3313
|
+
|
3314
|
+
return [
|
3315
|
+
...number(1),
|
3316
|
+
...setLastType(scope, TYPES.object)
|
3317
|
+
];
|
3318
|
+
};
|
3319
|
+
|
3320
|
+
const withType = (scope, wasm, type) => [
|
3321
|
+
...wasm,
|
3322
|
+
...setLastType(scope, type)
|
3323
|
+
];
|
3324
|
+
|
3325
|
+
const generateMember = (scope, decl, _global, _name) => {
|
3229
3326
|
const name = decl.object.name;
|
3230
3327
|
const pointer = scope.arrays?.get(name);
|
3231
3328
|
|
3232
|
-
const aotPointer = Prefs.aotPointerOpt && pointer
|
3329
|
+
const aotPointer = Prefs.aotPointerOpt && pointer;
|
3233
3330
|
|
3234
3331
|
// hack: .name
|
3235
3332
|
if (decl.property.name === 'name') {
|
@@ -3239,9 +3336,9 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3239
3336
|
// eg: __String_prototype_toLowerCase -> toLowerCase
|
3240
3337
|
if (nameProp.startsWith('__')) nameProp = nameProp.split('_').pop();
|
3241
3338
|
|
3242
|
-
return makeString(scope, nameProp, _global, _name, true);
|
3339
|
+
return withType(scope, makeString(scope, nameProp, _global, _name, true), TYPES.bytestring);
|
3243
3340
|
} else {
|
3244
|
-
return
|
3341
|
+
return withType(scope, number(0), TYPES.undefined);
|
3245
3342
|
}
|
3246
3343
|
}
|
3247
3344
|
|
@@ -3251,7 +3348,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3251
3348
|
if (func) {
|
3252
3349
|
const userFunc = funcIndex[name] && !importedFuncs[name] && !builtinFuncs[name] && !internalConstrs[name];
|
3253
3350
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
3254
|
-
return number(typedParams ? func.params.length / 2 : func.params.length);
|
3351
|
+
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3255
3352
|
}
|
3256
3353
|
|
3257
3354
|
if (builtinFuncs[name + '$constructor']) {
|
@@ -3261,24 +3358,88 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3261
3358
|
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3262
3359
|
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3263
3360
|
|
3264
|
-
return number(Math.max(regularParams, constructorParams));
|
3361
|
+
return withType(scope, number(Math.max(regularParams, constructorParams)), TYPES.number);
|
3362
|
+
}
|
3363
|
+
|
3364
|
+
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
|
3365
|
+
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params), TYPES.number);
|
3366
|
+
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3367
|
+
|
3368
|
+
if (Prefs.fastLength) {
|
3369
|
+
// presume valid length object
|
3370
|
+
return [
|
3371
|
+
...(aotPointer ? number(0, Valtype.i32) : [
|
3372
|
+
...generate(scope, decl.object),
|
3373
|
+
Opcodes.i32_to_u
|
3374
|
+
]),
|
3375
|
+
|
3376
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
|
3377
|
+
Opcodes.i32_from_u
|
3378
|
+
];
|
3265
3379
|
}
|
3266
3380
|
|
3267
|
-
|
3268
|
-
|
3269
|
-
if (
|
3381
|
+
const type = getNodeType(scope, decl.object);
|
3382
|
+
const known = knownType(scope, type);
|
3383
|
+
if (known != null) {
|
3384
|
+
if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
|
3385
|
+
...(aotPointer ? number(0, Valtype.i32) : [
|
3386
|
+
...generate(scope, decl.object),
|
3387
|
+
Opcodes.i32_to_u
|
3388
|
+
]),
|
3389
|
+
|
3390
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
|
3391
|
+
Opcodes.i32_from_u
|
3392
|
+
];
|
3393
|
+
|
3394
|
+
return number(0);
|
3395
|
+
}
|
3270
3396
|
|
3271
3397
|
return [
|
3272
|
-
...(
|
3273
|
-
|
3274
|
-
|
3275
|
-
|
3398
|
+
...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
|
3399
|
+
[ Opcodes.if, valtypeBinary ],
|
3400
|
+
...(aotPointer ? number(0, Valtype.i32) : [
|
3401
|
+
...generate(scope, decl.object),
|
3402
|
+
Opcodes.i32_to_u
|
3403
|
+
]),
|
3404
|
+
|
3405
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
|
3406
|
+
Opcodes.i32_from_u,
|
3276
3407
|
|
3277
|
-
|
3278
|
-
Opcodes.
|
3408
|
+
...setLastType(scope, TYPES.number),
|
3409
|
+
[ Opcodes.else ],
|
3410
|
+
...number(0),
|
3411
|
+
...setLastType(scope, TYPES.undefined),
|
3412
|
+
[ Opcodes.end ]
|
3279
3413
|
];
|
3280
3414
|
}
|
3281
3415
|
|
3416
|
+
// todo: generate this array procedurally during builtinFuncs creation
|
3417
|
+
if (['size', 'description'].includes(decl.property.name)) {
|
3418
|
+
const bc = {};
|
3419
|
+
const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
|
3420
|
+
|
3421
|
+
if (cands.length > 0) {
|
3422
|
+
for (const x of cands) {
|
3423
|
+
const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
|
3424
|
+
if (type == null) continue;
|
3425
|
+
|
3426
|
+
bc[type] = generateCall(scope, {
|
3427
|
+
callee: {
|
3428
|
+
type: 'Identifier',
|
3429
|
+
name: x
|
3430
|
+
},
|
3431
|
+
arguments: [ decl.object ],
|
3432
|
+
_protoInternalCall: true
|
3433
|
+
});
|
3434
|
+
}
|
3435
|
+
}
|
3436
|
+
|
3437
|
+
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3438
|
+
...bc,
|
3439
|
+
default: withType(scope, number(0), TYPES.undefined)
|
3440
|
+
}, valtypeBinary);
|
3441
|
+
}
|
3442
|
+
|
3282
3443
|
const object = generate(scope, decl.object);
|
3283
3444
|
const property = generate(scope, decl.property);
|
3284
3445
|
|
@@ -3293,24 +3454,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3293
3454
|
|
3294
3455
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
3295
3456
|
[TYPES.array]: [
|
3296
|
-
|
3297
|
-
...property,
|
3298
|
-
|
3299
|
-
// convert to i32 and turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
3300
|
-
Opcodes.i32_to_u,
|
3301
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
3302
|
-
[ Opcodes.i32_mul ],
|
3303
|
-
|
3304
|
-
...(aotPointer ? [] : [
|
3305
|
-
...object,
|
3306
|
-
Opcodes.i32_to_u,
|
3307
|
-
[ Opcodes.i32_add ]
|
3308
|
-
]),
|
3309
|
-
|
3310
|
-
// read from memory
|
3311
|
-
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
3312
|
-
|
3313
|
-
...number(TYPES.number, Valtype.i32),
|
3457
|
+
...loadArray(scope, object, property, aotPointer),
|
3314
3458
|
...setLastType(scope)
|
3315
3459
|
],
|
3316
3460
|
|
@@ -3341,9 +3485,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3341
3485
|
|
3342
3486
|
// return new string (page)
|
3343
3487
|
...number(newPointer),
|
3344
|
-
|
3345
|
-
...number(TYPES.string, Valtype.i32),
|
3346
|
-
...setLastType(scope)
|
3488
|
+
...setLastType(scope, TYPES.string)
|
3347
3489
|
],
|
3348
3490
|
[TYPES.bytestring]: [
|
3349
3491
|
// setup new/out array
|
@@ -3369,9 +3511,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
3369
3511
|
|
3370
3512
|
// return new string (page)
|
3371
3513
|
...number(newPointer),
|
3372
|
-
|
3373
|
-
...number(TYPES.bytestring, Valtype.i32),
|
3374
|
-
...setLastType(scope)
|
3514
|
+
...setLastType(scope, TYPES.bytestring)
|
3375
3515
|
],
|
3376
3516
|
|
3377
3517
|
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
|
@@ -3396,7 +3536,7 @@ const objectHack = node => {
|
|
3396
3536
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3397
3537
|
|
3398
3538
|
// if .name or .length, give up (hack within a hack!)
|
3399
|
-
if (['name', 'length'].includes(node.property.name)) {
|
3539
|
+
if (['name', 'length', 'size', 'description'].includes(node.property.name)) {
|
3400
3540
|
node.object = objectHack(node.object);
|
3401
3541
|
return;
|
3402
3542
|
}
|