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 |