porffor 0.20.10 → 0.21.0
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/codegen.js +155 -38
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -74,91 +74,94 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
74
74
|
return cacheAst(decl, generateCode(scope, decl));
|
75
75
|
|
76
76
|
case 'ReturnStatement':
|
77
|
-
return cacheAst(decl, generateReturn(scope, decl))
|
77
|
+
return cacheAst(decl, generateReturn(scope, decl));
|
78
78
|
|
79
79
|
case 'ExpressionStatement':
|
80
|
-
return cacheAst(decl, generateExp(scope, decl))
|
80
|
+
return cacheAst(decl, generateExp(scope, decl));
|
81
81
|
|
82
82
|
case 'SequenceExpression':
|
83
|
-
return cacheAst(decl, generateSequence(scope, decl))
|
83
|
+
return cacheAst(decl, generateSequence(scope, decl));
|
84
84
|
|
85
85
|
case 'ChainExpression':
|
86
|
-
return cacheAst(decl, generateChain(scope, decl))
|
86
|
+
return cacheAst(decl, generateChain(scope, decl));
|
87
87
|
|
88
88
|
case 'CallExpression':
|
89
|
-
return cacheAst(decl, generateCall(scope, decl, global, name, valueUnused))
|
89
|
+
return cacheAst(decl, generateCall(scope, decl, global, name, valueUnused));
|
90
90
|
|
91
91
|
case 'NewExpression':
|
92
|
-
return cacheAst(decl, generateNew(scope, decl, global, name))
|
92
|
+
return cacheAst(decl, generateNew(scope, decl, global, name));
|
93
93
|
|
94
94
|
case 'Literal':
|
95
|
-
return cacheAst(decl, generateLiteral(scope, decl, global, name))
|
95
|
+
return cacheAst(decl, generateLiteral(scope, decl, global, name));
|
96
96
|
|
97
97
|
case 'VariableDeclaration':
|
98
|
-
return cacheAst(decl, generateVar(scope, decl))
|
98
|
+
return cacheAst(decl, generateVar(scope, decl));
|
99
99
|
|
100
100
|
case 'AssignmentExpression':
|
101
|
-
return cacheAst(decl, generateAssign(scope, decl))
|
101
|
+
return cacheAst(decl, generateAssign(scope, decl));
|
102
102
|
|
103
103
|
case 'UnaryExpression':
|
104
|
-
return cacheAst(decl, generateUnary(scope, decl))
|
104
|
+
return cacheAst(decl, generateUnary(scope, decl));
|
105
105
|
|
106
106
|
case 'UpdateExpression':
|
107
|
-
return cacheAst(decl, generateUpdate(scope, decl, global, name, valueUnused))
|
107
|
+
return cacheAst(decl, generateUpdate(scope, decl, global, name, valueUnused));
|
108
108
|
|
109
109
|
case 'IfStatement':
|
110
|
-
return cacheAst(decl, generateIf(scope, decl))
|
110
|
+
return cacheAst(decl, generateIf(scope, decl));
|
111
111
|
|
112
112
|
case 'ForStatement':
|
113
|
-
return cacheAst(decl, generateFor(scope, decl))
|
113
|
+
return cacheAst(decl, generateFor(scope, decl));
|
114
114
|
|
115
115
|
case 'WhileStatement':
|
116
|
-
return cacheAst(decl, generateWhile(scope, decl))
|
116
|
+
return cacheAst(decl, generateWhile(scope, decl));
|
117
117
|
|
118
118
|
case 'DoWhileStatement':
|
119
|
-
return cacheAst(decl, generateDoWhile(scope, decl))
|
119
|
+
return cacheAst(decl, generateDoWhile(scope, decl));
|
120
120
|
|
121
121
|
case 'ForOfStatement':
|
122
|
-
return cacheAst(decl, generateForOf(scope, decl))
|
122
|
+
return cacheAst(decl, generateForOf(scope, decl));
|
123
|
+
|
124
|
+
case 'ForInStatement':
|
125
|
+
return cacheAst(decl, generateForIn(scope, decl));
|
123
126
|
|
124
127
|
case 'SwitchStatement':
|
125
|
-
return cacheAst(decl, generateSwitch(scope, decl))
|
128
|
+
return cacheAst(decl, generateSwitch(scope, decl));
|
126
129
|
|
127
130
|
case 'BreakStatement':
|
128
|
-
return cacheAst(decl, generateBreak(scope, decl))
|
131
|
+
return cacheAst(decl, generateBreak(scope, decl));
|
129
132
|
|
130
133
|
case 'ContinueStatement':
|
131
|
-
return cacheAst(decl, generateContinue(scope, decl))
|
134
|
+
return cacheAst(decl, generateContinue(scope, decl));
|
132
135
|
|
133
136
|
case 'LabeledStatement':
|
134
|
-
return cacheAst(decl, generateLabel(scope, decl))
|
137
|
+
return cacheAst(decl, generateLabel(scope, decl));
|
135
138
|
|
136
139
|
case 'EmptyStatement':
|
137
|
-
return cacheAst(decl, generateEmpty(scope, decl))
|
140
|
+
return cacheAst(decl, generateEmpty(scope, decl));
|
138
141
|
|
139
142
|
case 'MetaProperty':
|
140
|
-
return cacheAst(decl, generateMeta(scope, decl))
|
143
|
+
return cacheAst(decl, generateMeta(scope, decl));
|
141
144
|
|
142
145
|
case 'ConditionalExpression':
|
143
|
-
return cacheAst(decl, generateConditional(scope, decl))
|
146
|
+
return cacheAst(decl, generateConditional(scope, decl));
|
144
147
|
|
145
148
|
case 'ThrowStatement':
|
146
|
-
return cacheAst(decl, generateThrow(scope, decl))
|
149
|
+
return cacheAst(decl, generateThrow(scope, decl));
|
147
150
|
|
148
151
|
case 'TryStatement':
|
149
|
-
return cacheAst(decl, generateTry(scope, decl))
|
152
|
+
return cacheAst(decl, generateTry(scope, decl));
|
150
153
|
|
151
154
|
case 'DebuggerStatement':
|
152
|
-
return cacheAst(decl, [[ Opcodes.call, importedFuncs.debugger ]])
|
155
|
+
return cacheAst(decl, [[ Opcodes.call, importedFuncs.debugger ]]);
|
153
156
|
|
154
157
|
case 'ArrayExpression':
|
155
|
-
return cacheAst(decl, generateArray(scope, decl, global, name))
|
158
|
+
return cacheAst(decl, generateArray(scope, decl, global, name));
|
156
159
|
|
157
160
|
case 'ObjectExpression':
|
158
|
-
return cacheAst(decl, generateObject(scope, decl, global, name))
|
161
|
+
return cacheAst(decl, generateObject(scope, decl, global, name));
|
159
162
|
|
160
163
|
case 'MemberExpression':
|
161
|
-
return cacheAst(decl, generateMember(scope, decl, global, name))
|
164
|
+
return cacheAst(decl, generateMember(scope, decl, global, name));
|
162
165
|
|
163
166
|
case 'ExportNamedDeclaration':
|
164
167
|
const funcsBefore = funcs.map(x => x.name);
|
@@ -173,7 +176,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
173
176
|
}
|
174
177
|
}
|
175
178
|
|
176
|
-
return cacheAst(decl, [])
|
179
|
+
return cacheAst(decl, []);
|
177
180
|
|
178
181
|
case 'TaggedTemplateExpression': {
|
179
182
|
const funcs = {
|
@@ -228,7 +231,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
228
231
|
|
229
232
|
const func = decl.tag.name;
|
230
233
|
// hack for inline asm
|
231
|
-
if (!funcs[func]) return cacheAst(decl, todo(scope, 'tagged template expressions not implemented', true))
|
234
|
+
if (!funcs[func]) return cacheAst(decl, todo(scope, 'tagged template expressions not implemented', true));
|
232
235
|
|
233
236
|
const { quasis, expressions } = decl.quasi;
|
234
237
|
let str = quasis[0].value.raw;
|
@@ -244,17 +247,17 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
244
247
|
str += quasis[i + 1].value.raw;
|
245
248
|
}
|
246
249
|
|
247
|
-
return cacheAst(decl, funcs[func](str))
|
250
|
+
return cacheAst(decl, funcs[func](str));
|
248
251
|
}
|
249
252
|
|
250
253
|
default:
|
251
254
|
// ignore typescript nodes
|
252
255
|
if (decl.type.startsWith('TS') ||
|
253
256
|
decl.type === 'ImportDeclaration' && decl.importKind === 'type') {
|
254
|
-
return cacheAst(decl, [])
|
257
|
+
return cacheAst(decl, []);
|
255
258
|
}
|
256
259
|
|
257
|
-
return cacheAst(decl, todo(scope, `no generation for ${decl.type}!`))
|
260
|
+
return cacheAst(decl, todo(scope, `no generation for ${decl.type}!`));
|
258
261
|
}
|
259
262
|
};
|
260
263
|
|
@@ -3471,8 +3474,6 @@ const generateForOf = (scope, decl) => {
|
|
3471
3474
|
generateVar(scope, { kind: 'var', _bare: true, declarations: [ { id: { name: leftName } } ] })
|
3472
3475
|
}
|
3473
3476
|
|
3474
|
-
// if (!leftName) console.log(decl.left?.declarations?.[0]?.id ?? decl.left);
|
3475
|
-
|
3476
3477
|
const [ local, isGlobal ] = lookupName(scope, leftName);
|
3477
3478
|
if (!local) return todo(scope, 'for of failed to get left local (probably destructure)');
|
3478
3479
|
|
@@ -3784,6 +3785,120 @@ const generateForOf = (scope, decl) => {
|
|
3784
3785
|
return out;
|
3785
3786
|
};
|
3786
3787
|
|
3788
|
+
const generateForIn = (scope, decl) => {
|
3789
|
+
const out = [];
|
3790
|
+
|
3791
|
+
// todo: for in inside for in might fuck up?
|
3792
|
+
const pointer = localTmp(scope, '#forin_base_pointer', Valtype.i32);
|
3793
|
+
const length = localTmp(scope, '#forin_length', Valtype.i32);
|
3794
|
+
const counter = localTmp(scope, '#forin_counter', Valtype.i32);
|
3795
|
+
|
3796
|
+
out.push(
|
3797
|
+
// set pointer as right
|
3798
|
+
...generate(scope, decl.right),
|
3799
|
+
Opcodes.i32_to_u,
|
3800
|
+
[ Opcodes.local_set, pointer ],
|
3801
|
+
|
3802
|
+
// set counter as 0 (could be already used)
|
3803
|
+
...number(0, Valtype.i32),
|
3804
|
+
[ Opcodes.local_set, counter ],
|
3805
|
+
|
3806
|
+
// get length
|
3807
|
+
[ Opcodes.local_get, pointer ],
|
3808
|
+
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
3809
|
+
[ Opcodes.local_tee, length ],
|
3810
|
+
|
3811
|
+
[ Opcodes.if, Blocktype.void ]
|
3812
|
+
);
|
3813
|
+
|
3814
|
+
depth.push('if');
|
3815
|
+
depth.push('forin');
|
3816
|
+
depth.push('block');
|
3817
|
+
depth.push('block');
|
3818
|
+
|
3819
|
+
// setup local for left
|
3820
|
+
generate(scope, decl.left);
|
3821
|
+
|
3822
|
+
let leftName = decl.left.declarations?.[0]?.id?.name;
|
3823
|
+
if (!leftName && decl.left.name) {
|
3824
|
+
// todo: should be sloppy mode only
|
3825
|
+
leftName = decl.left.name;
|
3826
|
+
|
3827
|
+
generateVar(scope, { kind: 'var', _bare: true, declarations: [ { id: { name: leftName } } ] })
|
3828
|
+
}
|
3829
|
+
|
3830
|
+
const [ local, isGlobal ] = lookupName(scope, leftName);
|
3831
|
+
if (!local) return todo(scope, 'for of failed to get left local (probably destructure)');
|
3832
|
+
|
3833
|
+
// set type for local
|
3834
|
+
// todo: optimize away counter and use end pointer
|
3835
|
+
out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
|
3836
|
+
[TYPES.object]: [
|
3837
|
+
[ Opcodes.loop, Blocktype.void ],
|
3838
|
+
|
3839
|
+
[ Opcodes.local_get, pointer ],
|
3840
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3841
|
+
[ Opcodes.local_tee, localTmp(scope, '#forin_tmp', Valtype.i32) ],
|
3842
|
+
|
3843
|
+
...setType(scope, leftName, [
|
3844
|
+
[ Opcodes.i32_const, 31 ],
|
3845
|
+
[ Opcodes.i32_shr_u ],
|
3846
|
+
[ Opcodes.if, Valtype.i32 ],
|
3847
|
+
// unset MSB in tmp
|
3848
|
+
[ Opcodes.local_get, localTmp(scope, '#forin_tmp', Valtype.i32) ],
|
3849
|
+
...number(0x7fffffff, Valtype.i32),
|
3850
|
+
[ Opcodes.i32_and ],
|
3851
|
+
[ Opcodes.local_set, localTmp(scope, '#forin_tmp', Valtype.i32) ],
|
3852
|
+
|
3853
|
+
[ Opcodes.i32_const, ...unsignedLEB128(TYPES.string) ],
|
3854
|
+
[ Opcodes.else ],
|
3855
|
+
[ Opcodes.i32_const, ...unsignedLEB128(TYPES.bytestring) ],
|
3856
|
+
[ Opcodes.end ]
|
3857
|
+
]),
|
3858
|
+
|
3859
|
+
[ Opcodes.local_get, localTmp(scope, '#forin_tmp', Valtype.i32) ],
|
3860
|
+
Opcodes.i32_from_u,
|
3861
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3862
|
+
|
3863
|
+
[ Opcodes.block, Blocktype.void ],
|
3864
|
+
[ Opcodes.block, Blocktype.void ],
|
3865
|
+
...generate(scope, decl.body),
|
3866
|
+
[ Opcodes.end ],
|
3867
|
+
|
3868
|
+
// increment iter pointer by 14
|
3869
|
+
[ Opcodes.local_get, pointer ],
|
3870
|
+
...number(14, Valtype.i32),
|
3871
|
+
[ Opcodes.i32_add ],
|
3872
|
+
[ Opcodes.local_set, pointer ],
|
3873
|
+
|
3874
|
+
// increment counter by 1
|
3875
|
+
[ Opcodes.local_get, counter ],
|
3876
|
+
...number(1, Valtype.i32),
|
3877
|
+
[ Opcodes.i32_add ],
|
3878
|
+
[ Opcodes.local_tee, counter ],
|
3879
|
+
|
3880
|
+
// loop if counter != length
|
3881
|
+
[ Opcodes.local_get, length ],
|
3882
|
+
[ Opcodes.i32_ne ],
|
3883
|
+
[ Opcodes.br_if, 1 ],
|
3884
|
+
|
3885
|
+
[ Opcodes.end ],
|
3886
|
+
[ Opcodes.end ]
|
3887
|
+
],
|
3888
|
+
|
3889
|
+
// todo: use Object.keys as fallback
|
3890
|
+
default: internalThrow(scope, 'TypeError', `Tried for..in on unsupported type`)
|
3891
|
+
}, Blocktype.void));
|
3892
|
+
|
3893
|
+
out.push([ Opcodes.end ]); // end if
|
3894
|
+
|
3895
|
+
depth.pop();
|
3896
|
+
depth.pop();
|
3897
|
+
depth.pop();
|
3898
|
+
|
3899
|
+
return out;
|
3900
|
+
};
|
3901
|
+
|
3787
3902
|
const generateSwitch = (scope, decl) => {
|
3788
3903
|
const tmp = localTmp(scope, '#switch_disc');
|
3789
3904
|
const out = [
|
@@ -3840,7 +3955,7 @@ const generateSwitch = (scope, decl) => {
|
|
3840
3955
|
// find the nearest loop in depth map by type
|
3841
3956
|
const getNearestLoop = () => {
|
3842
3957
|
for (let i = depth.length - 1; i >= 0; i--) {
|
3843
|
-
if (['while', 'dowhile', 'for', 'forof', 'switch'].includes(depth[i])) return i;
|
3958
|
+
if (['while', 'dowhile', 'for', 'forof', 'forin', 'switch'].includes(depth[i])) return i;
|
3844
3959
|
}
|
3845
3960
|
|
3846
3961
|
return -1;
|
@@ -3859,6 +3974,7 @@ const generateBreak = (scope, decl) => {
|
|
3859
3974
|
while: 2, // loop > if (wanted branch) (we are here)
|
3860
3975
|
dowhile: 2, // loop > block (wanted branch) > block (we are here)
|
3861
3976
|
forof: 2, // loop > block (wanted branch) > block (we are here)
|
3977
|
+
forin: 2, // loop > block (wanted branch) > block (we are here)
|
3862
3978
|
if: 1, // break inside if, branch 0 to skip the rest of the if
|
3863
3979
|
switch: 1
|
3864
3980
|
})[type];
|
@@ -3880,7 +3996,8 @@ const generateContinue = (scope, decl) => {
|
|
3880
3996
|
for: 3, // loop (wanted branch) > if > block (we are here)
|
3881
3997
|
while: 1, // loop (wanted branch) > if (we are here)
|
3882
3998
|
dowhile: 3, // loop > block > block (wanted branch) (we are here)
|
3883
|
-
forof: 3 // loop > block > block (wanted branch) (we are here)
|
3999
|
+
forof: 3, // loop > block > block (wanted branch) (we are here)
|
4000
|
+
forin: 3 // loop > block > block (wanted branch) (we are here)
|
3884
4001
|
})[type];
|
3885
4002
|
|
3886
4003
|
return [
|
package/package.json
CHANGED