
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 }