@@ -91,7 +91,14 @@ type Temporaries = Map<IdentifierId, t.Expression>;
9191
9292class CodegenVisitor
9393 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+ >
95102{
96103 depth : number = 0 ;
97104 temp : Map < IdentifierId , t . Expression > = new Map ( ) ;
@@ -100,10 +107,77 @@ class CodegenVisitor
100107 this . depth ++ ;
101108 return [ ] ;
102109 }
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+ }
103134 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+ }
106179 }
180+
107181 visitValue ( value : InstructionValue ) : t . Expression {
108182 return codegenInstructionValue ( this . temp , value ) ;
109183 }
@@ -191,8 +265,25 @@ class CodegenVisitor
191265 return createWhileStatement ( terminal . loc , terminal . test , terminal . loop ) ;
192266 }
193267 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+ }
194285 return t . forStatement (
195- terminal . init as any , // TODO: make sure it's a variable declaration
286+ init ,
196287 terminal . test ,
197288 terminal . update ,
198289 terminal . loop
@@ -225,49 +316,6 @@ class CodegenVisitor
225316 visitCase ( test : t . Expression | null , block : t . Statement ) : t . SwitchCase {
226317 return t . switchCase ( test , [ block ] ) ;
227318 }
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- }
271319}
272320
273321function codegenLabel ( id : BlockId ) : string {
0 commit comments