| OLD | NEW | 
 | (Empty) | 
|     1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file |  | 
|     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. |  | 
|     4  |  | 
|     5 part of tree; |  | 
|     6  |  | 
|     7 abstract class Visitor<R> { |  | 
|     8   const Visitor(); |  | 
|     9  |  | 
|    10   R visitNode(Node node); |  | 
|    11  |  | 
|    12   R visitBlock(Block node) => visitStatement(node); |  | 
|    13   R visitBreakStatement(BreakStatement node) => visitGotoStatement(node); |  | 
|    14   R visitCascade(Cascade node) => visitExpression(node); |  | 
|    15   R visitCascadeReceiver(CascadeReceiver node) => visitExpression(node); |  | 
|    16   R visitCaseMatch(CaseMatch node) => visitNode(node); |  | 
|    17   R visitCatchBlock(CatchBlock node) => visitNode(node); |  | 
|    18   R visitClassNode(ClassNode node) => visitNode(node); |  | 
|    19   R visitCombinator(Combinator node) => visitNode(node); |  | 
|    20   R visitConditional(Conditional node) => visitExpression(node); |  | 
|    21   R visitContinueStatement(ContinueStatement node) => visitGotoStatement(node); |  | 
|    22   R visitDoWhile(DoWhile node) => visitLoop(node); |  | 
|    23   R visitEmptyStatement(EmptyStatement node) => visitStatement(node); |  | 
|    24   R visitExport(Export node) => visitLibraryDependency(node); |  | 
|    25   R visitExpression(Expression node) => visitNode(node); |  | 
|    26   R visitExpressionStatement(ExpressionStatement node) => visitStatement(node); |  | 
|    27   R visitFor(For node) => visitLoop(node); |  | 
|    28   R visitForIn(ForIn node) => visitLoop(node); |  | 
|    29   R visitFunctionDeclaration(FunctionDeclaration node) => visitStatement(node); |  | 
|    30   R visitFunctionExpression(FunctionExpression node) => visitExpression(node); |  | 
|    31   R visitGotoStatement(GotoStatement node) => visitStatement(node); |  | 
|    32   R visitIdentifier(Identifier node) => visitExpression(node); |  | 
|    33   R visitIf(If node) => visitStatement(node); |  | 
|    34   R visitImport(Import node) => visitLibraryDependency(node); |  | 
|    35   R visitLabel(Label node) => visitNode(node); |  | 
|    36   R visitLabeledStatement(LabeledStatement node) => visitStatement(node); |  | 
|    37   R visitLibraryDependency(LibraryDependency node) => visitLibraryTag(node); |  | 
|    38   R visitLibraryName(LibraryName node) => visitLibraryTag(node); |  | 
|    39   R visitLibraryTag(LibraryTag node) => visitNode(node); |  | 
|    40   R visitLiteral(Literal node) => visitExpression(node); |  | 
|    41   R visitLiteralBool(LiteralBool node) => visitLiteral(node); |  | 
|    42   R visitLiteralDouble(LiteralDouble node) => visitLiteral(node); |  | 
|    43   R visitLiteralInt(LiteralInt node) => visitLiteral(node); |  | 
|    44   R visitLiteralList(LiteralList node) => visitExpression(node); |  | 
|    45   R visitLiteralMap(LiteralMap node) => visitExpression(node); |  | 
|    46   R visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node); |  | 
|    47   R visitLiteralNull(LiteralNull node) => visitLiteral(node); |  | 
|    48   R visitLiteralString(LiteralString node) => visitStringNode(node); |  | 
|    49   R visitStringJuxtaposition(StringJuxtaposition node) => visitStringNode(node); |  | 
|    50   R visitLoop(Loop node) => visitStatement(node); |  | 
|    51   R visitMetadata(Metadata node) => visitNode(node); |  | 
|    52   R visitMixinApplication(MixinApplication node) => visitNode(node); |  | 
|    53   R visitModifiers(Modifiers node) => visitNode(node); |  | 
|    54   R visitNamedArgument(NamedArgument node) => visitExpression(node); |  | 
|    55   R visitNamedMixinApplication(NamedMixinApplication node) { |  | 
|    56     return visitMixinApplication(node); |  | 
|    57   } |  | 
|    58   R visitNewExpression(NewExpression node) => visitExpression(node); |  | 
|    59   R visitNodeList(NodeList node) => visitNode(node); |  | 
|    60   R visitOperator(Operator node) => visitIdentifier(node); |  | 
|    61   R visitParenthesizedExpression(ParenthesizedExpression node) { |  | 
|    62     return visitExpression(node); |  | 
|    63   } |  | 
|    64   R visitPart(Part node) => visitLibraryTag(node); |  | 
|    65   R visitPartOf(PartOf node) => visitNode(node); |  | 
|    66   R visitPostfix(Postfix node) => visitNodeList(node); |  | 
|    67   R visitPrefix(Prefix node) => visitNodeList(node); |  | 
|    68   R visitRedirectingFactoryBody(RedirectingFactoryBody node) { |  | 
|    69     return visitStatement(node); |  | 
|    70   } |  | 
|    71   R visitRethrow(Rethrow node) => visitStatement(node); |  | 
|    72   R visitReturn(Return node) => visitStatement(node); |  | 
|    73   R visitSend(Send node) => visitExpression(node); |  | 
|    74   R visitSendSet(SendSet node) => visitSend(node); |  | 
|    75   R visitStatement(Statement node) => visitNode(node); |  | 
|    76   R visitStringNode(StringNode node) => visitExpression(node); |  | 
|    77   R visitStringInterpolation(StringInterpolation node) => visitStringNode(node); |  | 
|    78   R visitStringInterpolationPart(StringInterpolationPart node) { |  | 
|    79     return visitNode(node); |  | 
|    80   } |  | 
|    81   R visitSwitchCase(SwitchCase node) => visitNode(node); |  | 
|    82   R visitSwitchStatement(SwitchStatement node) => visitStatement(node); |  | 
|    83   R visitLiteralSymbol(LiteralSymbol node) => visitExpression(node); |  | 
|    84   R visitThrow(Throw node) => visitExpression(node); |  | 
|    85   R visitTryStatement(TryStatement node) => visitStatement(node); |  | 
|    86   R visitTypeAnnotation(TypeAnnotation node) => visitNode(node); |  | 
|    87   R visitTypedef(Typedef node) => visitNode(node); |  | 
|    88   R visitTypeVariable(TypeVariable node) => visitNode(node); |  | 
|    89   R visitVariableDefinitions(VariableDefinitions node) => visitStatement(node); |  | 
|    90   R visitWhile(While node) => visitLoop(node); |  | 
|    91 } |  | 
|    92  |  | 
|    93 Token firstBeginToken(Node first, Node second) { |  | 
|    94   Token token = null; |  | 
|    95   if (first != null) { |  | 
|    96     token = first.getBeginToken(); |  | 
|    97   } |  | 
|    98   if (token == null && second != null) { |  | 
|    99     // [token] might be null even when [first] is not, e.g. for empty Modifiers. |  | 
|   100     token = second.getBeginToken(); |  | 
|   101   } |  | 
|   102   return token; |  | 
|   103 } |  | 
|   104  |  | 
|   105 /** |  | 
|   106  * A node in a syntax tree. |  | 
|   107  * |  | 
|   108  * The abstract part of "abstract syntax tree" is invalidated when |  | 
|   109  * supporting tools such as code formatting. These tools need concrete |  | 
|   110  * syntax such as parentheses and no constant folding. |  | 
|   111  * |  | 
|   112  * We support these tools by storing additional references back to the |  | 
|   113  * token stream. These references are stored in fields ending with |  | 
|   114  * "Token". |  | 
|   115  */ |  | 
|   116 abstract class Node extends NullTreeElementMixin implements Spannable { |  | 
|   117   final int hashCode; |  | 
|   118   static int _HASH_COUNTER = 0; |  | 
|   119  |  | 
|   120   Node() : hashCode = ++_HASH_COUNTER; |  | 
|   121  |  | 
|   122   accept(Visitor visitor); |  | 
|   123  |  | 
|   124   visitChildren(Visitor visitor); |  | 
|   125  |  | 
|   126   /** |  | 
|   127    * Returns this node unparsed to Dart source string. |  | 
|   128    */ |  | 
|   129   toString() => unparse(this); |  | 
|   130  |  | 
|   131   /** |  | 
|   132    * Returns Xml-like tree representation of this node. |  | 
|   133    */ |  | 
|   134   toDebugString() { |  | 
|   135     return PrettyPrinter.prettyPrint(this); |  | 
|   136   } |  | 
|   137  |  | 
|   138   String getObjectDescription() => super.toString(); |  | 
|   139  |  | 
|   140   Token getBeginToken(); |  | 
|   141  |  | 
|   142   Token getEndToken(); |  | 
|   143  |  | 
|   144   Block asBlock() => null; |  | 
|   145   BreakStatement asBreakStatement() => null; |  | 
|   146   Cascade asCascade() => null; |  | 
|   147   CascadeReceiver asCascadeReceiver() => null; |  | 
|   148   CaseMatch asCaseMatch() => null; |  | 
|   149   CatchBlock asCatchBlock() => null; |  | 
|   150   ClassNode asClassNode() => null; |  | 
|   151   Combinator asCombinator() => null; |  | 
|   152   Conditional asConditional() => null; |  | 
|   153   ContinueStatement asContinueStatement() => null; |  | 
|   154   DoWhile asDoWhile() => null; |  | 
|   155   EmptyStatement asEmptyStatement() => null; |  | 
|   156   ErrorExpression asErrorExpression() => null; |  | 
|   157   Export asExport() => null; |  | 
|   158   Expression asExpression() => null; |  | 
|   159   ExpressionStatement asExpressionStatement() => null; |  | 
|   160   For asFor() => null; |  | 
|   161   ForIn asForIn() => null; |  | 
|   162   FunctionDeclaration asFunctionDeclaration() => null; |  | 
|   163   FunctionExpression asFunctionExpression() => null; |  | 
|   164   Identifier asIdentifier() => null; |  | 
|   165   If asIf() => null; |  | 
|   166   Import asImport() => null; |  | 
|   167   Label asLabel() => null; |  | 
|   168   LabeledStatement asLabeledStatement() => null; |  | 
|   169   LibraryName asLibraryName() => null; |  | 
|   170   LibraryDependency asLibraryDependency() => null; |  | 
|   171   LiteralBool asLiteralBool() => null; |  | 
|   172   LiteralDouble asLiteralDouble() => null; |  | 
|   173   LiteralInt asLiteralInt() => null; |  | 
|   174   LiteralList asLiteralList() => null; |  | 
|   175   LiteralMap asLiteralMap() => null; |  | 
|   176   LiteralMapEntry asLiteralMapEntry() => null; |  | 
|   177   LiteralNull asLiteralNull() => null; |  | 
|   178   LiteralString asLiteralString() => null; |  | 
|   179   LiteralSymbol asLiteralSymbol() => null; |  | 
|   180   Metadata asMetadata() => null; |  | 
|   181   MixinApplication asMixinApplication() => null; |  | 
|   182   Modifiers asModifiers() => null; |  | 
|   183   NamedArgument asNamedArgument() => null; |  | 
|   184   NamedMixinApplication asNamedMixinApplication() => null; |  | 
|   185   NewExpression asNewExpression() => null; |  | 
|   186   NodeList asNodeList() => null; |  | 
|   187   Operator asOperator() => null; |  | 
|   188   ParenthesizedExpression asParenthesizedExpression() => null; |  | 
|   189   Part asPart() => null; |  | 
|   190   PartOf asPartOf() => null; |  | 
|   191   RedirectingFactoryBody asRedirectingFactoryBody() => null; |  | 
|   192   Rethrow asRethrow() => null; |  | 
|   193   Return asReturn() => null; |  | 
|   194   Send asSend() => null; |  | 
|   195   SendSet asSendSet() => null; |  | 
|   196   Statement asStatement() => null; |  | 
|   197   StringInterpolation asStringInterpolation() => null; |  | 
|   198   StringInterpolationPart asStringInterpolationPart() => null; |  | 
|   199   StringJuxtaposition asStringJuxtaposition() => null; |  | 
|   200   StringNode asStringNode() => null; |  | 
|   201   SwitchCase asSwitchCase() => null; |  | 
|   202   SwitchStatement asSwitchStatement() => null; |  | 
|   203   Throw asThrow() => null; |  | 
|   204   TryStatement asTryStatement() => null; |  | 
|   205   TypeAnnotation asTypeAnnotation() => null; |  | 
|   206   TypeVariable asTypeVariable() => null; |  | 
|   207   Typedef asTypedef() => null; |  | 
|   208   VariableDefinitions asVariableDefinitions() => null; |  | 
|   209   While asWhile() => null; |  | 
|   210  |  | 
|   211   bool isValidBreakTarget() => false; |  | 
|   212   bool isValidContinueTarget() => false; |  | 
|   213   bool isThis() => false; |  | 
|   214   bool isSuper() => false; |  | 
|   215  |  | 
|   216   bool get isErroneous => false; |  | 
|   217 } |  | 
|   218  |  | 
|   219 class ClassNode extends Node { |  | 
|   220   final Modifiers modifiers; |  | 
|   221   final Identifier name; |  | 
|   222   final Node superclass; |  | 
|   223   final NodeList interfaces; |  | 
|   224   final NodeList typeParameters; |  | 
|   225   final NodeList body; |  | 
|   226  |  | 
|   227   final Token beginToken; |  | 
|   228   final Token extendsKeyword; |  | 
|   229   final Token endToken; |  | 
|   230  |  | 
|   231   ClassNode(this.modifiers, this.name, this.typeParameters, this.superclass, |  | 
|   232             this.interfaces, this.beginToken, |  | 
|   233             this.extendsKeyword, this.body, this.endToken); |  | 
|   234  |  | 
|   235   ClassNode asClassNode() => this; |  | 
|   236  |  | 
|   237   accept(Visitor visitor) => visitor.visitClassNode(this); |  | 
|   238  |  | 
|   239   visitChildren(Visitor visitor) { |  | 
|   240     if (name != null) name.accept(visitor); |  | 
|   241     if (typeParameters != null) typeParameters.accept(visitor); |  | 
|   242     if (superclass != null) superclass.accept(visitor); |  | 
|   243     if (interfaces != null) interfaces.accept(visitor); |  | 
|   244     if (body != null) body.accept(visitor); |  | 
|   245   } |  | 
|   246  |  | 
|   247   Token getBeginToken() => beginToken; |  | 
|   248  |  | 
|   249   Token getEndToken() => endToken; |  | 
|   250 } |  | 
|   251  |  | 
|   252 class MixinApplication extends Node { |  | 
|   253   final TypeAnnotation superclass; |  | 
|   254   final NodeList mixins; |  | 
|   255  |  | 
|   256   MixinApplication(this.superclass, this.mixins); |  | 
|   257  |  | 
|   258   MixinApplication asMixinApplication() => this; |  | 
|   259  |  | 
|   260   accept(Visitor visitor) => visitor.visitMixinApplication(this); |  | 
|   261  |  | 
|   262   visitChildren(Visitor visitor) { |  | 
|   263     if (superclass != null) superclass.accept(visitor); |  | 
|   264     if (mixins != null) mixins.accept(visitor); |  | 
|   265   } |  | 
|   266  |  | 
|   267   Token getBeginToken() => superclass.getBeginToken(); |  | 
|   268   Token getEndToken() => mixins.getEndToken(); |  | 
|   269 } |  | 
|   270  |  | 
|   271 // TODO(kasperl): Let this share some structure with the typedef for function |  | 
|   272 // type aliases? |  | 
|   273 class NamedMixinApplication extends Node implements MixinApplication { |  | 
|   274   final Identifier name; |  | 
|   275   final NodeList typeParameters; |  | 
|   276  |  | 
|   277   final Modifiers modifiers; |  | 
|   278   final MixinApplication mixinApplication; |  | 
|   279   final NodeList interfaces; |  | 
|   280  |  | 
|   281   final Token classKeyword; |  | 
|   282   final Token endToken; |  | 
|   283  |  | 
|   284   NamedMixinApplication(this.name, this.typeParameters, |  | 
|   285                         this.modifiers, this.mixinApplication, this.interfaces, |  | 
|   286                         this.classKeyword, this.endToken); |  | 
|   287  |  | 
|   288   TypeAnnotation get superclass => mixinApplication.superclass; |  | 
|   289   NodeList get mixins => mixinApplication.mixins; |  | 
|   290  |  | 
|   291   MixinApplication asMixinApplication() => this; |  | 
|   292   NamedMixinApplication asNamedMixinApplication() => this; |  | 
|   293  |  | 
|   294   accept(Visitor visitor) => visitor.visitNamedMixinApplication(this); |  | 
|   295  |  | 
|   296   visitChildren(Visitor visitor) { |  | 
|   297     name.accept(visitor); |  | 
|   298     if (typeParameters != null) typeParameters.accept(visitor); |  | 
|   299     if (modifiers != null) modifiers.accept(visitor); |  | 
|   300     if (interfaces != null) interfaces.accept(visitor); |  | 
|   301     mixinApplication.accept(visitor); |  | 
|   302   } |  | 
|   303  |  | 
|   304   Token getBeginToken() => classKeyword; |  | 
|   305   Token getEndToken() => endToken; |  | 
|   306 } |  | 
|   307  |  | 
|   308 abstract class Expression extends Node { |  | 
|   309   Expression(); |  | 
|   310  |  | 
|   311   Expression asExpression() => this; |  | 
|   312  |  | 
|   313   // TODO(ahe): make class abstract instead of adding an abstract method. |  | 
|   314   accept(Visitor visitor); |  | 
|   315 } |  | 
|   316  |  | 
|   317 abstract class Statement extends Node { |  | 
|   318   Statement(); |  | 
|   319  |  | 
|   320   Statement asStatement() => this; |  | 
|   321  |  | 
|   322   // TODO(ahe): make class abstract instead of adding an abstract method. |  | 
|   323   accept(Visitor visitor); |  | 
|   324  |  | 
|   325   bool isValidBreakTarget() => true; |  | 
|   326 } |  | 
|   327  |  | 
|   328 /// Erroneous expression that behaves as a literal null. |  | 
|   329 class ErrorExpression extends LiteralNull { |  | 
|   330   ErrorExpression(token) |  | 
|   331       : super(token); |  | 
|   332  |  | 
|   333   ErrorExpression asErrorExpression() => this; |  | 
|   334  |  | 
|   335   bool get isErroneous => true; |  | 
|   336 } |  | 
|   337  |  | 
|   338 /** |  | 
|   339  * A message send aka method invocation. In Dart, most operations can |  | 
|   340  * (and should) be considered as message sends. Getters and setters |  | 
|   341  * are just methods with a special syntax. Consequently, we model |  | 
|   342  * property access, assignment, operators, and method calls with this |  | 
|   343  * one node. |  | 
|   344  */ |  | 
|   345 class Send extends Expression with StoredTreeElementMixin { |  | 
|   346   final Node receiver; |  | 
|   347   final Node selector; |  | 
|   348   final NodeList argumentsNode; |  | 
|   349   Link<Node> get arguments => argumentsNode.nodes; |  | 
|   350  |  | 
|   351   Send([this.receiver, this.selector, this.argumentsNode]); |  | 
|   352   Send.postfix(this.receiver, this.selector, [Node argument = null]) |  | 
|   353       : argumentsNode = (argument == null) |  | 
|   354         ? new Postfix() |  | 
|   355         : new Postfix.singleton(argument); |  | 
|   356   Send.prefix(this.receiver, this.selector, [Node argument = null]) |  | 
|   357       : argumentsNode = (argument == null) |  | 
|   358         ? new Prefix() |  | 
|   359         : new Prefix.singleton(argument); |  | 
|   360  |  | 
|   361   Send asSend() => this; |  | 
|   362  |  | 
|   363   accept(Visitor visitor) => visitor.visitSend(this); |  | 
|   364  |  | 
|   365   visitChildren(Visitor visitor) { |  | 
|   366     if (receiver != null) receiver.accept(visitor); |  | 
|   367     if (selector != null) selector.accept(visitor); |  | 
|   368     if (argumentsNode != null) argumentsNode.accept(visitor); |  | 
|   369   } |  | 
|   370  |  | 
|   371   int argumentCount() { |  | 
|   372     return (argumentsNode == null) ? -1 : argumentsNode.slowLength(); |  | 
|   373   } |  | 
|   374  |  | 
|   375   bool get isSuperCall { |  | 
|   376     return receiver != null && receiver.isSuper(); |  | 
|   377   } |  | 
|   378   bool get isOperator => selector is Operator; |  | 
|   379   bool get isPropertyAccess => argumentsNode == null; |  | 
|   380   bool get isFunctionObjectInvocation => selector == null; |  | 
|   381   bool get isPrefix => argumentsNode is Prefix; |  | 
|   382   bool get isPostfix => argumentsNode is Postfix; |  | 
|   383   bool get isCall => !isOperator && !isPropertyAccess; |  | 
|   384   bool get isIndex => |  | 
|   385       isOperator && identical(selector.asOperator().source, '[]'); |  | 
|   386   bool get isLogicalAnd => |  | 
|   387       isOperator && identical(selector.asOperator().source, '&&'); |  | 
|   388   bool get isLogicalOr => |  | 
|   389       isOperator && identical(selector.asOperator().source, '||'); |  | 
|   390  |  | 
|   391   bool get isTypeCast { |  | 
|   392     return isOperator |  | 
|   393         && identical(selector.asOperator().source, 'as'); |  | 
|   394   } |  | 
|   395  |  | 
|   396   bool get isTypeTest { |  | 
|   397     return isOperator |  | 
|   398         && identical(selector.asOperator().source, 'is'); |  | 
|   399   } |  | 
|   400  |  | 
|   401   bool get isIsNotCheck { |  | 
|   402     return isTypeTest && arguments.head.asSend() != null; |  | 
|   403   } |  | 
|   404  |  | 
|   405   TypeAnnotation get typeAnnotationFromIsCheckOrCast { |  | 
|   406     assert(isOperator); |  | 
|   407     assert(identical(selector.asOperator().source, 'is') || |  | 
|   408         identical(selector.asOperator().source, 'as')); |  | 
|   409     return isIsNotCheck |  | 
|   410         ? arguments.head.asSend().receiver |  | 
|   411         : arguments.head; |  | 
|   412   } |  | 
|   413  |  | 
|   414   Token getBeginToken() { |  | 
|   415     if (isPrefix && !isIndex) return selector.getBeginToken(); |  | 
|   416     return firstBeginToken(receiver, selector); |  | 
|   417   } |  | 
|   418  |  | 
|   419   Token getEndToken() { |  | 
|   420     if (isPrefix) { |  | 
|   421       if (receiver != null) return receiver.getEndToken(); |  | 
|   422       if (selector != null) return selector.getEndToken(); |  | 
|   423       return null; |  | 
|   424     } |  | 
|   425     if (!isPostfix && argumentsNode != null) { |  | 
|   426       Token token = argumentsNode.getEndToken(); |  | 
|   427       if (token != null) return token; |  | 
|   428     } |  | 
|   429     if (selector != null) return selector.getEndToken(); |  | 
|   430     return getBeginToken(); |  | 
|   431   } |  | 
|   432  |  | 
|   433   Send copyWithReceiver(Node newReceiver) { |  | 
|   434     assert(receiver == null); |  | 
|   435     return new Send(newReceiver, selector, argumentsNode); |  | 
|   436   } |  | 
|   437 } |  | 
|   438  |  | 
|   439 class Postfix extends NodeList { |  | 
|   440   Postfix() : super(null, const Link<Node>()); |  | 
|   441   Postfix.singleton(Node argument) : super.singleton(argument); |  | 
|   442 } |  | 
|   443  |  | 
|   444 class Prefix extends NodeList { |  | 
|   445   Prefix() : super(null, const Link<Node>()); |  | 
|   446   Prefix.singleton(Node argument) : super.singleton(argument); |  | 
|   447 } |  | 
|   448  |  | 
|   449 class SendSet extends Send { |  | 
|   450   final Operator assignmentOperator; |  | 
|   451   SendSet(receiver, selector, this.assignmentOperator, argumentsNode) |  | 
|   452     : super(receiver, selector, argumentsNode); |  | 
|   453   SendSet.postfix(receiver, |  | 
|   454                   selector, |  | 
|   455                   this.assignmentOperator, |  | 
|   456                   [Node argument = null]) |  | 
|   457       : super.postfix(receiver, selector, argument); |  | 
|   458   SendSet.prefix(receiver, |  | 
|   459                  selector, |  | 
|   460                  this.assignmentOperator, |  | 
|   461                  [Node argument = null]) |  | 
|   462       : super.prefix(receiver, selector, argument); |  | 
|   463  |  | 
|   464   SendSet asSendSet() => this; |  | 
|   465  |  | 
|   466   accept(Visitor visitor) => visitor.visitSendSet(this); |  | 
|   467  |  | 
|   468   visitChildren(Visitor visitor) { |  | 
|   469     super.visitChildren(visitor); |  | 
|   470     if (assignmentOperator != null) assignmentOperator.accept(visitor); |  | 
|   471   } |  | 
|   472  |  | 
|   473   Send copyWithReceiver(Node newReceiver) { |  | 
|   474     assert(receiver == null); |  | 
|   475     return new SendSet(newReceiver, selector, assignmentOperator, |  | 
|   476                        argumentsNode); |  | 
|   477   } |  | 
|   478  |  | 
|   479   Token getBeginToken() { |  | 
|   480     if (isPrefix) return assignmentOperator.getBeginToken(); |  | 
|   481     return super.getBeginToken(); |  | 
|   482   } |  | 
|   483  |  | 
|   484   Token getEndToken() { |  | 
|   485     if (isPostfix) return assignmentOperator.getEndToken(); |  | 
|   486     return super.getEndToken(); |  | 
|   487   } |  | 
|   488 } |  | 
|   489  |  | 
|   490 class NewExpression extends Expression { |  | 
|   491   /** The token NEW or CONST or `null` for metadata */ |  | 
|   492   final Token newToken; |  | 
|   493  |  | 
|   494   // Note: we expect that send.receiver is null. |  | 
|   495   final Send send; |  | 
|   496  |  | 
|   497   NewExpression([this.newToken, this.send]); |  | 
|   498  |  | 
|   499   NewExpression asNewExpression() => this; |  | 
|   500  |  | 
|   501   accept(Visitor visitor) => visitor.visitNewExpression(this); |  | 
|   502  |  | 
|   503   visitChildren(Visitor visitor) { |  | 
|   504     if (send != null) send.accept(visitor); |  | 
|   505   } |  | 
|   506  |  | 
|   507   bool get isConst { |  | 
|   508     return newToken == null || identical(newToken.stringValue, 'const'); |  | 
|   509   } |  | 
|   510  |  | 
|   511   Token getBeginToken() => newToken != null ? newToken : send.getBeginToken(); |  | 
|   512  |  | 
|   513   Token getEndToken() => send.getEndToken(); |  | 
|   514 } |  | 
|   515  |  | 
|   516 class NodeList extends Node { |  | 
|   517   final Link<Node> nodes; |  | 
|   518   final Token beginToken; |  | 
|   519   final Token endToken; |  | 
|   520   final String delimiter; |  | 
|   521   bool get isEmpty => nodes.isEmpty; |  | 
|   522  |  | 
|   523   NodeList([this.beginToken, this.nodes, this.endToken, this.delimiter]); |  | 
|   524  |  | 
|   525   Iterator<Node> get iterator => nodes.iterator; |  | 
|   526  |  | 
|   527   NodeList.singleton(Node node) : this(null, const Link<Node>().prepend(node)); |  | 
|   528   NodeList.empty() : this(null, const Link<Node>()); |  | 
|   529  |  | 
|   530   NodeList asNodeList() => this; |  | 
|   531  |  | 
|   532   int slowLength() { |  | 
|   533     int result = 0; |  | 
|   534     for (Link<Node> cursor = nodes; !cursor.isEmpty; cursor = cursor.tail) { |  | 
|   535       result++; |  | 
|   536     } |  | 
|   537     return result; |  | 
|   538   } |  | 
|   539  |  | 
|   540   accept(Visitor visitor) => visitor.visitNodeList(this); |  | 
|   541  |  | 
|   542   visitChildren(Visitor visitor) { |  | 
|   543     if (nodes == null) return; |  | 
|   544     for (Link<Node> link = nodes; !link.isEmpty; link = link.tail) { |  | 
|   545       if (link.head != null) link.head.accept(visitor); |  | 
|   546     } |  | 
|   547   } |  | 
|   548  |  | 
|   549   Token getBeginToken() { |  | 
|   550     if (beginToken != null) return beginToken; |  | 
|   551      if (nodes != null) { |  | 
|   552        for (Link<Node> link = nodes; !link.isEmpty; link = link.tail) { |  | 
|   553          if (link.head.getBeginToken() != null) { |  | 
|   554            return link.head.getBeginToken(); |  | 
|   555          } |  | 
|   556          if (link.head.getEndToken() != null) { |  | 
|   557            return link.head.getEndToken(); |  | 
|   558          } |  | 
|   559        } |  | 
|   560      } |  | 
|   561     return endToken; |  | 
|   562   } |  | 
|   563  |  | 
|   564   Token getEndToken() { |  | 
|   565     if (endToken != null) return endToken; |  | 
|   566     if (nodes != null) { |  | 
|   567       Link<Node> link = nodes; |  | 
|   568       if (link.isEmpty) return beginToken; |  | 
|   569       while (!link.tail.isEmpty) link = link.tail; |  | 
|   570       Node lastNode = link.head; |  | 
|   571       if (lastNode != null) { |  | 
|   572         if (lastNode.getEndToken() != null) return lastNode.getEndToken(); |  | 
|   573         if (lastNode.getBeginToken() != null) return lastNode.getBeginToken(); |  | 
|   574       } |  | 
|   575     } |  | 
|   576     return beginToken; |  | 
|   577   } |  | 
|   578 } |  | 
|   579  |  | 
|   580 class Block extends Statement { |  | 
|   581   final NodeList statements; |  | 
|   582  |  | 
|   583   Block(this.statements); |  | 
|   584  |  | 
|   585   Block asBlock() => this; |  | 
|   586  |  | 
|   587   accept(Visitor visitor) => visitor.visitBlock(this); |  | 
|   588  |  | 
|   589   visitChildren(Visitor visitor) { |  | 
|   590     if (statements != null) statements.accept(visitor); |  | 
|   591   } |  | 
|   592  |  | 
|   593   Token getBeginToken() => statements.getBeginToken(); |  | 
|   594  |  | 
|   595   Token getEndToken() => statements.getEndToken(); |  | 
|   596 } |  | 
|   597  |  | 
|   598 class If extends Statement { |  | 
|   599   final ParenthesizedExpression condition; |  | 
|   600   final Statement thenPart; |  | 
|   601   final Statement elsePart; |  | 
|   602  |  | 
|   603   final Token ifToken; |  | 
|   604   final Token elseToken; |  | 
|   605  |  | 
|   606   If(this.condition, this.thenPart, this.elsePart, |  | 
|   607      this.ifToken, this.elseToken); |  | 
|   608  |  | 
|   609   If asIf() => this; |  | 
|   610  |  | 
|   611   bool get hasElsePart => elsePart != null; |  | 
|   612  |  | 
|   613   accept(Visitor visitor) => visitor.visitIf(this); |  | 
|   614  |  | 
|   615   visitChildren(Visitor visitor) { |  | 
|   616     if (condition != null) condition.accept(visitor); |  | 
|   617     if (thenPart != null) thenPart.accept(visitor); |  | 
|   618     if (elsePart != null) elsePart.accept(visitor); |  | 
|   619   } |  | 
|   620  |  | 
|   621   Token getBeginToken() => ifToken; |  | 
|   622  |  | 
|   623   Token getEndToken() { |  | 
|   624     if (elsePart == null) return thenPart.getEndToken(); |  | 
|   625     return elsePart.getEndToken(); |  | 
|   626   } |  | 
|   627 } |  | 
|   628  |  | 
|   629 class Conditional extends Expression { |  | 
|   630   final Expression condition; |  | 
|   631   final Expression thenExpression; |  | 
|   632   final Expression elseExpression; |  | 
|   633  |  | 
|   634   final Token questionToken; |  | 
|   635   final Token colonToken; |  | 
|   636  |  | 
|   637   Conditional(this.condition, this.thenExpression, |  | 
|   638               this.elseExpression, this.questionToken, this.colonToken); |  | 
|   639  |  | 
|   640   Conditional asConditional() => this; |  | 
|   641  |  | 
|   642   accept(Visitor visitor) => visitor.visitConditional(this); |  | 
|   643  |  | 
|   644   visitChildren(Visitor visitor) { |  | 
|   645     condition.accept(visitor); |  | 
|   646     thenExpression.accept(visitor); |  | 
|   647     elseExpression.accept(visitor); |  | 
|   648   } |  | 
|   649  |  | 
|   650   Token getBeginToken() => condition.getBeginToken(); |  | 
|   651  |  | 
|   652   Token getEndToken() => elseExpression.getEndToken(); |  | 
|   653 } |  | 
|   654  |  | 
|   655 class For extends Loop { |  | 
|   656   /** Either a variable declaration or an expression. */ |  | 
|   657   final Node initializer; |  | 
|   658   /** Either an expression statement or an empty statement. */ |  | 
|   659   final Statement conditionStatement; |  | 
|   660   final NodeList update; |  | 
|   661  |  | 
|   662   final Token forToken; |  | 
|   663  |  | 
|   664   For(this.initializer, this.conditionStatement, this.update, body, |  | 
|   665       this.forToken) : super(body); |  | 
|   666  |  | 
|   667   For asFor() => this; |  | 
|   668  |  | 
|   669   Expression get condition { |  | 
|   670     if (conditionStatement is ExpressionStatement) { |  | 
|   671       return conditionStatement.asExpressionStatement().expression; |  | 
|   672     } else { |  | 
|   673       return null; |  | 
|   674     } |  | 
|   675   } |  | 
|   676  |  | 
|   677   accept(Visitor visitor) => visitor.visitFor(this); |  | 
|   678  |  | 
|   679   visitChildren(Visitor visitor) { |  | 
|   680     if (initializer != null) initializer.accept(visitor); |  | 
|   681     if (conditionStatement != null) conditionStatement.accept(visitor); |  | 
|   682     if (update != null) update.accept(visitor); |  | 
|   683     if (body != null) body.accept(visitor); |  | 
|   684   } |  | 
|   685  |  | 
|   686   Token getBeginToken() => forToken; |  | 
|   687  |  | 
|   688   Token getEndToken() { |  | 
|   689     return body.getEndToken(); |  | 
|   690   } |  | 
|   691 } |  | 
|   692  |  | 
|   693 class FunctionDeclaration extends Statement { |  | 
|   694   final FunctionExpression function; |  | 
|   695  |  | 
|   696   FunctionDeclaration(this.function); |  | 
|   697  |  | 
|   698   FunctionDeclaration asFunctionDeclaration() => this; |  | 
|   699  |  | 
|   700   accept(Visitor visitor) => visitor.visitFunctionDeclaration(this); |  | 
|   701  |  | 
|   702   visitChildren(Visitor visitor) => function.accept(visitor); |  | 
|   703  |  | 
|   704   Token getBeginToken() => function.getBeginToken(); |  | 
|   705   Token getEndToken() => function.getEndToken(); |  | 
|   706 } |  | 
|   707  |  | 
|   708 class FunctionExpression extends Expression with StoredTreeElementMixin { |  | 
|   709   final Node name; |  | 
|   710  |  | 
|   711   /** |  | 
|   712    * List of VariableDefinitions or NodeList. |  | 
|   713    * |  | 
|   714    * A NodeList can only occur at the end and holds named parameters. |  | 
|   715    */ |  | 
|   716   final NodeList parameters; |  | 
|   717  |  | 
|   718   final Statement body; |  | 
|   719   final TypeAnnotation returnType; |  | 
|   720   final Modifiers modifiers; |  | 
|   721   final NodeList initializers; |  | 
|   722  |  | 
|   723   final Token getOrSet; |  | 
|   724  |  | 
|   725   FunctionExpression(this.name, this.parameters, this.body, this.returnType, |  | 
|   726                      this.modifiers, this.initializers, this.getOrSet) { |  | 
|   727     assert(modifiers != null); |  | 
|   728   } |  | 
|   729  |  | 
|   730   FunctionExpression asFunctionExpression() => this; |  | 
|   731  |  | 
|   732   accept(Visitor visitor) => visitor.visitFunctionExpression(this); |  | 
|   733  |  | 
|   734   bool get isRedirectingFactory { |  | 
|   735     return body != null && body.asRedirectingFactoryBody() != null; |  | 
|   736   } |  | 
|   737  |  | 
|   738   visitChildren(Visitor visitor) { |  | 
|   739     if (modifiers != null) modifiers.accept(visitor); |  | 
|   740     if (returnType != null) returnType.accept(visitor); |  | 
|   741     if (name != null) name.accept(visitor); |  | 
|   742     if (parameters != null) parameters.accept(visitor); |  | 
|   743     if (initializers != null) initializers.accept(visitor); |  | 
|   744     if (body != null) body.accept(visitor); |  | 
|   745   } |  | 
|   746  |  | 
|   747   bool hasBody() => body.asEmptyStatement() == null; |  | 
|   748  |  | 
|   749   bool hasEmptyBody() { |  | 
|   750     Block block = body.asBlock(); |  | 
|   751     if (block == null) return false; |  | 
|   752     return block.statements.isEmpty; |  | 
|   753   } |  | 
|   754  |  | 
|   755   Token getBeginToken() { |  | 
|   756     Token token = firstBeginToken(modifiers, returnType); |  | 
|   757     if (token != null) return token; |  | 
|   758     if (getOrSet != null) return getOrSet; |  | 
|   759     return firstBeginToken(name, parameters); |  | 
|   760   } |  | 
|   761  |  | 
|   762   Token getEndToken() { |  | 
|   763     Token token = (body == null) ? null : body.getEndToken(); |  | 
|   764     token = (token == null) ? parameters.getEndToken() : token; |  | 
|   765     return (token == null) ? name.getEndToken() : token; |  | 
|   766   } |  | 
|   767 } |  | 
|   768  |  | 
|   769 typedef void DecodeErrorHandler(Token token, var error); |  | 
|   770  |  | 
|   771 abstract class Literal<T> extends Expression { |  | 
|   772   final Token token; |  | 
|   773   final DecodeErrorHandler handler; |  | 
|   774  |  | 
|   775   Literal(Token this.token, DecodeErrorHandler this.handler); |  | 
|   776  |  | 
|   777   T get value; |  | 
|   778  |  | 
|   779   visitChildren(Visitor visitor) {} |  | 
|   780  |  | 
|   781   Token getBeginToken() => token; |  | 
|   782  |  | 
|   783   Token getEndToken() => token; |  | 
|   784 } |  | 
|   785  |  | 
|   786 class LiteralInt extends Literal<int> { |  | 
|   787   LiteralInt(Token token, DecodeErrorHandler handler) : super(token, handler); |  | 
|   788  |  | 
|   789   LiteralInt asLiteralInt() => this; |  | 
|   790  |  | 
|   791   int get value { |  | 
|   792     try { |  | 
|   793       Token valueToken = token; |  | 
|   794       if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next; |  | 
|   795       return int.parse(valueToken.value); |  | 
|   796     } on FormatException catch (ex) { |  | 
|   797       (this.handler)(token, ex); |  | 
|   798     } |  | 
|   799   } |  | 
|   800  |  | 
|   801   accept(Visitor visitor) => visitor.visitLiteralInt(this); |  | 
|   802 } |  | 
|   803  |  | 
|   804 class LiteralDouble extends Literal<double> { |  | 
|   805   LiteralDouble(Token token, DecodeErrorHandler handler) |  | 
|   806     : super(token, handler); |  | 
|   807  |  | 
|   808   LiteralDouble asLiteralDouble() => this; |  | 
|   809  |  | 
|   810   double get value { |  | 
|   811     try { |  | 
|   812       Token valueToken = token; |  | 
|   813       if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next; |  | 
|   814       return double.parse(valueToken.value); |  | 
|   815     } on FormatException catch (ex) { |  | 
|   816       (this.handler)(token, ex); |  | 
|   817     } |  | 
|   818   } |  | 
|   819  |  | 
|   820   accept(Visitor visitor) => visitor.visitLiteralDouble(this); |  | 
|   821 } |  | 
|   822  |  | 
|   823 class LiteralBool extends Literal<bool> { |  | 
|   824   LiteralBool(Token token, DecodeErrorHandler handler) : super(token, handler); |  | 
|   825  |  | 
|   826   LiteralBool asLiteralBool() => this; |  | 
|   827  |  | 
|   828   bool get value { |  | 
|   829     if (identical(token.stringValue, 'true')) return true; |  | 
|   830     if (identical(token.stringValue, 'false')) return false; |  | 
|   831     (this.handler)(token, "not a bool ${token.value}"); |  | 
|   832     throw false; |  | 
|   833   } |  | 
|   834  |  | 
|   835   accept(Visitor visitor) => visitor.visitLiteralBool(this); |  | 
|   836 } |  | 
|   837  |  | 
|   838  |  | 
|   839 class StringQuoting { |  | 
|   840  |  | 
|   841   /// Cache of common quotings. |  | 
|   842   static const List<StringQuoting> _mapping = const <StringQuoting>[ |  | 
|   843     const StringQuoting($SQ, raw: false, leftQuoteLength: 1), |  | 
|   844     const StringQuoting($SQ, raw: true, leftQuoteLength: 1), |  | 
|   845     const StringQuoting($DQ, raw: false, leftQuoteLength: 1), |  | 
|   846     const StringQuoting($DQ, raw: true, leftQuoteLength: 1), |  | 
|   847     // No string quotes with 2 characters. |  | 
|   848     null, |  | 
|   849     null, |  | 
|   850     null, |  | 
|   851     null, |  | 
|   852     // Multiline quotings. |  | 
|   853     const StringQuoting($SQ, raw: false, leftQuoteLength: 3), |  | 
|   854     const StringQuoting($SQ, raw: true, leftQuoteLength: 3), |  | 
|   855     const StringQuoting($DQ, raw: false, leftQuoteLength: 3), |  | 
|   856     const StringQuoting($DQ, raw: true, leftQuoteLength: 3), |  | 
|   857     // Leading single whitespace or espaped newline. |  | 
|   858     const StringQuoting($SQ, raw: false, leftQuoteLength: 4), |  | 
|   859     const StringQuoting($SQ, raw: true, leftQuoteLength: 4), |  | 
|   860     const StringQuoting($DQ, raw: false, leftQuoteLength: 4), |  | 
|   861     const StringQuoting($DQ, raw: true, leftQuoteLength: 4), |  | 
|   862     // Other combinations of leading whitespace and/or escaped newline. |  | 
|   863     const StringQuoting($SQ, raw: false, leftQuoteLength: 5), |  | 
|   864     const StringQuoting($SQ, raw: true, leftQuoteLength: 5), |  | 
|   865     const StringQuoting($DQ, raw: false, leftQuoteLength: 5), |  | 
|   866     const StringQuoting($DQ, raw: true, leftQuoteLength: 5), |  | 
|   867     const StringQuoting($SQ, raw: false, leftQuoteLength: 6), |  | 
|   868     const StringQuoting($SQ, raw: true, leftQuoteLength: 6), |  | 
|   869     const StringQuoting($DQ, raw: false, leftQuoteLength: 6), |  | 
|   870     const StringQuoting($DQ, raw: true, leftQuoteLength: 6) |  | 
|   871   ]; |  | 
|   872  |  | 
|   873   final bool raw; |  | 
|   874   final int leftQuoteCharCount; |  | 
|   875   final int quote; |  | 
|   876   const StringQuoting(this.quote, { this.raw, int leftQuoteLength }) |  | 
|   877       : this.leftQuoteCharCount = leftQuoteLength; |  | 
|   878   String get quoteChar => identical(quote, $DQ) ? '"' : "'"; |  | 
|   879  |  | 
|   880   int get leftQuoteLength => (raw ? 1 : 0) + leftQuoteCharCount; |  | 
|   881   int get rightQuoteLength => (leftQuoteCharCount > 2) ? 3 : 1; |  | 
|   882   static StringQuoting getQuoting(int quote, bool raw, int leftQuoteLength) { |  | 
|   883     int quoteKindOffset = (quote == $DQ) ? 2 : 0; |  | 
|   884     int rawOffset = raw ? 1 : 0; |  | 
|   885     int index = (leftQuoteLength - 1) * 4 + rawOffset + quoteKindOffset; |  | 
|   886     if (index < _mapping.length) return _mapping[index]; |  | 
|   887     return new StringQuoting(quote, raw: raw, leftQuoteLength: leftQuoteLength); |  | 
|   888   } |  | 
|   889 } |  | 
|   890  |  | 
|   891 /** |  | 
|   892   * Superclass for classes representing string literals. |  | 
|   893   */ |  | 
|   894 abstract class StringNode extends Expression { |  | 
|   895   DartString get dartString; |  | 
|   896   bool get isInterpolation; |  | 
|   897  |  | 
|   898   StringNode asStringNode() => this; |  | 
|   899 } |  | 
|   900  |  | 
|   901 class LiteralString extends StringNode { |  | 
|   902   final Token token; |  | 
|   903   /** Non-null on validated string literals. */ |  | 
|   904   final DartString dartString; |  | 
|   905  |  | 
|   906   LiteralString(this.token, this.dartString); |  | 
|   907  |  | 
|   908   LiteralString asLiteralString() => this; |  | 
|   909  |  | 
|   910   void visitChildren(Visitor visitor) {} |  | 
|   911  |  | 
|   912   bool get isInterpolation => false; |  | 
|   913  |  | 
|   914   Token getBeginToken() => token; |  | 
|   915   Token getEndToken() => token; |  | 
|   916  |  | 
|   917   accept(Visitor visitor) => visitor.visitLiteralString(this); |  | 
|   918 } |  | 
|   919  |  | 
|   920 class LiteralNull extends Literal<String> { |  | 
|   921   LiteralNull(Token token) : super(token, null); |  | 
|   922  |  | 
|   923   LiteralNull asLiteralNull() => this; |  | 
|   924  |  | 
|   925   String get value => null; |  | 
|   926  |  | 
|   927   accept(Visitor visitor) => visitor.visitLiteralNull(this); |  | 
|   928 } |  | 
|   929  |  | 
|   930 class LiteralList extends Expression { |  | 
|   931   final NodeList typeArguments; |  | 
|   932   final NodeList elements; |  | 
|   933  |  | 
|   934   final Token constKeyword; |  | 
|   935  |  | 
|   936   LiteralList(this.typeArguments, this.elements, this.constKeyword); |  | 
|   937  |  | 
|   938   bool get isConst => constKeyword != null; |  | 
|   939  |  | 
|   940   LiteralList asLiteralList() => this; |  | 
|   941   accept(Visitor visitor) => visitor.visitLiteralList(this); |  | 
|   942  |  | 
|   943   visitChildren(Visitor visitor) { |  | 
|   944     if (typeArguments != null) typeArguments.accept(visitor); |  | 
|   945     elements.accept(visitor); |  | 
|   946   } |  | 
|   947  |  | 
|   948   Token getBeginToken() { |  | 
|   949     if (constKeyword != null) return constKeyword; |  | 
|   950     return firstBeginToken(typeArguments, elements); |  | 
|   951   } |  | 
|   952  |  | 
|   953   Token getEndToken() => elements.getEndToken(); |  | 
|   954 } |  | 
|   955  |  | 
|   956 class LiteralSymbol extends Expression { |  | 
|   957   final Token hashToken; |  | 
|   958   final NodeList identifiers; |  | 
|   959  |  | 
|   960   LiteralSymbol(this.hashToken, this.identifiers); |  | 
|   961  |  | 
|   962   LiteralSymbol asLiteralSymbol() => this; |  | 
|   963  |  | 
|   964   void visitChildren(Visitor visitor) { |  | 
|   965     if (identifiers != null) identifiers.accept(visitor); |  | 
|   966   } |  | 
|   967  |  | 
|   968   accept(Visitor visitor) => visitor.visitLiteralSymbol(this); |  | 
|   969  |  | 
|   970   Token getBeginToken() => hashToken; |  | 
|   971  |  | 
|   972   Token getEndToken() => identifiers.getEndToken(); |  | 
|   973  |  | 
|   974   String get slowNameString { |  | 
|   975     Unparser unparser = new Unparser(); |  | 
|   976     unparser.unparseNodeListOfIdentifiers(identifiers); |  | 
|   977     return unparser.result; |  | 
|   978   } |  | 
|   979 } |  | 
|   980  |  | 
|   981 class Identifier extends Expression with StoredTreeElementMixin { |  | 
|   982   final Token token; |  | 
|   983  |  | 
|   984   String get source => token.value; |  | 
|   985  |  | 
|   986   Identifier(Token this.token); |  | 
|   987  |  | 
|   988   bool isThis() => identical(source, 'this'); |  | 
|   989  |  | 
|   990   bool isSuper() => identical(source, 'super'); |  | 
|   991  |  | 
|   992   Identifier asIdentifier() => this; |  | 
|   993  |  | 
|   994   accept(Visitor visitor) => visitor.visitIdentifier(this); |  | 
|   995  |  | 
|   996   visitChildren(Visitor visitor) {} |  | 
|   997  |  | 
|   998   Token getBeginToken() => token; |  | 
|   999  |  | 
|  1000   Token getEndToken() => token; |  | 
|  1001 } |  | 
|  1002  |  | 
|  1003 class Operator extends Identifier { |  | 
|  1004   static const COMPLEX_OPERATORS = |  | 
|  1005       const ["--", "++", '+=', "-=", "*=", "/=", "%=", "&=", "|=", "~/=", "^=", |  | 
|  1006              ">>=", "<<="]; |  | 
|  1007  |  | 
|  1008   static const INCREMENT_OPERATORS = const <String>["++", "--"]; |  | 
|  1009  |  | 
|  1010   Operator(Token token) : super(token); |  | 
|  1011  |  | 
|  1012   Operator asOperator() => this; |  | 
|  1013  |  | 
|  1014   accept(Visitor visitor) => visitor.visitOperator(this); |  | 
|  1015 } |  | 
|  1016  |  | 
|  1017 class Return extends Statement { |  | 
|  1018   final Node expression; |  | 
|  1019   final Token beginToken; |  | 
|  1020   final Token endToken; |  | 
|  1021  |  | 
|  1022   Return(this.beginToken, this.endToken, this.expression); |  | 
|  1023  |  | 
|  1024   Return asReturn() => this; |  | 
|  1025  |  | 
|  1026   bool get hasExpression => expression != null; |  | 
|  1027  |  | 
|  1028   accept(Visitor visitor) => visitor.visitReturn(this); |  | 
|  1029  |  | 
|  1030   visitChildren(Visitor visitor) { |  | 
|  1031     if (expression != null) expression.accept(visitor); |  | 
|  1032   } |  | 
|  1033  |  | 
|  1034   Token getBeginToken() => beginToken; |  | 
|  1035  |  | 
|  1036   Token getEndToken() { |  | 
|  1037     if (endToken == null) return expression.getEndToken(); |  | 
|  1038     return endToken; |  | 
|  1039   } |  | 
|  1040 } |  | 
|  1041  |  | 
|  1042 class RedirectingFactoryBody extends Statement with StoredTreeElementMixin { |  | 
|  1043   final Node constructorReference; |  | 
|  1044   final Token beginToken; |  | 
|  1045   final Token endToken; |  | 
|  1046  |  | 
|  1047   RedirectingFactoryBody(this.beginToken, this.endToken, |  | 
|  1048                          this.constructorReference); |  | 
|  1049  |  | 
|  1050   RedirectingFactoryBody asRedirectingFactoryBody() => this; |  | 
|  1051  |  | 
|  1052   accept(Visitor visitor) => visitor.visitRedirectingFactoryBody(this); |  | 
|  1053  |  | 
|  1054   visitChildren(Visitor visitor) { |  | 
|  1055     constructorReference.accept(visitor); |  | 
|  1056   } |  | 
|  1057  |  | 
|  1058   Token getBeginToken() => beginToken; |  | 
|  1059  |  | 
|  1060   Token getEndToken() => endToken; |  | 
|  1061 } |  | 
|  1062  |  | 
|  1063 class ExpressionStatement extends Statement { |  | 
|  1064   final Expression expression; |  | 
|  1065   final Token endToken; |  | 
|  1066  |  | 
|  1067   ExpressionStatement(this.expression, this.endToken); |  | 
|  1068  |  | 
|  1069   ExpressionStatement asExpressionStatement() => this; |  | 
|  1070  |  | 
|  1071   accept(Visitor visitor) => visitor.visitExpressionStatement(this); |  | 
|  1072  |  | 
|  1073   visitChildren(Visitor visitor) { |  | 
|  1074     if (expression != null) expression.accept(visitor); |  | 
|  1075   } |  | 
|  1076  |  | 
|  1077   Token getBeginToken() => expression.getBeginToken(); |  | 
|  1078  |  | 
|  1079   Token getEndToken() => endToken; |  | 
|  1080 } |  | 
|  1081  |  | 
|  1082 class Throw extends Expression { |  | 
|  1083   final Expression expression; |  | 
|  1084  |  | 
|  1085   final Token throwToken; |  | 
|  1086   final Token endToken; |  | 
|  1087  |  | 
|  1088   Throw(this.expression, this.throwToken, this.endToken); |  | 
|  1089  |  | 
|  1090   Throw asThrow() => this; |  | 
|  1091  |  | 
|  1092   accept(Visitor visitor) => visitor.visitThrow(this); |  | 
|  1093  |  | 
|  1094   visitChildren(Visitor visitor) { |  | 
|  1095     expression.accept(visitor); |  | 
|  1096   } |  | 
|  1097  |  | 
|  1098   Token getBeginToken() => throwToken; |  | 
|  1099  |  | 
|  1100   Token getEndToken() => endToken; |  | 
|  1101 } |  | 
|  1102  |  | 
|  1103 class Rethrow extends Statement { |  | 
|  1104   final Token throwToken; |  | 
|  1105   final Token endToken; |  | 
|  1106  |  | 
|  1107   Rethrow(this.throwToken, this.endToken); |  | 
|  1108  |  | 
|  1109   Rethrow asRethrow() => this; |  | 
|  1110  |  | 
|  1111   accept(Visitor visitor) => visitor.visitRethrow(this); |  | 
|  1112   visitChildren(Visitor visitor) { } |  | 
|  1113  |  | 
|  1114   Token getBeginToken() => throwToken; |  | 
|  1115   Token getEndToken() => endToken; |  | 
|  1116 } |  | 
|  1117  |  | 
|  1118 class TypeAnnotation extends Node { |  | 
|  1119   final Expression typeName; |  | 
|  1120   final NodeList typeArguments; |  | 
|  1121  |  | 
|  1122   TypeAnnotation(Expression this.typeName, NodeList this.typeArguments); |  | 
|  1123  |  | 
|  1124   TypeAnnotation asTypeAnnotation() => this; |  | 
|  1125  |  | 
|  1126   accept(Visitor visitor) => visitor.visitTypeAnnotation(this); |  | 
|  1127  |  | 
|  1128   visitChildren(Visitor visitor) { |  | 
|  1129     typeName.accept(visitor); |  | 
|  1130     if (typeArguments != null) typeArguments.accept(visitor); |  | 
|  1131   } |  | 
|  1132  |  | 
|  1133   Token getBeginToken() => typeName.getBeginToken(); |  | 
|  1134  |  | 
|  1135   Token getEndToken() => typeName.getEndToken(); |  | 
|  1136 } |  | 
|  1137  |  | 
|  1138 class TypeVariable extends Node { |  | 
|  1139   final Identifier name; |  | 
|  1140   final TypeAnnotation bound; |  | 
|  1141   TypeVariable(Identifier this.name, TypeAnnotation this.bound); |  | 
|  1142  |  | 
|  1143   accept(Visitor visitor) => visitor.visitTypeVariable(this); |  | 
|  1144  |  | 
|  1145   visitChildren(Visitor visitor) { |  | 
|  1146     name.accept(visitor); |  | 
|  1147     if (bound != null) { |  | 
|  1148       bound.accept(visitor); |  | 
|  1149     } |  | 
|  1150   } |  | 
|  1151  |  | 
|  1152   TypeVariable asTypeVariable() => this; |  | 
|  1153  |  | 
|  1154   Token getBeginToken() => name.getBeginToken(); |  | 
|  1155  |  | 
|  1156   Token getEndToken() { |  | 
|  1157     return (bound != null) ? bound.getEndToken() : name.getEndToken(); |  | 
|  1158   } |  | 
|  1159 } |  | 
|  1160  |  | 
|  1161 class VariableDefinitions extends Statement { |  | 
|  1162   final NodeList metadata; |  | 
|  1163   final TypeAnnotation type; |  | 
|  1164   final Modifiers modifiers; |  | 
|  1165   final NodeList definitions; |  | 
|  1166  |  | 
|  1167   VariableDefinitions(this.type, |  | 
|  1168                       this.modifiers, |  | 
|  1169                       this.definitions) |  | 
|  1170       : this.metadata = null { |  | 
|  1171     assert(modifiers != null); |  | 
|  1172   } |  | 
|  1173  |  | 
|  1174   // TODO(johnniwinther): Make this its own node type. |  | 
|  1175   VariableDefinitions.forParameter(this.metadata, |  | 
|  1176                                    this.type, |  | 
|  1177                                    this.modifiers, |  | 
|  1178                                    this.definitions) { |  | 
|  1179     assert(modifiers != null); |  | 
|  1180   } |  | 
|  1181  |  | 
|  1182   VariableDefinitions asVariableDefinitions() => this; |  | 
|  1183  |  | 
|  1184   accept(Visitor visitor) => visitor.visitVariableDefinitions(this); |  | 
|  1185  |  | 
|  1186   visitChildren(Visitor visitor) { |  | 
|  1187     if (metadata != null) metadata.accept(visitor); |  | 
|  1188     if (type != null) type.accept(visitor); |  | 
|  1189     if (definitions != null) definitions.accept(visitor); |  | 
|  1190   } |  | 
|  1191  |  | 
|  1192   Token getBeginToken() { |  | 
|  1193     var token = firstBeginToken(modifiers, type); |  | 
|  1194     if (token == null) { |  | 
|  1195       token = definitions.getBeginToken(); |  | 
|  1196     } |  | 
|  1197     return token; |  | 
|  1198   } |  | 
|  1199  |  | 
|  1200   Token getEndToken() => definitions.getEndToken(); |  | 
|  1201 } |  | 
|  1202  |  | 
|  1203 abstract class Loop extends Statement { |  | 
|  1204   Expression get condition; |  | 
|  1205   final Statement body; |  | 
|  1206  |  | 
|  1207   Loop(this.body); |  | 
|  1208  |  | 
|  1209   bool isValidContinueTarget() => true; |  | 
|  1210 } |  | 
|  1211  |  | 
|  1212 class DoWhile extends Loop { |  | 
|  1213   final Token doKeyword; |  | 
|  1214   final Token whileKeyword; |  | 
|  1215   final Token endToken; |  | 
|  1216  |  | 
|  1217   final Expression condition; |  | 
|  1218  |  | 
|  1219   DoWhile(Statement body, Expression this.condition, |  | 
|  1220           Token this.doKeyword, Token this.whileKeyword, Token this.endToken) |  | 
|  1221     : super(body); |  | 
|  1222  |  | 
|  1223   DoWhile asDoWhile() => this; |  | 
|  1224  |  | 
|  1225   accept(Visitor visitor) => visitor.visitDoWhile(this); |  | 
|  1226  |  | 
|  1227   visitChildren(Visitor visitor) { |  | 
|  1228     if (condition != null) condition.accept(visitor); |  | 
|  1229     if (body != null) body.accept(visitor); |  | 
|  1230   } |  | 
|  1231  |  | 
|  1232   Token getBeginToken() => doKeyword; |  | 
|  1233  |  | 
|  1234   Token getEndToken() => endToken; |  | 
|  1235 } |  | 
|  1236  |  | 
|  1237 class While extends Loop { |  | 
|  1238   final Token whileKeyword; |  | 
|  1239   final Expression condition; |  | 
|  1240  |  | 
|  1241   While(Expression this.condition, Statement body, |  | 
|  1242         Token this.whileKeyword) : super(body); |  | 
|  1243  |  | 
|  1244   While asWhile() => this; |  | 
|  1245  |  | 
|  1246   accept(Visitor visitor) => visitor.visitWhile(this); |  | 
|  1247  |  | 
|  1248   visitChildren(Visitor visitor) { |  | 
|  1249     if (condition != null) condition.accept(visitor); |  | 
|  1250     if (body != null) body.accept(visitor); |  | 
|  1251   } |  | 
|  1252  |  | 
|  1253   Token getBeginToken() => whileKeyword; |  | 
|  1254  |  | 
|  1255   Token getEndToken() => body.getEndToken(); |  | 
|  1256 } |  | 
|  1257  |  | 
|  1258 class ParenthesizedExpression extends Expression { |  | 
|  1259   final Expression expression; |  | 
|  1260   final BeginGroupToken beginToken; |  | 
|  1261  |  | 
|  1262   ParenthesizedExpression(Expression this.expression, |  | 
|  1263                           BeginGroupToken this.beginToken); |  | 
|  1264  |  | 
|  1265   ParenthesizedExpression asParenthesizedExpression() => this; |  | 
|  1266  |  | 
|  1267   accept(Visitor visitor) => visitor.visitParenthesizedExpression(this); |  | 
|  1268  |  | 
|  1269   visitChildren(Visitor visitor) { |  | 
|  1270     if (expression != null) expression.accept(visitor); |  | 
|  1271   } |  | 
|  1272  |  | 
|  1273   Token getBeginToken() => beginToken; |  | 
|  1274  |  | 
|  1275   Token getEndToken() => beginToken.endGroup; |  | 
|  1276 } |  | 
|  1277  |  | 
|  1278 /** Representation of modifiers such as static, abstract, final, etc. */ |  | 
|  1279 class Modifiers extends Node { |  | 
|  1280   /** |  | 
|  1281    * Pseudo-constant for empty modifiers. |  | 
|  1282    */ |  | 
|  1283   static final Modifiers EMPTY = new Modifiers(new NodeList.empty()); |  | 
|  1284  |  | 
|  1285   /* TODO(ahe): The following should be validated relating to modifiers: |  | 
|  1286    * 1. The nodes must come in a certain order. |  | 
|  1287    * 2. The keywords "var" and "final" may not be used at the same time. |  | 
|  1288    * 3. The keywords "abstract" and "external" may not be used at the same time. |  | 
|  1289    * 4. The type of an element must be null if isVar() is true. |  | 
|  1290    */ |  | 
|  1291  |  | 
|  1292   final NodeList nodes; |  | 
|  1293   /** Bit pattern to easy check what modifiers are present. */ |  | 
|  1294   final int flags; |  | 
|  1295  |  | 
|  1296   static const int FLAG_STATIC = 1; |  | 
|  1297   static const int FLAG_ABSTRACT = FLAG_STATIC << 1; |  | 
|  1298   static const int FLAG_FINAL = FLAG_ABSTRACT << 1; |  | 
|  1299   static const int FLAG_VAR = FLAG_FINAL << 1; |  | 
|  1300   static const int FLAG_CONST = FLAG_VAR << 1; |  | 
|  1301   static const int FLAG_FACTORY = FLAG_CONST << 1; |  | 
|  1302   static const int FLAG_EXTERNAL = FLAG_FACTORY << 1; |  | 
|  1303  |  | 
|  1304   Modifiers(NodeList nodes) : this.withFlags(nodes, computeFlags(nodes.nodes)); |  | 
|  1305  |  | 
|  1306   Modifiers.withFlags(this.nodes, this.flags); |  | 
|  1307  |  | 
|  1308   static int computeFlags(Link<Node> nodes) { |  | 
|  1309     int flags = 0; |  | 
|  1310     for (; !nodes.isEmpty; nodes = nodes.tail) { |  | 
|  1311       String value = nodes.head.asIdentifier().source; |  | 
|  1312       if (identical(value, 'static')) flags |= FLAG_STATIC; |  | 
|  1313       else if (identical(value, 'abstract')) flags |= FLAG_ABSTRACT; |  | 
|  1314       else if (identical(value, 'final')) flags |= FLAG_FINAL; |  | 
|  1315       else if (identical(value, 'var')) flags |= FLAG_VAR; |  | 
|  1316       else if (identical(value, 'const')) flags |= FLAG_CONST; |  | 
|  1317       else if (identical(value, 'factory')) flags |= FLAG_FACTORY; |  | 
|  1318       else if (identical(value, 'external')) flags |= FLAG_EXTERNAL; |  | 
|  1319       else throw 'internal error: ${nodes.head}'; |  | 
|  1320     } |  | 
|  1321     return flags; |  | 
|  1322   } |  | 
|  1323  |  | 
|  1324   Node findModifier(String modifier) { |  | 
|  1325     Link<Node> nodeList = nodes.nodes; |  | 
|  1326     for (; !nodeList.isEmpty; nodeList = nodeList.tail) { |  | 
|  1327       String value = nodeList.head.asIdentifier().source; |  | 
|  1328       if(identical(value, modifier)) { |  | 
|  1329         return nodeList.head; |  | 
|  1330       } |  | 
|  1331     } |  | 
|  1332     return null; |  | 
|  1333   } |  | 
|  1334  |  | 
|  1335   Modifiers asModifiers() => this; |  | 
|  1336   Token getBeginToken() => nodes.getBeginToken(); |  | 
|  1337   Token getEndToken() => nodes.getEndToken(); |  | 
|  1338   accept(Visitor visitor) => visitor.visitModifiers(this); |  | 
|  1339   visitChildren(Visitor visitor) => nodes.accept(visitor); |  | 
|  1340  |  | 
|  1341   bool get isStatic => (flags & FLAG_STATIC) != 0; |  | 
|  1342   bool get isAbstract => (flags & FLAG_ABSTRACT) != 0; |  | 
|  1343   bool get isFinal => (flags & FLAG_FINAL) != 0; |  | 
|  1344   bool get isVar => (flags & FLAG_VAR) != 0; |  | 
|  1345   bool get isConst => (flags & FLAG_CONST) != 0; |  | 
|  1346   bool get isFactory => (flags & FLAG_FACTORY) != 0; |  | 
|  1347   bool get isExternal => (flags & FLAG_EXTERNAL) != 0; |  | 
|  1348  |  | 
|  1349   Node getStatic() => findModifier('static'); |  | 
|  1350  |  | 
|  1351   /** |  | 
|  1352    * Use this to check if the declaration is either explicitly or implicitly |  | 
|  1353    * final. |  | 
|  1354    */ |  | 
|  1355   bool get isFinalOrConst => isFinal || isConst; |  | 
|  1356  |  | 
|  1357   String toString() { |  | 
|  1358     return modifiersToString(isStatic: isStatic, |  | 
|  1359                              isAbstract: isAbstract, |  | 
|  1360                              isFinal: isFinal, |  | 
|  1361                              isVar: isVar, |  | 
|  1362                              isConst: isConst, |  | 
|  1363                              isFactory: isFactory, |  | 
|  1364                              isExternal: isExternal); |  | 
|  1365   } |  | 
|  1366 } |  | 
|  1367  |  | 
|  1368 class StringInterpolation extends StringNode { |  | 
|  1369   final LiteralString string; |  | 
|  1370   final NodeList parts; |  | 
|  1371  |  | 
|  1372   StringInterpolation(this.string, this.parts); |  | 
|  1373  |  | 
|  1374   StringInterpolation asStringInterpolation() => this; |  | 
|  1375  |  | 
|  1376   DartString get dartString => null; |  | 
|  1377   bool get isInterpolation => true; |  | 
|  1378  |  | 
|  1379   accept(Visitor visitor) => visitor.visitStringInterpolation(this); |  | 
|  1380  |  | 
|  1381   visitChildren(Visitor visitor) { |  | 
|  1382     string.accept(visitor); |  | 
|  1383     parts.accept(visitor); |  | 
|  1384   } |  | 
|  1385  |  | 
|  1386   Token getBeginToken() => string.getBeginToken(); |  | 
|  1387   Token getEndToken() => parts.getEndToken(); |  | 
|  1388 } |  | 
|  1389  |  | 
|  1390 class StringInterpolationPart extends Node { |  | 
|  1391   final Expression expression; |  | 
|  1392   final LiteralString string; |  | 
|  1393  |  | 
|  1394   StringInterpolationPart(this.expression, this.string); |  | 
|  1395  |  | 
|  1396   StringInterpolationPart asStringInterpolationPart() => this; |  | 
|  1397  |  | 
|  1398   accept(Visitor visitor) => visitor.visitStringInterpolationPart(this); |  | 
|  1399  |  | 
|  1400   visitChildren(Visitor visitor) { |  | 
|  1401     expression.accept(visitor); |  | 
|  1402     string.accept(visitor); |  | 
|  1403   } |  | 
|  1404  |  | 
|  1405   Token getBeginToken() => expression.getBeginToken(); |  | 
|  1406  |  | 
|  1407   Token getEndToken() => string.getEndToken(); |  | 
|  1408 } |  | 
|  1409  |  | 
|  1410 /** |  | 
|  1411  * A class representing juxtaposed string literals. |  | 
|  1412  * The string literals can be both plain literals and string interpolations. |  | 
|  1413  */ |  | 
|  1414 class StringJuxtaposition extends StringNode { |  | 
|  1415   final Expression first; |  | 
|  1416   final Expression second; |  | 
|  1417  |  | 
|  1418   /** |  | 
|  1419    * Caches the check for whether this juxtaposition contains a string |  | 
|  1420    * interpolation |  | 
|  1421    */ |  | 
|  1422   bool isInterpolationCache = null; |  | 
|  1423  |  | 
|  1424   /** |  | 
|  1425    * Caches a Dart string representation of the entire juxtaposition's |  | 
|  1426    * content. Only juxtapositions that don't (transitively) contains |  | 
|  1427    * interpolations have a static representation. |  | 
|  1428    */ |  | 
|  1429   DartString dartStringCache = null; |  | 
|  1430  |  | 
|  1431   StringJuxtaposition(this.first, this.second); |  | 
|  1432  |  | 
|  1433   StringJuxtaposition asStringJuxtaposition() => this; |  | 
|  1434  |  | 
|  1435   bool get isInterpolation { |  | 
|  1436     if (isInterpolationCache == null) { |  | 
|  1437       isInterpolationCache = (first.accept(const IsInterpolationVisitor()) || |  | 
|  1438                           second.accept(const IsInterpolationVisitor())); |  | 
|  1439     } |  | 
|  1440     return isInterpolationCache; |  | 
|  1441   } |  | 
|  1442  |  | 
|  1443   /** |  | 
|  1444    * Retrieve a single DartString that represents this entire juxtaposition |  | 
|  1445    * of string literals. |  | 
|  1446    * Should only be called if [isInterpolation] returns false. |  | 
|  1447    */ |  | 
|  1448   DartString get dartString { |  | 
|  1449     if (isInterpolation) { |  | 
|  1450       throw new SpannableAssertionFailure( |  | 
|  1451           this, "Getting dartString on interpolation;"); |  | 
|  1452     } |  | 
|  1453     if (dartStringCache == null) { |  | 
|  1454       DartString firstString = first.accept(const GetDartStringVisitor()); |  | 
|  1455       DartString secondString = second.accept(const GetDartStringVisitor()); |  | 
|  1456       if (firstString == null || secondString == null) { |  | 
|  1457         return null; |  | 
|  1458       } |  | 
|  1459       dartStringCache = new DartString.concat(firstString, secondString); |  | 
|  1460     } |  | 
|  1461     return dartStringCache; |  | 
|  1462   } |  | 
|  1463  |  | 
|  1464   accept(Visitor visitor) => visitor.visitStringJuxtaposition(this); |  | 
|  1465  |  | 
|  1466   void visitChildren(Visitor visitor) { |  | 
|  1467     first.accept(visitor); |  | 
|  1468     second.accept(visitor); |  | 
|  1469   } |  | 
|  1470  |  | 
|  1471   Token getBeginToken() => first.getBeginToken(); |  | 
|  1472  |  | 
|  1473   Token getEndToken() => second.getEndToken(); |  | 
|  1474 } |  | 
|  1475  |  | 
|  1476 class EmptyStatement extends Statement { |  | 
|  1477   final Token semicolonToken; |  | 
|  1478  |  | 
|  1479   EmptyStatement(this.semicolonToken); |  | 
|  1480  |  | 
|  1481   EmptyStatement asEmptyStatement() => this; |  | 
|  1482  |  | 
|  1483   accept(Visitor visitor) => visitor.visitEmptyStatement(this); |  | 
|  1484  |  | 
|  1485   visitChildren(Visitor visitor) {} |  | 
|  1486  |  | 
|  1487   Token getBeginToken() => semicolonToken; |  | 
|  1488  |  | 
|  1489   Token getEndToken() => semicolonToken; |  | 
|  1490 } |  | 
|  1491  |  | 
|  1492 class LiteralMap extends Expression { |  | 
|  1493   final NodeList typeArguments; |  | 
|  1494   final NodeList entries; |  | 
|  1495  |  | 
|  1496   final Token constKeyword; |  | 
|  1497  |  | 
|  1498   LiteralMap(this.typeArguments, this.entries, this.constKeyword); |  | 
|  1499  |  | 
|  1500   bool get isConst => constKeyword != null; |  | 
|  1501  |  | 
|  1502   LiteralMap asLiteralMap() => this; |  | 
|  1503  |  | 
|  1504   accept(Visitor visitor) => visitor.visitLiteralMap(this); |  | 
|  1505  |  | 
|  1506   visitChildren(Visitor visitor) { |  | 
|  1507     if (typeArguments != null) typeArguments.accept(visitor); |  | 
|  1508     entries.accept(visitor); |  | 
|  1509   } |  | 
|  1510  |  | 
|  1511   Token getBeginToken() { |  | 
|  1512     if (constKeyword != null) return constKeyword; |  | 
|  1513     return firstBeginToken(typeArguments, entries); |  | 
|  1514   } |  | 
|  1515  |  | 
|  1516   Token getEndToken() => entries.getEndToken(); |  | 
|  1517 } |  | 
|  1518  |  | 
|  1519 class LiteralMapEntry extends Node { |  | 
|  1520   final Expression key; |  | 
|  1521   final Expression value; |  | 
|  1522  |  | 
|  1523   final Token colonToken; |  | 
|  1524  |  | 
|  1525   LiteralMapEntry(this.key, this.colonToken, this.value); |  | 
|  1526  |  | 
|  1527   LiteralMapEntry asLiteralMapEntry() => this; |  | 
|  1528  |  | 
|  1529   accept(Visitor visitor) => visitor.visitLiteralMapEntry(this); |  | 
|  1530  |  | 
|  1531   visitChildren(Visitor visitor) { |  | 
|  1532     key.accept(visitor); |  | 
|  1533     value.accept(visitor); |  | 
|  1534   } |  | 
|  1535  |  | 
|  1536   Token getBeginToken() => key.getBeginToken(); |  | 
|  1537  |  | 
|  1538   Token getEndToken() => value.getEndToken(); |  | 
|  1539 } |  | 
|  1540  |  | 
|  1541 class NamedArgument extends Expression { |  | 
|  1542   final Identifier name; |  | 
|  1543   final Expression expression; |  | 
|  1544  |  | 
|  1545   final Token colonToken; |  | 
|  1546  |  | 
|  1547   NamedArgument(this.name, this.colonToken, this.expression); |  | 
|  1548  |  | 
|  1549   NamedArgument asNamedArgument() => this; |  | 
|  1550  |  | 
|  1551   accept(Visitor visitor) => visitor.visitNamedArgument(this); |  | 
|  1552  |  | 
|  1553   visitChildren(Visitor visitor) { |  | 
|  1554     name.accept(visitor); |  | 
|  1555     expression.accept(visitor); |  | 
|  1556   } |  | 
|  1557  |  | 
|  1558   Token getBeginToken() => name.getBeginToken(); |  | 
|  1559  |  | 
|  1560   Token getEndToken() => expression.getEndToken(); |  | 
|  1561 } |  | 
|  1562  |  | 
|  1563 class SwitchStatement extends Statement { |  | 
|  1564   final ParenthesizedExpression parenthesizedExpression; |  | 
|  1565   final NodeList cases; |  | 
|  1566  |  | 
|  1567   final Token switchKeyword; |  | 
|  1568  |  | 
|  1569   SwitchStatement(this.parenthesizedExpression, this.cases, |  | 
|  1570                   this.switchKeyword); |  | 
|  1571  |  | 
|  1572   SwitchStatement asSwitchStatement() => this; |  | 
|  1573  |  | 
|  1574   Expression get expression => parenthesizedExpression.expression; |  | 
|  1575  |  | 
|  1576   accept(Visitor visitor) => visitor.visitSwitchStatement(this); |  | 
|  1577  |  | 
|  1578   visitChildren(Visitor visitor) { |  | 
|  1579     parenthesizedExpression.accept(visitor); |  | 
|  1580     cases.accept(visitor); |  | 
|  1581   } |  | 
|  1582  |  | 
|  1583   Token getBeginToken() => switchKeyword; |  | 
|  1584  |  | 
|  1585   Token getEndToken() => cases.getEndToken(); |  | 
|  1586 } |  | 
|  1587  |  | 
|  1588 class CaseMatch extends Node { |  | 
|  1589   final Token caseKeyword; |  | 
|  1590   final Expression expression; |  | 
|  1591   final Token colonToken; |  | 
|  1592   CaseMatch(this.caseKeyword, this.expression, this.colonToken); |  | 
|  1593  |  | 
|  1594   CaseMatch asCaseMatch() => this; |  | 
|  1595   Token getBeginToken() => caseKeyword; |  | 
|  1596   Token getEndToken() => colonToken; |  | 
|  1597   accept(Visitor visitor) => visitor.visitCaseMatch(this); |  | 
|  1598   visitChildren(Visitor visitor) => expression.accept(visitor); |  | 
|  1599 } |  | 
|  1600  |  | 
|  1601 class SwitchCase extends Node { |  | 
|  1602   // The labels and case patterns are collected in [labelsAndCases]. |  | 
|  1603   // The default keyword, if present, is collected in [defaultKeyword]. |  | 
|  1604   // Any actual switch case must have at least one 'case' or 'default' |  | 
|  1605   // clause. |  | 
|  1606   // Notice: The labels and cases can occur interleaved in the source. |  | 
|  1607   // They are separated here, since the order is irrelevant to the meaning |  | 
|  1608   // of the switch. |  | 
|  1609  |  | 
|  1610   /** List of [Label] and [CaseMatch] nodes. */ |  | 
|  1611   final NodeList labelsAndCases; |  | 
|  1612   /** A "default" keyword token, if applicable. */ |  | 
|  1613   final Token defaultKeyword; |  | 
|  1614   /** List of statements, the body of the case. */ |  | 
|  1615   final NodeList statements; |  | 
|  1616  |  | 
|  1617   final Token startToken; |  | 
|  1618  |  | 
|  1619   SwitchCase(this.labelsAndCases, this.defaultKeyword, |  | 
|  1620              this.statements, this.startToken); |  | 
|  1621  |  | 
|  1622   SwitchCase asSwitchCase() => this; |  | 
|  1623  |  | 
|  1624   bool get isDefaultCase => defaultKeyword != null; |  | 
|  1625  |  | 
|  1626   bool isValidContinueTarget() => true; |  | 
|  1627  |  | 
|  1628   accept(Visitor visitor) => visitor.visitSwitchCase(this); |  | 
|  1629  |  | 
|  1630   visitChildren(Visitor visitor) { |  | 
|  1631     labelsAndCases.accept(visitor); |  | 
|  1632     statements.accept(visitor); |  | 
|  1633   } |  | 
|  1634  |  | 
|  1635   Token getBeginToken() { |  | 
|  1636     return startToken; |  | 
|  1637   } |  | 
|  1638  |  | 
|  1639   Token getEndToken() { |  | 
|  1640     if (statements.nodes.isEmpty) { |  | 
|  1641       // All cases must have at least one expression or be the default. |  | 
|  1642       if (defaultKeyword != null) { |  | 
|  1643         // The colon after 'default'. |  | 
|  1644         return defaultKeyword.next; |  | 
|  1645       } |  | 
|  1646       // The colon after the last expression. |  | 
|  1647       return labelsAndCases.getEndToken(); |  | 
|  1648     } else { |  | 
|  1649       return statements.getEndToken(); |  | 
|  1650     } |  | 
|  1651   } |  | 
|  1652 } |  | 
|  1653  |  | 
|  1654 abstract class GotoStatement extends Statement { |  | 
|  1655   final Identifier target; |  | 
|  1656   final Token keywordToken; |  | 
|  1657   final Token semicolonToken; |  | 
|  1658  |  | 
|  1659   GotoStatement(this.target, this.keywordToken, this.semicolonToken); |  | 
|  1660  |  | 
|  1661   visitChildren(Visitor visitor) { |  | 
|  1662     if (target != null) target.accept(visitor); |  | 
|  1663   } |  | 
|  1664  |  | 
|  1665   Token getBeginToken() => keywordToken; |  | 
|  1666  |  | 
|  1667   Token getEndToken() => semicolonToken; |  | 
|  1668  |  | 
|  1669   // TODO(ahe): make class abstract instead of adding an abstract method. |  | 
|  1670   accept(Visitor visitor); |  | 
|  1671 } |  | 
|  1672  |  | 
|  1673 class BreakStatement extends GotoStatement { |  | 
|  1674   BreakStatement(Identifier target, Token keywordToken, Token semicolonToken) |  | 
|  1675     : super(target, keywordToken, semicolonToken); |  | 
|  1676  |  | 
|  1677   BreakStatement asBreakStatement() => this; |  | 
|  1678  |  | 
|  1679   accept(Visitor visitor) => visitor.visitBreakStatement(this); |  | 
|  1680 } |  | 
|  1681  |  | 
|  1682 class ContinueStatement extends GotoStatement { |  | 
|  1683   ContinueStatement(Identifier target, Token keywordToken, Token semicolonToken) |  | 
|  1684     : super(target, keywordToken, semicolonToken); |  | 
|  1685  |  | 
|  1686   ContinueStatement asContinueStatement() => this; |  | 
|  1687  |  | 
|  1688   accept(Visitor visitor) => visitor.visitContinueStatement(this); |  | 
|  1689 } |  | 
|  1690  |  | 
|  1691 class ForIn extends Loop with StoredTreeElementMixin { |  | 
|  1692   final Node declaredIdentifier; |  | 
|  1693   final Expression expression; |  | 
|  1694  |  | 
|  1695   final Token forToken; |  | 
|  1696   final Token inToken; |  | 
|  1697  |  | 
|  1698   ForIn(this.declaredIdentifier, this.expression, |  | 
|  1699         Statement body, this.forToken, this.inToken) : super(body); |  | 
|  1700  |  | 
|  1701   Expression get condition => null; |  | 
|  1702  |  | 
|  1703   ForIn asForIn() => this; |  | 
|  1704  |  | 
|  1705   accept(Visitor visitor) => visitor.visitForIn(this); |  | 
|  1706  |  | 
|  1707   visitChildren(Visitor visitor) { |  | 
|  1708     declaredIdentifier.accept(visitor); |  | 
|  1709     expression.accept(visitor); |  | 
|  1710     body.accept(visitor); |  | 
|  1711   } |  | 
|  1712  |  | 
|  1713   Token getBeginToken() => forToken; |  | 
|  1714  |  | 
|  1715   Token getEndToken() => body.getEndToken(); |  | 
|  1716 } |  | 
|  1717  |  | 
|  1718 class Label extends Node { |  | 
|  1719   final Identifier identifier; |  | 
|  1720   final Token colonToken; |  | 
|  1721  |  | 
|  1722   Label(this.identifier, this.colonToken); |  | 
|  1723  |  | 
|  1724   String get labelName => identifier.source; |  | 
|  1725  |  | 
|  1726   Label asLabel() => this; |  | 
|  1727  |  | 
|  1728   accept(Visitor visitor) => visitor.visitLabel(this); |  | 
|  1729  |  | 
|  1730   void visitChildren(Visitor visitor) { |  | 
|  1731     identifier.accept(visitor); |  | 
|  1732   } |  | 
|  1733  |  | 
|  1734   Token getBeginToken() => identifier.token; |  | 
|  1735   Token getEndToken() => colonToken; |  | 
|  1736 } |  | 
|  1737  |  | 
|  1738 class LabeledStatement extends Statement { |  | 
|  1739   final NodeList labels; |  | 
|  1740   final Statement statement; |  | 
|  1741  |  | 
|  1742   LabeledStatement(this.labels, this.statement); |  | 
|  1743  |  | 
|  1744   LabeledStatement asLabeledStatement() => this; |  | 
|  1745  |  | 
|  1746   accept(Visitor visitor) => visitor.visitLabeledStatement(this); |  | 
|  1747  |  | 
|  1748   visitChildren(Visitor visitor) { |  | 
|  1749     labels.accept(visitor); |  | 
|  1750     statement.accept(visitor); |  | 
|  1751   } |  | 
|  1752  |  | 
|  1753   Token getBeginToken() => labels.getBeginToken(); |  | 
|  1754  |  | 
|  1755   Token getEndToken() => statement.getEndToken(); |  | 
|  1756  |  | 
|  1757   bool isValidContinueTarget() => statement.isValidContinueTarget(); |  | 
|  1758 } |  | 
|  1759  |  | 
|  1760 abstract class LibraryTag extends Node { |  | 
|  1761   final Link<MetadataAnnotation> metadata; |  | 
|  1762  |  | 
|  1763   LibraryTag(this.metadata); |  | 
|  1764  |  | 
|  1765   bool get isLibraryName => false; |  | 
|  1766   bool get isImport => false; |  | 
|  1767   bool get isExport => false; |  | 
|  1768   bool get isPart => false; |  | 
|  1769   bool get isPartOf => false; |  | 
|  1770 } |  | 
|  1771  |  | 
|  1772 class LibraryName extends LibraryTag { |  | 
|  1773   final Expression name; |  | 
|  1774  |  | 
|  1775   final Token libraryKeyword; |  | 
|  1776  |  | 
|  1777   LibraryName(this.libraryKeyword, |  | 
|  1778               this.name, |  | 
|  1779               Link<MetadataAnnotation> metadata) |  | 
|  1780     : super(metadata); |  | 
|  1781  |  | 
|  1782   bool get isLibraryName => true; |  | 
|  1783  |  | 
|  1784   LibraryName asLibraryName() => this; |  | 
|  1785  |  | 
|  1786   accept(Visitor visitor) => visitor.visitLibraryName(this); |  | 
|  1787  |  | 
|  1788   visitChildren(Visitor visitor) => name.accept(visitor); |  | 
|  1789  |  | 
|  1790   Token getBeginToken() => libraryKeyword; |  | 
|  1791  |  | 
|  1792   Token getEndToken() => name.getEndToken().next; |  | 
|  1793 } |  | 
|  1794  |  | 
|  1795 /** |  | 
|  1796  * This tag describes a dependency between one library and the exported |  | 
|  1797  * identifiers of another library. The other library is specified by the [uri]. |  | 
|  1798  * Combinators filter away some identifiers from the other library. |  | 
|  1799  */ |  | 
|  1800 abstract class LibraryDependency extends LibraryTag { |  | 
|  1801   final StringNode uri; |  | 
|  1802   final NodeList combinators; |  | 
|  1803  |  | 
|  1804   LibraryDependency(this.uri, |  | 
|  1805                     this.combinators, |  | 
|  1806                     Link<MetadataAnnotation> metadata) |  | 
|  1807     : super(metadata); |  | 
|  1808  |  | 
|  1809   LibraryDependency asLibraryDependency() => this; |  | 
|  1810 } |  | 
|  1811  |  | 
|  1812 /** |  | 
|  1813  * An [:import:] library tag. |  | 
|  1814  * |  | 
|  1815  * An import tag is dependency on another library where the exported identifiers |  | 
|  1816  * are put into the import scope of the importing library. The import scope is |  | 
|  1817  * only visible inside the library. |  | 
|  1818  */ |  | 
|  1819 class Import extends LibraryDependency { |  | 
|  1820   final Identifier prefix; |  | 
|  1821   final Token importKeyword; |  | 
|  1822   final bool isDeferred; |  | 
|  1823  |  | 
|  1824   Import(this.importKeyword, StringNode uri, |  | 
|  1825          this.prefix, NodeList combinators, |  | 
|  1826          Link<MetadataAnnotation> metadata, |  | 
|  1827          {this.isDeferred}) |  | 
|  1828       : super(uri, combinators, metadata); |  | 
|  1829  |  | 
|  1830   bool get isImport => true; |  | 
|  1831  |  | 
|  1832   Import asImport() => this; |  | 
|  1833  |  | 
|  1834   accept(Visitor visitor) => visitor.visitImport(this); |  | 
|  1835  |  | 
|  1836   visitChildren(Visitor visitor) { |  | 
|  1837     uri.accept(visitor); |  | 
|  1838     if (prefix != null) prefix.accept(visitor); |  | 
|  1839     if (combinators != null) combinators.accept(visitor); |  | 
|  1840   } |  | 
|  1841  |  | 
|  1842   Token getBeginToken() => importKeyword; |  | 
|  1843  |  | 
|  1844   Token getEndToken() { |  | 
|  1845     if (combinators != null) return combinators.getEndToken().next; |  | 
|  1846     if (prefix != null) return prefix.getEndToken().next; |  | 
|  1847     return uri.getEndToken().next; |  | 
|  1848   } |  | 
|  1849 } |  | 
|  1850  |  | 
|  1851 /** |  | 
|  1852  * An [:export:] library tag. |  | 
|  1853  * |  | 
|  1854  * An export tag is dependency on another library where the exported identifiers |  | 
|  1855  * are put into the export scope of the exporting library. The export scope is |  | 
|  1856  * not visible inside the library. |  | 
|  1857  */ |  | 
|  1858 class Export extends LibraryDependency { |  | 
|  1859   final Token exportKeyword; |  | 
|  1860  |  | 
|  1861   Export(this.exportKeyword, |  | 
|  1862          StringNode uri, |  | 
|  1863          NodeList combinators, |  | 
|  1864          Link<MetadataAnnotation> metadata) |  | 
|  1865       : super(uri, combinators, metadata); |  | 
|  1866  |  | 
|  1867   bool get isExport => true; |  | 
|  1868  |  | 
|  1869   Export asExport() => this; |  | 
|  1870  |  | 
|  1871   accept(Visitor visitor) => visitor.visitExport(this); |  | 
|  1872  |  | 
|  1873   visitChildren(Visitor visitor) { |  | 
|  1874     uri.accept(visitor); |  | 
|  1875     if (combinators != null) combinators.accept(visitor); |  | 
|  1876   } |  | 
|  1877  |  | 
|  1878   Token getBeginToken() => exportKeyword; |  | 
|  1879  |  | 
|  1880   Token getEndToken() { |  | 
|  1881     if (combinators != null) return combinators.getEndToken().next; |  | 
|  1882     return uri.getEndToken().next; |  | 
|  1883   } |  | 
|  1884 } |  | 
|  1885  |  | 
|  1886 class Part extends LibraryTag { |  | 
|  1887   final StringNode uri; |  | 
|  1888  |  | 
|  1889   final Token partKeyword; |  | 
|  1890  |  | 
|  1891   Part(this.partKeyword, this.uri, Link<MetadataAnnotation> metadata) |  | 
|  1892     : super(metadata); |  | 
|  1893  |  | 
|  1894   bool get isPart => true; |  | 
|  1895  |  | 
|  1896   Part asPart() => this; |  | 
|  1897  |  | 
|  1898   accept(Visitor visitor) => visitor.visitPart(this); |  | 
|  1899  |  | 
|  1900   visitChildren(Visitor visitor) => uri.accept(visitor); |  | 
|  1901  |  | 
|  1902   Token getBeginToken() => partKeyword; |  | 
|  1903  |  | 
|  1904   Token getEndToken() => uri.getEndToken().next; |  | 
|  1905 } |  | 
|  1906  |  | 
|  1907 class PartOf extends Node { |  | 
|  1908   final Expression name; |  | 
|  1909  |  | 
|  1910   final Token partKeyword; |  | 
|  1911  |  | 
|  1912   final Link<MetadataAnnotation> metadata; |  | 
|  1913  |  | 
|  1914   PartOf(this.partKeyword, this.name, this.metadata); |  | 
|  1915  |  | 
|  1916   Token get ofKeyword => partKeyword.next; |  | 
|  1917  |  | 
|  1918   bool get isPartOf => true; |  | 
|  1919  |  | 
|  1920   PartOf asPartOf() => this; |  | 
|  1921  |  | 
|  1922   accept(Visitor visitor) => visitor.visitPartOf(this); |  | 
|  1923  |  | 
|  1924   visitChildren(Visitor visitor) => name.accept(visitor); |  | 
|  1925  |  | 
|  1926   Token getBeginToken() => partKeyword; |  | 
|  1927  |  | 
|  1928   Token getEndToken() => name.getEndToken().next; |  | 
|  1929 } |  | 
|  1930  |  | 
|  1931 class Combinator extends Node { |  | 
|  1932   final NodeList identifiers; |  | 
|  1933  |  | 
|  1934   final Token keywordToken; |  | 
|  1935  |  | 
|  1936   Combinator(this.identifiers, this.keywordToken); |  | 
|  1937  |  | 
|  1938   bool get isShow => identical(keywordToken.stringValue, 'show'); |  | 
|  1939  |  | 
|  1940   bool get isHide => identical(keywordToken.stringValue, 'hide'); |  | 
|  1941  |  | 
|  1942   Combinator asCombinator() => this; |  | 
|  1943  |  | 
|  1944   accept(Visitor visitor) => visitor.visitCombinator(this); |  | 
|  1945  |  | 
|  1946   visitChildren(Visitor visitor) => identifiers.accept(visitor); |  | 
|  1947  |  | 
|  1948   Token getBeginToken() => keywordToken; |  | 
|  1949  |  | 
|  1950   Token getEndToken() => identifiers.getEndToken(); |  | 
|  1951 } |  | 
|  1952  |  | 
|  1953 class Typedef extends Node { |  | 
|  1954   final TypeAnnotation returnType; |  | 
|  1955   final Identifier name; |  | 
|  1956   final NodeList typeParameters; |  | 
|  1957   final NodeList formals; |  | 
|  1958  |  | 
|  1959   final Token typedefKeyword; |  | 
|  1960   final Token endToken; |  | 
|  1961  |  | 
|  1962   Typedef(this.returnType, this.name, this.typeParameters, this.formals, |  | 
|  1963           this.typedefKeyword, this.endToken); |  | 
|  1964  |  | 
|  1965   Typedef asTypedef() => this; |  | 
|  1966  |  | 
|  1967   accept(Visitor visitor) => visitor.visitTypedef(this); |  | 
|  1968  |  | 
|  1969   visitChildren(Visitor visitor) { |  | 
|  1970     if (returnType != null) returnType.accept(visitor); |  | 
|  1971     name.accept(visitor); |  | 
|  1972     if (typeParameters != null) typeParameters.accept(visitor); |  | 
|  1973     formals.accept(visitor); |  | 
|  1974   } |  | 
|  1975  |  | 
|  1976   Token getBeginToken() => typedefKeyword; |  | 
|  1977  |  | 
|  1978   Token getEndToken() => endToken; |  | 
|  1979 } |  | 
|  1980  |  | 
|  1981 class TryStatement extends Statement { |  | 
|  1982   final Block tryBlock; |  | 
|  1983   final NodeList catchBlocks; |  | 
|  1984   final Block finallyBlock; |  | 
|  1985  |  | 
|  1986   final Token tryKeyword; |  | 
|  1987   final Token finallyKeyword; |  | 
|  1988  |  | 
|  1989   TryStatement(this.tryBlock, this.catchBlocks, this.finallyBlock, |  | 
|  1990                this.tryKeyword, this.finallyKeyword); |  | 
|  1991  |  | 
|  1992   TryStatement asTryStatement() => this; |  | 
|  1993  |  | 
|  1994   accept(Visitor visitor) => visitor.visitTryStatement(this); |  | 
|  1995  |  | 
|  1996   visitChildren(Visitor visitor) { |  | 
|  1997     tryBlock.accept(visitor); |  | 
|  1998     catchBlocks.accept(visitor); |  | 
|  1999     if (finallyBlock != null) finallyBlock.accept(visitor); |  | 
|  2000   } |  | 
|  2001  |  | 
|  2002   Token getBeginToken() => tryKeyword; |  | 
|  2003  |  | 
|  2004   Token getEndToken() { |  | 
|  2005     if (finallyBlock != null) return finallyBlock.getEndToken(); |  | 
|  2006     if (!catchBlocks.isEmpty) return catchBlocks.getEndToken(); |  | 
|  2007     return tryBlock.getEndToken(); |  | 
|  2008   } |  | 
|  2009 } |  | 
|  2010  |  | 
|  2011 class Cascade extends Expression { |  | 
|  2012   final Expression expression; |  | 
|  2013   Cascade(this.expression); |  | 
|  2014  |  | 
|  2015   Cascade asCascade() => this; |  | 
|  2016   accept(Visitor visitor) => visitor.visitCascade(this); |  | 
|  2017  |  | 
|  2018   void visitChildren(Visitor visitor) { |  | 
|  2019     expression.accept(visitor); |  | 
|  2020   } |  | 
|  2021  |  | 
|  2022   Token getBeginToken() => expression.getBeginToken(); |  | 
|  2023  |  | 
|  2024   Token getEndToken() => expression.getEndToken(); |  | 
|  2025 } |  | 
|  2026  |  | 
|  2027 class CascadeReceiver extends Expression { |  | 
|  2028   final Expression expression; |  | 
|  2029   final Token cascadeOperator; |  | 
|  2030   CascadeReceiver(this.expression, this.cascadeOperator); |  | 
|  2031  |  | 
|  2032   CascadeReceiver asCascadeReceiver() => this; |  | 
|  2033   accept(Visitor visitor) => visitor.visitCascadeReceiver(this); |  | 
|  2034  |  | 
|  2035   void visitChildren(Visitor visitor) { |  | 
|  2036     expression.accept(visitor); |  | 
|  2037   } |  | 
|  2038  |  | 
|  2039   Token getBeginToken() => expression.getBeginToken(); |  | 
|  2040  |  | 
|  2041   Token getEndToken() => expression.getEndToken(); |  | 
|  2042 } |  | 
|  2043  |  | 
|  2044 class CatchBlock extends Node { |  | 
|  2045   final TypeAnnotation type; |  | 
|  2046   final NodeList formals; |  | 
|  2047   final Block block; |  | 
|  2048  |  | 
|  2049   final Token onKeyword; |  | 
|  2050   final Token catchKeyword; |  | 
|  2051  |  | 
|  2052   CatchBlock(this.type, this.formals, this.block, |  | 
|  2053              this.onKeyword, this.catchKeyword); |  | 
|  2054  |  | 
|  2055   CatchBlock asCatchBlock() => this; |  | 
|  2056  |  | 
|  2057   accept(Visitor visitor) => visitor.visitCatchBlock(this); |  | 
|  2058  |  | 
|  2059   Node get exception { |  | 
|  2060     if (formals == null || formals.nodes.isEmpty) return null; |  | 
|  2061     VariableDefinitions declarations = formals.nodes.head; |  | 
|  2062     return declarations.definitions.nodes.head; |  | 
|  2063   } |  | 
|  2064  |  | 
|  2065   Node get trace { |  | 
|  2066     if (formals == null || formals.nodes.isEmpty) return null; |  | 
|  2067     Link<Node> declarations = formals.nodes.tail; |  | 
|  2068     if (declarations.isEmpty) return null; |  | 
|  2069     VariableDefinitions head = declarations.head; |  | 
|  2070     return head.definitions.nodes.head; |  | 
|  2071   } |  | 
|  2072  |  | 
|  2073   visitChildren(Visitor visitor) { |  | 
|  2074     if (type != null) type.accept(visitor); |  | 
|  2075     if (formals != null) formals.accept(visitor); |  | 
|  2076     block.accept(visitor); |  | 
|  2077   } |  | 
|  2078  |  | 
|  2079   Token getBeginToken() => onKeyword != null ? onKeyword : catchKeyword; |  | 
|  2080  |  | 
|  2081   Token getEndToken() => block.getEndToken(); |  | 
|  2082 } |  | 
|  2083  |  | 
|  2084 class Metadata extends Node { |  | 
|  2085   final Token token; |  | 
|  2086   final Expression expression; |  | 
|  2087  |  | 
|  2088   Metadata(this.token, this.expression); |  | 
|  2089  |  | 
|  2090   Metadata asMetadata() => this; |  | 
|  2091  |  | 
|  2092   accept(Visitor visitor) => visitor.visitMetadata(this); |  | 
|  2093  |  | 
|  2094   visitChildren(Visitor visitor) { |  | 
|  2095     expression.accept(visitor); |  | 
|  2096   } |  | 
|  2097  |  | 
|  2098   Token getBeginToken() => token; |  | 
|  2099  |  | 
|  2100   Token getEndToken() => expression.getEndToken(); |  | 
|  2101 } |  | 
|  2102  |  | 
|  2103 class Initializers { |  | 
|  2104   static bool isSuperConstructorCall(Send node) { |  | 
|  2105     return (node.receiver == null && node.selector.isSuper()) || |  | 
|  2106            (node.receiver != null && |  | 
|  2107             node.receiver.isSuper() && |  | 
|  2108             node.selector.asIdentifier() != null); |  | 
|  2109   } |  | 
|  2110  |  | 
|  2111   static bool isConstructorRedirect(Send node) { |  | 
|  2112     return (node.receiver == null && node.selector.isThis()) || |  | 
|  2113            (node.receiver != null && |  | 
|  2114             node.receiver.isThis() && |  | 
|  2115             node.selector.asIdentifier() != null); |  | 
|  2116   } |  | 
|  2117 } |  | 
|  2118  |  | 
|  2119 class GetDartStringVisitor extends Visitor<DartString> { |  | 
|  2120   const GetDartStringVisitor(); |  | 
|  2121   DartString visitNode(Node node) => null; |  | 
|  2122   DartString visitStringJuxtaposition(StringJuxtaposition node) |  | 
|  2123       => node.dartString; |  | 
|  2124   DartString visitLiteralString(LiteralString node) => node.dartString; |  | 
|  2125 } |  | 
|  2126  |  | 
|  2127 class IsInterpolationVisitor extends Visitor<bool> { |  | 
|  2128   const IsInterpolationVisitor(); |  | 
|  2129   bool visitNode(Node node) => false; |  | 
|  2130   bool visitStringInterpolation(StringInterpolation node) => true; |  | 
|  2131   bool visitStringJuxtaposition(StringJuxtaposition node) |  | 
|  2132       => node.isInterpolation; |  | 
|  2133 } |  | 
|  2134  |  | 
|  2135 /// Erroneous node used to recover from parser errors.  Implements various |  | 
|  2136 /// interfaces and provides bare minimum of implementation to avoid unnecessary |  | 
|  2137 /// messages. |  | 
|  2138 class ErrorNode |  | 
|  2139     extends Node |  | 
|  2140     implements FunctionExpression, VariableDefinitions, Typedef { |  | 
|  2141   final Token token; |  | 
|  2142   final String reason; |  | 
|  2143   final Identifier name; |  | 
|  2144   final NodeList definitions; |  | 
|  2145  |  | 
|  2146   ErrorNode.internal(this.token, this.reason, this.name, this.definitions); |  | 
|  2147  |  | 
|  2148   factory ErrorNode(Token token, String reason) { |  | 
|  2149     Identifier name = new Identifier(token); |  | 
|  2150     NodeList definitions = new NodeList( |  | 
|  2151         null, const Link<Node>().prepend(name), null, null); |  | 
|  2152     return new ErrorNode.internal(token, reason, name, definitions); |  | 
|  2153   } |  | 
|  2154  |  | 
|  2155   Token get beginToken => token; |  | 
|  2156   Token get endToken => token; |  | 
|  2157  |  | 
|  2158   Token getBeginToken() => token; |  | 
|  2159  |  | 
|  2160   Token getEndToken() => token; |  | 
|  2161  |  | 
|  2162   accept(Visitor visitor) {} |  | 
|  2163  |  | 
|  2164   visitChildren(Visitor visitor) {} |  | 
|  2165  |  | 
|  2166   bool get isErroneous => true; |  | 
|  2167  |  | 
|  2168   // FunctionExpression. |  | 
|  2169   get parameters => null; |  | 
|  2170   get body => null; |  | 
|  2171   get returnType => null; |  | 
|  2172   get modifiers => Modifiers.EMPTY; |  | 
|  2173   get initializers => null; |  | 
|  2174   get getOrSet => null; |  | 
|  2175   get isRedirectingFactory => false; |  | 
|  2176   bool hasBody() => false; |  | 
|  2177   bool hasEmptyBody() => false; |  | 
|  2178  |  | 
|  2179   // VariableDefinitions. |  | 
|  2180   get metadata => null; |  | 
|  2181   get type => null; |  | 
|  2182  |  | 
|  2183   // Typedef. |  | 
|  2184   get typeParameters => null; |  | 
|  2185   get formals => null; |  | 
|  2186   get typedefKeyword => null; |  | 
|  2187 } |  | 
| OLD | NEW |