| Index: lib/compiler/implementation/tree/nodes.dart
|
| diff --git a/lib/compiler/implementation/tree/nodes.dart b/lib/compiler/implementation/tree/nodes.dart
|
| index 73986015e6c8156ccfaaec9cfe26830e75c01f1d..59cdd5013c50a069ba0adca996bb869306683b7f 100644
|
| --- a/lib/compiler/implementation/tree/nodes.dart
|
| +++ b/lib/compiler/implementation/tree/nodes.dart
|
| @@ -7,6 +7,7 @@ interface Visitor<R> {
|
| R visitBreakStatement(BreakStatement node);
|
| R visitCascade(Cascade node);
|
| R visitCascadeReceiver(CascadeReceiver node);
|
| + R visitCaseMatch(CaseMatch node);
|
| R visitCatchBlock(CatchBlock node);
|
| R visitClassNode(ClassNode node);
|
| R visitConditional(Conditional node);
|
| @@ -30,7 +31,6 @@ interface Visitor<R> {
|
| R visitLiteralMapEntry(LiteralMapEntry node);
|
| R visitLiteralNull(LiteralNull node);
|
| R visitLiteralString(LiteralString node);
|
| - R visitStringJuxtaposition(StringJuxtaposition node);
|
| R visitModifiers(Modifiers node);
|
| R visitNamedArgument(NamedArgument node);
|
| R visitNewExpression(NewExpression node);
|
| @@ -43,6 +43,7 @@ interface Visitor<R> {
|
| R visitSendSet(SendSet node);
|
| R visitStringInterpolation(StringInterpolation node);
|
| R visitStringInterpolationPart(StringInterpolationPart node);
|
| + R visitStringJuxtaposition(StringJuxtaposition node);
|
| R visitSwitchCase(SwitchCase node);
|
| R visitSwitchStatement(SwitchStatement node);
|
| R visitThrow(Throw node);
|
| @@ -113,6 +114,7 @@ class Node implements Hashable {
|
| BreakStatement asBreakStatement() => null;
|
| Cascade asCascade() => null;
|
| CascadeReceiver asCascadeReceiver() => null;
|
| + CaseMatch asCaseMatch() => null;
|
| CatchBlock asCatchBlock() => null;
|
| ClassNode asClassNode() => null;
|
| Conditional asConditional() => null;
|
| @@ -1321,32 +1323,56 @@ class SwitchStatement extends Statement {
|
| Token getEndToken() => cases.getEndToken();
|
| }
|
|
|
| +class CaseMatch extends Node {
|
| + final Token caseKeyword;
|
| + final Expression expression;
|
| + final Token colonToken;
|
| + CaseMatch(this.caseKeyword, this.expression, this.colonToken);
|
| +
|
| + CaseMatch asCaseMatch() => this;
|
| + Token getBeginToken() => caseKeyword;
|
| + Token getEndToken() => pattern.getEndToken().next();
|
| + accept(Visitor visitor) => visitor.visitCaseMatch(this);
|
| + visitChildren(Visitor visitor) => expression.accept(visitor);
|
| +}
|
| +
|
| class SwitchCase extends Node {
|
| // Represents the grammar:
|
| - // label? ('case' expression ':')* ('default' ':')? statement*
|
| - // Each expression is collected in [expressions].
|
| - // The 'case' keywords can be obtained using [caseKeywords()].
|
| + // (label | 'case' expression ':')* ('default' ':')? statement*
|
| + // The labels are collected in [labels].
|
| + // Each case patterns are collected in [cases].
|
| + // The default keyword, if present, is collected in [defaultKeyword].
|
| // Any actual switch case must have at least one 'case' or 'default'
|
| // clause.
|
| - final Label label;
|
| - final NodeList expressions;
|
| + // Notice: The labels and cases can occur interleaved in the source.
|
| + // They are separated here, since the order is irrelevant to the meaning
|
| + // of the switch.
|
| +
|
| + /** List of [Identifier] of labels. */
|
| + final NodeList labels;
|
| + /** List of [CaseMatch] structures. */
|
| + final NodeList cases;
|
| + /** A "default" keyword token, if applicable. */
|
| final Token defaultKeyword;
|
| + /** List of statements, the body of the case. */
|
| final NodeList statements;
|
|
|
| final Token startToken;
|
|
|
| - SwitchCase(this.label, this.expressions, this.defaultKeyword,
|
| + SwitchCase(this.labels, this.cases, this.defaultKeyword,
|
| this.statements, this.startToken);
|
|
|
| SwitchCase asSwitchCase() => this;
|
|
|
| bool get isDefaultCase() => defaultKeyword !== null;
|
|
|
| + bool isValidContinueTarget() => true;
|
| +
|
| accept(Visitor visitor) => visitor.visitSwitchCase(this);
|
|
|
| visitChildren(Visitor visitor) {
|
| - if (label !== null) label.accept(visitor);
|
| - expressions.accept(visitor);
|
| + labels.accept(visitor);
|
| + cases.accept(visitor);
|
| statements.accept(visitor);
|
| }
|
|
|
| @@ -1361,34 +1387,16 @@ class SwitchCase extends Node {
|
| // The colon after 'default'.
|
| return defaultKeyword.next;
|
| }
|
| - // The colon after the expression.
|
| - return expressions.getEndToken().next;
|
| + // The colon after the last expression.
|
| + return cases.getEndToken();
|
| } else {
|
| return statements.getEndToken();
|
| }
|
| }
|
| -
|
| - Link<Token> caseKeywords() {
|
| - Token token = startToken;
|
| - if (label !== null) {
|
| - // Skip past the label: <Identifier> ':'.
|
| - token = token.next.next;
|
| - }
|
| - LinkBuilder<Token> builder = new LinkBuilder<Token>();
|
| - Link<Expression> link = expressions.nodes;
|
| - while (token.stringValue === 'case') {
|
| - assert(token.next === link.head.getBeginToken());
|
| - builder.addLast(token);
|
| - Token colon = link.head.getEndToken().next;
|
| - token = colon.next;
|
| - link = link.tail;
|
| - }
|
| - return builder.toLink();
|
| - }
|
| }
|
|
|
| class GotoStatement extends Statement {
|
| - final Identifier target;
|
| + final Label target;
|
| final Token keywordToken;
|
| final Token semicolonToken;
|
|
|
| @@ -1407,7 +1415,7 @@ class GotoStatement extends Statement {
|
| }
|
|
|
| class BreakStatement extends GotoStatement {
|
| - BreakStatement(Identifier target, Token keywordToken, Token semicolonToken)
|
| + BreakStatement(Label target, Token keywordToken, Token semicolonToken)
|
| : super(target, keywordToken, semicolonToken);
|
|
|
| BreakStatement asBreakStatement() => this;
|
| @@ -1416,7 +1424,7 @@ class BreakStatement extends GotoStatement {
|
| }
|
|
|
| class ContinueStatement extends GotoStatement {
|
| - ContinueStatement(Identifier target, Token keywordToken, Token semicolonToken)
|
| + ContinueStatement(Label target, Token keywordToken, Token semicolonToken)
|
| : super(target, keywordToken, semicolonToken);
|
|
|
| ContinueStatement asContinueStatement() => this;
|
|
|