porffor 0.2.0-fbab1de → 0.2.0-fde989a
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/README.md +61 -41
- package/compiler/2c.js +316 -71
- package/compiler/builtins.js +43 -19
- package/compiler/codeGen.js +53 -32
- package/compiler/index.js +14 -3
- package/filesize.cmd +2 -0
- package/package.json +1 -1
- package/porf +2 -0
- package/runner/index.js +15 -2
- package/tmp.c +661 -0
- package/r.js +0 -9
package/compiler/builtins.js
CHANGED
@@ -170,25 +170,6 @@ export const BuiltinFuncs = function() {
|
|
170
170
|
]
|
171
171
|
};
|
172
172
|
|
173
|
-
// todo: return false for NaN
|
174
|
-
this.Boolean = {
|
175
|
-
params: [ valtypeBinary ],
|
176
|
-
locals: [],
|
177
|
-
returns: [ valtypeBinary ],
|
178
|
-
returnType: 'boolean',
|
179
|
-
wasm: [
|
180
|
-
[ Opcodes.local_get, 0 ],
|
181
|
-
...(valtype === 'f64' ? [
|
182
|
-
...number(0),
|
183
|
-
[ Opcodes.f64_ne ]
|
184
|
-
] : [
|
185
|
-
...Opcodes.eqz,
|
186
|
-
[ Opcodes.i32_eqz ]
|
187
|
-
]),
|
188
|
-
Opcodes.i32_from
|
189
|
-
]
|
190
|
-
};
|
191
|
-
|
192
173
|
// just return given (default 0) for (new) Object() as we somewhat supports object just not constructor
|
193
174
|
this.Object = {
|
194
175
|
params: [ valtypeBinary ],
|
@@ -699,6 +680,49 @@ export const BuiltinFuncs = function() {
|
|
699
680
|
};
|
700
681
|
|
701
682
|
|
683
|
+
this.__Porffor_type = {
|
684
|
+
params: [ valtypeBinary, Valtype.i32 ],
|
685
|
+
typedParams: true,
|
686
|
+
locals: [ Valtype.i32, Valtype.i32 ],
|
687
|
+
returns: [ valtypeBinary ],
|
688
|
+
returnType: process.argv.includes('-bytestring') ? '_bytestring' : 'string',
|
689
|
+
wasm: (scope, { TYPE_NAMES, typeSwitch, makeString }) => {
|
690
|
+
const bc = {};
|
691
|
+
for (const x in TYPE_NAMES) {
|
692
|
+
bc[x] = makeString(scope, TYPE_NAMES[x], false, '#Porffor_type_result');
|
693
|
+
}
|
694
|
+
|
695
|
+
return typeSwitch(scope, [ [ Opcodes.local_get, 1 ] ], bc);
|
696
|
+
}
|
697
|
+
};
|
698
|
+
|
699
|
+
const localIsOneOf = (getter, arr, valtype = valtypeBinary) => {
|
700
|
+
const out = [];
|
701
|
+
|
702
|
+
for (let i = 0; i < arr.length; i++) {
|
703
|
+
out.push(...getter, ...number(arr[i], valtype), valtype === Valtype.f64 ? [ Opcodes.f64_eq ] : [ Opcodes.i32_eq ]);
|
704
|
+
if (i !== 0) out.push([ Opcodes.i32_or ]);
|
705
|
+
}
|
706
|
+
|
707
|
+
return out;
|
708
|
+
};
|
709
|
+
|
710
|
+
this.__Porffor_pointer = {
|
711
|
+
params: [ valtypeBinary, Valtype.i32 ],
|
712
|
+
typedParams: true,
|
713
|
+
locals: [ Valtype.i32, Valtype.i32 ],
|
714
|
+
returns: [ valtypeBinary ],
|
715
|
+
wasm: (scope, { TYPES }) => [
|
716
|
+
...localIsOneOf([ [ Opcodes.local_get, 1 ] ], [ TYPES.string, TYPES._array, TYPES._bytestring ], Valtype.i32),
|
717
|
+
[ Opcodes.if, valtypeBinary ],
|
718
|
+
[ Opcodes.local_get, 0 ],
|
719
|
+
[ Opcodes.else ],
|
720
|
+
...number(NaN),
|
721
|
+
[ Opcodes.end ]
|
722
|
+
]
|
723
|
+
};
|
724
|
+
|
725
|
+
|
702
726
|
this.__SIMD_i32x4_load = {
|
703
727
|
params: [ Valtype.i32 ],
|
704
728
|
locals: [],
|
package/compiler/codeGen.js
CHANGED
@@ -160,7 +160,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
160
160
|
|
161
161
|
case 'TaggedTemplateExpression': {
|
162
162
|
const funcs = {
|
163
|
-
|
163
|
+
__Porffor_asm: str => {
|
164
164
|
let out = [];
|
165
165
|
|
166
166
|
for (const line of str.split('\n')) {
|
@@ -196,19 +196,19 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
196
196
|
return out;
|
197
197
|
},
|
198
198
|
|
199
|
-
|
200
|
-
|
199
|
+
__Porffor_bs: str => [
|
200
|
+
...makeString(scope, str, undefined, undefined, true),
|
201
201
|
|
202
|
-
|
203
|
-
|
204
|
-
|
202
|
+
...number(TYPES._bytestring, Valtype.i32),
|
203
|
+
setLastType(scope)
|
204
|
+
],
|
205
|
+
__Porffor_s: str => [
|
206
|
+
...makeString(scope, str, undefined, undefined, false),
|
205
207
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
}
|
211
|
-
}
|
208
|
+
...number(TYPES.string, Valtype.i32),
|
209
|
+
setLastType(scope)
|
210
|
+
],
|
211
|
+
};
|
212
212
|
|
213
213
|
const name = decl.tag.name;
|
214
214
|
// hack for inline asm
|
@@ -274,25 +274,25 @@ const generateIdent = (scope, decl) => {
|
|
274
274
|
const name = mapName(rawName);
|
275
275
|
let local = scope.locals[rawName];
|
276
276
|
|
277
|
-
if (builtinVars
|
277
|
+
if (Object.hasOwn(builtinVars, name)) {
|
278
278
|
if (builtinVars[name].floatOnly && valtype[0] === 'i') throw new Error(`Cannot use ${unhackName(name)} with integer valtype`);
|
279
279
|
return builtinVars[name];
|
280
280
|
}
|
281
281
|
|
282
|
-
if (builtinFuncs
|
282
|
+
if (Object.hasOwn(builtinFuncs, name) || Object.hasOwn(internalConstrs, name)) {
|
283
283
|
// todo: return an actual something
|
284
284
|
return number(1);
|
285
285
|
}
|
286
286
|
|
287
|
-
if (local === undefined) {
|
287
|
+
if (local?.idx === undefined) {
|
288
288
|
// no local var with name
|
289
|
-
if (
|
290
|
-
if (funcIndex
|
289
|
+
if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name]);
|
290
|
+
if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name]);
|
291
291
|
|
292
|
-
if (globals
|
292
|
+
if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
|
293
293
|
}
|
294
294
|
|
295
|
-
if (local === undefined && rawName.startsWith('__')) {
|
295
|
+
if (local?.idx === undefined && rawName.startsWith('__')) {
|
296
296
|
// return undefined if unknown key in already known var
|
297
297
|
let parent = rawName.slice(2).split('_').slice(0, -1).join('_');
|
298
298
|
if (parent.includes('_')) parent = '__' + parent;
|
@@ -301,7 +301,7 @@ const generateIdent = (scope, decl) => {
|
|
301
301
|
if (!parentLookup[1]) return number(UNDEFINED);
|
302
302
|
}
|
303
303
|
|
304
|
-
if (local === undefined) return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
304
|
+
if (local?.idx === undefined) return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
305
305
|
|
306
306
|
return [ [ Opcodes.local_get, local.idx ] ];
|
307
307
|
};
|
@@ -925,7 +925,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
925
925
|
[ Opcodes.i32_or ],
|
926
926
|
[ Opcodes.if, Blocktype.void ],
|
927
927
|
...number(0, Valtype.i32),
|
928
|
-
[ Opcodes.br,
|
928
|
+
[ Opcodes.br, 2 ],
|
929
929
|
[ Opcodes.end ],
|
930
930
|
|
931
931
|
...compareStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ]),
|
@@ -981,7 +981,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
981
981
|
localInd: allLocals.length,
|
982
982
|
};
|
983
983
|
|
984
|
-
wasm = wasm(scope, { TYPES, typeSwitch, makeArray });
|
984
|
+
wasm = wasm(scope, { TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString });
|
985
985
|
}
|
986
986
|
|
987
987
|
let baseGlobalIdx, i = 0;
|
@@ -1286,8 +1286,8 @@ const getNodeType = (scope, node) => {
|
|
1286
1286
|
const generateLiteral = (scope, decl, global, name) => {
|
1287
1287
|
if (decl.value === null) return number(NULL);
|
1288
1288
|
|
1289
|
+
// hack: just return 1 for regex literals
|
1289
1290
|
if (decl.regex) {
|
1290
|
-
scope.regex[name] = decl.regex;
|
1291
1291
|
return number(1);
|
1292
1292
|
}
|
1293
1293
|
|
@@ -1932,6 +1932,8 @@ const generateVar = (scope, decl) => {
|
|
1932
1932
|
for (const x of decl.declarations) {
|
1933
1933
|
const name = mapName(x.id.name);
|
1934
1934
|
|
1935
|
+
if (!name) return todo('destructuring is not supported yet');
|
1936
|
+
|
1935
1937
|
if (x.init && isFuncType(x.init.type)) {
|
1936
1938
|
// hack for let a = function () { ... }
|
1937
1939
|
x.init.id = { name };
|
@@ -2070,6 +2072,8 @@ const generateAssign = (scope, decl) => {
|
|
2070
2072
|
];
|
2071
2073
|
}
|
2072
2074
|
|
2075
|
+
if (!name) return todo('destructuring is not supported yet');
|
2076
|
+
|
2073
2077
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2074
2078
|
|
2075
2079
|
if (local === undefined) {
|
@@ -2383,7 +2387,13 @@ const generateForOf = (scope, decl) => {
|
|
2383
2387
|
// setup local for left
|
2384
2388
|
generate(scope, decl.left);
|
2385
2389
|
|
2386
|
-
|
2390
|
+
let leftName = decl.left.declarations?.[0]?.id?.name;
|
2391
|
+
if (!leftName && decl.left.name) {
|
2392
|
+
leftName = decl.left.name;
|
2393
|
+
|
2394
|
+
generateVar(scope, { kind: 'var', _bare: true, declarations: [ { id: { name: leftName } } ] })
|
2395
|
+
}
|
2396
|
+
|
2387
2397
|
const [ local, isGlobal ] = lookupName(scope, leftName);
|
2388
2398
|
|
2389
2399
|
depth.push('block');
|
@@ -2626,15 +2636,14 @@ const StoreOps = {
|
|
2626
2636
|
|
2627
2637
|
let data = [];
|
2628
2638
|
|
2629
|
-
const compileBytes = (val, itemType
|
2639
|
+
const compileBytes = (val, itemType) => {
|
2630
2640
|
// todo: this is a mess and needs confirming / ????
|
2631
2641
|
switch (itemType) {
|
2632
2642
|
case 'i8': return [ val % 256 ];
|
2633
|
-
case 'i16': return [ val % 256,
|
2634
|
-
|
2635
|
-
case 'i32':
|
2636
|
-
|
2637
|
-
return enforceFourBytes(signedLEB128(val));
|
2643
|
+
case 'i16': return [ val % 256, (val / 256 | 0) % 256 ];
|
2644
|
+
case 'i16': return [ val % 256, (val / 256 | 0) % 256 ];
|
2645
|
+
case 'i32': return [...new Uint8Array(new Int32Array([ val ]).buffer)];
|
2646
|
+
// todo: i64
|
2638
2647
|
|
2639
2648
|
case 'f64': return ieee754_binary64(val);
|
2640
2649
|
}
|
@@ -2724,7 +2733,7 @@ const byteStringable = str => {
|
|
2724
2733
|
return true;
|
2725
2734
|
};
|
2726
2735
|
|
2727
|
-
const makeString = (scope, str, global = false, name = '$undeclared') => {
|
2736
|
+
const makeString = (scope, str, global = false, name = '$undeclared', forceBytestring = undefined) => {
|
2728
2737
|
const rawElements = new Array(str.length);
|
2729
2738
|
let byteStringable = process.argv.includes('-bytestring');
|
2730
2739
|
for (let i = 0; i < str.length; i++) {
|
@@ -2734,6 +2743,8 @@ const makeString = (scope, str, global = false, name = '$undeclared') => {
|
|
2734
2743
|
if (byteStringable && c > 0xFF) byteStringable = false;
|
2735
2744
|
}
|
2736
2745
|
|
2746
|
+
if (byteStringable && forceBytestring === false) byteStringable = false;
|
2747
|
+
|
2737
2748
|
return makeArray(scope, {
|
2738
2749
|
rawElements
|
2739
2750
|
}, global, name, false, byteStringable ? 'i8' : 'i16')[0];
|
@@ -2859,7 +2870,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2859
2870
|
setLastType(scope)
|
2860
2871
|
],
|
2861
2872
|
|
2862
|
-
default:
|
2873
|
+
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet')
|
2863
2874
|
});
|
2864
2875
|
};
|
2865
2876
|
|
@@ -2981,6 +2992,16 @@ const generateCode = (scope, decl) => {
|
|
2981
2992
|
};
|
2982
2993
|
|
2983
2994
|
const internalConstrs = {
|
2995
|
+
Boolean: {
|
2996
|
+
generate: (scope, decl) => {
|
2997
|
+
if (decl.arguments.length === 0) return number(0);
|
2998
|
+
|
2999
|
+
// should generate/run all args
|
3000
|
+
return truthy(scope, generate(scope, decl.arguments[0]), getNodeType(scope, decl.arguments[0]), false, false);
|
3001
|
+
},
|
3002
|
+
type: TYPES.boolean
|
3003
|
+
},
|
3004
|
+
|
2984
3005
|
Array: {
|
2985
3006
|
generate: (scope, decl, global, name) => {
|
2986
3007
|
// new Array(i0, i1, ...)
|
package/compiler/index.js
CHANGED
@@ -68,11 +68,17 @@ export default (code, flags) => {
|
|
68
68
|
console.log([...pages.keys()].map(x => `\x1B[36m - ${x}\x1B[0m`).join('\n') + '\n');
|
69
69
|
}
|
70
70
|
|
71
|
-
const out = { wasm: sections, funcs, globals, tags, exceptions, pages };
|
71
|
+
const out = { wasm: sections, funcs, globals, tags, exceptions, pages, data };
|
72
72
|
|
73
73
|
const target = getArg('target') ?? getArg('t') ?? 'wasm';
|
74
74
|
const outFile = getArg('o');
|
75
75
|
|
76
|
+
if (target === 'wasm' && outFile) {
|
77
|
+
writeFileSync(outFile, Buffer.from(sections));
|
78
|
+
|
79
|
+
if (process.version) process.exit();
|
80
|
+
}
|
81
|
+
|
76
82
|
if (target === 'c') {
|
77
83
|
const c = toc(out);
|
78
84
|
out.c = c;
|
@@ -87,11 +93,16 @@ export default (code, flags) => {
|
|
87
93
|
}
|
88
94
|
|
89
95
|
if (target === 'native') {
|
90
|
-
|
96
|
+
let compiler = getArg('compiler') ?? 'clang';
|
91
97
|
const cO = getArg('cO') ?? 'Ofast';
|
92
98
|
|
99
|
+
if (compiler === 'zig') compiler = [ 'zig', 'cc' ];
|
100
|
+
else compiler = [ compiler ];
|
101
|
+
|
93
102
|
const tmpfile = 'tmp.c';
|
94
|
-
const args = [ compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native' ];
|
103
|
+
// const args = [ compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native', '-s', '-fno-unwind-tables', '-fno-asynchronous-unwind-tables', '-ffunction-sections', '-fdata-sections', '-Wl', '-fno-ident', '-fno-exceptions', '-ffast-math' ];
|
104
|
+
// const args = [ ...compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native', '-s', '-ffast-math', '-fno-exceptions', '-target', 'x86_64-linux' ];
|
105
|
+
const args = [ ...compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native', '-s', '-ffast-math', '-fno-exceptions' ];
|
95
106
|
|
96
107
|
const c = toc(out);
|
97
108
|
writeFileSync(tmpfile, c);
|
package/filesize.cmd
ADDED
package/package.json
CHANGED
package/porf
ADDED
package/runner/index.js
CHANGED
@@ -15,9 +15,22 @@ if (process.argv.includes('-compile-hints')) {
|
|
15
15
|
// --experimental-wasm-return-call (on by default)
|
16
16
|
}
|
17
17
|
|
18
|
-
|
18
|
+
let file = process.argv.slice(2).find(x => x[0] !== '-');
|
19
|
+
if (['run', 'wasm', 'native', 'c'].includes(file)) {
|
20
|
+
if (['wasm', 'native', 'c'].includes(file)) {
|
21
|
+
process.argv.push(`-target=${file}`);
|
22
|
+
}
|
23
|
+
|
24
|
+
file = process.argv.slice(process.argv.indexOf(file) + 1).find(x => x[0] !== '-');
|
25
|
+
|
26
|
+
const nonOptOutFile = process.argv.slice(process.argv.indexOf(file) + 1).find(x => x[0] !== '-');
|
27
|
+
if (nonOptOutFile) {
|
28
|
+
process.argv.push(`-o=${nonOptOutFile}`);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
19
32
|
if (!file) {
|
20
|
-
if (process.argv.includes('-v')) {
|
33
|
+
if (process.argv.includes('-v') || process.argv.includes('--version')) {
|
21
34
|
// just print version
|
22
35
|
console.log((await import('./version.js')).default);
|
23
36
|
process.exit(0);
|