| 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 backend_ast_nodes; | 5 library backend_ast_nodes; |
| 6 | 6 |
| 7 import '../constants/values.dart' as values; | 7 import '../constants/values.dart' as values; |
| 8 import '../dart_types.dart' as types; | 8 import '../dart_types.dart' as types; |
| 9 import '../elements/elements.dart' as elements; | 9 import '../elements/elements.dart' as elements; |
| 10 import '../tree/tree.dart' as tree; | 10 import '../tree/tree.dart' as tree; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 final String name; | 61 final String name; |
| 62 final List<TypeAnnotation> typeArguments; | 62 final List<TypeAnnotation> typeArguments; |
| 63 | 63 |
| 64 types.DartType dartType; | 64 types.DartType dartType; |
| 65 | 65 |
| 66 TypeAnnotation(this.name, [this.typeArguments = const <TypeAnnotation>[]]); | 66 TypeAnnotation(this.name, [this.typeArguments = const <TypeAnnotation>[]]); |
| 67 } | 67 } |
| 68 | 68 |
| 69 // STATEMENTS | 69 // STATEMENTS |
| 70 | 70 |
| 71 | |
| 72 class Block extends Statement { | 71 class Block extends Statement { |
| 73 final List<Statement> statements; | 72 final List<Statement> statements; |
| 74 | 73 |
| 75 Block(this.statements); | 74 Block(this.statements); |
| 76 } | 75 } |
| 77 | 76 |
| 78 class Break extends Statement { | 77 class Break extends Statement { |
| 79 final String label; | 78 final String label; |
| 80 | 79 |
| 81 Break([this.label]); | 80 Break([this.label]); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 101 } | 100 } |
| 102 | 101 |
| 103 class For extends Statement { | 102 class For extends Statement { |
| 104 final Node initializer; | 103 final Node initializer; |
| 105 final Expression condition; | 104 final Expression condition; |
| 106 final List<Expression> updates; | 105 final List<Expression> updates; |
| 107 final Statement body; | 106 final Statement body; |
| 108 | 107 |
| 109 /// Initializer must be [VariableDeclarations] or [Expression] or null. | 108 /// Initializer must be [VariableDeclarations] or [Expression] or null. |
| 110 For(this.initializer, this.condition, this.updates, this.body) { | 109 For(this.initializer, this.condition, this.updates, this.body) { |
| 111 assert(initializer == null | 110 assert(initializer == null || |
| 112 || initializer is VariableDeclarations | 111 initializer is VariableDeclarations || |
| 113 || initializer is Expression); | 112 initializer is Expression); |
| 114 } | 113 } |
| 115 } | 114 } |
| 116 | 115 |
| 117 class ForIn extends Statement { | 116 class ForIn extends Statement { |
| 118 final Node leftHandValue; | 117 final Node leftHandValue; |
| 119 final Expression expression; | 118 final Expression expression; |
| 120 final Statement body; | 119 final Statement body; |
| 121 | 120 |
| 122 /// [leftHandValue] must be [Identifier] or [VariableDeclarations] with | 121 /// [leftHandValue] must be [Identifier] or [VariableDeclarations] with |
| 123 /// exactly one definition, and that variable definition must have no | 122 /// exactly one definition, and that variable definition must have no |
| 124 /// initializer. | 123 /// initializer. |
| 125 ForIn(Node leftHandValue, this.expression, this.body) | 124 ForIn(Node leftHandValue, this.expression, this.body) |
| 126 : this.leftHandValue = leftHandValue { | 125 : this.leftHandValue = leftHandValue { |
| 127 assert(leftHandValue is Identifier | 126 assert(leftHandValue is Identifier || |
| 128 || (leftHandValue is VariableDeclarations | 127 (leftHandValue is VariableDeclarations && |
| 129 && leftHandValue.declarations.length == 1 | 128 leftHandValue.declarations.length == 1 && |
| 130 && leftHandValue.declarations[0].initializer == null)); | 129 leftHandValue.declarations[0].initializer == null)); |
| 131 } | 130 } |
| 132 } | 131 } |
| 133 | 132 |
| 134 class While extends Statement { | 133 class While extends Statement { |
| 135 final Expression condition; | 134 final Expression condition; |
| 136 final Statement body; | 135 final Statement body; |
| 137 | 136 |
| 138 While(this.condition, this.body); | 137 While(this.condition, this.body); |
| 139 } | 138 } |
| 140 | 139 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 153 If(this.condition, this.thenStatement, [this.elseStatement]); | 152 If(this.condition, this.thenStatement, [this.elseStatement]); |
| 154 } | 153 } |
| 155 | 154 |
| 156 class LabeledStatement extends Statement { | 155 class LabeledStatement extends Statement { |
| 157 final String label; | 156 final String label; |
| 158 final Statement statement; | 157 final Statement statement; |
| 159 | 158 |
| 160 LabeledStatement(this.label, this.statement); | 159 LabeledStatement(this.label, this.statement); |
| 161 } | 160 } |
| 162 | 161 |
| 163 class Rethrow extends Statement { | 162 class Rethrow extends Statement {} |
| 164 } | |
| 165 | 163 |
| 166 class Return extends Statement { | 164 class Return extends Statement { |
| 167 final Expression expression; | 165 final Expression expression; |
| 168 | 166 |
| 169 Return([this.expression]); | 167 Return([this.expression]); |
| 170 } | 168 } |
| 171 | 169 |
| 172 class Switch extends Statement { | 170 class Switch extends Statement { |
| 173 final Expression expression; | 171 final Expression expression; |
| 174 final List<SwitchCase> cases; | 172 final List<SwitchCase> cases; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 } | 220 } |
| 223 } | 221 } |
| 224 | 222 |
| 225 class VariableDeclarations extends Statement { | 223 class VariableDeclarations extends Statement { |
| 226 final TypeAnnotation type; | 224 final TypeAnnotation type; |
| 227 final bool isFinal; | 225 final bool isFinal; |
| 228 final bool isConst; | 226 final bool isConst; |
| 229 final List<VariableDeclaration> declarations; | 227 final List<VariableDeclaration> declarations; |
| 230 | 228 |
| 231 VariableDeclarations(this.declarations, | 229 VariableDeclarations(this.declarations, |
| 232 { this.type, | 230 {this.type, this.isFinal: false, this.isConst: false}) { |
| 233 this.isFinal: false, | |
| 234 this.isConst: false }) { | |
| 235 // Cannot be both final and const. | 231 // Cannot be both final and const. |
| 236 assert(!isFinal || !isConst); | 232 assert(!isFinal || !isConst); |
| 237 } | 233 } |
| 238 } | 234 } |
| 239 | 235 |
| 240 class VariableDeclaration extends Node { | 236 class VariableDeclaration extends Node { |
| 241 final String name; | 237 final String name; |
| 242 final Expression initializer; | 238 final Expression initializer; |
| 243 | 239 |
| 244 elements.Element element; | 240 elements.Element element; |
| 245 | 241 |
| 246 VariableDeclaration(this.name, [this.initializer]); | 242 VariableDeclaration(this.name, [this.initializer]); |
| 247 } | 243 } |
| 248 | 244 |
| 249 | |
| 250 class FunctionDeclaration extends Statement { | 245 class FunctionDeclaration extends Statement { |
| 251 final FunctionExpression function; | 246 final FunctionExpression function; |
| 252 | 247 |
| 253 TypeAnnotation get returnType => function.returnType; | 248 TypeAnnotation get returnType => function.returnType; |
| 254 Parameters get parameters => function.parameters; | 249 Parameters get parameters => function.parameters; |
| 255 String get name => function.name; | 250 String get name => function.name; |
| 256 Statement get body => function.body; | 251 Statement get body => function.body; |
| 257 | 252 |
| 258 FunctionDeclaration(this.function); | 253 FunctionDeclaration(this.function); |
| 259 } | 254 } |
| 260 | 255 |
| 261 class Parameters extends Node { | 256 class Parameters extends Node { |
| 262 final List<Parameter> requiredParameters; | 257 final List<Parameter> requiredParameters; |
| 263 final List<Parameter> optionalParameters; | 258 final List<Parameter> optionalParameters; |
| 264 final bool hasNamedParameters; | 259 final bool hasNamedParameters; |
| 265 | 260 |
| 266 Parameters(this.requiredParameters, | 261 Parameters(this.requiredParameters, |
| 267 [ this.optionalParameters, | 262 [this.optionalParameters, this.hasNamedParameters = false]); |
| 268 this.hasNamedParameters = false ]); | |
| 269 | 263 |
| 270 Parameters.named(this.requiredParameters, this.optionalParameters) | 264 Parameters.named(this.requiredParameters, this.optionalParameters) |
| 271 : hasNamedParameters = true; | 265 : hasNamedParameters = true; |
| 272 | 266 |
| 273 Parameters.positional(this.requiredParameters, this.optionalParameters) | 267 Parameters.positional(this.requiredParameters, this.optionalParameters) |
| 274 : hasNamedParameters = false; | 268 : hasNamedParameters = false; |
| 275 | 269 |
| 276 bool get hasOptionalParameters => | 270 bool get hasOptionalParameters => |
| 277 optionalParameters != null && optionalParameters.length > 0; | 271 optionalParameters != null && optionalParameters.length > 0; |
| 278 } | 272 } |
| 279 | 273 |
| 280 class Parameter extends Node { | 274 class Parameter extends Node { |
| 281 final String name; | 275 final String name; |
| 282 | 276 |
| 283 /// Type of parameter, or return type of function parameter. | 277 /// Type of parameter, or return type of function parameter. |
| 284 final TypeAnnotation type; | 278 final TypeAnnotation type; |
| 285 | 279 |
| 286 Expression defaultValue; | 280 Expression defaultValue; |
| 287 | 281 |
| 288 /// Parameters to function parameter. Null for non-function parameters. | 282 /// Parameters to function parameter. Null for non-function parameters. |
| 289 final Parameters parameters; | 283 final Parameters parameters; |
| 290 | 284 |
| 291 elements.FormalElement element; | 285 elements.FormalElement element; |
| 292 | 286 |
| 293 Parameter(this.name, {this.type, this.defaultValue}) | 287 Parameter(this.name, {this.type, this.defaultValue}) : parameters = null; |
| 294 : parameters = null; | |
| 295 | 288 |
| 296 Parameter.function(this.name, | 289 Parameter.function(this.name, TypeAnnotation returnType, this.parameters, |
| 297 TypeAnnotation returnType, | 290 [this.defaultValue]) |
| 298 this.parameters, | 291 : type = returnType { |
| 299 [ this.defaultValue ]) : type = returnType { | |
| 300 assert(parameters != null); | 292 assert(parameters != null); |
| 301 } | 293 } |
| 302 | 294 |
| 303 /// True if this is a function parameter. | 295 /// True if this is a function parameter. |
| 304 bool get isFunction => parameters != null; | 296 bool get isFunction => parameters != null; |
| 305 } | 297 } |
| 306 | 298 |
| 307 // EXPRESSIONS | 299 // EXPRESSIONS |
| 308 | 300 |
| 309 abstract class Initializer extends Expression {} | 301 abstract class Initializer extends Expression {} |
| (...skipping 15 matching lines...) Expand all Loading... |
| 325 class FunctionExpression extends Expression implements RootNode { | 317 class FunctionExpression extends Expression implements RootNode { |
| 326 final TypeAnnotation returnType; | 318 final TypeAnnotation returnType; |
| 327 String name; | 319 String name; |
| 328 final Parameters parameters; | 320 final Parameters parameters; |
| 329 final Statement body; | 321 final Statement body; |
| 330 final bool isGetter; | 322 final bool isGetter; |
| 331 final bool isSetter; | 323 final bool isSetter; |
| 332 | 324 |
| 333 elements.FunctionElement element; | 325 elements.FunctionElement element; |
| 334 | 326 |
| 335 FunctionExpression(this.parameters, | 327 FunctionExpression(this.parameters, this.body, |
| 336 this.body, | 328 {this.name, |
| 337 { this.name, | 329 this.returnType, |
| 338 this.returnType, | 330 this.isGetter: false, |
| 339 this.isGetter: false, | 331 this.isSetter: false}) { |
| 340 this.isSetter: false }) { | |
| 341 // Function must have a name if it has a return type | 332 // Function must have a name if it has a return type |
| 342 assert(returnType == null || name != null); | 333 assert(returnType == null || name != null); |
| 343 } | 334 } |
| 344 } | 335 } |
| 345 | 336 |
| 346 class ConstructorDefinition extends FunctionExpression { | 337 class ConstructorDefinition extends FunctionExpression { |
| 347 final List<Initializer> initializers; | 338 final List<Initializer> initializers; |
| 348 final bool isConst; | 339 final bool isConst; |
| 349 | 340 |
| 350 ConstructorDefinition(Parameters parameters, Statement body, | 341 ConstructorDefinition(Parameters parameters, Statement body, |
| 351 this.initializers, String name, this.isConst) | 342 this.initializers, String name, this.isConst) |
| 352 : super(parameters, body, name: name); | 343 : super(parameters, body, name: name); |
| 353 } | 344 } |
| 354 | 345 |
| 355 class Conditional extends Expression { | 346 class Conditional extends Expression { |
| 356 final Expression condition; | 347 final Expression condition; |
| 357 final Expression thenExpression; | 348 final Expression thenExpression; |
| 358 final Expression elseExpression; | 349 final Expression elseExpression; |
| 359 | 350 |
| 360 Conditional(this.condition, this.thenExpression, this.elseExpression); | 351 Conditional(this.condition, this.thenExpression, this.elseExpression); |
| 361 } | 352 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 382 final values.PrimitiveConstantValue value; | 373 final values.PrimitiveConstantValue value; |
| 383 | 374 |
| 384 Literal(this.value); | 375 Literal(this.value); |
| 385 } | 376 } |
| 386 | 377 |
| 387 class LiteralList extends Expression { | 378 class LiteralList extends Expression { |
| 388 final bool isConst; | 379 final bool isConst; |
| 389 final TypeAnnotation typeArgument; | 380 final TypeAnnotation typeArgument; |
| 390 final List<Expression> values; | 381 final List<Expression> values; |
| 391 | 382 |
| 392 LiteralList(this.values, { this.typeArgument, this.isConst: false }); | 383 LiteralList(this.values, {this.typeArgument, this.isConst: false}); |
| 393 } | 384 } |
| 394 | 385 |
| 395 class LiteralMap extends Expression { | 386 class LiteralMap extends Expression { |
| 396 final bool isConst; | 387 final bool isConst; |
| 397 final List<TypeAnnotation> typeArguments; | 388 final List<TypeAnnotation> typeArguments; |
| 398 final List<LiteralMapEntry> entries; | 389 final List<LiteralMapEntry> entries; |
| 399 | 390 |
| 400 LiteralMap(this.entries, { this.typeArguments, this.isConst: false }) { | 391 LiteralMap(this.entries, {this.typeArguments, this.isConst: false}) { |
| 401 assert(this.typeArguments == null | 392 assert(this.typeArguments == null || |
| 402 || this.typeArguments.length == 0 | 393 this.typeArguments.length == 0 || |
| 403 || this.typeArguments.length == 2); | 394 this.typeArguments.length == 2); |
| 404 } | 395 } |
| 405 } | 396 } |
| 406 | 397 |
| 407 class LiteralMapEntry extends Node { | 398 class LiteralMapEntry extends Node { |
| 408 final Expression key; | 399 final Expression key; |
| 409 final Expression value; | 400 final Expression value; |
| 410 | 401 |
| 411 LiteralMapEntry(this.key, this.value); | 402 LiteralMapEntry(this.key, this.value); |
| 412 } | 403 } |
| 413 | 404 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 /// or `const T.f(..)`. | 488 /// or `const T.f(..)`. |
| 498 class CallNew extends Expression { | 489 class CallNew extends Expression { |
| 499 final bool isConst; | 490 final bool isConst; |
| 500 final TypeAnnotation type; | 491 final TypeAnnotation type; |
| 501 final String constructorName; | 492 final String constructorName; |
| 502 final List<Argument> arguments; | 493 final List<Argument> arguments; |
| 503 | 494 |
| 504 elements.FunctionElement constructor; | 495 elements.FunctionElement constructor; |
| 505 types.DartType dartType; | 496 types.DartType dartType; |
| 506 | 497 |
| 507 CallNew(this.type, | 498 CallNew(this.type, this.arguments, |
| 508 this.arguments, | 499 {this.constructorName, this.isConst: false}); |
| 509 { this.constructorName, | |
| 510 this.isConst: false }); | |
| 511 } | 500 } |
| 512 | 501 |
| 513 /// Expression of form `T.f(..)`. | 502 /// Expression of form `T.f(..)`. |
| 514 class CallStatic extends Expression { | 503 class CallStatic extends Expression { |
| 515 final String className; | 504 final String className; |
| 516 final String methodName; | 505 final String methodName; |
| 517 final List<Argument> arguments; | 506 final List<Argument> arguments; |
| 518 | 507 |
| 519 elements.Element element; | 508 elements.Element element; |
| 520 | 509 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 543 } | 532 } |
| 544 } | 533 } |
| 545 | 534 |
| 546 /// Expression of form `e is T` or `e is! T` or `e as T`. | 535 /// Expression of form `e is T` or `e is! T` or `e as T`. |
| 547 class TypeOperator extends Expression { | 536 class TypeOperator extends Expression { |
| 548 final Expression expression; | 537 final Expression expression; |
| 549 final String operator; | 538 final String operator; |
| 550 final TypeAnnotation type; | 539 final TypeAnnotation type; |
| 551 | 540 |
| 552 TypeOperator(this.expression, this.operator, this.type) { | 541 TypeOperator(this.expression, this.operator, this.type) { |
| 553 assert(operator == 'is' | 542 assert(operator == 'is' || operator == 'as' || operator == 'is!'); |
| 554 || operator == 'as' | |
| 555 || operator == 'is!'); | |
| 556 } | 543 } |
| 557 } | 544 } |
| 558 | 545 |
| 559 class Increment extends Expression { | 546 class Increment extends Expression { |
| 560 final Expression expression; | 547 final Expression expression; |
| 561 final String operator; | 548 final String operator; |
| 562 final bool isPrefix; | 549 final bool isPrefix; |
| 563 | 550 |
| 564 Increment(this.expression, this.operator, this.isPrefix) { | 551 Increment(this.expression, this.operator, this.isPrefix) { |
| 565 assert(operator == '++' || operator == '--'); | 552 assert(operator == '++' || operator == '--'); |
| 566 assert(expression.assignable); | 553 assert(expression.assignable); |
| 567 } | 554 } |
| 568 | 555 |
| 569 Increment.prefix(Expression expression, String operator) | 556 Increment.prefix(Expression expression, String operator) |
| 570 : this(expression, operator, true); | 557 : this(expression, operator, true); |
| 571 | 558 |
| 572 Increment.postfix(Expression expression, String operator) | 559 Increment.postfix(Expression expression, String operator) |
| 573 : this(expression, operator, false); | 560 : this(expression, operator, false); |
| 574 } | 561 } |
| 575 | 562 |
| 576 class Assignment extends Expression { | 563 class Assignment extends Expression { |
| 577 static final _operators = | 564 static final _operators = new Set.from([ |
| 578 new Set.from(['=', '|=', '^=', '&=', '<<=', '>>=', | 565 '=', |
| 579 '+=', '-=', '*=', '/=', '%=', '~/=']); | 566 '|=', |
| 567 '^=', |
| 568 '&=', |
| 569 '<<=', |
| 570 '>>=', |
| 571 '+=', |
| 572 '-=', |
| 573 '*=', |
| 574 '/=', |
| 575 '%=', |
| 576 '~/=' |
| 577 ]); |
| 580 | 578 |
| 581 final Expression left; | 579 final Expression left; |
| 582 final String operator; | 580 final String operator; |
| 583 final Expression right; | 581 final Expression right; |
| 584 | 582 |
| 585 Assignment(this.left, this.operator, this.right) { | 583 Assignment(this.left, this.operator, this.right) { |
| 586 assert(_operators.contains(operator)); | 584 assert(_operators.contains(operator)); |
| 587 assert(left.assignable); | 585 assert(left.assignable); |
| 588 } | 586 } |
| 589 } | 587 } |
| 590 | 588 |
| 591 class Throw extends Expression { | 589 class Throw extends Expression { |
| 592 final Expression expression; | 590 final Expression expression; |
| 593 | 591 |
| 594 Throw(this.expression); | 592 Throw(this.expression); |
| 595 } | 593 } |
| 596 | 594 |
| 597 class This extends Expression { | 595 class This extends Expression { |
| 598 static final This _instance = new This._create(); | 596 static final This _instance = new This._create(); |
| 599 | 597 |
| 600 factory This() => _instance; | 598 factory This() => _instance; |
| 601 This._create(); | 599 This._create(); |
| 602 } | 600 } |
| 603 | 601 |
| 604 // UNPARSER | 602 // UNPARSER |
| 605 | 603 |
| 606 bool isUnaryOperator(String op) { | 604 bool isUnaryOperator(String op) { |
| 607 return op == '!' || op == '-' || op == '~'; | 605 return op == '!' || op == '-' || op == '~'; |
| 608 } | 606 } |
| 607 |
| 609 bool isBinaryOperator(String op) { | 608 bool isBinaryOperator(String op) { |
| 610 return BINARY_PRECEDENCE.containsKey(op); | 609 return BINARY_PRECEDENCE.containsKey(op); |
| 611 } | 610 } |
| 611 |
| 612 /// True if the given operator can be converted to a compound assignment. | 612 /// True if the given operator can be converted to a compound assignment. |
| 613 bool isCompoundableOperator(String op) { | 613 bool isCompoundableOperator(String op) { |
| 614 switch (BINARY_PRECEDENCE[op]) { | 614 switch (BINARY_PRECEDENCE[op]) { |
| 615 case BITWISE_OR: | 615 case BITWISE_OR: |
| 616 case BITWISE_XOR: | 616 case BITWISE_XOR: |
| 617 case BITWISE_AND: | 617 case BITWISE_AND: |
| 618 case SHIFT: | 618 case SHIFT: |
| 619 case ADDITIVE: | 619 case ADDITIVE: |
| 620 case MULTIPLICATIVE: | 620 case MULTIPLICATIVE: |
| 621 return true; | 621 return true; |
| 622 default: | 622 default: |
| 623 return false; | 623 return false; |
| 624 } | 624 } |
| 625 } | 625 } |
| 626 | 626 |
| 627 | |
| 628 // Precedence levels | 627 // Precedence levels |
| 629 const int EXPRESSION = 1; | 628 const int EXPRESSION = 1; |
| 630 const int CONDITIONAL = 2; | 629 const int CONDITIONAL = 2; |
| 631 const int LOGICAL_OR = 3; | 630 const int LOGICAL_OR = 3; |
| 632 const int LOGICAL_AND = 4; | 631 const int LOGICAL_AND = 4; |
| 633 const int EQUALITY = 6; | 632 const int EQUALITY = 6; |
| 634 const int RELATIONAL = 7; | 633 const int RELATIONAL = 7; |
| 635 const int BITWISE_OR = 8; | 634 const int BITWISE_OR = 8; |
| 636 const int BITWISE_XOR = 9; | 635 const int BITWISE_XOR = 9; |
| 637 const int BITWISE_AND = 10; | 636 const int BITWISE_AND = 10; |
| 638 const int SHIFT = 11; | 637 const int SHIFT = 11; |
| 639 const int ADDITIVE = 12; | 638 const int ADDITIVE = 12; |
| 640 const int MULTIPLICATIVE = 13; | 639 const int MULTIPLICATIVE = 13; |
| 641 const int UNARY = 14; | 640 const int UNARY = 14; |
| 642 const int POSTFIX_INCREMENT = 15; | 641 const int POSTFIX_INCREMENT = 15; |
| 643 const int TYPE_LITERAL = 19; | 642 const int TYPE_LITERAL = 19; |
| 644 const int PRIMARY = 20; | 643 const int PRIMARY = 20; |
| 645 | 644 |
| 646 /// Precedence level required for the callee in a [FunctionCall]. | 645 /// Precedence level required for the callee in a [FunctionCall]. |
| 647 const int CALLEE = 21; | 646 const int CALLEE = 21; |
| 648 | 647 |
| 649 const Map<String,int> BINARY_PRECEDENCE = const { | 648 const Map<String, int> BINARY_PRECEDENCE = const { |
| 650 '&&': LOGICAL_AND, | 649 '&&': LOGICAL_AND, |
| 651 '||': LOGICAL_OR, | 650 '||': LOGICAL_OR, |
| 652 | |
| 653 '==': EQUALITY, | 651 '==': EQUALITY, |
| 654 '!=': EQUALITY, | 652 '!=': EQUALITY, |
| 655 | |
| 656 '>': RELATIONAL, | 653 '>': RELATIONAL, |
| 657 '>=': RELATIONAL, | 654 '>=': RELATIONAL, |
| 658 '<': RELATIONAL, | 655 '<': RELATIONAL, |
| 659 '<=': RELATIONAL, | 656 '<=': RELATIONAL, |
| 660 | |
| 661 '|': BITWISE_OR, | 657 '|': BITWISE_OR, |
| 662 '^': BITWISE_XOR, | 658 '^': BITWISE_XOR, |
| 663 '&': BITWISE_AND, | 659 '&': BITWISE_AND, |
| 664 | |
| 665 '>>': SHIFT, | 660 '>>': SHIFT, |
| 666 '<<': SHIFT, | 661 '<<': SHIFT, |
| 667 | |
| 668 '+': ADDITIVE, | 662 '+': ADDITIVE, |
| 669 '-': ADDITIVE, | 663 '-': ADDITIVE, |
| 670 | |
| 671 '*': MULTIPLICATIVE, | 664 '*': MULTIPLICATIVE, |
| 672 '%': MULTIPLICATIVE, | 665 '%': MULTIPLICATIVE, |
| 673 '/': MULTIPLICATIVE, | 666 '/': MULTIPLICATIVE, |
| 674 '~/': MULTIPLICATIVE, | 667 '~/': MULTIPLICATIVE, |
| 675 }; | 668 }; |
| 676 | 669 |
| 677 /// Return true if binary operators with the given precedence level are | 670 /// Return true if binary operators with the given precedence level are |
| 678 /// (left) associative. False if they are non-associative. | 671 /// (left) associative. False if they are non-associative. |
| 679 bool isAssociativeBinaryOperator(int precedence) { | 672 bool isAssociativeBinaryOperator(int precedence) { |
| 680 return precedence != EQUALITY && precedence != RELATIONAL; | 673 return precedence != EQUALITY && precedence != RELATIONAL; |
| 681 } | 674 } |
| 682 | 675 |
| 683 /// True if [x] is a letter, digit, or underscore. | 676 /// True if [x] is a letter, digit, or underscore. |
| 684 /// Such characters may not follow a shorthand string interpolation. | 677 /// Such characters may not follow a shorthand string interpolation. |
| 685 bool isIdentifierPartNoDollar(dynamic x) { | 678 bool isIdentifierPartNoDollar(dynamic x) { |
| 686 if (x is! int) { | 679 if (x is! int) { |
| 687 return false; | 680 return false; |
| 688 } | 681 } |
| 689 return (characters.$0 <= x && x <= characters.$9) || | 682 return (characters.$0 <= x && x <= characters.$9) || |
| 690 (characters.$A <= x && x <= characters.$Z) || | 683 (characters.$A <= x && x <= characters.$Z) || |
| 691 (characters.$a <= x && x <= characters.$z) || | 684 (characters.$a <= x && x <= characters.$z) || |
| 692 (x == characters.$_); | 685 (x == characters.$_); |
| 693 } | 686 } |
| 694 | 687 |
| 695 /// The unparser will apply the following syntactic rewritings: | 688 /// The unparser will apply the following syntactic rewritings: |
| 696 /// Use short-hand function returns: | 689 /// Use short-hand function returns: |
| 697 /// foo(){return E} ==> foo() => E; | 690 /// foo(){return E} ==> foo() => E; |
| 698 /// Remove empty else branch: | 691 /// Remove empty else branch: |
| 699 /// if (E) S else ; ==> if (E) S | 692 /// if (E) S else ; ==> if (E) S |
| 700 /// Flatten nested blocks: | 693 /// Flatten nested blocks: |
| 701 /// {S; {S; S}; S} ==> {S; S; S; S} | 694 /// {S; {S; S}; S} ==> {S; S; S; S} |
| 702 /// Remove empty statements from block: | 695 /// Remove empty statements from block: |
| (...skipping 17 matching lines...) Expand all Loading... |
| 720 /// | 713 /// |
| 721 /// The following transformations might be applied here in the future: | 714 /// The following transformations might be applied here in the future: |
| 722 /// Use implicit dynamic types: | 715 /// Use implicit dynamic types: |
| 723 /// dynamic x = E ==> var x = E | 716 /// dynamic x = E ==> var x = E |
| 724 /// <dynamic>[] ==> [] | 717 /// <dynamic>[] ==> [] |
| 725 class Unparser { | 718 class Unparser { |
| 726 StringSink output; | 719 StringSink output; |
| 727 | 720 |
| 728 Unparser(this.output); | 721 Unparser(this.output); |
| 729 | 722 |
| 730 | |
| 731 void write(String s) { | 723 void write(String s) { |
| 732 output.write(s); | 724 output.write(s); |
| 733 } | 725 } |
| 734 | 726 |
| 735 /// Outputs each element from [items] separated by [separator]. | 727 /// Outputs each element from [items] separated by [separator]. |
| 736 /// The actual printing must be performed by the [callback]. | 728 /// The actual printing must be performed by the [callback]. |
| 737 void writeEach(String separator, Iterable items, void callback(any)) { | 729 void writeEach(String separator, Iterable items, void callback(any)) { |
| 738 bool first = true; | 730 bool first = true; |
| 739 for (var x in items) { | 731 for (var x in items) { |
| 740 if (first) { | 732 if (first) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 | 771 |
| 780 /// Prints the expression [e]. | 772 /// Prints the expression [e]. |
| 781 void writeExpression(Expression e) { | 773 void writeExpression(Expression e) { |
| 782 writeExp(e, EXPRESSION); | 774 writeExp(e, EXPRESSION); |
| 783 } | 775 } |
| 784 | 776 |
| 785 /// Prints [e] as an expression with precedence of at least [minPrecedence], | 777 /// Prints [e] as an expression with precedence of at least [minPrecedence], |
| 786 /// using parentheses if necessary to raise the precedence level. | 778 /// using parentheses if necessary to raise the precedence level. |
| 787 /// Abusing terminology slightly, the function accepts a [Receiver] which | 779 /// Abusing terminology slightly, the function accepts a [Receiver] which |
| 788 /// may also be the [SuperReceiver] object. | 780 /// may also be the [SuperReceiver] object. |
| 789 void writeExp(Receiver e, int minPrecedence, {beginStmt:false}) { | 781 void writeExp(Receiver e, int minPrecedence, {beginStmt: false}) { |
| 790 void withPrecedence(int actual, void action()) { | 782 void withPrecedence(int actual, void action()) { |
| 791 if (actual < minPrecedence) { | 783 if (actual < minPrecedence) { |
| 792 write("("); | 784 write("("); |
| 793 beginStmt = false; | 785 beginStmt = false; |
| 794 action(); | 786 action(); |
| 795 write(")"); | 787 write(")"); |
| 796 } else { | 788 } else { |
| 797 action(); | 789 action(); |
| 798 } | 790 } |
| 799 } | 791 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 835 write(' ? '); | 827 write(' ? '); |
| 836 writeExp(e.thenExpression, EXPRESSION); | 828 writeExp(e.thenExpression, EXPRESSION); |
| 837 write(' : '); | 829 write(' : '); |
| 838 writeExp(e.elseExpression, EXPRESSION); | 830 writeExp(e.elseExpression, EXPRESSION); |
| 839 }); | 831 }); |
| 840 } else if (e is Identifier) { | 832 } else if (e is Identifier) { |
| 841 write(e.name); | 833 write(e.name); |
| 842 } else if (e is Literal) { | 834 } else if (e is Literal) { |
| 843 if (e.value.isString) { | 835 if (e.value.isString) { |
| 844 writeStringLiteral(e); | 836 writeStringLiteral(e); |
| 845 } | 837 } else if (e.value.isDouble) { |
| 846 else if (e.value.isDouble) { | |
| 847 double v = e.value.primitiveValue; | 838 double v = e.value.primitiveValue; |
| 848 if (v == double.INFINITY) { | 839 if (v == double.INFINITY) { |
| 849 withPrecedence(MULTIPLICATIVE, () { | 840 withPrecedence(MULTIPLICATIVE, () { |
| 850 write('1/0.0'); | 841 write('1/0.0'); |
| 851 }); | 842 }); |
| 852 } else if (v == double.NEGATIVE_INFINITY) { | 843 } else if (v == double.NEGATIVE_INFINITY) { |
| 853 withPrecedence(MULTIPLICATIVE, () { | 844 withPrecedence(MULTIPLICATIVE, () { |
| 854 write('-1/0.0'); | 845 write('-1/0.0'); |
| 855 }); | 846 }); |
| 856 } else if (v.isNaN) { | 847 } else if (v.isNaN) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 868 write(' const '); | 859 write(' const '); |
| 869 } | 860 } |
| 870 if (e.typeArgument != null) { | 861 if (e.typeArgument != null) { |
| 871 write('<'); | 862 write('<'); |
| 872 writeType(e.typeArgument); | 863 writeType(e.typeArgument); |
| 873 write('>'); | 864 write('>'); |
| 874 } | 865 } |
| 875 write('['); | 866 write('['); |
| 876 writeEach(',', e.values, writeExpression); | 867 writeEach(',', e.values, writeExpression); |
| 877 write(']'); | 868 write(']'); |
| 878 } | 869 } else if (e is LiteralMap) { |
| 879 else if (e is LiteralMap) { | |
| 880 // The curly brace can be mistaken for a block statement if we | 870 // The curly brace can be mistaken for a block statement if we |
| 881 // are at the beginning of a statement. | 871 // are at the beginning of a statement. |
| 882 bool needParen = beginStmt; | 872 bool needParen = beginStmt; |
| 883 if (e.isConst) { | 873 if (e.isConst) { |
| 884 write(' const '); | 874 write(' const '); |
| 885 needParen = false; | 875 needParen = false; |
| 886 } | 876 } |
| 887 if (e.typeArguments.length > 0) { | 877 if (e.typeArguments.length > 0) { |
| 888 write('<'); | 878 write('<'); |
| 889 writeEach(',', e.typeArguments, writeType); | 879 writeEach(',', e.typeArguments, writeType); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 913 } else if (e is ReifyTypeVar) { | 903 } else if (e is ReifyTypeVar) { |
| 914 withPrecedence(PRIMARY, () { | 904 withPrecedence(PRIMARY, () { |
| 915 write(e.name); | 905 write(e.name); |
| 916 }); | 906 }); |
| 917 } else if (e is StringConcat) { | 907 } else if (e is StringConcat) { |
| 918 writeStringLiteral(e); | 908 writeStringLiteral(e); |
| 919 } else if (e is UnaryOperator) { | 909 } else if (e is UnaryOperator) { |
| 920 Receiver operand = e.operand; | 910 Receiver operand = e.operand; |
| 921 // !(x == y) ==> x != y. | 911 // !(x == y) ==> x != y. |
| 922 if (e.operatorName == '!' && | 912 if (e.operatorName == '!' && |
| 923 operand is BinaryOperator && operand.operator == '==') { | 913 operand is BinaryOperator && |
| 914 operand.operator == '==') { |
| 924 withPrecedence(EQUALITY, () { | 915 withPrecedence(EQUALITY, () { |
| 925 writeExp(operand.left, RELATIONAL); | 916 writeExp(operand.left, RELATIONAL); |
| 926 writeOperator('!='); | 917 writeOperator('!='); |
| 927 writeExp(operand.right, RELATIONAL); | 918 writeExp(operand.right, RELATIONAL); |
| 928 }); | 919 }); |
| 929 } | 920 } |
| 930 // !(x is T) ==> x is!T | 921 // !(x is T) ==> x is!T |
| 931 else if (e.operatorName == '!' && | 922 else if (e.operatorName == '!' && |
| 932 operand is TypeOperator && operand.operator == 'is') { | 923 operand is TypeOperator && |
| 924 operand.operator == 'is') { |
| 933 withPrecedence(RELATIONAL, () { | 925 withPrecedence(RELATIONAL, () { |
| 934 writeExp(operand.expression, BITWISE_OR, beginStmt: beginStmt); | 926 writeExp(operand.expression, BITWISE_OR, beginStmt: beginStmt); |
| 935 write(' is!'); | 927 write(' is!'); |
| 936 writeType(operand.type); | 928 writeType(operand.type); |
| 937 }); | 929 }); |
| 938 } | 930 } else { |
| 939 else { | |
| 940 withPrecedence(UNARY, () { | 931 withPrecedence(UNARY, () { |
| 941 writeOperator(e.operatorName); | 932 writeOperator(e.operatorName); |
| 942 writeExp(e.operand, UNARY); | 933 writeExp(e.operand, UNARY); |
| 943 }); | 934 }); |
| 944 } | 935 } |
| 945 } else if (e is BinaryOperator) { | 936 } else if (e is BinaryOperator) { |
| 946 int precedence = BINARY_PRECEDENCE[e.operator]; | 937 int precedence = BINARY_PRECEDENCE[e.operator]; |
| 947 withPrecedence(precedence, () { | 938 withPrecedence(precedence, () { |
| 948 // All binary operators are left-associative or non-associative. | 939 // All binary operators are left-associative or non-associative. |
| 949 // For each operand, we use either the same precedence level as | 940 // For each operand, we use either the same precedence level as |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1093 } else if (stmt is Continue) { | 1084 } else if (stmt is Continue) { |
| 1094 write('continue'); | 1085 write('continue'); |
| 1095 if (stmt.label != null) { | 1086 if (stmt.label != null) { |
| 1096 write(' '); | 1087 write(' '); |
| 1097 write(stmt.label); | 1088 write(stmt.label); |
| 1098 } | 1089 } |
| 1099 write(';'); | 1090 write(';'); |
| 1100 } else if (stmt is EmptyStatement) { | 1091 } else if (stmt is EmptyStatement) { |
| 1101 write(';'); | 1092 write(';'); |
| 1102 } else if (stmt is ExpressionStatement) { | 1093 } else if (stmt is ExpressionStatement) { |
| 1103 writeExp(stmt.expression, EXPRESSION, beginStmt:true); | 1094 writeExp(stmt.expression, EXPRESSION, beginStmt: true); |
| 1104 write(';'); | 1095 write(';'); |
| 1105 } else if (stmt is For) { | 1096 } else if (stmt is For) { |
| 1106 write('for('); | 1097 write('for('); |
| 1107 Node init = stmt.initializer; | 1098 Node init = stmt.initializer; |
| 1108 if (init is Expression) { | 1099 if (init is Expression) { |
| 1109 writeExp(init, EXPRESSION); | 1100 writeExp(init, EXPRESSION); |
| 1110 } else if (init is VariableDeclarations) { | 1101 } else if (init is VariableDeclarations) { |
| 1111 writeVariableDefinitions(init); | 1102 writeVariableDefinitions(init); |
| 1112 } | 1103 } |
| 1113 write(';'); | 1104 write(';'); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1239 } | 1230 } |
| 1240 } else { | 1231 } else { |
| 1241 throw "Unexpected statement: $stmt"; | 1232 throw "Unexpected statement: $stmt"; |
| 1242 } | 1233 } |
| 1243 } | 1234 } |
| 1244 | 1235 |
| 1245 /// Writes a variable definition statement without the trailing semicolon | 1236 /// Writes a variable definition statement without the trailing semicolon |
| 1246 void writeVariableDefinitions(VariableDeclarations vds) { | 1237 void writeVariableDefinitions(VariableDeclarations vds) { |
| 1247 if (vds.isConst) | 1238 if (vds.isConst) |
| 1248 write('const '); | 1239 write('const '); |
| 1249 else if (vds.isFinal) | 1240 else if (vds.isFinal) write('final '); |
| 1250 write('final '); | |
| 1251 if (vds.type != null) { | 1241 if (vds.type != null) { |
| 1252 writeType(vds.type); | 1242 writeType(vds.type); |
| 1253 write(' '); | 1243 write(' '); |
| 1254 } | 1244 } |
| 1255 if (!vds.isConst && !vds.isFinal && vds.type == null) { | 1245 if (!vds.isConst && !vds.isFinal && vds.type == null) { |
| 1256 write('var '); | 1246 write('var '); |
| 1257 } | 1247 } |
| 1258 writeEach(',', vds.declarations, (VariableDeclaration vd) { | 1248 writeEach(',', vds.declarations, (VariableDeclaration vd) { |
| 1259 write(vd.name); | 1249 write(vd.name); |
| 1260 if (vd.initializer != null) { | 1250 if (vd.initializer != null) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1300 write('<'); | 1290 write('<'); |
| 1301 writeEach(',', type.typeArguments, writeType); | 1291 writeEach(',', type.typeArguments, writeType); |
| 1302 write('>'); | 1292 write('>'); |
| 1303 } | 1293 } |
| 1304 } | 1294 } |
| 1305 | 1295 |
| 1306 /// A list of string quotings that the printer may use to quote strings. | 1296 /// A list of string quotings that the printer may use to quote strings. |
| 1307 // Ignore multiline quotings for now. Would need to make sure that no | 1297 // Ignore multiline quotings for now. Would need to make sure that no |
| 1308 // newline (potentially prefixed by whitespace) follows the quoting. | 1298 // newline (potentially prefixed by whitespace) follows the quoting. |
| 1309 static const _QUOTINGS = const <tree.StringQuoting>[ | 1299 static const _QUOTINGS = const <tree.StringQuoting>[ |
| 1310 const tree.StringQuoting(characters.$DQ, raw: false, leftQuoteLength: 1), | 1300 const tree.StringQuoting(characters.$DQ, raw: false, leftQuoteLength: 1), |
| 1311 const tree.StringQuoting(characters.$DQ, raw: true, leftQuoteLength: 1), | 1301 const tree.StringQuoting(characters.$DQ, raw: true, leftQuoteLength: 1), |
| 1312 const tree.StringQuoting(characters.$SQ, raw: false, leftQuoteLength: 1), | 1302 const tree.StringQuoting(characters.$SQ, raw: false, leftQuoteLength: 1), |
| 1313 const tree.StringQuoting(characters.$SQ, raw: true, leftQuoteLength: 1), | 1303 const tree.StringQuoting(characters.$SQ, raw: true, leftQuoteLength: 1), |
| 1314 ]; | 1304 ]; |
| 1315 | 1305 |
| 1316 static StringLiteralOutput analyzeStringLiteral(Expression node) { | 1306 static StringLiteralOutput analyzeStringLiteral(Expression node) { |
| 1317 // Flatten the StringConcat tree. | 1307 // Flatten the StringConcat tree. |
| 1318 List parts = []; // Expression or int (char node) | 1308 List parts = []; // Expression or int (char node) |
| 1319 void collectParts(Expression e) { | 1309 void collectParts(Expression e) { |
| 1320 if (e is StringConcat) { | 1310 if (e is StringConcat) { |
| 1321 e.expressions.forEach(collectParts); | 1311 e.expressions.forEach(collectParts); |
| 1322 } else if (e is Literal && e.value.isString) { | 1312 } else if (e is Literal && e.value.isString) { |
| 1323 for (int char in e.value.primitiveValue) { | 1313 for (int char in e.value.primitiveValue) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 } else { | 1354 } else { |
| 1365 nonRaws.add(index); | 1355 nonRaws.add(index); |
| 1366 } | 1356 } |
| 1367 if (q.quote == characters.$SQ) { | 1357 if (q.quote == characters.$SQ) { |
| 1368 sqs.add(index); | 1358 sqs.add(index); |
| 1369 } else { | 1359 } else { |
| 1370 dqs.add(index); | 1360 dqs.add(index); |
| 1371 } | 1361 } |
| 1372 } | 1362 } |
| 1373 | 1363 |
| 1374 | |
| 1375 /// Applies additional cost to each track in [penalized], and considers | 1364 /// Applies additional cost to each track in [penalized], and considers |
| 1376 /// switching from each [penalized] to a [nonPenalized] track. | 1365 /// switching from each [penalized] to a [nonPenalized] track. |
| 1377 void penalize(List<int> penalized, | 1366 void penalize(List<int> penalized, List<int> nonPenalized, int endIndex, |
| 1378 List<int> nonPenalized, | 1367 num cost(tree.StringQuoting q)) { |
| 1379 int endIndex, | |
| 1380 num cost(tree.StringQuoting q)) { | |
| 1381 for (int j in penalized) { | 1368 for (int j in penalized) { |
| 1382 // Check if another track can benefit from switching from this track. | 1369 // Check if another track can benefit from switching from this track. |
| 1383 for (int k in nonPenalized) { | 1370 for (int k in nonPenalized) { |
| 1384 num newCost = best[j].cost | 1371 num newCost = best[j].cost + |
| 1385 + 1 // Whitespace in string juxtaposition | 1372 1 // Whitespace in string juxtaposition |
| 1386 + getQuoteCost(best[k].quoting); | 1373 + |
| 1374 getQuoteCost(best[k].quoting); |
| 1387 if (newCost < best[k].cost) { | 1375 if (newCost < best[k].cost) { |
| 1388 best[k] = new OpenStringChunk( | 1376 best[k] = new OpenStringChunk( |
| 1389 best[j].end(endIndex), | 1377 best[j].end(endIndex), best[k].quoting, newCost); |
| 1390 best[k].quoting, | |
| 1391 newCost); | |
| 1392 } | 1378 } |
| 1393 } | 1379 } |
| 1394 best[j].cost += cost(best[j].quoting); | 1380 best[j].cost += cost(best[j].quoting); |
| 1395 } | 1381 } |
| 1396 } | 1382 } |
| 1397 | 1383 |
| 1398 // Iterate through the string and update the score for each StringQuoting. | 1384 // Iterate through the string and update the score for each StringQuoting. |
| 1399 for (int i = 0; i < parts.length; i++) { | 1385 for (int i = 0; i < parts.length; i++) { |
| 1400 var part = parts[i]; | 1386 var part = parts[i]; |
| 1401 if (part is int) { | 1387 if (part is int) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1426 penalize(raws, nonRaws, i, (q) => double.INFINITY); | 1412 penalize(raws, nonRaws, i, (q) => double.INFINITY); |
| 1427 | 1413 |
| 1428 // Splitting a string can sometimes allow us to use a shorthand | 1414 // Splitting a string can sometimes allow us to use a shorthand |
| 1429 // string interpolation that would otherwise be illegal. | 1415 // string interpolation that would otherwise be illegal. |
| 1430 // E.g. "...${foo}x..." -> "...$foo" 'x...' | 1416 // E.g. "...${foo}x..." -> "...$foo" 'x...' |
| 1431 // If are other factors that make splitting advantageous, | 1417 // If are other factors that make splitting advantageous, |
| 1432 // we can gain even more by doing the split here. | 1418 // we can gain even more by doing the split here. |
| 1433 if (part is Identifier && | 1419 if (part is Identifier && |
| 1434 !part.name.contains(r'$') && | 1420 !part.name.contains(r'$') && |
| 1435 i + 1 < parts.length && | 1421 i + 1 < parts.length && |
| 1436 isIdentifierPartNoDollar(parts[i+1])) { | 1422 isIdentifierPartNoDollar(parts[i + 1])) { |
| 1437 for (int j in nonRaws) { | 1423 for (int j in nonRaws) { |
| 1438 for (int k = 0; k < best.length; k++) { | 1424 for (int k = 0; k < best.length; k++) { |
| 1439 num newCost = best[j].cost | 1425 num newCost = best[j].cost + |
| 1440 + 1 // Whitespace in string juxtaposition | 1426 1 // Whitespace in string juxtaposition |
| 1441 - 2 // Save two curly braces | 1427 - |
| 1442 + getQuoteCost(best[k].quoting); | 1428 2 // Save two curly braces |
| 1429 + |
| 1430 getQuoteCost(best[k].quoting); |
| 1443 if (newCost < best[k].cost) { | 1431 if (newCost < best[k].cost) { |
| 1444 best[k] = new OpenStringChunk( | 1432 best[k] = new OpenStringChunk( |
| 1445 best[j].end(i+1), | 1433 best[j].end(i + 1), best[k].quoting, newCost); |
| 1446 best[k].quoting, | |
| 1447 newCost); | |
| 1448 } | 1434 } |
| 1449 } | 1435 } |
| 1450 } | 1436 } |
| 1451 } | 1437 } |
| 1452 } | 1438 } |
| 1453 } | 1439 } |
| 1454 | 1440 |
| 1455 // Select the cheapest strategy | 1441 // Select the cheapest strategy |
| 1456 OpenStringChunk bestChunk = best[0]; | 1442 OpenStringChunk bestChunk = best[0]; |
| 1457 for (OpenStringChunk chunk in best) { | 1443 for (OpenStringChunk chunk in best) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1474 startIndex = chunk.previous.endIndex; | 1460 startIndex = chunk.previous.endIndex; |
| 1475 } else { | 1461 } else { |
| 1476 startIndex = 0; | 1462 startIndex = 0; |
| 1477 } | 1463 } |
| 1478 if (chunk.quoting.raw) { | 1464 if (chunk.quoting.raw) { |
| 1479 write('r'); | 1465 write('r'); |
| 1480 } | 1466 } |
| 1481 write(chunk.quoting.quoteChar); | 1467 write(chunk.quoting.quoteChar); |
| 1482 bool raw = chunk.quoting.raw; | 1468 bool raw = chunk.quoting.raw; |
| 1483 int quoteCode = chunk.quoting.quote; | 1469 int quoteCode = chunk.quoting.quote; |
| 1484 for (int i=startIndex; i<chunk.endIndex; i++) { | 1470 for (int i = startIndex; i < chunk.endIndex; i++) { |
| 1485 var part = parts[i]; | 1471 var part = parts[i]; |
| 1486 if (part is int) { | 1472 if (part is int) { |
| 1487 int char = part; | 1473 int char = part; |
| 1488 write(getEscapedCharacter(char, quoteCode, raw)); | 1474 write(getEscapedCharacter(char, quoteCode, raw)); |
| 1489 } else if (part is Identifier && | 1475 } else if (part is Identifier && |
| 1490 !part.name.contains(r'$') && | 1476 !part.name.contains(r'$') && |
| 1491 (i == chunk.endIndex - 1 || | 1477 (i == chunk.endIndex - 1 || |
| 1492 !isIdentifierPartNoDollar(parts[i+1]))) { | 1478 !isIdentifierPartNoDollar(parts[i + 1]))) { |
| 1493 write(r'$'); | 1479 write(r'$'); |
| 1494 write(part.name); | 1480 write(part.name); |
| 1495 } else { | 1481 } else { |
| 1496 write(r'${'); | 1482 write(r'${'); |
| 1497 writeExpression(part); | 1483 writeExpression(part); |
| 1498 write('}'); | 1484 write('}'); |
| 1499 } | 1485 } |
| 1500 } | 1486 } |
| 1501 write(chunk.quoting.quoteChar); | 1487 write(chunk.quoting.quoteChar); |
| 1502 } | 1488 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1524 case characters.$TAB: | 1510 case characters.$TAB: |
| 1525 return r'\t'; | 1511 return r'\t'; |
| 1526 case characters.$VTAB: | 1512 case characters.$VTAB: |
| 1527 return r'\v'; | 1513 return r'\v'; |
| 1528 case characters.$EOF: | 1514 case characters.$EOF: |
| 1529 return r'\x00'; | 1515 return r'\x00'; |
| 1530 default: | 1516 default: |
| 1531 return new String.fromCharCode(char); | 1517 return new String.fromCharCode(char); |
| 1532 } | 1518 } |
| 1533 } | 1519 } |
| 1534 | |
| 1535 } | 1520 } |
| 1536 | 1521 |
| 1537 /// The contents of a string literal together with a strategy for printing it. | 1522 /// The contents of a string literal together with a strategy for printing it. |
| 1538 class StringLiteralOutput { | 1523 class StringLiteralOutput { |
| 1539 /// Mix of [Expression] and `int`. Each expression is a string interpolation, | 1524 /// Mix of [Expression] and `int`. Each expression is a string interpolation, |
| 1540 /// and each `int` is the character code of a character in a string literal. | 1525 /// and each `int` is the character code of a character in a string literal. |
| 1541 final List parts; | 1526 final List parts; |
| 1542 final StringChunk chunk; | 1527 final StringChunk chunk; |
| 1543 | 1528 |
| 1544 StringLiteralOutput(this.parts, this.chunk); | 1529 StringLiteralOutput(this.parts, this.chunk); |
| 1545 } | 1530 } |
| 1546 | 1531 |
| 1547 | |
| 1548 /// Strategy for printing a prefix of a string literal. | 1532 /// Strategy for printing a prefix of a string literal. |
| 1549 /// A chunk represents the substring going from [:previous.endIndex:] to | 1533 /// A chunk represents the substring going from [:previous.endIndex:] to |
| 1550 /// [endIndex] (or from 0 to [endIndex] if [previous] is null). | 1534 /// [endIndex] (or from 0 to [endIndex] if [previous] is null). |
| 1551 class StringChunk { | 1535 class StringChunk { |
| 1552 final StringChunk previous; | 1536 final StringChunk previous; |
| 1553 final tree.StringQuoting quoting; | 1537 final tree.StringQuoting quoting; |
| 1554 final int endIndex; | 1538 final int endIndex; |
| 1555 | 1539 |
| 1556 StringChunk(this.previous, this.quoting, this.endIndex); | 1540 StringChunk(this.previous, this.quoting, this.endIndex); |
| 1557 } | 1541 } |
| 1558 | 1542 |
| 1559 /// [StringChunk] that has not yet been assigned an [endIndex]. | 1543 /// [StringChunk] that has not yet been assigned an [endIndex]. |
| 1560 /// It additionally has a [cost] denoting the number of auxilliary characters | 1544 /// It additionally has a [cost] denoting the number of auxilliary characters |
| 1561 /// (quotes, spaces, etc) needed to print the literal using this strategy | 1545 /// (quotes, spaces, etc) needed to print the literal using this strategy |
| 1562 class OpenStringChunk { | 1546 class OpenStringChunk { |
| 1563 final StringChunk previous; | 1547 final StringChunk previous; |
| 1564 final tree.StringQuoting quoting; | 1548 final tree.StringQuoting quoting; |
| 1565 num cost; | 1549 num cost; |
| 1566 | 1550 |
| 1567 OpenStringChunk(this.previous, this.quoting, this.cost); | 1551 OpenStringChunk(this.previous, this.quoting, this.cost); |
| 1568 | 1552 |
| 1569 StringChunk end(int endIndex) { | 1553 StringChunk end(int endIndex) { |
| 1570 return new StringChunk(previous, quoting, endIndex); | 1554 return new StringChunk(previous, quoting, endIndex); |
| 1571 } | 1555 } |
| 1572 } | 1556 } |
| OLD | NEW |