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