porffor 0.41.2 → 0.41.4
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/_internal_string.ts +0 -4
- package/compiler/builtins/object.ts +2 -1
- package/compiler/builtins/porffor.d.ts +4 -2
- package/compiler/builtins/string_f64.ts +30 -5
- package/compiler/builtins/z_ecma262.ts +6 -0
- package/compiler/builtins_precompiled.js +59 -58
- package/compiler/codegen.js +132 -97
- package/compiler/types.js +1 -0
- package/compiler/wrap.js +2 -0
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -96,10 +96,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
96
96
|
return cacheAst(decl, generateChain(scope, decl));
|
97
97
|
|
98
98
|
case 'CallExpression':
|
99
|
-
return cacheAst(decl, generateCall(scope, decl, global, name, valueUnused));
|
100
|
-
|
101
99
|
case 'NewExpression':
|
102
|
-
return cacheAst(decl,
|
100
|
+
return cacheAst(decl, generateCall(scope, decl, global, name, valueUnused));
|
103
101
|
|
104
102
|
case 'ThisExpression':
|
105
103
|
return cacheAst(decl, generateThis(scope, decl));
|
@@ -189,6 +187,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
189
187
|
case 'TemplateLiteral':
|
190
188
|
return cacheAst(decl, generateTemplate(scope, decl));
|
191
189
|
|
190
|
+
case 'TaggedTemplateExpression':
|
191
|
+
return cacheAst(decl, generateTaggedTemplate(scope, decl, global, name));
|
192
|
+
|
192
193
|
case 'ExportNamedDeclaration':
|
193
194
|
if (!decl.declaration) return todo(scope, 'unsupported export declaration');
|
194
195
|
|
@@ -209,79 +210,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
209
210
|
|
210
211
|
return cacheAst(decl, []);
|
211
212
|
|
212
|
-
case 'TaggedTemplateExpression': {
|
213
|
-
const funcs = {
|
214
|
-
__Porffor_wasm: str => {
|
215
|
-
let out = [];
|
216
|
-
|
217
|
-
for (const line of str.split('\n')) {
|
218
|
-
const asm = line.trim().split(';;')[0].split(' ').filter(x => x);
|
219
|
-
if (!asm[0]) continue; // blank
|
220
|
-
|
221
|
-
if (asm[0] === 'local') {
|
222
|
-
const [ name, type ] = asm.slice(1);
|
223
|
-
scope.locals[name] = { idx: scope.localInd++, type: Valtype[type] };
|
224
|
-
continue;
|
225
|
-
}
|
226
|
-
|
227
|
-
if (asm[0] === 'returns') {
|
228
|
-
scope.returns = asm.slice(1).map(x => Valtype[x]);
|
229
|
-
continue;
|
230
|
-
}
|
231
|
-
|
232
|
-
let inst = Opcodes[asm[0].replace('.', '_')];
|
233
|
-
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
234
|
-
if (!Array.isArray(inst)) inst = [ inst ];
|
235
|
-
|
236
|
-
const immediates = asm.slice(1).map(x => {
|
237
|
-
const int = parseInt(x);
|
238
|
-
if (Number.isNaN(int)) {
|
239
|
-
if (builtinFuncs[x]) {
|
240
|
-
if (funcIndex[x] == null) includeBuiltin(scope, x);
|
241
|
-
return funcIndex[x];
|
242
|
-
}
|
243
|
-
|
244
|
-
return scope.locals[x]?.idx ?? globals[x].idx;
|
245
|
-
}
|
246
|
-
return int;
|
247
|
-
});
|
248
|
-
|
249
|
-
const encodeFunc = ({
|
250
|
-
[Opcodes.f64_const]: x => x,
|
251
|
-
[Opcodes.if]: unsignedLEB128,
|
252
|
-
[Opcodes.loop]: unsignedLEB128
|
253
|
-
})[inst[0]] ?? signedLEB128;
|
254
|
-
out.push([ ...inst, ...immediates.flatMap(x => encodeFunc(x)) ]);
|
255
|
-
}
|
256
|
-
|
257
|
-
return out;
|
258
|
-
},
|
259
|
-
|
260
|
-
__Porffor_bs: str => makeString(scope, str, global, name, true),
|
261
|
-
__Porffor_s: str => makeString(scope, str, global, name, false)
|
262
|
-
};
|
263
|
-
|
264
|
-
const func = decl.tag.name;
|
265
|
-
// hack for inline asm
|
266
|
-
if (!funcs[func]) return cacheAst(decl, todo(scope, 'tagged template expressions not implemented', true));
|
267
|
-
|
268
|
-
const { quasis, expressions } = decl.quasi;
|
269
|
-
let str = quasis[0].value.raw;
|
270
|
-
|
271
|
-
for (let i = 0; i < expressions.length; i++) {
|
272
|
-
const e = expressions[i];
|
273
|
-
if (!e.name) {
|
274
|
-
if (e.type === 'BinaryExpression' && e.operator === '+' && e.left.type === 'Identifier' && e.right.type === 'Literal') {
|
275
|
-
str += lookupName(scope, e.left.name)[0].idx + e.right.value;
|
276
|
-
} else todo(scope, 'unsupported expression in intrinsic');
|
277
|
-
} else str += lookupName(scope, e.name)[0].idx;
|
278
|
-
|
279
|
-
str += quasis[i + 1].value.raw;
|
280
|
-
}
|
281
|
-
|
282
|
-
return cacheAst(decl, funcs[func](str));
|
283
|
-
}
|
284
|
-
|
285
213
|
default:
|
286
214
|
// ignore typescript nodes
|
287
215
|
if (decl.type.startsWith('TS') ||
|
@@ -601,18 +529,21 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
|
|
601
529
|
[ Opcodes.i32_eqz ], */
|
602
530
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
603
531
|
] ],
|
604
|
-
|
605
|
-
// [ 'default', [
|
606
|
-
// // other types are always truthy
|
607
|
-
// ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
608
|
-
// ...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
609
|
-
// ] ]
|
532
|
+
|
610
533
|
...(truthyMode === 'full' ? [ [ [ TYPES.booleanobject, TYPES.numberobject ], [
|
611
534
|
// always truthy :))
|
612
535
|
...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
613
536
|
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
614
537
|
] ] ] : []),
|
538
|
+
|
615
539
|
[ 'default', def ]
|
540
|
+
|
541
|
+
// [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
|
542
|
+
// [ 'default', [
|
543
|
+
// // other types are always truthy
|
544
|
+
// ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
545
|
+
// ...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
546
|
+
// ] ]
|
616
547
|
], intOut ? Valtype.i32 : valtypeBinary)
|
617
548
|
];
|
618
549
|
};
|
@@ -666,18 +597,21 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode
|
|
666
597
|
[ Opcodes.i32_eqz ],
|
667
598
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
668
599
|
] ],
|
669
|
-
|
670
|
-
// [ 'default', [
|
671
|
-
// // other types are always truthy
|
672
|
-
// ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
673
|
-
// ...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
674
|
-
// ] ]
|
600
|
+
|
675
601
|
...(truthyMode === 'full' ? [ [ [ TYPES.booleanobject, TYPES.numberobject ], [
|
676
602
|
// always truthy :))
|
677
603
|
...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
678
604
|
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
679
605
|
] ] ] : []),
|
606
|
+
|
680
607
|
[ 'default', def ]
|
608
|
+
|
609
|
+
// [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
|
610
|
+
// [ 'default', [
|
611
|
+
// // other types are always truthy
|
612
|
+
// ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
613
|
+
// ...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
614
|
+
// ] ]
|
681
615
|
], intOut ? Valtype.i32 : valtypeBinary)
|
682
616
|
];
|
683
617
|
};
|
@@ -749,7 +683,8 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
749
683
|
// todo: niche null hell with 0
|
750
684
|
|
751
685
|
if ((knownLeft === TYPES.string || knownRight === TYPES.string) ||
|
752
|
-
(knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
|
686
|
+
(knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) ||
|
687
|
+
(knownLeft === TYPES.stringobject || knownRight === TYPES.stringobject)) {
|
753
688
|
if (op === '+') {
|
754
689
|
// string concat (a + b)
|
755
690
|
return concatStrings(scope, left, right, leftType, rightType);
|
@@ -887,6 +822,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
|
|
887
822
|
// switch primitive types to primitive object types
|
888
823
|
if (checkType === TYPES.number) checkType = TYPES.numberobject;
|
889
824
|
if (checkType === TYPES.boolean) checkType = TYPES.booleanobject;
|
825
|
+
if (checkType === TYPES.string) checkType = TYPES.stringobject;
|
890
826
|
|
891
827
|
// currently unsupported types
|
892
828
|
if ([TYPES.string].includes(checkType)) {
|
@@ -1269,6 +1205,14 @@ const getNodeType = (scope, node) => {
|
|
1269
1205
|
|
1270
1206
|
if (node.type === 'CallExpression' || node.type === 'NewExpression') {
|
1271
1207
|
const name = node.callee.name;
|
1208
|
+
|
1209
|
+
// hack: special primitive object types
|
1210
|
+
if (node.type === 'NewExpression') {
|
1211
|
+
if (name === 'Number') return TYPES.numberobject;
|
1212
|
+
if (name === 'Boolean') return TYPES.booleanobject;
|
1213
|
+
if (name === 'String') return TYPES.stringobject;
|
1214
|
+
}
|
1215
|
+
|
1272
1216
|
if (name == null) {
|
1273
1217
|
// iife
|
1274
1218
|
if (scope.locals['#last_type']) return getLastType(scope);
|
@@ -1375,11 +1319,14 @@ const getNodeType = (scope, node) => {
|
|
1375
1319
|
|
1376
1320
|
if ((knownLeft != null || knownRight != null) && !(
|
1377
1321
|
(knownLeft === TYPES.string || knownRight === TYPES.string) ||
|
1378
|
-
(knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
|
1322
|
+
(knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) ||
|
1323
|
+
(knownLeft === TYPES.stringobject || knownRight === TYPES.stringobject)
|
1379
1324
|
)) return TYPES.number;
|
1380
1325
|
|
1381
|
-
if (
|
1382
|
-
|
1326
|
+
if (
|
1327
|
+
(knownLeft === TYPES.string || knownRight === TYPES.string) ||
|
1328
|
+
(knownLeft === TYPES.stringobject || knownRight === TYPES.stringobject)
|
1329
|
+
) return TYPES.string;
|
1383
1330
|
|
1384
1331
|
// guess bytestring, could really be bytestring or string
|
1385
1332
|
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
|
@@ -1727,6 +1674,7 @@ const aliasPrimObjsBC = bc => {
|
|
1727
1674
|
|
1728
1675
|
add(TYPES.boolean, TYPES.booleanobject);
|
1729
1676
|
add(TYPES.number, TYPES.numberobject);
|
1677
|
+
add(TYPES.string, TYPES.stringobject);
|
1730
1678
|
};
|
1731
1679
|
|
1732
1680
|
const createThisArg = (scope, decl) => {
|
@@ -1803,6 +1751,8 @@ const createThisArg = (scope, decl) => {
|
|
1803
1751
|
};
|
1804
1752
|
|
1805
1753
|
const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
1754
|
+
if (decl.type === 'NewExpression') decl._new = true;
|
1755
|
+
|
1806
1756
|
let out = [];
|
1807
1757
|
let name = decl.callee.name;
|
1808
1758
|
|
@@ -2100,6 +2050,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2100
2050
|
};
|
2101
2051
|
}
|
2102
2052
|
|
2053
|
+
// alias primitive prototype with primitive object types
|
2054
|
+
aliasPrimObjsBC(protoBC);
|
2055
|
+
|
2103
2056
|
return [
|
2104
2057
|
...(usePointerCache ? [
|
2105
2058
|
...rawPointer,
|
@@ -2583,11 +2536,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2583
2536
|
return out;
|
2584
2537
|
};
|
2585
2538
|
|
2586
|
-
const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
|
2587
|
-
...decl,
|
2588
|
-
_new: true
|
2589
|
-
}, _global, _name);
|
2590
|
-
|
2591
2539
|
const generateThis = (scope, decl) => {
|
2592
2540
|
if (!scope.constr) {
|
2593
2541
|
// this in a non-constructor context is a reference to globalThis
|
@@ -5885,6 +5833,92 @@ export const generateTemplate = (scope, decl) => {
|
|
5885
5833
|
return generate(scope, current);
|
5886
5834
|
};
|
5887
5835
|
|
5836
|
+
const generateTaggedTemplate = (scope, decl, global = false, name = undefined) => {
|
5837
|
+
const intrinsics = {
|
5838
|
+
__Porffor_wasm: str => {
|
5839
|
+
let out = [];
|
5840
|
+
|
5841
|
+
for (const line of str.split('\n')) {
|
5842
|
+
const asm = line.trim().split(';;')[0].split(' ').filter(x => x);
|
5843
|
+
if (!asm[0]) continue; // blank
|
5844
|
+
|
5845
|
+
if (asm[0] === 'local') {
|
5846
|
+
const [ name, type ] = asm.slice(1);
|
5847
|
+
scope.locals[name] = { idx: scope.localInd++, type: Valtype[type] };
|
5848
|
+
continue;
|
5849
|
+
}
|
5850
|
+
|
5851
|
+
if (asm[0] === 'returns') {
|
5852
|
+
scope.returns = asm.slice(1).map(x => Valtype[x]);
|
5853
|
+
continue;
|
5854
|
+
}
|
5855
|
+
|
5856
|
+
let inst = Opcodes[asm[0].replace('.', '_')];
|
5857
|
+
if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
|
5858
|
+
if (!Array.isArray(inst)) inst = [ inst ];
|
5859
|
+
|
5860
|
+
const immediates = asm.slice(1).map(x => {
|
5861
|
+
const int = parseInt(x);
|
5862
|
+
if (Number.isNaN(int)) {
|
5863
|
+
if (builtinFuncs[x]) {
|
5864
|
+
if (funcIndex[x] == null) includeBuiltin(scope, x);
|
5865
|
+
return funcIndex[x];
|
5866
|
+
}
|
5867
|
+
|
5868
|
+
return scope.locals[x]?.idx ?? globals[x].idx;
|
5869
|
+
}
|
5870
|
+
return int;
|
5871
|
+
});
|
5872
|
+
|
5873
|
+
const encodeFunc = ({
|
5874
|
+
[Opcodes.f64_const]: x => x,
|
5875
|
+
[Opcodes.if]: unsignedLEB128,
|
5876
|
+
[Opcodes.loop]: unsignedLEB128
|
5877
|
+
})[inst[0]] ?? signedLEB128;
|
5878
|
+
out.push([ ...inst, ...immediates.flatMap(x => encodeFunc(x)) ]);
|
5879
|
+
}
|
5880
|
+
|
5881
|
+
return out;
|
5882
|
+
},
|
5883
|
+
|
5884
|
+
__Porffor_bs: str => makeString(scope, str, global, name, true),
|
5885
|
+
__Porffor_s: str => makeString(scope, str, global, name, false)
|
5886
|
+
};
|
5887
|
+
|
5888
|
+
const { quasis, expressions } = decl.quasi;
|
5889
|
+
if (intrinsics[decl.tag.name]) {
|
5890
|
+
let str = quasis[0].value.raw;
|
5891
|
+
|
5892
|
+
for (let i = 0; i < expressions.length; i++) {
|
5893
|
+
const e = expressions[i];
|
5894
|
+
if (!e.name) {
|
5895
|
+
if (e.type === 'BinaryExpression' && e.operator === '+' && e.left.type === 'Identifier' && e.right.type === 'Literal') {
|
5896
|
+
str += lookupName(scope, e.left.name)[0].idx + e.right.value;
|
5897
|
+
} else todo(scope, 'unsupported expression in intrinsic');
|
5898
|
+
} else str += lookupName(scope, e.name)[0].idx;
|
5899
|
+
|
5900
|
+
str += quasis[i + 1].value.raw;
|
5901
|
+
}
|
5902
|
+
|
5903
|
+
return cacheAst(decl, intrinsics[decl.tag.name](str));
|
5904
|
+
}
|
5905
|
+
|
5906
|
+
return generate(scope, {
|
5907
|
+
type: 'CallExpression',
|
5908
|
+
callee: decl.tag,
|
5909
|
+
arguments: [
|
5910
|
+
{ // strings
|
5911
|
+
type: 'ArrayExpression',
|
5912
|
+
elements: quasis.map(x => ({
|
5913
|
+
type: 'Literal',
|
5914
|
+
value: x.value.cooked
|
5915
|
+
}))
|
5916
|
+
},
|
5917
|
+
...expressions
|
5918
|
+
]
|
5919
|
+
});
|
5920
|
+
};
|
5921
|
+
|
5888
5922
|
globalThis._uniqId = 0;
|
5889
5923
|
const uniqId = () => '_' + globalThis._uniqId++;
|
5890
5924
|
|
@@ -6195,6 +6229,7 @@ const generateFunc = (scope, decl) => {
|
|
6195
6229
|
].includes(typeAnno.type)) {
|
6196
6230
|
let types = [ typeAnno.type ];
|
6197
6231
|
if (typeAnno.type === TYPES.number) types.push(TYPES.numberobject);
|
6232
|
+
if (typeAnno.type === TYPES.string) types.push(TYPES.stringobject);
|
6198
6233
|
|
6199
6234
|
prelude.push(
|
6200
6235
|
...typeIsNotOneOf([ [ Opcodes.local_get, func.locals[name].idx + 1 ] ], types),
|
package/compiler/types.js
CHANGED
package/compiler/wrap.js
CHANGED
@@ -159,6 +159,8 @@ ${flags & 0b0001 ? ` get func idx: ${get}
|
|
159
159
|
return Array.from(read(Uint8Array, memory, value + 4, length)).map(x => String.fromCharCode(x)).join('');
|
160
160
|
}
|
161
161
|
|
162
|
+
case TYPES.stringobject: return new String(porfToJSValue({ memory, funcs, pages }, value, TYPES.string));
|
163
|
+
|
162
164
|
case TYPES.array: {
|
163
165
|
let length = read(Uint32Array, memory, value, 1)[0];
|
164
166
|
if (override) length = override;
|
package/package.json
CHANGED