Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library rewrite_async; | |
| 6 | |
| 7 import "js.dart"; | |
| 8 import "../helpers/helpers.dart"; | |
| 9 import 'dart:collection'; | |
| 10 import "dart:math" show max; | |
| 11 import 'package:compiler/src/util/util.dart'; | |
| 12 | |
| 13 class AsyncFinder extends BaseVisitor { | |
| 14 @override | |
| 15 visitFun(Fun node) { | |
| 16 switch (node.asyncModifier) { | |
| 17 case const AsyncModifier.sync(): | |
| 18 node.visitChildren(this); | |
| 19 break; | |
| 20 case const AsyncModifier.async(): | |
| 21 | |
| 22 node.visitChildren(this); | |
| 23 break; | |
| 24 case const AsyncModifier.syncStar(): | |
| 25 throw "Sync* is not supported yet"; | |
| 26 case const AsyncModifier.asyncStar(): | |
| 27 throw "Async* is not supported yet"; | |
| 28 } | |
| 29 } | |
| 30 | |
| 31 } | |
| 32 | |
| 33 class AnalysisPrinter extends BaseVisitor { | |
| 34 int indent = 0; | |
| 35 var awaits; | |
| 36 visitNode(Node node) { | |
| 37 indent ++; | |
| 38 node.visitChildren(this); | |
| 39 indent --; | |
| 40 } | |
| 41 } | |
| 42 | |
| 43 class Analysis extends NodeVisitor { | |
| 44 Set<Node> awaits = new Set<Node>(); | |
| 45 | |
| 46 Map<Node, Node> targets = new Map<Node, Node>(); | |
| 47 List<Node> loopsAndSwitches = new List<Node>(); | |
| 48 List<LabeledStatement> labelledStatements = new List<LabeledStatement>(); | |
| 49 | |
| 50 bool visit(Node node) { | |
| 51 bool result = node.accept(this); | |
|
floitsch
2015/01/20 16:06:15
don't call it "result".
sigurdm
2015/02/02 10:20:15
Called it containsAwait
| |
| 52 if (result) { | |
| 53 awaits.add(node); | |
| 54 } | |
| 55 return result; | |
| 56 } | |
| 57 | |
| 58 analyze(Fun node) { | |
| 59 visit(node.body); | |
| 60 } | |
| 61 | |
| 62 @override | |
| 63 visitAccess(PropertyAccess node) { | |
| 64 bool x = visit(node.receiver); | |
| 65 bool y = visit(node.selector); | |
| 66 return x || y; | |
| 67 } | |
| 68 | |
| 69 @override | |
| 70 visitArrayHole(ArrayHole node) { | |
| 71 // TODO: implement visitArrayHole | |
|
floitsch
2015/01/20 16:06:15
should be trivial. There is no expression in the h
sigurdm
2015/02/02 10:20:14
Done.
| |
| 72 } | |
| 73 | |
| 74 @override | |
| 75 visitArrayInitializer(ArrayInitializer node) { | |
| 76 // TODO: implement visitArrayInitializer | |
| 77 } | |
| 78 | |
| 79 @override | |
| 80 visitAssignment(Assignment node) { | |
| 81 bool x = visit(node.leftHandSide); | |
|
floitsch
2015/01/20 16:06:15
x -> left
y -> right
sigurdm
2015/02/02 10:20:15
Done.
| |
| 82 bool y = node.value == null | |
| 83 ? false | |
| 84 : visit(node.value); | |
| 85 return x || y; | |
| 86 } | |
| 87 | |
| 88 @override | |
| 89 visitAwait(Await node) { | |
| 90 visit(node.expression); | |
| 91 return true; | |
| 92 } | |
| 93 | |
| 94 @override | |
| 95 visitBinary(Binary node) { | |
| 96 bool x = visit(node.left); | |
| 97 bool y = visit(node.right); | |
| 98 return x || y; | |
| 99 } | |
| 100 | |
| 101 @override | |
| 102 visitBlob(Blob node) { | |
| 103 return false; | |
| 104 } | |
| 105 | |
| 106 @override | |
| 107 visitBlock(Block node) { | |
| 108 bool result = false; | |
| 109 for (var s in node.statements) { | |
| 110 if (visit(s)) result = true; | |
| 111 } | |
| 112 return result; | |
| 113 } | |
| 114 | |
| 115 @override | |
| 116 visitBreak(Break node) { | |
| 117 if (node.targetLabel != null) { | |
| 118 targets[node] = labelledStatements.lastWhere( | |
| 119 (LabeledStatement stm) => stm.label == node.targetLabel); | |
| 120 } else { | |
| 121 targets[node] = loopsAndSwitches.last; | |
| 122 } | |
| 123 return false; | |
| 124 } | |
| 125 | |
| 126 @override | |
| 127 visitCall(Call node) { | |
| 128 bool result = visit(node.target); | |
| 129 for (var s in node.arguments) { | |
| 130 if (visit(s)) result = true; | |
| 131 } | |
| 132 return result; | |
| 133 } | |
| 134 | |
| 135 @override | |
| 136 visitCase(Case node) { | |
| 137 bool x = visit(node.expression); | |
| 138 bool y = visit(node.body); | |
| 139 return x || y; | |
| 140 } | |
| 141 | |
| 142 @override | |
| 143 visitCatch(Catch node) { | |
| 144 bool x = visit(node.declaration); | |
| 145 bool y = visit(node.body); | |
| 146 return x || y; | |
| 147 } | |
| 148 | |
| 149 @override | |
| 150 visitComment(Comment node) { | |
| 151 return false; | |
| 152 } | |
| 153 | |
| 154 @override | |
| 155 visitConditional(Conditional node) { | |
| 156 bool x = visit(node.condition); | |
| 157 bool y = visit(node.then); | |
| 158 bool z = visit(node.otherwise); | |
| 159 return x || y || z; | |
| 160 } | |
| 161 | |
| 162 @override | |
| 163 visitContinue(Continue node) { | |
| 164 if (node.targetLabel != null) { | |
| 165 targets[node] = labelledStatements.lastWhere( | |
| 166 (LabeledStatement stm) => stm.label == node.targetLabel); | |
| 167 } else { | |
| 168 targets[node] = loopsAndSwitches.lastWhere( | |
| 169 (Node node) => node is! Switch); | |
| 170 } | |
| 171 return false; | |
| 172 } | |
| 173 | |
| 174 @override | |
| 175 visitDefault(Default node) { | |
| 176 return visit(node.body); | |
| 177 } | |
| 178 | |
| 179 @override | |
| 180 visitDo(Do node) { | |
| 181 loopsAndSwitches.add(node); | |
| 182 bool x = visit(node.body); | |
| 183 bool y = visit(node.condition); | |
| 184 loopsAndSwitches.removeLast(); | |
| 185 return x || y; | |
| 186 } | |
| 187 | |
| 188 @override | |
| 189 visitEmptyStatement(EmptyStatement node) { | |
| 190 return false; | |
| 191 } | |
| 192 | |
| 193 @override | |
| 194 visitExpressionStatement(ExpressionStatement node) { | |
| 195 return visit(node.expression); | |
| 196 } | |
| 197 | |
| 198 @override | |
| 199 visitFor(For node) { | |
| 200 loopsAndSwitches.add(node); | |
|
floitsch
2015/01/20 16:06:15
I would add the loopsAndSwitches only for the body
sigurdm
2015/02/02 10:20:15
Good point
Done
| |
| 201 bool x = visit(node.init); | |
| 202 bool y = visit(node.condition); | |
| 203 bool z = visit(node.update); | |
| 204 bool u = visit(node.body); | |
| 205 loopsAndSwitches.removeLast(); | |
| 206 return x || y || z || u; | |
| 207 } | |
| 208 | |
| 209 @override | |
| 210 visitForIn(ForIn node) { | |
| 211 loopsAndSwitches.add(node); | |
| 212 loopsAndSwitches.removeLast(); | |
| 213 // TODO: implement visitForIn | |
| 214 throw "BADDD"; | |
| 215 } | |
| 216 | |
| 217 @override | |
| 218 visitFun(Fun node) { | |
| 219 return false; | |
| 220 } | |
| 221 | |
| 222 @override | |
| 223 visitFunctionDeclaration(FunctionDeclaration node) { | |
| 224 return false; | |
| 225 } | |
| 226 | |
| 227 @override | |
| 228 visitIf(If node) { | |
| 229 bool x = visit(node.condition); | |
| 230 bool y = visit(node.then); | |
| 231 bool z = visit(node.otherwise); | |
| 232 return x || y || z; | |
| 233 } | |
| 234 | |
| 235 @override | |
| 236 visitInterpolatedExpression(InterpolatedExpression node) { | |
| 237 // TODO: implement visitInterpolatedExpression | |
| 238 } | |
| 239 | |
| 240 @override | |
| 241 visitInterpolatedLiteral(InterpolatedLiteral node) { | |
| 242 // TODO: implement visitInterpolatedLiteral | |
| 243 } | |
| 244 | |
| 245 @override | |
| 246 visitInterpolatedParameter(InterpolatedParameter node) { | |
| 247 // TODO: implement visitInterpolatedParameter | |
| 248 } | |
| 249 | |
| 250 @override | |
| 251 visitInterpolatedSelector(InterpolatedSelector node) { | |
| 252 // TODO: implement visitInterpolatedSelector | |
| 253 } | |
| 254 | |
| 255 @override | |
| 256 visitInterpolatedStatement(InterpolatedStatement node) { | |
| 257 // TODO: implement visitInterpolatedStatement | |
| 258 } | |
| 259 | |
| 260 @override | |
| 261 visitLabeledStatement(LabeledStatement node) { | |
| 262 labelledStatements.add(node); | |
| 263 bool result = visit(node.body); | |
| 264 labelledStatements.removeLast(); | |
| 265 return result; | |
| 266 } | |
| 267 | |
| 268 @override | |
| 269 visitLiteralBool(LiteralBool node) { | |
| 270 return false; | |
| 271 } | |
| 272 | |
| 273 @override | |
| 274 visitLiteralExpression(LiteralExpression node) { | |
| 275 // TODO: implement visitLiteralExpression | |
| 276 } | |
| 277 | |
| 278 @override | |
| 279 visitLiteralNull(LiteralNull node) { | |
| 280 return false; | |
| 281 } | |
| 282 | |
| 283 @override | |
| 284 visitLiteralNumber(LiteralNumber node) { | |
| 285 return false; | |
| 286 } | |
| 287 | |
| 288 @override | |
| 289 visitLiteralStatement(LiteralStatement node) { | |
| 290 // TODO: implement visitLiteralStatement | |
| 291 } | |
| 292 | |
| 293 @override | |
| 294 visitLiteralString(LiteralString node) { | |
| 295 return false; | |
| 296 } | |
| 297 | |
| 298 @override | |
| 299 visitNamedFunction(NamedFunction node) { | |
| 300 return false; | |
| 301 } | |
| 302 | |
| 303 @override | |
| 304 visitNew(New node) { | |
| 305 return visitCall(node); | |
| 306 } | |
| 307 | |
| 308 @override | |
| 309 visitObjectInitializer(ObjectInitializer node) { | |
| 310 bool result = false; | |
| 311 for (Property property in node.properties) { | |
| 312 if (visit(property)) result = true; | |
| 313 } | |
| 314 return result; | |
| 315 } | |
| 316 | |
| 317 @override | |
| 318 visitParameter(Parameter node) { | |
| 319 } | |
| 320 | |
| 321 @override | |
| 322 visitPostfix(Postfix node) { | |
| 323 return visit(node.argument); | |
| 324 } | |
| 325 | |
| 326 @override | |
| 327 visitPrefix(Prefix node) { | |
| 328 return visit(node.argument); | |
| 329 } | |
| 330 | |
| 331 @override | |
| 332 visitProgram(Program node) { | |
| 333 throw "Unexpected"; | |
| 334 } | |
| 335 | |
| 336 @override | |
| 337 visitProperty(Property node) { | |
| 338 return visit(node.value); | |
| 339 } | |
| 340 | |
| 341 @override | |
| 342 visitRegExpLiteral(RegExpLiteral node) { | |
| 343 return false; | |
| 344 } | |
| 345 | |
| 346 @override | |
| 347 visitReturn(Return node) { | |
| 348 if (node.value == null) return false; | |
| 349 return visit(node.value); | |
| 350 } | |
| 351 | |
| 352 @override | |
| 353 visitSwitch(Switch node) { | |
| 354 loopsAndSwitches.add(node); | |
| 355 bool result = visit(node.key); | |
| 356 for (SwitchClause clause in node.cases) { | |
| 357 if (visit(clause)) result = true; | |
| 358 } | |
| 359 loopsAndSwitches.removeLast(); | |
| 360 return result; | |
| 361 } | |
| 362 | |
| 363 @override | |
| 364 visitThis(This node) { | |
| 365 return false; | |
| 366 } | |
| 367 | |
| 368 @override | |
| 369 visitThrow(Throw node) { | |
| 370 return visit(node.expression); | |
| 371 } | |
| 372 | |
| 373 @override | |
| 374 visitTry(Try node) { | |
| 375 bool x = visit(node.body); | |
| 376 bool y = node.catchPart == null ? false : visit(node.catchPart); | |
| 377 bool z = node.finallyPart == null ? false : visit(node.finallyPart); | |
| 378 return x || y || z; | |
| 379 } | |
| 380 | |
| 381 @override | |
| 382 visitVariableDeclaration(VariableDeclaration node) { | |
| 383 return false; | |
| 384 } | |
| 385 | |
| 386 @override | |
| 387 visitVariableDeclarationList(VariableDeclarationList node) { | |
| 388 bool result = false; | |
| 389 for (VariableInitialization init in node.declarations) { | |
| 390 if (visit(init)) result = true; | |
| 391 } | |
| 392 return result; | |
| 393 } | |
| 394 | |
| 395 @override | |
| 396 visitVariableInitialization(VariableInitialization node) { | |
| 397 return visitAssignment(node); | |
| 398 } | |
| 399 | |
| 400 @override | |
| 401 visitVariableUse(VariableUse node) { | |
| 402 return false; | |
| 403 } | |
| 404 | |
| 405 @override | |
| 406 visitWhile(While node) { | |
| 407 loopsAndSwitches.add(node); | |
| 408 // Be careful to avoid short-circuit. | |
| 409 bool x = visit(node.condition); | |
| 410 bool y = visit(node.body); | |
| 411 loopsAndSwitches.removeLast(); | |
| 412 return x || y; | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 class AsyncRewriter extends NodeVisitor { | |
| 417 | |
| 418 // The set of all nodes containing an await nested somewhere. | |
| 419 Set<Node> __containsAwait; | |
| 420 | |
| 421 // Local variables are hoisted to the top of the function, so we collect them | |
| 422 // here. | |
| 423 List<VariableDeclaration> localVariables = new List<VariableDeclaration>(); | |
| 424 | |
| 425 Map<Node, Node> __targets = new Map<Node, Node>(); | |
| 426 Map<Node, int> continueLabels = new Map<Node, int>(); | |
| 427 Map<Node, int> breakLabels = new Map<Node, int>(); | |
| 428 | |
| 429 List<Pair<String, String>> variableRenamings = | |
| 430 new List<Pair<String, String>>(); | |
| 431 Set<String> usedNames = new Set<String>(); | |
| 432 | |
| 433 List<int> errorHandlerLabels = new List<int>(); | |
| 434 | |
| 435 // TODO(sigurdm): use namer for these. | |
| 436 String resultName = "__result"; | |
| 437 String helperName = "__helper"; | |
| 438 String gotoName = "__goto"; | |
| 439 String handlerName = "__handler"; | |
| 440 String errorName = "__error"; | |
| 441 | |
| 442 int __currentLabel = 0; | |
| 443 | |
| 444 int highWaterMark = 0; | |
| 445 int currentTempVarIndex = 0; | |
| 446 | |
| 447 int allocateTempVar() { | |
| 448 assert(highWaterMark >= currentTempVarIndex); | |
| 449 currentTempVarIndex++; | |
| 450 highWaterMark = max(currentTempVarIndex, highWaterMark); | |
| 451 return currentTempVarIndex; | |
| 452 } | |
| 453 | |
| 454 deallocateTempVar([howMany = 1]) { | |
| 455 currentTempVarIndex -= howMany; | |
| 456 } | |
| 457 | |
| 458 Expression useTempVar(int i) { | |
| 459 return new VariableUse("__temp$i"); | |
| 460 } | |
| 461 | |
| 462 | |
| 463 String freshName(String originalName) { | |
| 464 String result = "__$originalName"; | |
| 465 int counter = 1; | |
| 466 while (usedNames.contains(result)) { | |
| 467 result = "__$originalName$counter"; | |
| 468 ++counter; | |
| 469 } | |
| 470 usedNames.add(result); | |
| 471 return result; | |
| 472 } | |
| 473 | |
| 474 /// We collect all the pieces in this map, and output a switch with a case | |
| 475 /// for each label. | |
| 476 /// The order is important, therefore the type is explicitly LinkedHashMap. | |
|
floitsch
2015/01/20 16:06:15
New line before.
sigurdm
2015/02/02 10:20:15
Done.
| |
| 477 LinkedHashMap<int, List<Statement>> labelledParts = | |
| 478 new LinkedHashMap<int, List<Statement>>(); | |
| 479 | |
| 480 // Description of each label for readability of the non-minified output. | |
| 481 Map<int, String> labelComments = new Map<int, String>(); | |
| 482 | |
| 483 // True if the function has any try blocks containing await. | |
| 484 bool tryBlocks = false; | |
| 485 | |
| 486 List<Statement> currentStatementBuffer; | |
| 487 | |
| 488 void addStatement(Statement node) { | |
| 489 currentStatementBuffer.add(node); | |
| 490 } | |
| 491 | |
| 492 void addExpressionStatement(Expression node) { | |
| 493 addStatement(new ExpressionStatement(node)); | |
| 494 } | |
| 495 | |
| 496 Expression methodCall(Expression callee, | |
| 497 String methodName, | |
| 498 List<Expression> args) { | |
| 499 return new Call(new PropertyAccess.field(callee, methodName), args); | |
| 500 } | |
| 501 | |
| 502 int newLabel([String comment]) { | |
| 503 int result = __currentLabel; | |
| 504 __currentLabel++; | |
| 505 if (comment != null) { | |
| 506 labelComments[result] = comment; | |
| 507 } | |
| 508 return result; | |
| 509 } | |
| 510 | |
| 511 void beginLabel(int label) { | |
| 512 assert(!labelledParts.containsKey(label)); | |
| 513 labelledParts[label] = currentStatementBuffer = new List<Statement>(); | |
| 514 addStatement(new Comment(labelComments[label])); | |
| 515 } | |
| 516 | |
| 517 /// Returns a statement assigning to the `__goto` variable. This should be | |
| 518 /// followed by a break for the goto to be executed. Use [gotoWithBreak] or | |
| 519 /// [addGoto] for this. | |
| 520 Statement goto(int label) { | |
| 521 return new ExpressionStatement( | |
| 522 new Assignment(new VariableUse(gotoName), new LiteralNumber("$label"))); | |
| 523 } | |
| 524 | |
| 525 /// Returns a block with the same effect as [addGoto]. | |
| 526 Block gotoAndBreak(int label) { | |
| 527 List<Statement> statements = new List<Statement>(); | |
| 528 if (labelComments.containsKey(label)) { | |
| 529 statements.add(new Comment("goto ${labelComments[label]}")); | |
| 530 } | |
| 531 statements.add(goto(label)); | |
| 532 statements.add(new Break(null)); | |
| 533 return new Block(statements); | |
| 534 } | |
| 535 | |
| 536 /// Add a goto to [label] including the break. | |
| 537 /// Will also insert a comment describing the label if available. | |
| 538 void addGoto(int label) { | |
| 539 if (labelComments.containsKey(label)) { | |
| 540 addStatement(new Comment("goto ${labelComments[label]}")); | |
| 541 } | |
| 542 addStatement(goto(label)); | |
| 543 addStatement(new Break(null)); | |
| 544 } | |
| 545 | |
| 546 bool transform(Node node) { | |
|
floitsch
2015/01/20 16:06:14
shouldTransform
sigurdm
2015/02/02 10:20:15
Done.
| |
| 547 return node is Break || node is Continue || __containsAwait.contains(node); | |
| 548 } | |
| 549 | |
| 550 /// Main entry point. | |
| 551 Fun rewrite(Fun node) { | |
| 552 assert(node.asyncModifier == const AsyncModifier.async()); | |
| 553 Analysis analysis = new Analysis(); | |
| 554 analysis.analyze(node); | |
| 555 __containsAwait = analysis.awaits; | |
| 556 __targets = analysis.targets; | |
| 557 new AnalysisPrinter()..awaits = analysis.awaits | |
| 558 ..visitNode(node); | |
| 559 return node.accept(this); | |
| 560 } | |
| 561 | |
| 562 visitStatement(Statement node) { | |
| 563 node.accept(this); | |
| 564 } | |
| 565 | |
| 566 void visitExpressionIgnoreResult(Expression node) { | |
| 567 addExpressionStatement(node.accept(this)); | |
| 568 } | |
| 569 | |
| 570 Expression visitExpression(Expression node) { | |
| 571 return node.accept(this); | |
| 572 } | |
| 573 | |
| 574 Expression _storeIfNecessary(Expression result) { | |
| 575 if (result is Literal) return result; | |
|
floitsch
2015/01/20 16:06:15
I guess this will be wrong, once you have list-lit
sigurdm
2015/02/02 10:20:14
Actually list-literals are not Literal, but Object
| |
| 576 Expression tempVar = useTempVar(allocateTempVar()); | |
| 577 addExpressionStatement(new Assignment(tempVar, result)); | |
| 578 return tempVar; | |
| 579 } | |
| 580 | |
| 581 withExpression(Expression node, fn(Expression result), {bool store}) { | |
| 582 int oldTempVarIndex = currentTempVarIndex; | |
| 583 Expression visited = visitExpression(node); | |
| 584 if (store) { | |
| 585 visited = _storeIfNecessary(visited); | |
| 586 } | |
| 587 var result = fn(visited); | |
| 588 currentTempVarIndex = oldTempVarIndex; | |
| 589 return result; | |
| 590 } | |
| 591 | |
| 592 withExpression2(Expression node1, Expression node2, | |
| 593 fn(Expression result1, Expression result2)) { | |
| 594 int oldTempVarIndex = currentTempVarIndex; | |
| 595 Expression r1 = visitExpression(node1); | |
| 596 if (transform(node2)) { | |
| 597 r1 = _storeIfNecessary(r1); | |
| 598 } | |
| 599 Expression r2 = visitExpression(node2); | |
| 600 var result = fn(r1, r2); | |
| 601 currentTempVarIndex = oldTempVarIndex; | |
| 602 return result; | |
| 603 } | |
| 604 | |
| 605 withExpressions(List<Node> nodes, fn(List<Node> results)) { | |
| 606 int oldTempVarIndex = currentTempVarIndex; | |
| 607 // Find last occurence of a 'transform' expression in [nodes]. | |
| 608 // All expressions before that must be stored in temp-vars. | |
| 609 int lastTransformIndex = 0; | |
| 610 for (int i = nodes.length - 1; i >= 0; --i) { | |
| 611 if (transform(nodes[i])) { | |
| 612 lastTransformIndex = i; | |
| 613 break; | |
| 614 } | |
| 615 } | |
| 616 List<Node> visited = nodes.take(lastTransformIndex).map((Node node) { | |
| 617 return _storeIfNecessary(visitExpression(node)); | |
| 618 }).toList(); | |
| 619 visited.addAll(nodes.skip(lastTransformIndex).map((Node node) { | |
| 620 return visitExpression(node); | |
| 621 })); | |
| 622 var result = fn(visited); | |
| 623 currentTempVarIndex = oldTempVarIndex; | |
| 624 return result; | |
| 625 } | |
| 626 | |
| 627 // [[Fun(a1, ..., an) S ]] => | |
| 628 // Fun(a1, ..., an) { | |
| 629 // vars(S); // Declaration of local variables of S. | |
| 630 // var __goto = 0; | |
| 631 // var __handler = null; // The current error handler. | |
| 632 // Fun helper(__result) { | |
| 633 // while(true) { | |
| 634 // try { | |
| 635 // switch(__goto) { | |
| 636 // case 0: | |
| 637 // [[S]]; | |
| 638 // } | |
| 639 // } catch(__error) { | |
| 640 // if (handler === null) throw error; | |
| 641 // __goto = __handler; | |
| 642 // __result = __error; | |
| 643 // } | |
| 644 // } | |
| 645 // } | |
| 646 // } | |
| 647 visitAsyncFun(Fun node) { | |
| 648 beginLabel(newLabel("Function start")); | |
| 649 visitStatement(node.body); | |
| 650 List<SwitchClause> clauses = labelledParts.keys.map((label) { | |
| 651 return new Case(new LiteralNumber("$label"), | |
| 652 new Block(labelledParts[label])); | |
| 653 }).toList(); | |
| 654 Statement helperBody = new Switch(new VariableUse(gotoName), | |
| 655 clauses); | |
| 656 if (tryBlocks) { | |
| 657 helperBody = new Try(new Block([helperBody]), | |
|
floitsch
2015/01/20 16:06:15
consider using the `js` templates.
You will actual
sigurdm
2015/02/02 10:20:14
Yeah - it is better like that.
| |
| 658 new Catch((new VariableDeclaration(errorName)), | |
| 659 new Block([new If.noElse(new Binary("===", | |
| 660 new VariableUse(handlerName), new LiteralNull()), | |
| 661 new Throw(new VariableUse(errorName))), | |
| 662 new ExpressionStatement(new Assignment( | |
| 663 new VariableUse(resultName), | |
| 664 new VariableUse(errorName))), | |
| 665 new ExpressionStatement(new Assignment( | |
| 666 new VariableUse(gotoName), | |
| 667 new VariableUse(handlerName))), | |
| 668 ])), null); | |
| 669 } | |
| 670 helperBody = new While(new LiteralBool(true), helperBody); | |
| 671 helperBody = new Block([helperBody]); | |
| 672 List<VariableInitialization> inits = | |
| 673 [new VariableInitialization(new VariableDeclaration(gotoName), | |
| 674 new LiteralNumber("0")), | |
| 675 new VariableInitialization(new VariableDeclaration(handlerName), | |
| 676 new LiteralNull())]; | |
| 677 inits.addAll(localVariables.map( | |
| 678 (VariableDeclaration decl) => new VariableInitialization(decl, null))); | |
| 679 VariableDeclarationList varDecl = new VariableDeclarationList(inits); | |
| 680 inits.addAll(new Iterable.generate(highWaterMark, (int i) { | |
| 681 return new VariableInitialization( | |
| 682 new VariableDeclaration("__temp${i + 1}"), | |
| 683 null); | |
| 684 })); | |
| 685 Fun helper = new Fun([new Parameter(resultName)], helperBody); | |
| 686 return new Fun(node.params, | |
| 687 new Block([new ExpressionStatement(varDecl), | |
| 688 new FunctionDeclaration(new VariableDeclaration(helperName), | |
| 689 helper), | |
| 690 new Return( | |
| 691 new New(new PropertyAccess.field( | |
| 692 new VariableUse("Future"), "microtask"), | |
| 693 [new VariableUse(helperName)]))])); | |
| 694 } | |
| 695 | |
| 696 @override | |
| 697 visitFun(Fun node) { | |
| 698 switch (node.asyncModifier) { | |
| 699 case const AsyncModifier.sync(): | |
| 700 return node; | |
| 701 case const AsyncModifier.async(): | |
| 702 return visitAsyncFun(node); | |
| 703 case const AsyncModifier.syncStar(): | |
| 704 throw "Sync* is not supported yet"; | |
| 705 case const AsyncModifier.asyncStar(): | |
| 706 throw "Async* is not supported yet"; | |
| 707 } | |
| 708 | |
| 709 } | |
| 710 | |
| 711 @override | |
| 712 visitAccess(PropertyAccess node) { | |
| 713 return withExpression2(node.receiver, node.selector, | |
| 714 (receiver, selector) => new PropertyAccess(receiver, selector)); | |
| 715 } | |
| 716 | |
| 717 unreachable(Node node) { | |
| 718 throw("The transformer should never meet: $node"); | |
|
floitsch
2015/01/20 16:06:15
If the function is intendend to stay, make it have
sigurdm
2015/02/02 10:20:14
Done.
| |
| 719 } | |
| 720 | |
| 721 @override | |
| 722 visitArrayHole(ArrayHole node) { | |
| 723 return node; | |
| 724 } | |
| 725 | |
| 726 @override | |
| 727 visitArrayInitializer(ArrayInitializer node) { | |
| 728 withExpressions(node.elements, (elements) { | |
| 729 return new ArrayInitializer(elements); | |
| 730 }); | |
| 731 } | |
| 732 | |
| 733 // C([[e1 = e2]] => | |
| 734 // C([[e1]] = [[e2]]) | |
| 735 @override | |
| 736 visitAssignment(Assignment node) { | |
| 737 Expression leftHandSide = node.leftHandSide; | |
| 738 if (leftHandSide is VariableUse) { | |
| 739 return withExpression(node.value, (Expression value) { | |
| 740 return new Assignment(leftHandSide, value); | |
| 741 }, store: false); | |
| 742 } else if (leftHandSide is PropertyAccess) { | |
| 743 return withExpressions( | |
| 744 [leftHandSide.receiver, leftHandSide.selector, node.value], | |
| 745 (evaluated) { | |
| 746 return new Assignment( | |
| 747 new PropertyAccess(evaluated[0], evaluated[1]), | |
| 748 evaluated[2]); | |
| 749 }); | |
| 750 } else { | |
| 751 throw "Unexpected assignment left hand side $leftHandSide"; | |
| 752 } | |
| 753 } | |
| 754 | |
| 755 // C([[await e]]) => | |
| 756 // __goto = `newLabel(afterCall) | |
| 757 // [[e]].then(__helper, onError: (error) {__goto = `currentHandler } ); | |
| 758 // case afterCall: | |
| 759 // C(__result); | |
| 760 @override | |
| 761 Expression visitAwait(Await node) { | |
| 762 int afterWait = newLabel("Returning from await."); | |
| 763 withExpression(node.expression, (Expression expression) { | |
| 764 addStatement(goto(afterWait)); | |
| 765 addStatement(new Return(new Call( | |
| 766 new PropertyAccess.field(expression, "then"), | |
| 767 [new VariableUse(helperName), | |
| 768 new Fun([new Parameter(errorName)], | |
| 769 new Block([new ExpressionStatement( | |
| 770 new Assignment(new VariableUse(gotoName), | |
| 771 currentErrorHandler)), | |
| 772 new ExpressionStatement(new Call( | |
| 773 new VariableUse(helperName), | |
| 774 [new VariableUse(errorName)]))]))]))); | |
| 775 }, store: false); | |
| 776 beginLabel(afterWait); | |
| 777 return new VariableUse(resultName); | |
| 778 } | |
| 779 | |
| 780 Expression get currentErrorHandler { | |
| 781 return errorHandlerLabels.isEmpty | |
| 782 ? new LiteralNull() | |
| 783 : new LiteralNumber("${errorHandlerLabels.last}"); | |
| 784 } | |
| 785 | |
| 786 // TODO short-circuiting operators!! | |
| 787 @override | |
| 788 Expression visitBinary(Binary node) { | |
| 789 return withExpression2(node.left, node.right, | |
| 790 (left, right) => new Binary(node.op, left, right)); | |
| 791 } | |
| 792 | |
| 793 @override | |
| 794 visitBlob(Blob node) { | |
| 795 return node; | |
| 796 } | |
| 797 | |
| 798 @override | |
| 799 void visitBlock(Block node) { | |
| 800 for (Statement statement in node.statements) { | |
| 801 visitStatement(statement); | |
| 802 } | |
| 803 } | |
| 804 | |
| 805 @override | |
| 806 void visitBreak(Break node) { | |
| 807 int target = breakLabels[__targets[node]]; | |
| 808 if (target != null) { | |
| 809 addGoto(target); | |
| 810 } else { | |
| 811 addStatement(node); | |
| 812 } | |
| 813 } | |
| 814 | |
| 815 @override | |
| 816 Expression visitCall(Call node) { | |
| 817 bool storeTarget = node.arguments.any(transform); | |
| 818 return withExpression(node.target, (target) { | |
| 819 return withExpressions(node.arguments, (List<Expression> arguments) { | |
| 820 return new Call(target, arguments); | |
| 821 }); | |
| 822 }, store: storeTarget); | |
| 823 } | |
| 824 | |
| 825 @override | |
| 826 visitCase(Case node) { | |
| 827 return unreachable(node); | |
| 828 } | |
| 829 | |
| 830 @override | |
| 831 visitCatch(Catch node) { | |
| 832 return unreachable(node); | |
| 833 } | |
| 834 | |
| 835 @override | |
| 836 visitComment(Comment node) { | |
| 837 addStatement(node); | |
| 838 } | |
| 839 | |
| 840 @override | |
| 841 Expression visitConditional(Conditional node) { | |
| 842 if (!transform(node.then) && !transform(node.otherwise)) { | |
| 843 return withExpression(node.condition, (Expression condition) { | |
| 844 return new Conditional(condition, node.then, node.otherwise); | |
| 845 }); | |
| 846 } | |
| 847 int thenLabel = newLabel("then"); | |
| 848 int joinLabel = newLabel("join"); | |
| 849 int elseLabel = newLabel("else"); | |
| 850 withExpression(node.condition, (Expression condition) { | |
| 851 addExpressionStatement(new Assignment(new VariableUse(gotoName), | |
| 852 new Conditional(condition, new LiteralNumber("$thenLabel"), | |
| 853 new LiteralNumber("$elseLabel")))); | |
| 854 }, store: false); | |
| 855 addStatement(new Break(null)); | |
| 856 beginLabel(thenLabel); | |
| 857 withExpression(node.then, (Expression value) { | |
| 858 addExpressionStatement(new Assignment( | |
| 859 new VariableUse(resultName), | |
| 860 value)); | |
| 861 }, store: false); | |
| 862 addGoto(joinLabel); | |
| 863 beginLabel(elseLabel); | |
| 864 withExpression(node.otherwise, (Expression value) { | |
| 865 addExpressionStatement(new Assignment( | |
| 866 new VariableUse(resultName), | |
| 867 value)); | |
| 868 }, store: false); | |
| 869 beginLabel(joinLabel); | |
| 870 return new VariableUse(resultName); | |
| 871 } | |
| 872 | |
| 873 @override | |
| 874 visitContinue(Continue node) { | |
| 875 int target = continueLabels[__targets[node]]; | |
| 876 if (target != null) { | |
| 877 addGoto(target); | |
| 878 } else { | |
| 879 addStatement(node); | |
| 880 } | |
| 881 } | |
| 882 | |
| 883 @override | |
| 884 visitDefault(Default node) => unreachable(node); | |
| 885 | |
| 886 @override | |
| 887 visitDo(Do node) { | |
| 888 throw "TODO"; | |
| 889 } | |
| 890 | |
| 891 @override | |
| 892 visitEmptyStatement(EmptyStatement node) => node; | |
| 893 | |
| 894 @override | |
| 895 visitExpressionStatement(ExpressionStatement node) { | |
| 896 if (node.expression is VariableDeclarationList) { | |
| 897 // Treat VariableDeclarationList as a statement. | |
| 898 visitVariableDeclarationList(node.expression); | |
| 899 } else { | |
| 900 visitExpressionIgnoreResult(node.expression); | |
| 901 } | |
| 902 } | |
| 903 | |
| 904 @override | |
| 905 visitFor(For node) { | |
| 906 throw "TODO"; | |
| 907 } | |
| 908 | |
| 909 @override | |
| 910 visitForIn(ForIn node) { | |
| 911 throw "TODO"; | |
| 912 } | |
| 913 | |
| 914 @override | |
| 915 visitFunctionDeclaration(FunctionDeclaration node) { | |
| 916 return node; | |
| 917 } | |
| 918 | |
| 919 Block translateInBlock(Statement node) { | |
| 920 List<Statement> oldBuffer = currentStatementBuffer; | |
| 921 List<Statement> resultBuffer = currentStatementBuffer = new List(); | |
| 922 visitStatement(node); | |
| 923 currentStatementBuffer = oldBuffer; | |
| 924 return new Block(resultBuffer); | |
| 925 } | |
| 926 | |
| 927 @override | |
| 928 visitIf(If node) { | |
| 929 if (!transform(node.then) && !transform(node.otherwise)) { | |
| 930 withExpression(node.condition, (Expression condition) { | |
| 931 addStatement(new If(condition, | |
| 932 translateInBlock(node.then), | |
| 933 translateInBlock(node.otherwise))); | |
| 934 }, store: false); | |
| 935 return; | |
| 936 } | |
| 937 int thenLabel = newLabel("then"); | |
| 938 int joinLabel = newLabel("join"); | |
| 939 int elseLabel = node.otherwise is EmptyStatement | |
| 940 ? joinLabel | |
| 941 : newLabel("else"); | |
| 942 | |
| 943 withExpression(node.condition, (Expression condition) { | |
| 944 addExpressionStatement(new Assignment(new VariableUse(gotoName), | |
| 945 new Conditional(condition, new LiteralNumber("$thenLabel"), | |
| 946 new LiteralNumber("$elseLabel")))); | |
| 947 }, store: false); | |
| 948 addStatement(new Break(null)); | |
| 949 beginLabel(thenLabel); | |
| 950 visitStatement(node.then); | |
| 951 if (node.otherwise is EmptyStatement) { | |
| 952 addGoto(joinLabel); | |
| 953 beginLabel(elseLabel); | |
| 954 visitStatement(node.otherwise); | |
| 955 } | |
| 956 beginLabel(joinLabel); | |
| 957 } | |
| 958 | |
| 959 @override | |
| 960 visitInterpolatedExpression(InterpolatedExpression node) { | |
| 961 throw "Unsupported"; | |
| 962 } | |
| 963 | |
| 964 @override | |
| 965 visitInterpolatedLiteral(InterpolatedLiteral node) => throw "Unsupported"; | |
| 966 | |
| 967 @override | |
| 968 visitInterpolatedParameter(InterpolatedParameter node) => throw "Unsupported"; | |
| 969 | |
| 970 @override | |
| 971 visitInterpolatedSelector(InterpolatedSelector node) => throw "Unsupported"; | |
| 972 | |
| 973 @override | |
| 974 visitInterpolatedStatement(InterpolatedStatement node) => throw "Unsupported"; | |
| 975 | |
| 976 @override | |
| 977 visitLabeledStatement(LabeledStatement node) { | |
| 978 int breakLabel = newLabel("break ${node.label}"); | |
| 979 int continueLabel = newLabel("continue ${node.label}"); | |
| 980 breakLabels[node] = breakLabel; | |
| 981 continueLabels[node] = continueLabel; | |
| 982 | |
| 983 beginLabel(continueLabel); | |
| 984 visitStatement(node.body); | |
| 985 beginLabel(breakLabel); | |
| 986 } | |
| 987 | |
| 988 @override | |
| 989 visitLiteralBool(LiteralBool node) => node; | |
| 990 | |
| 991 @override | |
| 992 visitLiteralExpression(LiteralExpression node) => throw "Unsupported"; | |
| 993 | |
| 994 @override | |
| 995 visitLiteralNull(LiteralNull node) => node; | |
| 996 | |
| 997 @override | |
| 998 visitLiteralNumber(LiteralNumber node) => node; | |
| 999 | |
| 1000 @override | |
| 1001 visitLiteralStatement(LiteralStatement node) => throw "Unsupported"; | |
| 1002 | |
| 1003 @override | |
| 1004 visitLiteralString(LiteralString node) => node; | |
| 1005 | |
| 1006 @override | |
| 1007 visitNamedFunction(NamedFunction node) { | |
| 1008 throw "TODO"; | |
| 1009 } | |
| 1010 | |
| 1011 @override | |
| 1012 visitNew(New node) { | |
| 1013 bool storeTarget = node.arguments.any(transform); | |
| 1014 return withExpression(node.target, (target) { | |
| 1015 return withExpressions(node.arguments, (List<Expression> arguments) { | |
| 1016 return new New(target, arguments); | |
| 1017 }); | |
| 1018 }, store: storeTarget); | |
| 1019 } | |
| 1020 | |
| 1021 @override | |
| 1022 visitObjectInitializer(ObjectInitializer node) { | |
| 1023 return withExpressions(node.properties, (List<Node> properties) { | |
| 1024 return new ObjectInitializer(properties); | |
| 1025 }); | |
| 1026 } | |
| 1027 | |
| 1028 @override | |
| 1029 visitParameter(Parameter node) { | |
| 1030 throw "Unexpected"; | |
| 1031 } | |
| 1032 | |
| 1033 @override | |
| 1034 visitPostfix(Postfix node) { | |
| 1035 return withExpression(node.argument, | |
| 1036 (Expression argument) => new Postfix(node.op, argument), store: false); | |
| 1037 } | |
| 1038 | |
| 1039 @override | |
| 1040 visitPrefix(Prefix node) { | |
| 1041 return withExpression(node.argument, | |
| 1042 (Expression argument) => new Prefix(node.op, argument), store: false); | |
| 1043 } | |
| 1044 | |
| 1045 @override | |
| 1046 visitProgram(Program node) => throw "Unsupported"; | |
| 1047 | |
| 1048 @override | |
| 1049 visitProperty(Property node) { | |
| 1050 return withExpression(node.value, | |
| 1051 (Expression value) => new Property(node.name, value), store: false); | |
| 1052 } | |
| 1053 | |
| 1054 @override | |
| 1055 visitRegExpLiteral(RegExpLiteral node) => node; | |
| 1056 | |
| 1057 @override | |
| 1058 visitReturn(Return node) { | |
| 1059 if (node.value == null) { | |
| 1060 addStatement(node); | |
| 1061 } else { | |
| 1062 withExpression(node.value, (Expression value) { | |
| 1063 addStatement(new Return(value)); | |
| 1064 }, store: false); | |
| 1065 } | |
| 1066 } | |
| 1067 | |
| 1068 // [[switch(e) { | |
| 1069 // case i: Si; | |
| 1070 // ... | |
| 1071 // default: Sd; | |
| 1072 // }]] => | |
| 1073 // case #before | |
| 1074 // switch([[e]]) { | |
| 1075 // case i: __goto = #i; | |
| 1076 // ... | |
| 1077 // default: __goto = #defaultLabel; | |
| 1078 // } | |
| 1079 // case #i: | |
| 1080 // [[Si, breakLabels|#after, continueLabels|#before]] | |
| 1081 // // Notice fallthough/ | |
| 1082 // ... | |
| 1083 // case #defaultLabel: | |
| 1084 // [[Si, breakLabels|#after, continueLabels|#before]] | |
| 1085 // case #afterSwitch: | |
| 1086 @override | |
| 1087 visitSwitch(Switch node) { | |
| 1088 if (!node.cases.any(transform)) { | |
| 1089 // If only the key has an await, translation can be simplified. | |
| 1090 withExpression(node.key, (Expression key) { | |
| 1091 List<SwitchClause> cases = node.cases.map((SwitchClause clause) { | |
| 1092 if (clause is Case) { | |
| 1093 return new Case(clause.expression, translateInBlock(clause.body)); | |
| 1094 } else if (clause is Default) { | |
| 1095 return new Default(translateInBlock(clause.body)); | |
| 1096 } | |
| 1097 }).toList(); | |
| 1098 addStatement(new Switch(key, cases)); | |
| 1099 }); | |
| 1100 return; | |
| 1101 } | |
| 1102 int before = newLabel("switch"); | |
| 1103 int after = newLabel("after switch"); | |
| 1104 breakLabels[node] = after; | |
| 1105 | |
| 1106 beginLabel(before); | |
| 1107 List<int> labels = new List<int>(node.cases.length); | |
| 1108 | |
| 1109 if (!node.cases.every( | |
| 1110 (SwitchClause x) => !(x is Case && transform(x.expression)))){ | |
| 1111 int defaultIndex = null; // Null means no default was found. | |
| 1112 // If there is an await in one of the keys, we have to use a chain of ifs. | |
| 1113 | |
| 1114 withExpression(node.key, (Expression key) { | |
| 1115 int i = 0; | |
| 1116 for (SwitchClause clause in node.cases) { | |
| 1117 if (clause is Default) { | |
| 1118 // The default case is handled last. | |
| 1119 defaultIndex = i; | |
| 1120 labels[i] = newLabel("default"); | |
| 1121 continue; | |
| 1122 } else if (clause is Case) { | |
| 1123 labels[i] = newLabel("case"); | |
| 1124 withExpression(clause.expression, (expression) { | |
| 1125 addStatement(new If.noElse(new Binary("===", key, expression), | |
| 1126 gotoAndBreak(labels[i]))); | |
| 1127 }, store: false); | |
| 1128 } | |
| 1129 i++; | |
| 1130 } | |
| 1131 }, store: true); | |
| 1132 | |
| 1133 if (defaultIndex == null) { | |
| 1134 addGoto(after); | |
| 1135 } else { | |
| 1136 addGoto(labels[defaultIndex]); | |
| 1137 } | |
| 1138 | |
| 1139 } else { | |
| 1140 bool hasDefault = false; | |
| 1141 int i = 0; | |
| 1142 List<SwitchClause> clauses = new List<SwitchClause>(); | |
| 1143 for (SwitchClause clause in node.cases) { | |
| 1144 if (clause is Case) { | |
| 1145 labels[i] = newLabel("case"); | |
| 1146 clauses.add(new Case(clause.expression, gotoAndBreak(labels[i]))); | |
| 1147 } else if (i is Default) { | |
| 1148 labels[i] = newLabel("default"); | |
| 1149 clauses.add(new Default(gotoAndBreak(labels[i]))); | |
| 1150 hasDefault = true; | |
| 1151 } else { | |
| 1152 throw "Unknown switchclause $i"; | |
| 1153 } | |
| 1154 i++; | |
| 1155 } | |
| 1156 withExpression(node.key, (Expression key) { | |
| 1157 addStatement(new Switch(key, clauses)); | |
| 1158 }, store: false); | |
| 1159 if (!hasDefault) { | |
| 1160 addGoto(after); | |
| 1161 } | |
| 1162 } | |
| 1163 for (int i = 0; i < labels.length; i++) { | |
| 1164 beginLabel(labels[i]); | |
| 1165 visitStatement(node.cases[i].body); | |
| 1166 } | |
| 1167 beginLabel(after); | |
| 1168 } | |
| 1169 | |
| 1170 @override | |
| 1171 visitThis(This node) => node; | |
| 1172 | |
| 1173 @override | |
| 1174 visitThrow(Throw node) { | |
| 1175 withExpression(node.expression, (Expression expression) { | |
| 1176 addStatement(new Throw(expression)); | |
| 1177 }, store: false); | |
| 1178 } | |
| 1179 | |
| 1180 setHandler() { | |
| 1181 addExpressionStatement( | |
| 1182 new Assignment(new VariableUse(handlerName), currentErrorHandler)); | |
| 1183 } | |
| 1184 | |
| 1185 @override | |
| 1186 void visitTry(Try node) { | |
| 1187 if (!transform(node)) { | |
| 1188 Block body = translateInBlock(node.body); | |
| 1189 Catch catchPart = node.catchPart == null | |
| 1190 ? null | |
| 1191 : new Catch(node.catchPart.declaration, | |
| 1192 translateInBlock(node.catchPart.body)); | |
| 1193 Block finallyPart = node.finallyPart == null | |
| 1194 ? null | |
| 1195 : translateInBlock(node.finallyPart); | |
| 1196 addStatement(new Try(body, | |
| 1197 catchPart, | |
| 1198 finallyPart)); | |
| 1199 return; | |
| 1200 } | |
| 1201 tryBlocks = true; | |
| 1202 int handlerLabel = newLabel("catch"); | |
| 1203 int finallyLabel = newLabel("finally"); | |
| 1204 errorHandlerLabels.add(handlerLabel); | |
| 1205 setHandler(); | |
| 1206 visitStatement(node.body); | |
| 1207 errorHandlerLabels.removeLast(); | |
| 1208 setHandler(); | |
| 1209 addGoto(finallyLabel); | |
| 1210 beginLabel(handlerLabel); | |
| 1211 if (node.catchPart != null) { | |
| 1212 String errorRename = freshName(node.catchPart.declaration.name); | |
| 1213 localVariables.add(new VariableDeclaration(errorRename)); | |
| 1214 variableRenamings.add( | |
| 1215 new Pair(node.catchPart.declaration.name, errorRename)); | |
| 1216 addExpressionStatement(new Assignment( | |
| 1217 new VariableUse(errorRename), | |
| 1218 new VariableUse(resultName))); | |
| 1219 visitStatement(node.catchPart.body); | |
| 1220 variableRenamings.removeLast(); | |
| 1221 } | |
| 1222 beginLabel(finallyLabel); | |
| 1223 if (node.finallyPart != null) { | |
| 1224 visitStatement(node.finallyPart); | |
| 1225 } | |
| 1226 } | |
| 1227 | |
| 1228 @override | |
| 1229 visitVariableDeclaration(VariableDeclaration node) { | |
| 1230 throw "TODO"; | |
| 1231 } | |
| 1232 | |
| 1233 @override | |
| 1234 void visitVariableDeclarationList(VariableDeclarationList node) { | |
| 1235 // Declaration of local variables is hoisted outside the helper | |
| 1236 // But the initialization is done here. | |
| 1237 for (VariableInitialization initialization in node.declarations) { | |
| 1238 VariableDeclaration declaration = initialization.declaration; | |
| 1239 localVariables.add(declaration); | |
| 1240 if (initialization.value != null) { | |
| 1241 withExpression(initialization.value, (Expression value) { | |
| 1242 addStatement(new ExpressionStatement( | |
| 1243 new Assignment(declaration, value))); | |
| 1244 }, store: false); | |
| 1245 } | |
| 1246 } | |
| 1247 } | |
| 1248 | |
| 1249 @override | |
| 1250 visitVariableInitialization(VariableInitialization node) { | |
| 1251 // These should be handled by visitVariableDeclarationList. | |
| 1252 throw "Unexpected variableInitialization"; | |
| 1253 } | |
| 1254 | |
| 1255 @override | |
| 1256 visitVariableUse(VariableUse node) { | |
| 1257 String renaming = variableRenamings.lastWhere( | |
| 1258 (Pair renaming) => renaming.a == node.name, orElse: () { | |
| 1259 return new Pair(null, null); | |
| 1260 }).b; | |
| 1261 if (renaming == null) return node; | |
| 1262 return new VariableUse(renaming); | |
| 1263 } | |
| 1264 | |
| 1265 @override | |
| 1266 visitWhile(While node) { | |
| 1267 if (!transform(node.body)) { | |
| 1268 // If only the condition has an await, translation can be simplified. | |
| 1269 withExpression(node.condition, (Expression condition) { | |
| 1270 addStatement(new While(condition, translateInBlock(node.body))); | |
| 1271 }, store: false); | |
| 1272 return; | |
| 1273 } | |
| 1274 int continueLabel = newLabel("while condition"); | |
| 1275 continueLabels[node] = continueLabel; | |
| 1276 beginLabel(continueLabel); | |
| 1277 | |
| 1278 int bodyLabel = newLabel("while body"); | |
| 1279 int after = newLabel("after while"); | |
| 1280 breakLabels[node] = after; | |
| 1281 withExpression(node.condition, (Expression cond) { | |
| 1282 addExpressionStatement(new Assignment(new VariableUse(gotoName), | |
| 1283 new Conditional(cond, new LiteralNumber("$bodyLabel"), | |
| 1284 new LiteralNumber("$after")))); | |
| 1285 }, store: false); | |
| 1286 addStatement(new Break(null)); | |
| 1287 beginLabel(bodyLabel); | |
| 1288 visitStatement(node.body); | |
| 1289 addGoto(continueLabel); | |
| 1290 beginLabel(after); | |
| 1291 } | |
| 1292 } | |
| OLD | NEW |