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 |