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