| 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 dart_tree; | 5 library dart_tree; |
| 6 | 6 |
| 7 import '../dart2jslib.dart' as dart2js; | 7 import '../dart2jslib.dart' as dart2js; |
| 8 import '../elements/elements.dart' | 8 import '../elements/elements.dart' |
| 9 show Element, FunctionElement, FunctionSignature, ParameterElement, | 9 show Element, FunctionElement, FunctionSignature, ParameterElement, |
| 10 ClassElement; | 10 ClassElement; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 /** | 31 /** |
| 32 * The base class of all Tree nodes. | 32 * The base class of all Tree nodes. |
| 33 */ | 33 */ |
| 34 abstract class Node { | 34 abstract class Node { |
| 35 } | 35 } |
| 36 | 36 |
| 37 /** | 37 /** |
| 38 * The base class of [Expression]s. | 38 * The base class of [Expression]s. |
| 39 */ | 39 */ |
| 40 abstract class Expression extends Node { | 40 abstract class Expression extends Node { |
| 41 accept(Visitor v); | 41 accept(ExpressionVisitor v); |
| 42 | 42 |
| 43 /// Temporary variable used by [StatementRewriter]. | 43 /// Temporary variable used by [StatementRewriter]. |
| 44 /// If set to true, this expression has already had enclosing assignments | 44 /// If set to true, this expression has already had enclosing assignments |
| 45 /// propagated into its variables, and should not be processed again. | 45 /// propagated into its variables, and should not be processed again. |
| 46 /// It is only set for expressions that are known to be in risk of redundant | 46 /// It is only set for expressions that are known to be in risk of redundant |
| 47 /// processing. | 47 /// processing. |
| 48 bool processed = false; | 48 bool processed = false; |
| 49 } | 49 } |
| 50 | 50 |
| 51 abstract class Statement extends Node { | 51 abstract class Statement extends Node { |
| 52 Statement get next; | 52 Statement get next; |
| 53 void set next(Statement s); | 53 void set next(Statement s); |
| 54 accept(Visitor v); | 54 accept(StatementVisitor v); |
| 55 } | 55 } |
| 56 | 56 |
| 57 /** | 57 /** |
| 58 * Labels name [LabeledStatement]s. | 58 * Labels name [LabeledStatement]s. |
| 59 */ | 59 */ |
| 60 class Label { | 60 class Label { |
| 61 // A counter used to generate names. The counter is reset to 0 for each | 61 // A counter used to generate names. The counter is reset to 0 for each |
| 62 // function emitted. | 62 // function emitted. |
| 63 static int counter = 0; | 63 static int counter = 0; |
| 64 static String _newName() => 'L${counter++}'; | 64 static String _newName() => 'L${counter++}'; |
| 65 | 65 |
| 66 String cachedName; | 66 String cachedName; |
| 67 | 67 |
| 68 String get name { | 68 String get name { |
| 69 if (cachedName == null) cachedName = _newName(); | 69 if (cachedName == null) cachedName = _newName(); |
| 70 return cachedName; | 70 return cachedName; |
| 71 } | 71 } |
| 72 | 72 |
| 73 /// Number of [Break] statements that target this label. | 73 /// Number of [Break] or [Continue] statements that target this label. |
| 74 /// The [Break] constructor will increment this automatically, but the | 74 /// The [Break] constructor will increment this automatically, but the |
| 75 /// counter must be decremented by hand when a [Break] becomes orphaned. | 75 /// counter must be decremented by hand when a [Break] becomes orphaned. |
| 76 int breakCount = 0; | 76 int useCount = 0; |
| 77 | 77 |
| 78 /// The [LabeledStatement] binding this label. | 78 /// The [LabeledStatement] or [WhileTrue] binding this label. |
| 79 LabeledStatement binding; | 79 JumpTarget binding; |
| 80 } | 80 } |
| 81 | 81 |
| 82 /** | 82 /** |
| 83 * Variables are [Expression]s. | 83 * Variables are [Expression]s. |
| 84 */ | 84 */ |
| 85 class Variable extends Expression { | 85 class Variable extends Expression { |
| 86 // A counter used to generate names. The counter is reset to 0 for each | 86 // A counter used to generate names. The counter is reset to 0 for each |
| 87 // function emitted. | 87 // function emitted. |
| 88 static int counter = 0; | 88 static int counter = 0; |
| 89 static String _newName() => 'v${counter++}'; | 89 static String _newName() => 'v${counter++}'; |
| 90 | 90 |
| 91 Element element; | 91 Element element; |
| 92 String cachedName; | 92 String cachedName; |
| 93 | 93 |
| 94 String get name { | 94 String get name { |
| 95 if (cachedName != null) return cachedName; | 95 if (cachedName != null) return cachedName; |
| 96 return cachedName = ((element == null) ? _newName() : element.name); | 96 return cachedName = ((element == null) ? _newName() : element.name); |
| 97 } | 97 } |
| 98 | 98 |
| 99 Variable(this.element); | 99 Variable(this.element); |
| 100 | 100 |
| 101 accept(Visitor visitor) => visitor.visitVariable(this); | 101 accept(ExpressionVisitor visitor) => visitor.visitVariable(this); |
| 102 } | 102 } |
| 103 | 103 |
| 104 /** | 104 /** |
| 105 * Common interface for invocations with arguments. | 105 * Common interface for invocations with arguments. |
| 106 */ | 106 */ |
| 107 abstract class Invoke { | 107 abstract class Invoke { |
| 108 List<Expression> get arguments; | 108 List<Expression> get arguments; |
| 109 Selector get selector; | 109 Selector get selector; |
| 110 } | 110 } |
| 111 | 111 |
| 112 /** | 112 /** |
| 113 * A call to a static target. | 113 * A call to a static target. |
| 114 * | 114 * |
| 115 * In contrast to the CPS-based IR, the arguments can be arbitrary expressions. | 115 * In contrast to the CPS-based IR, the arguments can be arbitrary expressions. |
| 116 */ | 116 */ |
| 117 class InvokeStatic extends Expression implements Invoke { | 117 class InvokeStatic extends Expression implements Invoke { |
| 118 final FunctionElement target; | 118 final FunctionElement target; |
| 119 final List<Expression> arguments; | 119 final List<Expression> arguments; |
| 120 final Selector selector; | 120 final Selector selector; |
| 121 | 121 |
| 122 InvokeStatic(this.target, this.selector, this.arguments); | 122 InvokeStatic(this.target, this.selector, this.arguments); |
| 123 | 123 |
| 124 accept(Visitor visitor) => visitor.visitInvokeStatic(this); | 124 accept(ExpressionVisitor visitor) => visitor.visitInvokeStatic(this); |
| 125 } | 125 } |
| 126 | 126 |
| 127 /** | 127 /** |
| 128 * A call to a method, operator, getter, setter or index getter/setter. | 128 * A call to a method, operator, getter, setter or index getter/setter. |
| 129 * | 129 * |
| 130 * In contrast to the CPS-based IR, the receiver and arguments can be | 130 * In contrast to the CPS-based IR, the receiver and arguments can be |
| 131 * arbitrary expressions. | 131 * arbitrary expressions. |
| 132 */ | 132 */ |
| 133 class InvokeMethod extends Expression implements Invoke { | 133 class InvokeMethod extends Expression implements Invoke { |
| 134 Expression receiver; | 134 Expression receiver; |
| 135 final Selector selector; | 135 final Selector selector; |
| 136 final List<Expression> arguments; | 136 final List<Expression> arguments; |
| 137 | 137 |
| 138 InvokeMethod(this.receiver, this.selector, this.arguments) { | 138 InvokeMethod(this.receiver, this.selector, this.arguments) { |
| 139 assert(receiver != null); | 139 assert(receiver != null); |
| 140 } | 140 } |
| 141 | 141 |
| 142 accept(Visitor visitor) => visitor.visitInvokeMethod(this); | 142 accept(ExpressionVisitor visitor) => visitor.visitInvokeMethod(this); |
| 143 } | 143 } |
| 144 | 144 |
| 145 /** | 145 /** |
| 146 * Non-const call to a factory or generative constructor. | 146 * Non-const call to a factory or generative constructor. |
| 147 */ | 147 */ |
| 148 class InvokeConstructor extends Expression implements Invoke { | 148 class InvokeConstructor extends Expression implements Invoke { |
| 149 final GenericType type; | 149 final GenericType type; |
| 150 final FunctionElement target; | 150 final FunctionElement target; |
| 151 final List<Expression> arguments; | 151 final List<Expression> arguments; |
| 152 final Selector selector; | 152 final Selector selector; |
| 153 | 153 |
| 154 InvokeConstructor(this.type, this.target, this.selector, this.arguments); | 154 InvokeConstructor(this.type, this.target, this.selector, this.arguments); |
| 155 | 155 |
| 156 ClassElement get targetClass => target.enclosingElement; | 156 ClassElement get targetClass => target.enclosingElement; |
| 157 | 157 |
| 158 accept(Visitor visitor) => visitor.visitInvokeConstructor(this); | 158 accept(ExpressionVisitor visitor) => visitor.visitInvokeConstructor(this); |
| 159 } | 159 } |
| 160 | 160 |
| 161 /// Calls [toString] on each argument and concatenates the results. | 161 /// Calls [toString] on each argument and concatenates the results. |
| 162 class ConcatenateStrings extends Expression { | 162 class ConcatenateStrings extends Expression { |
| 163 final List<Expression> arguments; | 163 final List<Expression> arguments; |
| 164 | 164 |
| 165 ConcatenateStrings(this.arguments); | 165 ConcatenateStrings(this.arguments); |
| 166 | 166 |
| 167 accept(Visitor visitor) => visitor.visitConcatenateStrings(this); | 167 accept(ExpressionVisitor visitor) => visitor.visitConcatenateStrings(this); |
| 168 } | 168 } |
| 169 | 169 |
| 170 /** | 170 /** |
| 171 * A constant. | 171 * A constant. |
| 172 */ | 172 */ |
| 173 class Constant extends Expression { | 173 class Constant extends Expression { |
| 174 dart2js.Constant value; | 174 dart2js.Constant value; |
| 175 | 175 |
| 176 Constant(this.value); | 176 Constant(this.value); |
| 177 | 177 |
| 178 accept(Visitor visitor) => visitor.visitConstant(this); | 178 accept(ExpressionVisitor visitor) => visitor.visitConstant(this); |
| 179 } | 179 } |
| 180 | 180 |
| 181 class LiteralList extends Expression { | 181 class LiteralList extends Expression { |
| 182 final List<Expression> values; | 182 final List<Expression> values; |
| 183 | 183 |
| 184 LiteralList(this.values) ; | 184 LiteralList(this.values) ; |
| 185 | 185 |
| 186 accept(Visitor visitor) => visitor.visitLiteralList(this); | 186 accept(ExpressionVisitor visitor) => visitor.visitLiteralList(this); |
| 187 } | 187 } |
| 188 | 188 |
| 189 class LiteralMap extends Expression { | 189 class LiteralMap extends Expression { |
| 190 final List<Expression> keys; | 190 final List<Expression> keys; |
| 191 final List<Expression> values; | 191 final List<Expression> values; |
| 192 | 192 |
| 193 LiteralMap(this.keys, this.values) ; | 193 LiteralMap(this.keys, this.values) ; |
| 194 | 194 |
| 195 accept(Visitor visitor) => visitor.visitLiteralMap(this); | 195 accept(ExpressionVisitor visitor) => visitor.visitLiteralMap(this); |
| 196 } | 196 } |
| 197 | 197 |
| 198 class InvokeConstConstructor extends Expression implements Invoke { | 198 class InvokeConstConstructor extends Expression implements Invoke { |
| 199 final GenericType type; | 199 final GenericType type; |
| 200 final FunctionElement target; | 200 final FunctionElement target; |
| 201 final List<Expression> arguments; | 201 final List<Expression> arguments; |
| 202 final Selector selector; | 202 final Selector selector; |
| 203 | 203 |
| 204 ClassElement get targetClass => target.enclosingElement; | 204 ClassElement get targetClass => target.enclosingElement; |
| 205 | 205 |
| 206 InvokeConstConstructor(this.type, this.target, this.selector, this.arguments); | 206 InvokeConstConstructor(this.type, this.target, this.selector, this.arguments); |
| 207 | 207 |
| 208 accept(Visitor visitor) => visitor.visitInvokeConstConstructor(this); | 208 accept(ExpressionVisitor visitor) => visitor.visitInvokeConstConstructor(this)
; |
| 209 } | 209 } |
| 210 | 210 |
| 211 /// A conditional expression. | 211 /// A conditional expression. |
| 212 class Conditional extends Expression { | 212 class Conditional extends Expression { |
| 213 Expression condition; | 213 Expression condition; |
| 214 Expression thenExpression; | 214 Expression thenExpression; |
| 215 Expression elseExpression; | 215 Expression elseExpression; |
| 216 | 216 |
| 217 Conditional(this.condition, this.thenExpression, this.elseExpression); | 217 Conditional(this.condition, this.thenExpression, this.elseExpression); |
| 218 | 218 |
| 219 accept(Visitor visitor) => visitor.visitConditional(this); | 219 accept(ExpressionVisitor visitor) => visitor.visitConditional(this); |
| 220 } | 220 } |
| 221 | 221 |
| 222 /// An && or || expression. The operator is internally represented as a boolean | 222 /// An && or || expression. The operator is internally represented as a boolean |
| 223 /// [isAnd] to simplify rewriting of logical operators. | 223 /// [isAnd] to simplify rewriting of logical operators. |
| 224 class LogicalOperator extends Expression { | 224 class LogicalOperator extends Expression { |
| 225 Expression left; | 225 Expression left; |
| 226 bool isAnd; | 226 bool isAnd; |
| 227 Expression right; | 227 Expression right; |
| 228 | 228 |
| 229 LogicalOperator(this.left, this.right, this.isAnd); | 229 LogicalOperator(this.left, this.right, this.isAnd); |
| 230 LogicalOperator.and(this.left, this.right) : isAnd = true; | 230 LogicalOperator.and(this.left, this.right) : isAnd = true; |
| 231 LogicalOperator.or(this.left, this.right) : isAnd = false; | 231 LogicalOperator.or(this.left, this.right) : isAnd = false; |
| 232 | 232 |
| 233 String get operator => isAnd ? '&&' : '||'; | 233 String get operator => isAnd ? '&&' : '||'; |
| 234 | 234 |
| 235 accept(Visitor visitor) => visitor.visitLogicalOperator(this); | 235 accept(ExpressionVisitor visitor) => visitor.visitLogicalOperator(this); |
| 236 } | 236 } |
| 237 | 237 |
| 238 /// Logical negation. | 238 /// Logical negation. |
| 239 class Not extends Expression { | 239 class Not extends Expression { |
| 240 Expression operand; | 240 Expression operand; |
| 241 | 241 |
| 242 Not(this.operand); | 242 Not(this.operand); |
| 243 | 243 |
| 244 accept(Visitor visitor) => visitor.visitNot(this); | 244 accept(ExpressionVisitor visitor) => visitor.visitNot(this); |
| 245 } |
| 246 |
| 247 /// A [LabeledStatement] or [WhileTrue] or [WhileCondition]. |
| 248 abstract class JumpTarget extends Statement { |
| 249 Label get label; |
| 250 Statement get body; |
| 245 } | 251 } |
| 246 | 252 |
| 247 /** | 253 /** |
| 248 * A labeled statement. Breaks to the label within the labeled statement | 254 * A labeled statement. Breaks to the label within the labeled statement |
| 249 * target the successor statement. | 255 * target the successor statement. |
| 250 */ | 256 */ |
| 251 class LabeledStatement extends Statement { | 257 class LabeledStatement extends JumpTarget { |
| 252 Statement next; | 258 Statement next; |
| 253 final Label label; | 259 final Label label; |
| 254 Statement body; | 260 Statement body; |
| 255 | 261 |
| 256 LabeledStatement(this.label, this.body, this.next) { | 262 LabeledStatement(this.label, this.body, this.next) { |
| 257 assert(label.binding == null); | 263 assert(label.binding == null); |
| 258 label.binding = this; | 264 label.binding = this; |
| 259 } | 265 } |
| 260 | 266 |
| 261 accept(Visitor visitor) => visitor.visitLabeledStatement(this); | 267 accept(StatementVisitor visitor) => visitor.visitLabeledStatement(this); |
| 268 } |
| 269 |
| 270 /// A [WhileTrue] or [WhileCondition] loop. |
| 271 abstract class Loop extends JumpTarget { |
| 272 /// When a [Continue] to a loop is executed, all update expressions are |
| 273 /// evaluated right-to-left before control resumes at the head of the loop. |
| 274 List<Expression> get updates; |
| 275 } |
| 276 |
| 277 /** |
| 278 * A labeled while(true) loop. |
| 279 */ |
| 280 class WhileTrue extends Loop { |
| 281 final Label label; |
| 282 Statement body; |
| 283 final List<Expression> updates = <Expression>[]; |
| 284 |
| 285 WhileTrue(this.label, this.body) { |
| 286 assert(label.binding == null); |
| 287 label.binding = this; |
| 288 } |
| 289 |
| 290 Statement get next => null; |
| 291 void set next(Statement s) => throw 'UNREACHABLE'; |
| 292 |
| 293 accept(StatementVisitor visitor) => visitor.visitWhileTrue(this); |
| 294 } |
| 295 |
| 296 /** |
| 297 * A while loop with a condition. If the condition is false, control resumes |
| 298 * at the [next] statement. |
| 299 * |
| 300 * It is NOT valid to target this statement with a [Break]. |
| 301 * The only way to reach [next] is for the condition to evaluate to false. |
| 302 * |
| 303 * [WhileCondition] statements are introduced in the [LoopRewriter] and is |
| 304 * assumed not to occur before then. |
| 305 */ |
| 306 class WhileCondition extends Loop { |
| 307 final Label label; |
| 308 Expression condition; |
| 309 Statement body; |
| 310 Statement next; |
| 311 final List<Expression> updates; |
| 312 |
| 313 WhileCondition(this.label, this.condition, this.body, |
| 314 this.next, this.updates) { |
| 315 assert(label.binding == null); |
| 316 label.binding = this; |
| 317 } |
| 318 |
| 319 accept(StatementVisitor visitor) => visitor.visitWhileCondition(this); |
| 320 } |
| 321 |
| 322 |
| 323 /// A [Break] or [Continue] statement. |
| 324 abstract class Jump extends Statement { |
| 325 Label get target; |
| 326 } |
| 327 |
| 328 /** |
| 329 * A break from an enclosing [LabeledStatement]. The break targets the |
| 330 * labeled statement's successor statement. |
| 331 */ |
| 332 class Break extends Jump { |
| 333 final Label target; |
| 334 |
| 335 Statement get next => null; |
| 336 void set next(Statement s) => throw 'UNREACHABLE'; |
| 337 |
| 338 Break(this.target) { |
| 339 ++target.useCount; |
| 340 } |
| 341 |
| 342 accept(StatementVisitor visitor) => visitor.visitBreak(this); |
| 343 } |
| 344 |
| 345 /** |
| 346 * A continue to an enclosing [WhileTrue] loop. The continue targets the |
| 347 * loop's body. |
| 348 */ |
| 349 class Continue extends Jump { |
| 350 final Label target; |
| 351 |
| 352 Statement get next => null; |
| 353 void set next(Statement s) => throw 'UNREACHABLE'; |
| 354 |
| 355 Continue(this.target) { |
| 356 ++target.useCount; |
| 357 } |
| 358 |
| 359 accept(StatementVisitor visitor) => visitor.visitContinue(this); |
| 262 } | 360 } |
| 263 | 361 |
| 264 /** | 362 /** |
| 265 * An assignments of an [Expression] to a [Variable]. | 363 * An assignments of an [Expression] to a [Variable]. |
| 266 * | 364 * |
| 267 * In contrast to the CPS-based IR, non-primitive expressions can be assigned | 365 * In contrast to the CPS-based IR, non-primitive expressions can be assigned |
| 268 * to variables. | 366 * to variables. |
| 269 */ | 367 */ |
| 270 class Assign extends Statement { | 368 class Assign extends Statement { |
| 271 Statement next; | 369 Statement next; |
| 272 final Variable variable; | 370 final Variable variable; |
| 273 Expression definition; | 371 Expression definition; |
| 274 final bool hasExactlyOneUse; | 372 final bool hasExactlyOneUse; |
| 275 | 373 |
| 276 Assign(this.variable, this.definition, this.next, this.hasExactlyOneUse); | 374 Assign(this.variable, this.definition, this.next, this.hasExactlyOneUse); |
| 277 | 375 |
| 278 accept(Visitor visitor) => visitor.visitAssign(this); | 376 accept(StatementVisitor visitor) => visitor.visitAssign(this); |
| 279 } | 377 } |
| 280 | 378 |
| 379 |
| 281 /** | 380 /** |
| 282 * A return exit from the function. | 381 * A return exit from the function. |
| 283 * | 382 * |
| 284 * In contrast to the CPS-based IR, the return value is an arbitrary | 383 * In contrast to the CPS-based IR, the return value is an arbitrary |
| 285 * expression. | 384 * expression. |
| 286 */ | 385 */ |
| 287 class Return extends Statement { | 386 class Return extends Statement { |
| 288 /// Should not be null. Use [Constant] with [NullConstant] for void returns. | 387 /// Should not be null. Use [Constant] with [NullConstant] for void returns. |
| 289 Expression value; | 388 Expression value; |
| 290 | 389 |
| 291 Statement get next => null; | 390 Statement get next => null; |
| 292 void set next(Statement s) => throw 'UNREACHABLE'; | 391 void set next(Statement s) => throw 'UNREACHABLE'; |
| 293 | 392 |
| 294 Return(this.value); | 393 Return(this.value); |
| 295 | 394 |
| 296 accept(Visitor visitor) => visitor.visitReturn(this); | 395 accept(StatementVisitor visitor) => visitor.visitReturn(this); |
| 297 } | 396 } |
| 298 | 397 |
| 299 /** | |
| 300 * A break from an enclosing [LabeledStatement]. The break targets the | |
| 301 * labeled statement's successor statement. | |
| 302 */ | |
| 303 class Break extends Statement { | |
| 304 Label _target; | |
| 305 | 398 |
| 306 Label get target => _target; | |
| 307 void set target(Label newTarget) { | |
| 308 ++newTarget.breakCount; | |
| 309 --_target.breakCount; | |
| 310 _target = newTarget; | |
| 311 } | |
| 312 | 399 |
| 313 Statement get next => null; | |
| 314 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 315 | |
| 316 Break(this._target) { | |
| 317 ++target.breakCount; | |
| 318 } | |
| 319 | |
| 320 accept(Visitor visitor) => visitor.visitBreak(this); | |
| 321 } | |
| 322 | |
| 323 /** | |
| 324 * A continue to an enclosing [While] loop. The continue targets the | |
| 325 * loop's body. | |
| 326 */ | |
| 327 class Continue extends Statement { | |
| 328 Label target; | |
| 329 | |
| 330 Statement get next => null; | |
| 331 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 332 | |
| 333 Continue(this.target); | |
| 334 | |
| 335 accept(Visitor visitor) => visitor.visitContinue(this); | |
| 336 } | |
| 337 | 400 |
| 338 /** | 401 /** |
| 339 * A conditional branch based on the true value of an [Expression]. | 402 * A conditional branch based on the true value of an [Expression]. |
| 340 */ | 403 */ |
| 341 class If extends Statement { | 404 class If extends Statement { |
| 342 Expression condition; | 405 Expression condition; |
| 343 Statement thenStatement; | 406 Statement thenStatement; |
| 344 Statement elseStatement; | 407 Statement elseStatement; |
| 345 | 408 |
| 346 Statement get next => null; | 409 Statement get next => null; |
| 347 void set next(Statement s) => throw 'UNREACHABLE'; | 410 void set next(Statement s) => throw 'UNREACHABLE'; |
| 348 | 411 |
| 349 If(this.condition, this.thenStatement, this.elseStatement); | 412 If(this.condition, this.thenStatement, this.elseStatement); |
| 350 | 413 |
| 351 accept(Visitor visitor) => visitor.visitIf(this); | 414 accept(StatementVisitor visitor) => visitor.visitIf(this); |
| 352 } | |
| 353 | |
| 354 /** | |
| 355 * A labeled while(true) loop. | |
| 356 */ | |
| 357 class While extends Statement { | |
| 358 final Label label; | |
| 359 Statement body; | |
| 360 | |
| 361 While(this.label, this.body); | |
| 362 | |
| 363 Statement get next => null; | |
| 364 void set next(Statement s) => throw 'UNREACHABLE'; | |
| 365 | |
| 366 accept(Visitor visitor) => visitor.visitWhile(this); | |
| 367 } | 415 } |
| 368 | 416 |
| 369 | 417 |
| 370 class ExpressionStatement extends Statement { | 418 class ExpressionStatement extends Statement { |
| 371 Statement next; | 419 Statement next; |
| 372 Expression expression; | 420 Expression expression; |
| 373 | 421 |
| 374 ExpressionStatement(this.expression, this.next); | 422 ExpressionStatement(this.expression, this.next); |
| 375 | 423 |
| 376 accept(Visitor visitor) => visitor.visitExpressionStatement(this); | 424 accept(StatementVisitor visitor) => visitor.visitExpressionStatement(this); |
| 377 } | 425 } |
| 378 | 426 |
| 379 class FunctionDefinition extends Node { | 427 class FunctionDefinition extends Node { |
| 380 final List<Variable> parameters; | 428 final List<Variable> parameters; |
| 381 Statement body; | 429 Statement body; |
| 382 | 430 |
| 383 FunctionDefinition(this.parameters, this.body); | 431 FunctionDefinition(this.parameters, this.body); |
| 384 } | 432 } |
| 385 | 433 |
| 386 abstract class Visitor<S, E> { | 434 abstract class ExpressionVisitor<E> { |
| 387 E visitExpression(Expression e) => e.accept(this); | 435 E visitExpression(Expression e) => e.accept(this); |
| 388 E visitVariable(Variable node); | 436 E visitVariable(Variable node); |
| 389 E visitInvokeStatic(InvokeStatic node); | 437 E visitInvokeStatic(InvokeStatic node); |
| 390 E visitInvokeMethod(InvokeMethod node); | 438 E visitInvokeMethod(InvokeMethod node); |
| 391 E visitInvokeConstructor(InvokeConstructor node); | 439 E visitInvokeConstructor(InvokeConstructor node); |
| 392 E visitConcatenateStrings(ConcatenateStrings node); | 440 E visitConcatenateStrings(ConcatenateStrings node); |
| 393 E visitConstant(Constant node); | 441 E visitConstant(Constant node); |
| 394 E visitConditional(Conditional node); | 442 E visitConditional(Conditional node); |
| 395 E visitLogicalOperator(LogicalOperator node); | 443 E visitLogicalOperator(LogicalOperator node); |
| 396 E visitNot(Not node); | 444 E visitNot(Not node); |
| 397 E visitLiteralList(LiteralList node); | 445 E visitLiteralList(LiteralList node); |
| 398 E visitLiteralMap(LiteralMap node); | 446 E visitLiteralMap(LiteralMap node); |
| 399 E visitInvokeConstConstructor(InvokeConstConstructor node); | 447 E visitInvokeConstConstructor(InvokeConstConstructor node); |
| 448 } |
| 400 | 449 |
| 450 abstract class StatementVisitor<S> { |
| 401 S visitStatement(Statement s) => s.accept(this); | 451 S visitStatement(Statement s) => s.accept(this); |
| 402 S visitLabeledStatement(LabeledStatement node); | 452 S visitLabeledStatement(LabeledStatement node); |
| 403 S visitAssign(Assign node); | 453 S visitAssign(Assign node); |
| 404 S visitReturn(Return node); | 454 S visitReturn(Return node); |
| 405 S visitBreak(Break node); | 455 S visitBreak(Break node); |
| 406 S visitContinue(Continue node); | 456 S visitContinue(Continue node); |
| 407 S visitIf(If node); | 457 S visitIf(If node); |
| 408 S visitWhile(While node); | 458 S visitWhileTrue(WhileTrue node); |
| 459 S visitWhileCondition(WhileCondition node); |
| 409 S visitExpressionStatement(ExpressionStatement node); | 460 S visitExpressionStatement(ExpressionStatement node); |
| 410 } | 461 } |
| 411 | 462 |
| 463 abstract class Visitor<S,E> implements ExpressionVisitor<E>, |
| 464 StatementVisitor<S> { |
| 465 E visitExpression(Expression e) => e.accept(this); |
| 466 S visitStatement(Statement s) => s.accept(this); |
| 467 } |
| 468 |
| 412 /** | 469 /** |
| 413 * Builder translates from CPS-based IR to direct-style Tree. | 470 * Builder translates from CPS-based IR to direct-style Tree. |
| 414 * | 471 * |
| 415 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced | 472 * A call `Invoke(fun, cont, args)`, where cont is a singly-referenced |
| 416 * non-exit continuation `Cont(v, body)` is translated into a direct-style call | 473 * non-exit continuation `Cont(v, body)` is translated into a direct-style call |
| 417 * whose value is bound in the continuation body: | 474 * whose value is bound in the continuation body: |
| 418 * | 475 * |
| 419 * `LetVal(v, Invoke(fun, args), body)` | 476 * `LetVal(v, Invoke(fun, args), body)` |
| 420 * | 477 * |
| 421 * and the continuation definition is eliminated. A similar translation is | 478 * and the continuation definition is eliminated. A similar translation is |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 // inline at the invocation site. | 686 // inline at the invocation site. |
| 630 // - If there are multiple uses, translate to Break. | 687 // - If there are multiple uses, translate to Break. |
| 631 // * Recursive continuations | 688 // * Recursive continuations |
| 632 // - There is a single non-recursive invocation. Translate | 689 // - There is a single non-recursive invocation. Translate |
| 633 // the continuation body inline as a labeled loop at the | 690 // the continuation body inline as a labeled loop at the |
| 634 // invocation site. | 691 // invocation site. |
| 635 // - Translate the recursive invocations to Continue. | 692 // - Translate the recursive invocations to Continue. |
| 636 if (cont.isRecursive) { | 693 if (cont.isRecursive) { |
| 637 return node.isRecursive | 694 return node.isRecursive |
| 638 ? new Continue(labels[cont]) | 695 ? new Continue(labels[cont]) |
| 639 : new While(labels[cont], visit(cont.body)); | 696 : new WhileTrue(labels[cont], visit(cont.body)); |
| 640 } else { | 697 } else { |
| 641 return cont.hasExactlyOneUse | 698 return cont.hasExactlyOneUse |
| 642 ? visit(cont.body) | 699 ? visit(cont.body) |
| 643 : new Break(labels[cont]); | 700 : new Break(labels[cont]); |
| 644 } | 701 } |
| 645 }); | 702 }); |
| 646 } | 703 } |
| 647 } | 704 } |
| 648 | 705 |
| 649 Statement visitBranch(ir.Branch node) { | 706 Statement visitBranch(ir.Branch node) { |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 * v0 = foo(); return v0; | 826 * v0 = foo(); return v0; |
| 770 * | 827 * |
| 771 * This can lead to propagation of v0. | 828 * This can lead to propagation of v0. |
| 772 * | 829 * |
| 773 * See [visitBreak] and [visitLabeledStatement]. | 830 * See [visitBreak] and [visitLabeledStatement]. |
| 774 * | 831 * |
| 775 * | 832 * |
| 776 * REDIRECT BREAKS: | 833 * REDIRECT BREAKS: |
| 777 * Labeled statements whose next is a break become flattened and all breaks | 834 * Labeled statements whose next is a break become flattened and all breaks |
| 778 * to their label are redirected. | 835 * to their label are redirected. |
| 779 * For example: | 836 * For example, where 'jump' is either break or continue: |
| 780 * | 837 * |
| 781 * L0: {... break L0 ...}; break L1 | 838 * L0: {... break L0 ...}; jump L1 |
| 782 * ==> | 839 * ==> |
| 783 * {... break L1 ...} | 840 * {... jump L1 ...} |
| 784 * | 841 * |
| 785 * This may trigger a flattening of nested ifs in case the eliminated label | 842 * This may trigger a flattening of nested ifs in case the eliminated label |
| 786 * separated two ifs. | 843 * separated two ifs. |
| 787 */ | 844 */ |
| 788 class StatementRewriter extends Visitor<Statement, Expression> { | 845 class StatementRewriter extends Visitor<Statement, Expression> { |
| 789 // The binding environment. The rightmost element of the list is the nearest | 846 // The binding environment. The rightmost element of the list is the nearest |
| 790 // available enclosing binding. | 847 // available enclosing binding. |
| 791 List<Assign> environment; | 848 List<Assign> environment; |
| 792 | 849 |
| 793 /// Substitution map for labels. Any break to a label L should be substituted | 850 /// Substitution map for labels. Any break to a label L should be substituted |
| 794 /// for a break to L' if L maps to L'. | 851 /// for a break to L' if L maps to L'. |
| 795 Map<Label, Label> labelRedirects = <Label, Label>{}; | 852 Map<Label, Jump> labelRedirects = <Label, Jump>{}; |
| 796 | 853 |
| 797 /// Returns the redirect target of [label] or [label] itself if it should not | 854 /// Returns the redirect target of [label] or [label] itself if it should not |
| 798 /// be redirected. | 855 /// be redirected. |
| 799 Label redirect(Label label) { | 856 Jump redirect(Break jump) { |
| 800 Label newTarget = labelRedirects[label]; | 857 Jump newJump = labelRedirects[jump.target]; |
| 801 return newTarget != null ? newTarget : label; | 858 return newJump != null ? newJump : jump; |
| 802 } | 859 } |
| 803 | 860 |
| 804 void rewrite(FunctionDefinition definition) { | 861 void rewrite(FunctionDefinition definition) { |
| 805 environment = <Assign>[]; | 862 environment = <Assign>[]; |
| 806 definition.body = visitStatement(definition.body); | 863 definition.body = visitStatement(definition.body); |
| 807 | 864 |
| 808 // TODO(kmillikin): Allow definitions that are not propagated. Here, | 865 // TODO(kmillikin): Allow definitions that are not propagated. Here, |
| 809 // this means rebuilding the binding with a recursively unnamed definition, | 866 // this means rebuilding the binding with a recursively unnamed definition, |
| 810 // or else introducing a variable definition and an assignment. | 867 // or else introducing a variable definition and an assignment. |
| 811 assert(environment.isEmpty); | 868 assert(environment.isEmpty); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 911 } | 968 } |
| 912 | 969 |
| 913 Statement visitReturn(Return node) { | 970 Statement visitReturn(Return node) { |
| 914 node.value = visitExpression(node.value); | 971 node.value = visitExpression(node.value); |
| 915 return node; | 972 return node; |
| 916 } | 973 } |
| 917 | 974 |
| 918 | 975 |
| 919 Statement visitBreak(Break node) { | 976 Statement visitBreak(Break node) { |
| 920 // Redirect through chain of breaks. | 977 // Redirect through chain of breaks. |
| 921 // Note that breakCount was accounted for at visitLabeledStatement. | 978 // Note that useCount was accounted for at visitLabeledStatement. |
| 922 node.target = redirect(node.target); | 979 // Note redirect may return either a Break or Continue statement. |
| 923 if (node.target.breakCount == 1) { | 980 node = redirect(node); |
| 924 --node.target.breakCount; | 981 if (node is Break && node.target.useCount == 1) { |
| 982 --node.target.useCount; |
| 925 return visitStatement(node.target.binding.next); | 983 return visitStatement(node.target.binding.next); |
| 926 } | 984 } |
| 927 return node; | 985 return node; |
| 928 } | 986 } |
| 929 | 987 |
| 930 Statement visitContinue(Continue node) { | 988 Statement visitContinue(Continue node) { |
| 931 return node; | 989 return node; |
| 932 } | 990 } |
| 933 | 991 |
| 934 Statement visitLabeledStatement(LabeledStatement node) { | 992 Statement visitLabeledStatement(LabeledStatement node) { |
| 935 if (node.next is Break) { | 993 if (node.next is Jump) { |
| 936 // Eliminate label if next is just a break statement | 994 // Eliminate label if next is a break or continue statement |
| 937 // Breaks to this label are redirected to the outer label. | 995 // Breaks to this label are redirected to the outer label. |
| 938 // Note that breakCount for the two labels is updated proactively here | 996 // Note that breakCount for the two labels is updated proactively here |
| 939 // so breaks can reliably tell if they should inline their target. | 997 // so breaks can reliably tell if they should inline their target. |
| 940 Break next = node.next; | 998 Jump next = node.next; |
| 941 Label newTarget = redirect(next.target); | 999 Jump newJump = redirect(next); |
| 942 labelRedirects[node.label] = newTarget; | 1000 labelRedirects[node.label] = newJump; |
| 943 newTarget.breakCount += node.label.breakCount; | 1001 newJump.target.useCount += node.label.useCount - 1; |
| 944 node.label.breakCount = 0; | 1002 node.label.useCount = 0; |
| 945 Statement result = visitStatement(node.body); | 1003 Statement result = visitStatement(node.body); |
| 946 labelRedirects.remove(node.label); // Save some space. | 1004 labelRedirects.remove(node.label); // Save some space. |
| 947 return result; | 1005 return result; |
| 948 } | 1006 } |
| 949 | 1007 |
| 950 node.body = visitStatement(node.body); | 1008 node.body = visitStatement(node.body); |
| 951 | 1009 |
| 952 if (node.label.breakCount == 0) { | 1010 if (node.label.useCount == 0) { |
| 953 // Eliminate the label if next was inlined at a break | 1011 // Eliminate the label if next was inlined at a break |
| 954 return node.body; | 1012 return node.body; |
| 955 } | 1013 } |
| 956 | 1014 |
| 957 node.next = visitStatement(node.next); | 1015 node.next = visitStatement(node.next); |
| 958 return node; | 1016 return node; |
| 959 } | 1017 } |
| 960 | 1018 |
| 961 Statement visitIf(If node) { | 1019 Statement visitIf(If node) { |
| 962 node.condition = visitExpression(node.condition); | 1020 node.condition = visitExpression(node.condition); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 984 if (reduced.next is Break) { | 1042 if (reduced.next is Break) { |
| 985 // In case the break can now be inlined. | 1043 // In case the break can now be inlined. |
| 986 reduced = visitStatement(reduced); | 1044 reduced = visitStatement(reduced); |
| 987 } | 1045 } |
| 988 return reduced; | 1046 return reduced; |
| 989 } | 1047 } |
| 990 | 1048 |
| 991 return node; | 1049 return node; |
| 992 } | 1050 } |
| 993 | 1051 |
| 994 Statement visitWhile(While node) { | 1052 Statement visitWhileTrue(WhileTrue node) { |
| 995 // Do not propagate assignments into loops. Doing so is not safe for | 1053 // Do not propagate assignments into loops. Doing so is not safe for |
| 996 // variables modified in the loop (the initial value will be propagated). | 1054 // variables modified in the loop (the initial value will be propagated). |
| 997 List<Assign> savedEnvironment = environment; | 1055 List<Assign> savedEnvironment = environment; |
| 998 environment = <Assign>[]; | 1056 environment = <Assign>[]; |
| 999 node.body = visitStatement(node.body); | 1057 node.body = visitStatement(node.body); |
| 1000 assert(environment.isEmpty); | 1058 assert(environment.isEmpty); |
| 1001 environment = savedEnvironment; | 1059 environment = savedEnvironment; |
| 1002 return node; | 1060 return node; |
| 1003 } | 1061 } |
| 1004 | 1062 |
| 1063 Statement visitWhileCondition(WhileCondition node) { |
| 1064 // Not introduced yet |
| 1065 throw "Unexpected WhileCondition in StatementRewriter"; |
| 1066 } |
| 1067 |
| 1005 Expression visitConstant(Constant node) { | 1068 Expression visitConstant(Constant node) { |
| 1006 return node; | 1069 return node; |
| 1007 } | 1070 } |
| 1008 | 1071 |
| 1009 Expression visitLiteralList(LiteralList node) { | 1072 Expression visitLiteralList(LiteralList node) { |
| 1010 // Process values right-to-left, the opposite of evaluation order. | 1073 // Process values right-to-left, the opposite of evaluation order. |
| 1011 for (int i = node.values.length - 1; i >= 0; --i) { | 1074 for (int i = node.values.length - 1; i >= 0; --i) { |
| 1012 node.values[i] = visitExpression(node.values[i]); | 1075 node.values[i] = visitExpression(node.values[i]); |
| 1013 } | 1076 } |
| 1014 return node; | 1077 return node; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1081 return null; | 1144 return null; |
| 1082 } | 1145 } |
| 1083 | 1146 |
| 1084 /// Returns a statement equivalent to both [s] and [t], or null if [s] and | 1147 /// Returns a statement equivalent to both [s] and [t], or null if [s] and |
| 1085 /// [t] are incompatible. | 1148 /// [t] are incompatible. |
| 1086 /// If non-null is returned, the caller MUST discard [s] and [t] and use | 1149 /// If non-null is returned, the caller MUST discard [s] and [t] and use |
| 1087 /// the returned statement instead. | 1150 /// the returned statement instead. |
| 1088 /// If two breaks are combined, the label's break counter will be decremented. | 1151 /// If two breaks are combined, the label's break counter will be decremented. |
| 1089 static Statement combineStatements(Statement s, Statement t) { | 1152 static Statement combineStatements(Statement s, Statement t) { |
| 1090 if (s is Break && t is Break && s.target == t.target) { | 1153 if (s is Break && t is Break && s.target == t.target) { |
| 1091 --t.target.breakCount; // Two breaks become one. | 1154 --t.target.useCount; // Two breaks become one. |
| 1155 return s; |
| 1156 } |
| 1157 if (s is Continue && t is Continue && s.target == t.target) { |
| 1158 --t.target.useCount; // Two continues become one. |
| 1092 return s; | 1159 return s; |
| 1093 } | 1160 } |
| 1094 if (s is Return && t is Return && equivalentExpressions(s.value, t.value)) { | 1161 if (s is Return && t is Return && equivalentExpressions(s.value, t.value)) { |
| 1095 return s; | 1162 return s; |
| 1096 } | 1163 } |
| 1097 return null; | 1164 return null; |
| 1098 } | 1165 } |
| 1099 | 1166 |
| 1100 /// True if the two expressions both syntactically and semantically | 1167 /// True if the two expressions both syntactically and semantically |
| 1101 /// equivalent. | 1168 /// equivalent. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1168 If innerIf = outerThen; | 1235 If innerIf = outerThen; |
| 1169 Statement innerThen = getBranch(innerIf, branch2); | 1236 Statement innerThen = getBranch(innerIf, branch2); |
| 1170 Statement innerElse = getBranch(innerIf, !branch2); | 1237 Statement innerElse = getBranch(innerIf, !branch2); |
| 1171 if (innerElse is Break && innerElse.target == outerElse.target) { | 1238 if (innerElse is Break && innerElse.target == outerElse.target) { |
| 1172 // We always put S in the then branch of the result, and adjust the | 1239 // We always put S in the then branch of the result, and adjust the |
| 1173 // condition expression if S was actually found in the else branch(es). | 1240 // condition expression if S was actually found in the else branch(es). |
| 1174 outerIf.condition = new LogicalOperator.and( | 1241 outerIf.condition = new LogicalOperator.and( |
| 1175 makeCondition(outerIf.condition, branch1), | 1242 makeCondition(outerIf.condition, branch1), |
| 1176 makeCondition(innerIf.condition, branch2)); | 1243 makeCondition(innerIf.condition, branch2)); |
| 1177 outerIf.thenStatement = innerThen; | 1244 outerIf.thenStatement = innerThen; |
| 1178 --innerElse.target.breakCount; | 1245 --innerElse.target.useCount; |
| 1179 | 1246 |
| 1180 // Try to inline the remaining break. Do not propagate assignments. | 1247 // Try to inline the remaining break. Do not propagate assignments. |
| 1181 List<Assign> savedEnvironment = environment; | 1248 List<Assign> savedEnvironment = environment; |
| 1182 environment = <Assign>[]; | 1249 environment = <Assign>[]; |
| 1183 outerIf.elseStatement = visitStatement(outerElse); | 1250 outerIf.elseStatement = visitStatement(outerElse); |
| 1184 assert(environment.isEmpty); | 1251 assert(environment.isEmpty); |
| 1185 environment = savedEnvironment; | 1252 environment = savedEnvironment; |
| 1186 | 1253 |
| 1187 return outerIf.elseStatement is If && innerThen is Break; | 1254 return outerIf.elseStatement is If && innerThen is Break; |
| 1188 } | 1255 } |
| 1189 } | 1256 } |
| 1190 return false; | 1257 return false; |
| 1191 } | 1258 } |
| 1192 | 1259 |
| 1193 Expression makeCondition(Expression e, bool polarity) { | 1260 Expression makeCondition(Expression e, bool polarity) { |
| 1194 return polarity ? e : new Not(e); | 1261 return polarity ? e : new Not(e); |
| 1195 } | 1262 } |
| 1196 | 1263 |
| 1197 Statement getBranch(If node, bool polarity) { | 1264 Statement getBranch(If node, bool polarity) { |
| 1198 return polarity ? node.thenStatement : node.elseStatement; | 1265 return polarity ? node.thenStatement : node.elseStatement; |
| 1199 } | 1266 } |
| 1200 } | 1267 } |
| 1201 | 1268 |
| 1269 /// Rewrites [WhileTrue] statements with an [If] body into a [WhileCondition], |
| 1270 /// in situations where only one of the branches contains a [Continue] to the |
| 1271 /// loop. Schematically: |
| 1272 /// |
| 1273 /// L: |
| 1274 /// while (true) { |
| 1275 /// if (E) { |
| 1276 /// S1 (has references to L) |
| 1277 /// } else { |
| 1278 /// S2 (has no references to L) |
| 1279 /// } |
| 1280 /// } |
| 1281 /// ==> |
| 1282 /// L: |
| 1283 /// while (E) { |
| 1284 /// S1 |
| 1285 /// }; |
| 1286 /// S2 |
| 1287 /// |
| 1288 /// A similar transformation is used when S2 occurs in the 'then' position. |
| 1289 /// |
| 1290 /// Note that the above pattern needs no iteration since nested ifs |
| 1291 /// have been collapsed previously in the [StatementRewriter] phase. |
| 1292 class LoopRewriter extends StatementVisitor<Statement> { |
| 1293 |
| 1294 Set<Label> usedContinueLabels = new Set<Label>(); |
| 1295 |
| 1296 void rewrite(FunctionDefinition function) { |
| 1297 function.body = visitStatement(function.body); |
| 1298 } |
| 1299 |
| 1300 Statement visitLabeledStatement(LabeledStatement node) { |
| 1301 node.body = visitStatement(node.body); |
| 1302 node.next = visitStatement(node.next); |
| 1303 return node; |
| 1304 } |
| 1305 |
| 1306 Statement visitAssign(Assign node) { |
| 1307 node.next = visitStatement(node.next); |
| 1308 return node; |
| 1309 } |
| 1310 |
| 1311 Statement visitReturn(Return node) { |
| 1312 return node; |
| 1313 } |
| 1314 |
| 1315 Statement visitBreak(Break node) { |
| 1316 return node; |
| 1317 } |
| 1318 |
| 1319 Statement visitContinue(Continue node) { |
| 1320 usedContinueLabels.add(node.target); |
| 1321 return node; |
| 1322 } |
| 1323 |
| 1324 Statement visitIf(If node) { |
| 1325 node.thenStatement = visitStatement(node.thenStatement); |
| 1326 node.elseStatement = visitStatement(node.elseStatement); |
| 1327 return node; |
| 1328 } |
| 1329 |
| 1330 Statement visitWhileTrue(WhileTrue node) { |
| 1331 assert(!usedContinueLabels.contains(node.label)); |
| 1332 if (node.body is If) { |
| 1333 If body = node.body; |
| 1334 body.thenStatement = visitStatement(body.thenStatement); |
| 1335 bool thenHasContinue = usedContinueLabels.remove(node.label); |
| 1336 body.elseStatement = visitStatement(body.elseStatement); |
| 1337 bool elseHasContinue = usedContinueLabels.remove(node.label); |
| 1338 if (thenHasContinue && !elseHasContinue) { |
| 1339 node.label.binding = null; // Prepare to rebind the label. |
| 1340 return new WhileCondition( |
| 1341 node.label, |
| 1342 body.condition, |
| 1343 body.thenStatement, |
| 1344 body.elseStatement, |
| 1345 node.updates); |
| 1346 } else if (!thenHasContinue && elseHasContinue) { |
| 1347 node.label.binding = null; |
| 1348 return new WhileCondition( |
| 1349 node.label, |
| 1350 new Not(body.condition), |
| 1351 body.elseStatement, |
| 1352 body.thenStatement, |
| 1353 node.updates); |
| 1354 } |
| 1355 } else { |
| 1356 node.body = visitStatement(node.body); |
| 1357 usedContinueLabels.remove(node.label); |
| 1358 } |
| 1359 return node; |
| 1360 } |
| 1361 |
| 1362 Statement visitWhileCondition(WhileCondition node) { |
| 1363 // Note: not reachable but the implementation is trivial |
| 1364 node.body = visitStatement(node.body); |
| 1365 node.next = visitStatement(node.next); |
| 1366 return node; |
| 1367 } |
| 1368 |
| 1369 Statement visitExpressionStatement(ExpressionStatement node) { |
| 1370 node.next = visitStatement(node.next); |
| 1371 // for (;;) { ... E; continue* L ... } |
| 1372 // ==> |
| 1373 // for(;;E) { ... continue* L ... } |
| 1374 if (node.next is Continue) { |
| 1375 Continue jump = node.next; |
| 1376 if (jump.target.useCount == 1) { |
| 1377 Loop target = jump.target.binding; |
| 1378 target.updates.add(node.expression); |
| 1379 return jump; // Return the continue statement. |
| 1380 // NOTE: The pattern may reclick in an enclosing expression statement. |
| 1381 } |
| 1382 } |
| 1383 return node; |
| 1384 } |
| 1385 |
| 1386 } |
| 1202 | 1387 |
| 1203 | 1388 |
| 1204 /// Rewrites logical expressions to be more compact. | 1389 /// Rewrites logical expressions to be more compact. |
| 1205 /// | 1390 /// |
| 1206 /// In this class an expression is said to occur in "boolean context" if | 1391 /// In this class an expression is said to occur in "boolean context" if |
| 1207 /// its result is immediately applied to boolean conversion. | 1392 /// its result is immediately applied to boolean conversion. |
| 1208 /// | 1393 /// |
| 1209 /// IF STATEMENTS: | 1394 /// IF STATEMENTS: |
| 1210 /// | 1395 /// |
| 1211 /// We apply the following two rules to [If] statements (see [visitIf]). | 1396 /// We apply the following two rules to [If] statements (see [visitIf]). |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1327 if (!emptyElse && node.condition is Not) { | 1512 if (!emptyElse && node.condition is Not) { |
| 1328 node.condition = (node.condition as Not).operand; | 1513 node.condition = (node.condition as Not).operand; |
| 1329 Statement tmp = node.thenStatement; | 1514 Statement tmp = node.thenStatement; |
| 1330 node.thenStatement = node.elseStatement; | 1515 node.thenStatement = node.elseStatement; |
| 1331 node.elseStatement = tmp; | 1516 node.elseStatement = tmp; |
| 1332 } | 1517 } |
| 1333 | 1518 |
| 1334 return node; | 1519 return node; |
| 1335 } | 1520 } |
| 1336 | 1521 |
| 1337 Statement visitWhile(While node) { | 1522 Statement visitWhileTrue(WhileTrue node) { |
| 1338 node.body = visitStatement(node.body); | 1523 node.body = visitStatement(node.body); |
| 1339 return node; | 1524 return node; |
| 1340 } | 1525 } |
| 1341 | 1526 |
| 1527 Statement visitWhileCondition(WhileCondition node) { |
| 1528 node.condition = makeCondition(node.condition, true, liftNots: false); |
| 1529 node.body = visitStatement(node.body); |
| 1530 node.next = visitStatement(node.next); |
| 1531 return node; |
| 1532 } |
| 1533 |
| 1342 Statement visitExpressionStatement(ExpressionStatement node) { | 1534 Statement visitExpressionStatement(ExpressionStatement node) { |
| 1343 // TODO(asgerf): in non-checked mode we can remove Not from the expression. | 1535 // TODO(asgerf): in non-checked mode we can remove Not from the expression. |
| 1344 node.expression = visitExpression(node.expression); | 1536 node.expression = visitExpression(node.expression); |
| 1345 node.next = visitStatement(node.next); | 1537 node.next = visitStatement(node.next); |
| 1346 return node; | 1538 return node; |
| 1347 } | 1539 } |
| 1348 | 1540 |
| 1349 | 1541 |
| 1350 Expression visitVariable(Variable node) { | 1542 Expression visitVariable(Variable node) { |
| 1351 return node; | 1543 return node; |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1602 } | 1794 } |
| 1603 } | 1795 } |
| 1604 | 1796 |
| 1605 /// Destructively updates each entry of [l] with the result of visiting it. | 1797 /// Destructively updates each entry of [l] with the result of visiting it. |
| 1606 void _rewriteList(List<Expression> l) { | 1798 void _rewriteList(List<Expression> l) { |
| 1607 for (int i = 0; i < l.length; i++) { | 1799 for (int i = 0; i < l.length; i++) { |
| 1608 l[i] = visitExpression(l[i]); | 1800 l[i] = visitExpression(l[i]); |
| 1609 } | 1801 } |
| 1610 } | 1802 } |
| 1611 } | 1803 } |
| OLD | NEW |