1 //
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 19 Jul 06 Brian Frank Creation
7 //
8
9 **
10 ** Stmt
11 **
12 abstract class Stmt : Node
13 {
14
15 //////////////////////////////////////////////////////////////////////////
16 // Construction
17 //////////////////////////////////////////////////////////////////////////
18
19 new make(Location location, StmtId id)
20 : super(location)
21 {
22 this.id = id
23 }
24
25 //////////////////////////////////////////////////////////////////////////
26 // Stmt
27 //////////////////////////////////////////////////////////////////////////
28
29 **
30 ** Does this statement always cause us to exit the method (or does it
31 ** cause us to loop forever without a break to the next statement)
32 **
33 abstract Bool isExit()
34
35 //////////////////////////////////////////////////////////////////////////
36 // Tree
37 //////////////////////////////////////////////////////////////////////////
38
39 Void walk(Visitor v, VisitDepth depth)
40 {
41 v.enterStmt(this)
42 walkChildren(v, depth)
43 v.visitStmt(this)
44 v.exitStmt(this)
45 }
46
47 virtual Void walkChildren(Visitor v, VisitDepth depth)
48 {
49 }
50
51 static Expr walkExpr(Visitor v, VisitDepth depth, Expr expr)
52 {
53 if (depth === VisitDepth.expr && expr != null)
54 return expr.walk(v)
55 else
56 return expr
57 }
58
59 //////////////////////////////////////////////////////////////////////////
60 // Fields
61 //////////////////////////////////////////////////////////////////////////
62
63 readonly StmtId id
64
65 }
66
67 **************************************************************************
68 ** NopStmt
69 **************************************************************************
70
71 **
72 ** NopStmt is no operation do nothing statement.
73 **
74 class NopStmt : Stmt
75 {
76 new make(Location location) : super(location, StmtId.nop) {}
77
78 override Bool isExit() { return false }
79
80 override Void print(AstWriter out)
81 {
82 out.w("nop").nl
83 }
84 }
85
86 **************************************************************************
87 ** ExprStmt
88 **************************************************************************
89
90 **
91 ** ExprStmt is a statement with a stand along expression such
92 ** as an assignment or method call.
93 **
94 class ExprStmt : Stmt
95 {
96 new make(Expr expr)
97 : super(expr.location, StmtId.expr)
98 {
99 this.expr = expr
100 }
101
102 override Bool isExit() { return false }
103
104 override Void walkChildren(Visitor v, VisitDepth depth)
105 {
106 expr = walkExpr(v, depth, expr)
107 }
108
109 override Void print(AstWriter out)
110 {
111 printOpt(out)
112 }
113
114 Void printOpt(AstWriter out, Bool nl := true)
115 {
116 expr.print(out)
117 if (nl) out.nl
118 }
119
120 Expr expr
121 }
122
123 **************************************************************************
124 ** LocalDefStmt
125 **************************************************************************
126
127 **
128 ** LocalDefStmt models a local variable declaration and its
129 ** optional initialization expression.
130 **
131 class LocalDefStmt : Stmt
132 {
133 new make(Location location)
134 : super(location, StmtId.localDef)
135 {
136 isCatchVar = false
137 }
138
139 override Bool isExit() { return false }
140
141 override Void walkChildren(Visitor v, VisitDepth depth)
142 {
143 init = walkExpr(v, depth, init)
144 }
145
146 new makeCatchVar(Catch c)
147 : super.make(c.location, StmtId.localDef)
148 {
149 ctype = c.errType
150 name = c.errVariable
151 isCatchVar = true
152 }
153
154 override Void print(AstWriter out) { printOpt(out) }
155
156 Void printOpt(AstWriter out, Bool nl := true)
157 {
158 if (ctype != null) out.w("$ctype ")
159 out.w(name)
160 if (init != null) out.w(" init: $init")
161 if (nl) out.nl
162 }
163
164 CType ctype // type of the variable (or null if inferred)
165 Str name // variable name
166 Expr init // rhs of init; in ResolveExpr it becomes full assign expr
167 Bool isCatchVar // is this auto-generated var for "catch (Err x)"
168 MethodVar var // variable binding
169 }
170
171 **************************************************************************
172 ** IfStmt
173 **************************************************************************
174
175 **
176 ** IfStmt models an if or if/else statement.
177 **
178 class IfStmt : Stmt
179 {
180 new make(Location location) : super(location, StmtId.ifStmt) {}
181
182 override Bool isExit()
183 {
184 if (falseBlock == null) return false
185 return trueBlock.isExit && falseBlock.isExit
186 }
187
188 override Void walkChildren(Visitor v, VisitDepth depth)
189 {
190 condition = walkExpr(v, depth, condition)
191 trueBlock.walk(v, depth)
192 if (falseBlock != null) falseBlock.walk(v, depth)
193 }
194
195 override Void print(AstWriter out)
196 {
197 out.w("if ($condition)").nl
198 trueBlock.print(out)
199 if (falseBlock != null)
200 {
201 out.w("else").nl
202 falseBlock.print(out)
203 }
204 }
205
206 Expr condition // test expression
207 Block trueBlock // block to execute if condition true
208 Block falseBlock // else clause or null
209 }
210
211 **************************************************************************
212 ** ReturnStmt
213 **************************************************************************
214
215 **
216 ** ReturnStmt returns from the method
217 **
218 class ReturnStmt : Stmt
219 {
220 new make(Location location, Expr expr := null)
221 : super(location, StmtId.returnStmt)
222 {
223 this.expr = expr
224 }
225
226 override Bool isExit() { return true }
227
228 override Void walkChildren(Visitor v, VisitDepth depth)
229 {
230 expr = walkExpr(v, depth, expr)
231 }
232
233 override Void print(AstWriter out)
234 {
235 out.w("return")
236 if (expr != null) out.w(" $expr")
237 out.nl
238 }
239
240
241 Expr expr // expr to return of null if void return
242 MethodVar leaveVar // to stash result for leave from protected region
243 }
244
245 **************************************************************************
246 ** ThrowStmt
247 **************************************************************************
248
249 **
250 ** ThrowStmt throws an exception
251 **
252 class ThrowStmt : Stmt
253 {
254 new make(Location location) : super(location, StmtId.throwStmt) {}
255
256 override Bool isExit() { return true }
257
258 override Void walkChildren(Visitor v, VisitDepth depth)
259 {
260 exception = walkExpr(v, depth, exception)
261 }
262
263 override Void print(AstWriter out)
264 {
265 out.w("throw $exception").nl
266 }
267
268 Expr exception // exception to throw
269 }
270
271 **************************************************************************
272 ** ForStmt
273 **************************************************************************
274
275 **
276 ** ForStmt models a for loop of the format:
277 ** for (init; condition; update) block
278 **
279 class ForStmt : Stmt
280 {
281 new make(Location location) : super(location, StmtId.forStmt) {}
282
283 override Bool isExit()
284 {
285 return false
286 }
287
288 override Void walkChildren(Visitor v, VisitDepth depth)
289 {
290 if (init != null) init.walk(v, depth)
291 condition = walkExpr(v, depth, condition)
292 update = walkExpr(v, depth, update)
293 block.walk(v, depth)
294 }
295
296 override Void print(AstWriter out)
297 {
298 out.w("for (")
299 if (init != null) init->printOpt(out, false)
300 out.w("; ")
301 if (condition != null) condition.print(out)
302 out.w("; ")
303 if (update != null) update.print(out)
304 out.w(")").nl
305 block.print(out)
306 }
307
308 Stmt init // loop initialization
309 Expr condition // loop condition
310 Expr update // loop update
311 Block block // code to run inside loop
312 }
313
314 **************************************************************************
315 ** WhileStmt
316 **************************************************************************
317
318 **
319 ** WhileStmt models a while loop of the format:
320 ** while (condition) block
321 **
322 class WhileStmt : Stmt
323 {
324 new make(Location location) : super(location, StmtId.whileStmt) {}
325
326 override Bool isExit()
327 {
328 return false
329 }
330
331 override Void walkChildren(Visitor v, VisitDepth depth)
332 {
333 condition = walkExpr(v, depth, condition)
334 block.walk(v, depth)
335 }
336
337 override Void print(AstWriter out)
338 {
339 out.w("while ($condition)").nl
340 block.print(out)
341 }
342
343 Expr condition // loop condition
344 Block block // code to run inside loop
345 }
346
347 **************************************************************************
348 ** BreakStmt
349 **************************************************************************
350
351 **
352 ** BreakStmt breaks out of a while/for loop.
353 **
354 class BreakStmt : Stmt
355 {
356 new make(Location location) : super(location, StmtId.breakStmt) {}
357
358 override Bool isExit() { return false }
359
360 override Void print(AstWriter out)
361 {
362 out.w("break").nl
363 }
364
365 Stmt loop // loop to break out of
366 }
367
368 **************************************************************************
369 ** ContinueStmt
370 **************************************************************************
371
372 **
373 ** ContinueStmt continues a while/for loop.
374 **
375 class ContinueStmt : Stmt
376 {
377 new make(Location location) : super(location, StmtId.continueStmt) {}
378
379 override Bool isExit() { return false }
380
381 override Void print(AstWriter out)
382 {
383 out.w("continue").nl
384 }
385
386 Stmt loop // loop to continue
387 }
388
389 **************************************************************************
390 ** TryStmt
391 **************************************************************************
392
393 **
394 ** TryStmt models a try/catch/finally block
395 **
396 class TryStmt : Stmt
397 {
398 new make(Location location)
399 : super(location, StmtId.tryStmt)
400 {
401 catches = Catch[,]
402 }
403
404 override Bool isExit()
405 {
406 if (!block.isExit) return false
407 return catches.all |Catch c->Bool| { return c.block.isExit }
408 }
409
410 override Void walkChildren(Visitor v, VisitDepth depth)
411 {
412 block.walk(v, depth)
413 catches.each |Catch c| { c.block.walk(v, depth) }
414 if (finallyBlock != null)
415 {
416 v.enterFinally(this)
417 finallyBlock.walk(v, depth)
418 v.exitFinally(this)
419 }
420 }
421
422 override Void print(AstWriter out)
423 {
424 out.w("try").nl
425 block.print(out)
426 catches.each |Catch c| { c.print(out) }
427 if (finallyBlock != null)
428 {
429 out.w("finally").nl
430 finallyBlock.print(out)
431 }
432 }
433
434 Expr exception // expression which leaves exception on stack
435 Block block // body of try block
436 Catch[] catches // list of catch clauses
437 Block finallyBlock // body of finally block or null
438 }
439
440 **
441 ** Catch models a single catch clause of a TryStmt
442 **
443 class Catch : Node
444 {
445 new make(Location location) : super(location) {}
446
447 override Void print(AstWriter out)
448 {
449 out.w("catch")
450 if (errType != null) out.w("($errType $errVariable)")
451 out.nl
452 block.print(out)
453 }
454
455 TypeRef errType // Err type to catch or null for catch-all
456 Str errVariable // name of err local variable
457 Block block // body of catch block
458 Int start // start offset generated in CodeAsm
459 Int end // end offset generated in CodeAsm
460 }
461
462 **************************************************************************
463 ** SwitchStmt
464 **************************************************************************
465
466 **
467 ** SwitchStmt models a switch and its case and default block
468 **
469 class SwitchStmt : Stmt
470 {
471 new make(Location location)
472 : super(location, StmtId.switchStmt)
473 {
474 cases = Case[,]
475 }
476
477 override Bool isExit()
478 {
479 if (defaultBlock == null) return false
480 if (!defaultBlock.isExit) return false
481 return cases.all |Case c->Bool| { return c.block.isExit }
482 }
483
484 override Void walkChildren(Visitor v, VisitDepth depth)
485 {
486 condition = walkExpr(v, depth, condition)
487 cases.each |Case c| { c.walk(v, depth) }
488 if (defaultBlock != null) defaultBlock.walk(v, depth)
489 }
490
491 override Void print(AstWriter out)
492 {
493 out.w("switch ($condition)").nl
494 out.w("{").nl
495 out.indent
496 cases.each |Case c| { c.print(out) }
497 if (defaultBlock != null)
498 {
499 out.w("default:").nl
500 out.indent
501 defaultBlock.printOpt(out, false)
502 out.unindent
503 }
504 out.unindent
505 out.w("}").nl
506 }
507
508 Expr condition // test expression
509 Case[] cases // list of case blocks
510 Block defaultBlock // default block (or null)
511 Bool isTableswitch // just for testing
512 }
513
514 **
515 ** Case models a single case block of a SwitchStmt
516 **
517 class Case : Node
518 {
519 new make(Location location)
520 : super(location)
521 {
522 cases = Expr[,]
523 }
524
525 Void walk(Visitor v, VisitDepth depth)
526 {
527 if (depth === VisitDepth.expr)
528 cases = Expr.walkExprs(v, cases)
529
530 block.walk(v, depth)
531 }
532
533 override Void print(AstWriter out)
534 {
535 cases.each |Expr c| { out.w("case $c:").nl }
536 out.indent
537 if (block != null) block.printOpt(out, false)
538 out.unindent
539 }
540
541 Expr[] cases // list of case target (literal expressions)
542 Block block // code to run for case
543 Int startOffset // start offset for CodeAsm
544 }
545
546 **************************************************************************
547 ** StmtId
548 **************************************************************************
549
550 enum StmtId
551 {
552 nop,
553 expr,
554 localDef,
555 ifStmt,
556 returnStmt,
557 throwStmt,
558 forStmt,
559 whileStmt,
560 breakStmt,
561 continueStmt,
562 tryStmt,
563 switchStmt
564 }
2 // Copyright (c) 2006, Brian Frank and Andy Frank
3 // Licensed under the Academic Free License version 3.0
4 //
5 // History:
6 // 19 Jul 06 Brian Frank Creation
7 //
8
9 **
10 ** Stmt
11 **
12 abstract class Stmt : Node
13 {
14
15 //////////////////////////////////////////////////////////////////////////
16 // Construction
17 //////////////////////////////////////////////////////////////////////////
18
19 new make(Location location, StmtId id)
20 : super(location)
21 {
22 this.id = id
23 }
24
25 //////////////////////////////////////////////////////////////////////////
26 // Stmt
27 //////////////////////////////////////////////////////////////////////////
28
29 **
30 ** Does this statement always cause us to exit the method (or does it
31 ** cause us to loop forever without a break to the next statement)
32 **
33 abstract Bool isExit()
34
35 //////////////////////////////////////////////////////////////////////////
36 // Tree
37 //////////////////////////////////////////////////////////////////////////
38
39 Void walk(Visitor v, VisitDepth depth)
40 {
41 v.enterStmt(this)
42 walkChildren(v, depth)
43 v.visitStmt(this)
44 v.exitStmt(this)
45 }
46
47 virtual Void walkChildren(Visitor v, VisitDepth depth)
48 {
49 }
50
51 static Expr walkExpr(Visitor v, VisitDepth depth, Expr expr)
52 {
53 if (depth === VisitDepth.expr && expr != null)
54 return expr.walk(v)
55 else
56 return expr
57 }
58
59 //////////////////////////////////////////////////////////////////////////
60 // Fields
61 //////////////////////////////////////////////////////////////////////////
62
63 readonly StmtId id
64
65 }
66
67 **************************************************************************
68 ** NopStmt
69 **************************************************************************
70
71 **
72 ** NopStmt is no operation do nothing statement.
73 **
74 class NopStmt : Stmt
75 {
76 new make(Location location) : super(location, StmtId.nop) {}
77
78 override Bool isExit() { return false }
79
80 override Void print(AstWriter out)
81 {
82 out.w("nop").nl
83 }
84 }
85
86 **************************************************************************
87 ** ExprStmt
88 **************************************************************************
89
90 **
91 ** ExprStmt is a statement with a stand along expression such
92 ** as an assignment or method call.
93 **
94 class ExprStmt : Stmt
95 {
96 new make(Expr expr)
97 : super(expr.location, StmtId.expr)
98 {
99 this.expr = expr
100 }
101
102 override Bool isExit() { return false }
103
104 override Void walkChildren(Visitor v, VisitDepth depth)
105 {
106 expr = walkExpr(v, depth, expr)
107 }
108
109 override Void print(AstWriter out)
110 {
111 printOpt(out)
112 }
113
114 Void printOpt(AstWriter out, Bool nl := true)
115 {
116 expr.print(out)
117 if (nl) out.nl
118 }
119
120 Expr expr
121 }
122
123 **************************************************************************
124 ** LocalDefStmt
125 **************************************************************************
126
127 **
128 ** LocalDefStmt models a local variable declaration and its
129 ** optional initialization expression.
130 **
131 class LocalDefStmt : Stmt
132 {
133 new make(Location location)
134 : super(location, StmtId.localDef)
135 {
136 isCatchVar = false
137 }
138
139 override Bool isExit() { return false }
140
141 override Void walkChildren(Visitor v, VisitDepth depth)
142 {
143 init = walkExpr(v, depth, init)
144 }
145
146 new makeCatchVar(Catch c)
147 : super.make(c.location, StmtId.localDef)
148 {
149 ctype = c.errType
150 name = c.errVariable
151 isCatchVar = true
152 }
153
154 override Void print(AstWriter out) { printOpt(out) }
155
156 Void printOpt(AstWriter out, Bool nl := true)
157 {
158 if (ctype != null) out.w("$ctype ")
159 out.w(name)
160 if (init != null) out.w(" init: $init")
161 if (nl) out.nl
162 }
163
164 CType ctype // type of the variable (or null if inferred)
165 Str name // variable name
166 Expr init // rhs of init; in ResolveExpr it becomes full assign expr
167 Bool isCatchVar // is this auto-generated var for "catch (Err x)"
168 MethodVar var // variable binding
169 }
170
171 **************************************************************************
172 ** IfStmt
173 **************************************************************************
174
175 **
176 ** IfStmt models an if or if/else statement.
177 **
178 class IfStmt : Stmt
179 {
180 new make(Location location) : super(location, StmtId.ifStmt) {}
181
182 override Bool isExit()
183 {
184 if (falseBlock == null) return false
185 return trueBlock.isExit && falseBlock.isExit
186 }
187
188 override Void walkChildren(Visitor v, VisitDepth depth)
189 {
190 condition = walkExpr(v, depth, condition)
191 trueBlock.walk(v, depth)
192 if (falseBlock != null) falseBlock.walk(v, depth)
193 }
194
195 override Void print(AstWriter out)
196 {
197 out.w("if ($condition)").nl
198 trueBlock.print(out)
199 if (falseBlock != null)
200 {
201 out.w("else").nl
202 falseBlock.print(out)
203 }
204 }
205
206 Expr condition // test expression
207 Block trueBlock // block to execute if condition true
208 Block falseBlock // else clause or null
209 }
210
211 **************************************************************************
212 ** ReturnStmt
213 **************************************************************************
214
215 **
216 ** ReturnStmt returns from the method
217 **
218 class ReturnStmt : Stmt
219 {
220 new make(Location location, Expr expr := null)
221 : super(location, StmtId.returnStmt)
222 {
223 this.expr = expr
224 }
225
226 override Bool isExit() { return true }
227
228 override Void walkChildren(Visitor v, VisitDepth depth)
229 {
230 expr = walkExpr(v, depth, expr)
231 }
232
233 override Void print(AstWriter out)
234 {
235 out.w("return")
236 if (expr != null) out.w(" $expr")
237 out.nl
238 }
239
240
241 Expr expr // expr to return of null if void return
242 MethodVar leaveVar // to stash result for leave from protected region
243 }
244
245 **************************************************************************
246 ** ThrowStmt
247 **************************************************************************
248
249 **
250 ** ThrowStmt throws an exception
251 **
252 class ThrowStmt : Stmt
253 {
254 new make(Location location) : super(location, StmtId.throwStmt) {}
255
256 override Bool isExit() { return true }
257
258 override Void walkChildren(Visitor v, VisitDepth depth)
259 {
260 exception = walkExpr(v, depth, exception)
261 }
262
263 override Void print(AstWriter out)
264 {
265 out.w("throw $exception").nl
266 }
267
268 Expr exception // exception to throw
269 }
270
271 **************************************************************************
272 ** ForStmt
273 **************************************************************************
274
275 **
276 ** ForStmt models a for loop of the format:
277 ** for (init; condition; update) block
278 **
279 class ForStmt : Stmt
280 {
281 new make(Location location) : super(location, StmtId.forStmt) {}
282
283 override Bool isExit()
284 {
285 return false
286 }
287
288 override Void walkChildren(Visitor v, VisitDepth depth)
289 {
290 if (init != null) init.walk(v, depth)
291 condition = walkExpr(v, depth, condition)
292 update = walkExpr(v, depth, update)
293 block.walk(v, depth)
294 }
295
296 override Void print(AstWriter out)
297 {
298 out.w("for (")
299 if (init != null) init->printOpt(out, false)
300 out.w("; ")
301 if (condition != null) condition.print(out)
302 out.w("; ")
303 if (update != null) update.print(out)
304 out.w(")").nl
305 block.print(out)
306 }
307
308 Stmt init // loop initialization
309 Expr condition // loop condition
310 Expr update // loop update
311 Block block // code to run inside loop
312 }
313
314 **************************************************************************
315 ** WhileStmt
316 **************************************************************************
317
318 **
319 ** WhileStmt models a while loop of the format:
320 ** while (condition) block
321 **
322 class WhileStmt : Stmt
323 {
324 new make(Location location) : super(location, StmtId.whileStmt) {}
325
326 override Bool isExit()
327 {
328 return false
329 }
330
331 override Void walkChildren(Visitor v, VisitDepth depth)
332 {
333 condition = walkExpr(v, depth, condition)
334 block.walk(v, depth)
335 }
336
337 override Void print(AstWriter out)
338 {
339 out.w("while ($condition)").nl
340 block.print(out)
341 }
342
343 Expr condition // loop condition
344 Block block // code to run inside loop
345 }
346
347 **************************************************************************
348 ** BreakStmt
349 **************************************************************************
350
351 **
352 ** BreakStmt breaks out of a while/for loop.
353 **
354 class BreakStmt : Stmt
355 {
356 new make(Location location) : super(location, StmtId.breakStmt) {}
357
358 override Bool isExit() { return false }
359
360 override Void print(AstWriter out)
361 {
362 out.w("break").nl
363 }
364
365 Stmt loop // loop to break out of
366 }
367
368 **************************************************************************
369 ** ContinueStmt
370 **************************************************************************
371
372 **
373 ** ContinueStmt continues a while/for loop.
374 **
375 class ContinueStmt : Stmt
376 {
377 new make(Location location) : super(location, StmtId.continueStmt) {}
378
379 override Bool isExit() { return false }
380
381 override Void print(AstWriter out)
382 {
383 out.w("continue").nl
384 }
385
386 Stmt loop // loop to continue
387 }
388
389 **************************************************************************
390 ** TryStmt
391 **************************************************************************
392
393 **
394 ** TryStmt models a try/catch/finally block
395 **
396 class TryStmt : Stmt
397 {
398 new make(Location location)
399 : super(location, StmtId.tryStmt)
400 {
401 catches = Catch[,]
402 }
403
404 override Bool isExit()
405 {
406 if (!block.isExit) return false
407 return catches.all |Catch c->Bool| { return c.block.isExit }
408 }
409
410 override Void walkChildren(Visitor v, VisitDepth depth)
411 {
412 block.walk(v, depth)
413 catches.each |Catch c| { c.block.walk(v, depth) }
414 if (finallyBlock != null)
415 {
416 v.enterFinally(this)
417 finallyBlock.walk(v, depth)
418 v.exitFinally(this)
419 }
420 }
421
422 override Void print(AstWriter out)
423 {
424 out.w("try").nl
425 block.print(out)
426 catches.each |Catch c| { c.print(out) }
427 if (finallyBlock != null)
428 {
429 out.w("finally").nl
430 finallyBlock.print(out)
431 }
432 }
433
434 Expr exception // expression which leaves exception on stack
435 Block block // body of try block
436 Catch[] catches // list of catch clauses
437 Block finallyBlock // body of finally block or null
438 }
439
440 **
441 ** Catch models a single catch clause of a TryStmt
442 **
443 class Catch : Node
444 {
445 new make(Location location) : super(location) {}
446
447 override Void print(AstWriter out)
448 {
449 out.w("catch")
450 if (errType != null) out.w("($errType $errVariable)")
451 out.nl
452 block.print(out)
453 }
454
455 TypeRef errType // Err type to catch or null for catch-all
456 Str errVariable // name of err local variable
457 Block block // body of catch block
458 Int start // start offset generated in CodeAsm
459 Int end // end offset generated in CodeAsm
460 }
461
462 **************************************************************************
463 ** SwitchStmt
464 **************************************************************************
465
466 **
467 ** SwitchStmt models a switch and its case and default block
468 **
469 class SwitchStmt : Stmt
470 {
471 new make(Location location)
472 : super(location, StmtId.switchStmt)
473 {
474 cases = Case[,]
475 }
476
477 override Bool isExit()
478 {
479 if (defaultBlock == null) return false
480 if (!defaultBlock.isExit) return false
481 return cases.all |Case c->Bool| { return c.block.isExit }
482 }
483
484 override Void walkChildren(Visitor v, VisitDepth depth)
485 {
486 condition = walkExpr(v, depth, condition)
487 cases.each |Case c| { c.walk(v, depth) }
488 if (defaultBlock != null) defaultBlock.walk(v, depth)
489 }
490
491 override Void print(AstWriter out)
492 {
493 out.w("switch ($condition)").nl
494 out.w("{").nl
495 out.indent
496 cases.each |Case c| { c.print(out) }
497 if (defaultBlock != null)
498 {
499 out.w("default:").nl
500 out.indent
501 defaultBlock.printOpt(out, false)
502 out.unindent
503 }
504 out.unindent
505 out.w("}").nl
506 }
507
508 Expr condition // test expression
509 Case[] cases // list of case blocks
510 Block defaultBlock // default block (or null)
511 Bool isTableswitch // just for testing
512 }
513
514 **
515 ** Case models a single case block of a SwitchStmt
516 **
517 class Case : Node
518 {
519 new make(Location location)
520 : super(location)
521 {
522 cases = Expr[,]
523 }
524
525 Void walk(Visitor v, VisitDepth depth)
526 {
527 if (depth === VisitDepth.expr)
528 cases = Expr.walkExprs(v, cases)
529
530 block.walk(v, depth)
531 }
532
533 override Void print(AstWriter out)
534 {
535 cases.each |Expr c| { out.w("case $c:").nl }
536 out.indent
537 if (block != null) block.printOpt(out, false)
538 out.unindent
539 }
540
541 Expr[] cases // list of case target (literal expressions)
542 Block block // code to run for case
543 Int startOffset // start offset for CodeAsm
544 }
545
546 **************************************************************************
547 ** StmtId
548 **************************************************************************
549
550 enum StmtId
551 {
552 nop,
553 expr,
554 localDef,
555 ifStmt,
556 returnStmt,
557 throwStmt,
558 forStmt,
559 whileStmt,
560 breakStmt,
561 continueStmt,
562 tryStmt,
563 switchStmt
564 }