| 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 |