Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/tree/nodes.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698