OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library code_generator; | 5 library code_generator; |
6 | 6 |
7 import 'glue.dart'; | 7 import 'glue.dart'; |
8 | 8 |
9 import '../../closure.dart' show ClosureClassElement; | 9 import '../../closure.dart' show ClosureClassElement; |
10 import '../../common/codegen.dart' show CodegenRegistry; | 10 import '../../common/codegen.dart' show CodegenRegistry; |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 if (!declaredVariables.add(use.name)) break; | 101 if (!declaredVariables.add(use.name)) break; |
102 | 102 |
103 js.VariableInitialization jsVariable = new js.VariableInitialization( | 103 js.VariableInitialization jsVariable = new js.VariableInitialization( |
104 new js.VariableDeclaration(use.name), | 104 new js.VariableDeclaration(use.name), |
105 assign.value); | 105 assign.value); |
106 jsVariables.add(jsVariable); | 106 jsVariables.add(jsVariable); |
107 | 107 |
108 ++accumulatorIndex; | 108 ++accumulatorIndex; |
109 } | 109 } |
110 | 110 |
| 111 // If the last statement is a for loop with an initializer expression, try |
| 112 // to pull that expression into an initializer as well. |
| 113 pullFromForLoop: |
| 114 if (accumulatorIndex < accumulator.length && |
| 115 accumulator[accumulatorIndex] is js.For) { |
| 116 js.For forLoop = accumulator[accumulatorIndex]; |
| 117 if (forLoop.init is! js.Assignment) break pullFromForLoop; |
| 118 js.Assignment assign = forLoop.init; |
| 119 if (assign.leftHandSide is! js.VariableUse) break pullFromForLoop; |
| 120 if (assign.op != null) break pullFromForLoop; // Compound assignment. |
| 121 js.VariableUse use = assign.leftHandSide; |
| 122 |
| 123 // We cannot declare a variable more than once. |
| 124 if (!declaredVariables.add(use.name)) break pullFromForLoop; |
| 125 |
| 126 js.VariableInitialization jsVariable = new js.VariableInitialization( |
| 127 new js.VariableDeclaration(use.name), |
| 128 assign.value); |
| 129 jsVariables.add(jsVariable); |
| 130 |
| 131 // Remove the initializer from the for loop. |
| 132 accumulator[accumulatorIndex] = |
| 133 new js.For(null, forLoop.condition, forLoop.update, forLoop.body); |
| 134 } |
| 135 |
111 // Discard the statements that were pulled in the initializer. | 136 // Discard the statements that were pulled in the initializer. |
112 if (accumulatorIndex > 0) { | 137 if (accumulatorIndex > 0) { |
113 accumulator = accumulator.sublist(accumulatorIndex); | 138 accumulator = accumulator.sublist(accumulatorIndex); |
114 } | 139 } |
115 | 140 |
116 // Declare remaining variables. | 141 // Declare remaining variables. |
117 for (tree_ir.Variable variable in variableNames.keys) { | 142 for (tree_ir.Variable variable in variableNames.keys) { |
118 String name = getVariableName(variable); | 143 String name = getVariableName(variable); |
119 if (declaredVariables.contains(name)) continue; | 144 if (declaredVariables.contains(name)) continue; |
120 js.VariableInitialization jsVariable = new js.VariableInitialization( | 145 js.VariableInitialization jsVariable = new js.VariableInitialization( |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 | 534 |
510 js.Block buildBodyBlock(tree_ir.Statement statement) { | 535 js.Block buildBodyBlock(tree_ir.Statement statement) { |
511 List<js.Statement> savedAccumulator = accumulator; | 536 List<js.Statement> savedAccumulator = accumulator; |
512 accumulator = <js.Statement>[]; | 537 accumulator = <js.Statement>[]; |
513 visitStatement(statement); | 538 visitStatement(statement); |
514 js.Statement result = new js.Block(accumulator); | 539 js.Statement result = new js.Block(accumulator); |
515 accumulator = savedAccumulator; | 540 accumulator = savedAccumulator; |
516 return result; | 541 return result; |
517 } | 542 } |
518 | 543 |
| 544 js.Expression makeSequence(List<tree_ir.Expression> list) { |
| 545 return list.map(visitExpression).reduce((x,y) => new js.Binary(',', x, y)); |
| 546 } |
| 547 |
519 @override | 548 @override |
520 void visitWhileCondition(tree_ir.WhileCondition node) { | 549 void visitWhileCondition(tree_ir.WhileCondition node) { |
521 js.Expression condition = visitExpression(node.condition); | 550 js.Expression condition = visitExpression(node.condition); |
522 shortBreak.push(node.next); | 551 shortBreak.push(node.next); |
523 shortContinue.push(node); | 552 shortContinue.push(node); |
524 fallthrough.push(node); | 553 fallthrough.push(node); |
525 js.Statement jsBody = buildBodyStatement(node.body); | 554 js.Statement body = buildBodyStatement(node.body); |
526 fallthrough.pop(); | 555 fallthrough.pop(); |
527 shortContinue.pop(); | 556 shortContinue.pop(); |
528 shortBreak.pop(); | 557 shortBreak.pop(); |
529 accumulator.add(insertLabel(node.label, new js.While(condition, jsBody))); | 558 js.Statement loopNode; |
| 559 if (node.updates.isEmpty) { |
| 560 loopNode = new js.While(condition, body); |
| 561 } else { // Compile as a for loop. |
| 562 js.Expression init; |
| 563 if (accumulator.isNotEmpty && |
| 564 accumulator.last is js.ExpressionStatement) { |
| 565 // Take the preceding expression from the accumulator and use |
| 566 // it as the initializer expression. |
| 567 js.ExpressionStatement initStmt = accumulator.removeLast(); |
| 568 init = initStmt.expression; |
| 569 } |
| 570 js.Expression update = makeSequence(node.updates); |
| 571 loopNode = new js.For(init, condition, update, body); |
| 572 } |
| 573 accumulator.add(insertLabel(node.label, loopNode)); |
530 visitStatement(node.next); | 574 visitStatement(node.next); |
531 } | 575 } |
532 | 576 |
533 @override | 577 @override |
534 void visitWhileTrue(tree_ir.WhileTrue node) { | 578 void visitWhileTrue(tree_ir.WhileTrue node) { |
535 js.Expression condition = new js.LiteralBool(true); | 579 js.Expression condition = new js.LiteralBool(true); |
536 // A short break in the while will jump to the current fallthrough target. | 580 // A short break in the while will jump to the current fallthrough target. |
537 shortBreak.push(fallthrough.target); | 581 shortBreak.push(fallthrough.target); |
538 shortContinue.push(node); | 582 shortContinue.push(node); |
539 fallthrough.push(node); | 583 fallthrough.push(node); |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
852 js.Expression visitAwait(tree_ir.Await node) { | 896 js.Expression visitAwait(tree_ir.Await node) { |
853 return new js.Await(visitExpression(node.input)); | 897 return new js.Await(visitExpression(node.input)); |
854 } | 898 } |
855 | 899 |
856 visitFunctionExpression(tree_ir.FunctionExpression node) { | 900 visitFunctionExpression(tree_ir.FunctionExpression node) { |
857 // FunctionExpressions are currently unused. | 901 // FunctionExpressions are currently unused. |
858 // We might need them if we want to emit raw JS nested functions. | 902 // We might need them if we want to emit raw JS nested functions. |
859 throw 'FunctionExpressions should not be used'; | 903 throw 'FunctionExpressions should not be used'; |
860 } | 904 } |
861 } | 905 } |
OLD | NEW |