@@ -91,7 +91,14 @@ type Temporaries = Map<IdentifierId, t.Expression>;
91
91
92
92
class CodegenVisitor
93
93
implements
94
- Visitor < Array < t . Statement > , t . Expression , t . Statement , t . SwitchCase >
94
+ Visitor <
95
+ Array < t . Statement > ,
96
+ Array < t . Statement > ,
97
+ Array < t . Statement > ,
98
+ t . Expression ,
99
+ t . Statement ,
100
+ t . SwitchCase
101
+ >
95
102
{
96
103
depth : number = 0 ;
97
104
temp : Map < IdentifierId , t . Expression > = new Map ( ) ;
@@ -100,10 +107,77 @@ class CodegenVisitor
100
107
this . depth ++ ;
101
108
return [ ] ;
102
109
}
110
+ appendBlock (
111
+ block : t . Statement [ ] ,
112
+ item : t . Statement ,
113
+ blockId ?: BlockId | undefined
114
+ ) : void {
115
+ if ( item . type === "EmptyStatement" ) {
116
+ return ;
117
+ }
118
+ if ( blockId !== undefined ) {
119
+ block . push (
120
+ createLabelledStatement (
121
+ item . loc ,
122
+ t . identifier ( codegenLabel ( blockId ) ) ,
123
+ item
124
+ )
125
+ ) ;
126
+ } else {
127
+ block . push ( item ) ;
128
+ }
129
+ }
130
+ leaveBlock ( block : t . Statement [ ] ) : t . Statement {
131
+ this . depth -- ;
132
+ return t . blockStatement ( block ) ;
133
+ }
103
134
enterValueBlock ( ) : t . Statement [ ] {
104
- this . depth ++ ;
105
- return [ ] ;
135
+ return this . enterBlock ( ) ;
136
+ }
137
+ appendValueBlock ( block : t . Statement [ ] , item : t . Statement ) : void {
138
+ this . appendBlock ( block , item ) ;
139
+ }
140
+ leaveValueBlock ( block : t . Statement [ ] , place : t . Expression ) : t . Expression {
141
+ this . depth -- ;
142
+ if ( block . length === 0 ) {
143
+ return place ;
144
+ }
145
+ const expressions = block . map ( ( stmt ) => {
146
+ switch ( stmt . type ) {
147
+ case "ExpressionStatement" :
148
+ return stmt . expression ;
149
+ default :
150
+ todoInvariant (
151
+ false ,
152
+ `Handle conversion of ${ stmt . type } to expression`
153
+ ) ;
154
+ }
155
+ } ) ;
156
+ expressions . push ( place ) ;
157
+ return t . sequenceExpression ( expressions ) ;
158
+ }
159
+
160
+ enterInitBlock ( block : t . Statement [ ] ) : t . Statement [ ] {
161
+ return this . enterBlock ( ) ;
162
+ }
163
+
164
+ appendInitBlock ( block : t . Statement [ ] , item : t . Statement ) : void {
165
+ this . appendBlock ( block , item ) ;
166
+ }
167
+ leaveInitBlock ( block : t . Statement [ ] ) : t . Statement [ ] {
168
+ switch ( block . length ) {
169
+ case 0 : {
170
+ return [ t . emptyStatement ( ) ] ;
171
+ }
172
+ case 1 : {
173
+ return [ block [ 0 ] ] ;
174
+ }
175
+ default : {
176
+ return [ t . blockStatement ( block ) ] ;
177
+ }
178
+ }
106
179
}
180
+
107
181
visitValue ( value : InstructionValue ) : t . Expression {
108
182
return codegenInstructionValue ( this . temp , value ) ;
109
183
}
@@ -191,8 +265,25 @@ class CodegenVisitor
191
265
return createWhileStatement ( terminal . loc , terminal . test , terminal . loop ) ;
192
266
}
193
267
case "for" : {
268
+ const initBlock = terminal . init ;
269
+ invariant (
270
+ initBlock . length === 1 ,
271
+ "Expected for init to be a single expression or statement"
272
+ ) ;
273
+ const initStatement = initBlock [ 0 ] ! ;
274
+ let init ;
275
+ if ( initStatement . type === "VariableDeclaration" ) {
276
+ init = initStatement ;
277
+ } else if ( initStatement . type === "ExpressionStatement" ) {
278
+ init = initStatement . expression ;
279
+ } else {
280
+ invariant (
281
+ false ,
282
+ `Expected 'for' init block to contain variable declaration or an expression, got '${ initStatement . type } '.`
283
+ ) ;
284
+ }
194
285
return t . forStatement (
195
- terminal . init as any , // TODO: make sure it's a variable declaration
286
+ init ,
196
287
terminal . test ,
197
288
terminal . update ,
198
289
terminal . loop
@@ -225,49 +316,6 @@ class CodegenVisitor
225
316
visitCase ( test : t . Expression | null , block : t . Statement ) : t . SwitchCase {
226
317
return t . switchCase ( test , [ block ] ) ;
227
318
}
228
- appendBlock (
229
- block : t . Statement [ ] ,
230
- item : t . Statement ,
231
- blockId ?: BlockId | undefined
232
- ) : void {
233
- if ( item . type === "EmptyStatement" ) {
234
- return ;
235
- }
236
- if ( blockId !== undefined ) {
237
- block . push (
238
- createLabelledStatement (
239
- item . loc ,
240
- t . identifier ( codegenLabel ( blockId ) ) ,
241
- item
242
- )
243
- ) ;
244
- } else {
245
- block . push ( item ) ;
246
- }
247
- }
248
- leaveBlock ( block : t . Statement [ ] ) : t . Statement {
249
- this . depth -- ;
250
- return t . blockStatement ( block ) ;
251
- }
252
- leaveValueBlock ( block : t . Statement [ ] , place : t . Expression ) : t . Expression {
253
- this . depth -- ;
254
- if ( block . length === 0 ) {
255
- return place ;
256
- }
257
- const expressions = block . map ( ( stmt ) => {
258
- switch ( stmt . type ) {
259
- case "ExpressionStatement" :
260
- return stmt . expression ;
261
- default :
262
- todoInvariant (
263
- false ,
264
- `Handle conversion of ${ stmt . type } to expression`
265
- ) ;
266
- }
267
- } ) ;
268
- expressions . push ( place ) ;
269
- return t . sequenceExpression ( expressions ) ;
270
- }
271
319
}
272
320
273
321
function codegenLabel ( id : BlockId ) : string {
0 commit comments