Index: pkg/compiler/lib/src/tree/nodes.dart |
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart |
deleted file mode 100644 |
index 1e4b75d2ebae3f775beebbf41333e23bfcf61c10..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/lib/src/tree/nodes.dart |
+++ /dev/null |
@@ -1,2274 +0,0 @@ |
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-part of tree; |
- |
-abstract class Visitor<R> { |
- const Visitor(); |
- |
- R visitNode(Node node); |
- |
- R visitAsyncModifier(AsyncModifier node) => visitNode(node); |
- R visitAwait(Await node) => visitExpression(node); |
- R visitBlock(Block node) => visitStatement(node); |
- R visitBreakStatement(BreakStatement node) => visitGotoStatement(node); |
- R visitCascade(Cascade node) => visitExpression(node); |
- R visitCascadeReceiver(CascadeReceiver node) => visitExpression(node); |
- R visitCaseMatch(CaseMatch node) => visitNode(node); |
- R visitCatchBlock(CatchBlock node) => visitNode(node); |
- R visitClassNode(ClassNode node) => visitNode(node); |
- R visitCombinator(Combinator node) => visitNode(node); |
- R visitConditional(Conditional node) => visitExpression(node); |
- R visitContinueStatement(ContinueStatement node) => visitGotoStatement(node); |
- R visitDoWhile(DoWhile node) => visitLoop(node); |
- R visitEmptyStatement(EmptyStatement node) => visitStatement(node); |
- R visitExport(Export node) => visitLibraryDependency(node); |
- R visitExpression(Expression node) => visitNode(node); |
- R visitExpressionStatement(ExpressionStatement node) => visitStatement(node); |
- R visitFor(For node) => visitLoop(node); |
- R visitForIn(ForIn node) => visitLoop(node); |
- R visitFunctionDeclaration(FunctionDeclaration node) => visitStatement(node); |
- R visitFunctionExpression(FunctionExpression node) => visitExpression(node); |
- R visitGotoStatement(GotoStatement node) => visitStatement(node); |
- R visitIdentifier(Identifier node) => visitExpression(node); |
- R visitIf(If node) => visitStatement(node); |
- R visitImport(Import node) => visitLibraryDependency(node); |
- R visitLabel(Label node) => visitNode(node); |
- R visitLabeledStatement(LabeledStatement node) => visitStatement(node); |
- R visitLibraryDependency(LibraryDependency node) => visitLibraryTag(node); |
- R visitLibraryName(LibraryName node) => visitLibraryTag(node); |
- R visitLibraryTag(LibraryTag node) => visitNode(node); |
- R visitLiteral(Literal node) => visitExpression(node); |
- R visitLiteralBool(LiteralBool node) => visitLiteral(node); |
- R visitLiteralDouble(LiteralDouble node) => visitLiteral(node); |
- R visitLiteralInt(LiteralInt node) => visitLiteral(node); |
- R visitLiteralList(LiteralList node) => visitExpression(node); |
- R visitLiteralMap(LiteralMap node) => visitExpression(node); |
- R visitLiteralMapEntry(LiteralMapEntry node) => visitNode(node); |
- R visitLiteralNull(LiteralNull node) => visitLiteral(node); |
- R visitLiteralString(LiteralString node) => visitStringNode(node); |
- R visitStringJuxtaposition(StringJuxtaposition node) => visitStringNode(node); |
- R visitLoop(Loop node) => visitStatement(node); |
- R visitMetadata(Metadata node) => visitNode(node); |
- R visitMixinApplication(MixinApplication node) => visitNode(node); |
- R visitModifiers(Modifiers node) => visitNode(node); |
- R visitNamedArgument(NamedArgument node) => visitExpression(node); |
- R visitNamedMixinApplication(NamedMixinApplication node) { |
- return visitMixinApplication(node); |
- } |
- R visitNewExpression(NewExpression node) => visitExpression(node); |
- R visitNodeList(NodeList node) => visitNode(node); |
- R visitOperator(Operator node) => visitIdentifier(node); |
- R visitParenthesizedExpression(ParenthesizedExpression node) { |
- return visitExpression(node); |
- } |
- R visitPart(Part node) => visitLibraryTag(node); |
- R visitPartOf(PartOf node) => visitNode(node); |
- R visitPostfix(Postfix node) => visitNodeList(node); |
- R visitPrefix(Prefix node) => visitNodeList(node); |
- R visitRedirectingFactoryBody(RedirectingFactoryBody node) { |
- return visitStatement(node); |
- } |
- R visitRethrow(Rethrow node) => visitStatement(node); |
- R visitReturn(Return node) => visitStatement(node); |
- R visitSend(Send node) => visitExpression(node); |
- R visitSendSet(SendSet node) => visitSend(node); |
- R visitStatement(Statement node) => visitNode(node); |
- R visitStringNode(StringNode node) => visitExpression(node); |
- R visitStringInterpolation(StringInterpolation node) => visitStringNode(node); |
- R visitStringInterpolationPart(StringInterpolationPart node) { |
- return visitNode(node); |
- } |
- R visitSwitchCase(SwitchCase node) => visitNode(node); |
- R visitSwitchStatement(SwitchStatement node) => visitStatement(node); |
- R visitLiteralSymbol(LiteralSymbol node) => visitExpression(node); |
- R visitThrow(Throw node) => visitExpression(node); |
- R visitTryStatement(TryStatement node) => visitStatement(node); |
- R visitTypeAnnotation(TypeAnnotation node) => visitNode(node); |
- R visitTypedef(Typedef node) => visitNode(node); |
- R visitTypeVariable(TypeVariable node) => visitNode(node); |
- R visitVariableDefinitions(VariableDefinitions node) => visitStatement(node); |
- R visitWhile(While node) => visitLoop(node); |
- R visitYield(Yield node) => visitStatement(node); |
-} |
- |
-Token firstBeginToken(Node first, Node second) { |
- Token token = null; |
- if (first != null) { |
- token = first.getBeginToken(); |
- } |
- if (token == null && second != null) { |
- // [token] might be null even when [first] is not, e.g. for empty Modifiers. |
- token = second.getBeginToken(); |
- } |
- return token; |
-} |
- |
-/** |
- * A node in a syntax tree. |
- * |
- * The abstract part of "abstract syntax tree" is invalidated when |
- * supporting tools such as code formatting. These tools need concrete |
- * syntax such as parentheses and no constant folding. |
- * |
- * We support these tools by storing additional references back to the |
- * token stream. These references are stored in fields ending with |
- * "Token". |
- */ |
-abstract class Node extends NullTreeElementMixin implements Spannable { |
- final int hashCode; |
- static int _HASH_COUNTER = 0; |
- |
- Node() : hashCode = ++_HASH_COUNTER; |
- |
- accept(Visitor visitor); |
- |
- visitChildren(Visitor visitor); |
- |
- /** |
- * Returns this node unparsed to Dart source string. |
- */ |
- toString() => unparse(this); |
- |
- /** |
- * Returns Xml-like tree representation of this node. |
- */ |
- toDebugString() { |
- return PrettyPrinter.prettyPrint(this); |
- } |
- |
- String getObjectDescription() => super.toString(); |
- |
- Token getBeginToken(); |
- |
- Token getEndToken(); |
- |
- AsyncModifier asAsyncModifier() => null; |
- Await asAwait() => null; |
- Block asBlock() => null; |
- BreakStatement asBreakStatement() => null; |
- Cascade asCascade() => null; |
- CascadeReceiver asCascadeReceiver() => null; |
- CaseMatch asCaseMatch() => null; |
- CatchBlock asCatchBlock() => null; |
- ClassNode asClassNode() => null; |
- Combinator asCombinator() => null; |
- Conditional asConditional() => null; |
- ContinueStatement asContinueStatement() => null; |
- DoWhile asDoWhile() => null; |
- EmptyStatement asEmptyStatement() => null; |
- ErrorExpression asErrorExpression() => null; |
- Export asExport() => null; |
- Expression asExpression() => null; |
- ExpressionStatement asExpressionStatement() => null; |
- For asFor() => null; |
- ForIn asForIn() => null; |
- FunctionDeclaration asFunctionDeclaration() => null; |
- FunctionExpression asFunctionExpression() => null; |
- Identifier asIdentifier() => null; |
- If asIf() => null; |
- Import asImport() => null; |
- Label asLabel() => null; |
- LabeledStatement asLabeledStatement() => null; |
- LibraryName asLibraryName() => null; |
- LibraryDependency asLibraryDependency() => null; |
- LiteralBool asLiteralBool() => null; |
- LiteralDouble asLiteralDouble() => null; |
- LiteralInt asLiteralInt() => null; |
- LiteralList asLiteralList() => null; |
- LiteralMap asLiteralMap() => null; |
- LiteralMapEntry asLiteralMapEntry() => null; |
- LiteralNull asLiteralNull() => null; |
- LiteralString asLiteralString() => null; |
- LiteralSymbol asLiteralSymbol() => null; |
- Metadata asMetadata() => null; |
- MixinApplication asMixinApplication() => null; |
- Modifiers asModifiers() => null; |
- NamedArgument asNamedArgument() => null; |
- NamedMixinApplication asNamedMixinApplication() => null; |
- NewExpression asNewExpression() => null; |
- NodeList asNodeList() => null; |
- Operator asOperator() => null; |
- ParenthesizedExpression asParenthesizedExpression() => null; |
- Part asPart() => null; |
- PartOf asPartOf() => null; |
- RedirectingFactoryBody asRedirectingFactoryBody() => null; |
- Rethrow asRethrow() => null; |
- Return asReturn() => null; |
- Send asSend() => null; |
- SendSet asSendSet() => null; |
- Statement asStatement() => null; |
- StringInterpolation asStringInterpolation() => null; |
- StringInterpolationPart asStringInterpolationPart() => null; |
- StringJuxtaposition asStringJuxtaposition() => null; |
- StringNode asStringNode() => null; |
- SwitchCase asSwitchCase() => null; |
- SwitchStatement asSwitchStatement() => null; |
- Throw asThrow() => null; |
- TryStatement asTryStatement() => null; |
- TypeAnnotation asTypeAnnotation() => null; |
- TypeVariable asTypeVariable() => null; |
- Typedef asTypedef() => null; |
- VariableDefinitions asVariableDefinitions() => null; |
- While asWhile() => null; |
- Yield asYield() => null; |
- |
- bool isValidBreakTarget() => false; |
- bool isValidContinueTarget() => false; |
- bool isThis() => false; |
- bool isSuper() => false; |
- |
- bool get isErroneous => false; |
-} |
- |
-class ClassNode extends Node { |
- final Modifiers modifiers; |
- final Identifier name; |
- final Node superclass; |
- final NodeList interfaces; |
- final NodeList typeParameters; |
- final NodeList body; |
- |
- final Token beginToken; |
- final Token extendsKeyword; |
- final Token endToken; |
- |
- ClassNode(this.modifiers, this.name, this.typeParameters, this.superclass, |
- this.interfaces, this.beginToken, |
- this.extendsKeyword, this.body, this.endToken); |
- |
- ClassNode asClassNode() => this; |
- |
- accept(Visitor visitor) => visitor.visitClassNode(this); |
- |
- visitChildren(Visitor visitor) { |
- if (name != null) name.accept(visitor); |
- if (typeParameters != null) typeParameters.accept(visitor); |
- if (superclass != null) superclass.accept(visitor); |
- if (interfaces != null) interfaces.accept(visitor); |
- if (body != null) body.accept(visitor); |
- } |
- |
- Token getBeginToken() => beginToken; |
- |
- Token getEndToken() => endToken; |
-} |
- |
-class MixinApplication extends Node { |
- final TypeAnnotation superclass; |
- final NodeList mixins; |
- |
- MixinApplication(this.superclass, this.mixins); |
- |
- MixinApplication asMixinApplication() => this; |
- |
- accept(Visitor visitor) => visitor.visitMixinApplication(this); |
- |
- visitChildren(Visitor visitor) { |
- if (superclass != null) superclass.accept(visitor); |
- if (mixins != null) mixins.accept(visitor); |
- } |
- |
- Token getBeginToken() => superclass.getBeginToken(); |
- Token getEndToken() => mixins.getEndToken(); |
-} |
- |
-// TODO(kasperl): Let this share some structure with the typedef for function |
-// type aliases? |
-class NamedMixinApplication extends Node implements MixinApplication { |
- final Identifier name; |
- final NodeList typeParameters; |
- |
- final Modifiers modifiers; |
- final MixinApplication mixinApplication; |
- final NodeList interfaces; |
- |
- final Token classKeyword; |
- final Token endToken; |
- |
- NamedMixinApplication(this.name, this.typeParameters, |
- this.modifiers, this.mixinApplication, this.interfaces, |
- this.classKeyword, this.endToken); |
- |
- TypeAnnotation get superclass => mixinApplication.superclass; |
- NodeList get mixins => mixinApplication.mixins; |
- |
- MixinApplication asMixinApplication() => this; |
- NamedMixinApplication asNamedMixinApplication() => this; |
- |
- accept(Visitor visitor) => visitor.visitNamedMixinApplication(this); |
- |
- visitChildren(Visitor visitor) { |
- name.accept(visitor); |
- if (typeParameters != null) typeParameters.accept(visitor); |
- if (modifiers != null) modifiers.accept(visitor); |
- if (interfaces != null) interfaces.accept(visitor); |
- mixinApplication.accept(visitor); |
- } |
- |
- Token getBeginToken() => classKeyword; |
- Token getEndToken() => endToken; |
-} |
- |
-abstract class Expression extends Node { |
- Expression(); |
- |
- Expression asExpression() => this; |
- |
- // TODO(ahe): make class abstract instead of adding an abstract method. |
- accept(Visitor visitor); |
-} |
- |
-abstract class Statement extends Node { |
- Statement(); |
- |
- Statement asStatement() => this; |
- |
- // TODO(ahe): make class abstract instead of adding an abstract method. |
- accept(Visitor visitor); |
- |
- bool isValidBreakTarget() => true; |
-} |
- |
-/// Erroneous expression that behaves as a literal null. |
-class ErrorExpression extends LiteralNull { |
- ErrorExpression(token) |
- : super(token); |
- |
- ErrorExpression asErrorExpression() => this; |
- |
- bool get isErroneous => true; |
-} |
- |
-/** |
- * A message send aka method invocation. In Dart, most operations can |
- * (and should) be considered as message sends. Getters and setters |
- * are just methods with a special syntax. Consequently, we model |
- * property access, assignment, operators, and method calls with this |
- * one node. |
- */ |
-class Send extends Expression with StoredTreeElementMixin { |
- final Node receiver; |
- final Node selector; |
- final NodeList argumentsNode; |
- Link<Node> get arguments => argumentsNode.nodes; |
- |
- Send([this.receiver, this.selector, this.argumentsNode]); |
- Send.postfix(this.receiver, this.selector, [Node argument = null]) |
- : argumentsNode = (argument == null) |
- ? new Postfix() |
- : new Postfix.singleton(argument); |
- Send.prefix(this.receiver, this.selector, [Node argument = null]) |
- : argumentsNode = (argument == null) |
- ? new Prefix() |
- : new Prefix.singleton(argument); |
- |
- Send asSend() => this; |
- |
- accept(Visitor visitor) => visitor.visitSend(this); |
- |
- visitChildren(Visitor visitor) { |
- if (receiver != null) receiver.accept(visitor); |
- if (selector != null) selector.accept(visitor); |
- if (argumentsNode != null) argumentsNode.accept(visitor); |
- } |
- |
- int argumentCount() { |
- return (argumentsNode == null) ? -1 : argumentsNode.slowLength(); |
- } |
- |
- bool get isSuperCall { |
- return receiver != null && receiver.isSuper(); |
- } |
- bool get isOperator => selector is Operator; |
- bool get isPropertyAccess => argumentsNode == null; |
- bool get isFunctionObjectInvocation => selector == null; |
- bool get isPrefix => argumentsNode is Prefix; |
- bool get isPostfix => argumentsNode is Postfix; |
- bool get isCall => !isOperator && !isPropertyAccess; |
- bool get isIndex => |
- isOperator && identical(selector.asOperator().source, '[]'); |
- bool get isLogicalAnd => |
- isOperator && identical(selector.asOperator().source, '&&'); |
- bool get isLogicalOr => |
- isOperator && identical(selector.asOperator().source, '||'); |
- |
- bool get isTypeCast { |
- return isOperator |
- && identical(selector.asOperator().source, 'as'); |
- } |
- |
- bool get isTypeTest { |
- return isOperator |
- && identical(selector.asOperator().source, 'is'); |
- } |
- |
- bool get isIsNotCheck { |
- return isTypeTest && arguments.head.asSend() != null; |
- } |
- |
- TypeAnnotation get typeAnnotationFromIsCheckOrCast { |
- assert(isOperator); |
- assert(identical(selector.asOperator().source, 'is') || |
- identical(selector.asOperator().source, 'as')); |
- return isIsNotCheck |
- ? arguments.head.asSend().receiver |
- : arguments.head; |
- } |
- |
- Token getBeginToken() { |
- if (isPrefix && !isIndex) return selector.getBeginToken(); |
- return firstBeginToken(receiver, selector); |
- } |
- |
- Token getEndToken() { |
- if (isPrefix) { |
- if (receiver != null) return receiver.getEndToken(); |
- if (selector != null) return selector.getEndToken(); |
- return null; |
- } |
- if (!isPostfix && argumentsNode != null) { |
- Token token = argumentsNode.getEndToken(); |
- if (token != null) return token; |
- } |
- if (selector != null) return selector.getEndToken(); |
- return getBeginToken(); |
- } |
- |
- Send copyWithReceiver(Node newReceiver) { |
- assert(receiver == null); |
- return new Send(newReceiver, selector, argumentsNode); |
- } |
-} |
- |
-class Postfix extends NodeList { |
- Postfix() : super(null, const Link<Node>()); |
- Postfix.singleton(Node argument) : super.singleton(argument); |
-} |
- |
-class Prefix extends NodeList { |
- Prefix() : super(null, const Link<Node>()); |
- Prefix.singleton(Node argument) : super.singleton(argument); |
-} |
- |
-class SendSet extends Send { |
- final Operator assignmentOperator; |
- SendSet(receiver, selector, this.assignmentOperator, argumentsNode) |
- : super(receiver, selector, argumentsNode); |
- SendSet.postfix(receiver, |
- selector, |
- this.assignmentOperator, |
- [Node argument = null]) |
- : super.postfix(receiver, selector, argument); |
- SendSet.prefix(receiver, |
- selector, |
- this.assignmentOperator, |
- [Node argument = null]) |
- : super.prefix(receiver, selector, argument); |
- |
- SendSet asSendSet() => this; |
- |
- accept(Visitor visitor) => visitor.visitSendSet(this); |
- |
- visitChildren(Visitor visitor) { |
- super.visitChildren(visitor); |
- if (assignmentOperator != null) assignmentOperator.accept(visitor); |
- } |
- |
- Send copyWithReceiver(Node newReceiver) { |
- assert(receiver == null); |
- return new SendSet(newReceiver, selector, assignmentOperator, |
- argumentsNode); |
- } |
- |
- Token getBeginToken() { |
- if (isPrefix) return assignmentOperator.getBeginToken(); |
- return super.getBeginToken(); |
- } |
- |
- Token getEndToken() { |
- if (isPostfix) return assignmentOperator.getEndToken(); |
- return super.getEndToken(); |
- } |
-} |
- |
-class NewExpression extends Expression { |
- /** The token NEW or CONST or `null` for metadata */ |
- final Token newToken; |
- |
- // Note: we expect that send.receiver is null. |
- final Send send; |
- |
- NewExpression([this.newToken, this.send]); |
- |
- NewExpression asNewExpression() => this; |
- |
- accept(Visitor visitor) => visitor.visitNewExpression(this); |
- |
- visitChildren(Visitor visitor) { |
- if (send != null) send.accept(visitor); |
- } |
- |
- bool get isConst { |
- return newToken == null || identical(newToken.stringValue, 'const'); |
- } |
- |
- Token getBeginToken() => newToken != null ? newToken : send.getBeginToken(); |
- |
- Token getEndToken() => send.getEndToken(); |
-} |
- |
-class NodeList extends Node { |
- final Link<Node> nodes; |
- final Token beginToken; |
- final Token endToken; |
- final String delimiter; |
- bool get isEmpty => nodes.isEmpty; |
- |
- NodeList([this.beginToken, this.nodes, this.endToken, this.delimiter]); |
- |
- Iterator<Node> get iterator => nodes.iterator; |
- |
- NodeList.singleton(Node node) : this(null, const Link<Node>().prepend(node)); |
- NodeList.empty() : this(null, const Link<Node>()); |
- |
- NodeList asNodeList() => this; |
- |
- int slowLength() { |
- int result = 0; |
- for (Link<Node> cursor = nodes; !cursor.isEmpty; cursor = cursor.tail) { |
- result++; |
- } |
- return result; |
- } |
- |
- accept(Visitor visitor) => visitor.visitNodeList(this); |
- |
- visitChildren(Visitor visitor) { |
- if (nodes == null) return; |
- for (Link<Node> link = nodes; !link.isEmpty; link = link.tail) { |
- if (link.head != null) link.head.accept(visitor); |
- } |
- } |
- |
- Token getBeginToken() { |
- if (beginToken != null) return beginToken; |
- if (nodes != null) { |
- for (Link<Node> link = nodes; !link.isEmpty; link = link.tail) { |
- if (link.head.getBeginToken() != null) { |
- return link.head.getBeginToken(); |
- } |
- if (link.head.getEndToken() != null) { |
- return link.head.getEndToken(); |
- } |
- } |
- } |
- return endToken; |
- } |
- |
- Token getEndToken() { |
- if (endToken != null) return endToken; |
- if (nodes != null) { |
- Link<Node> link = nodes; |
- if (link.isEmpty) return beginToken; |
- while (!link.tail.isEmpty) link = link.tail; |
- Node lastNode = link.head; |
- if (lastNode != null) { |
- if (lastNode.getEndToken() != null) return lastNode.getEndToken(); |
- if (lastNode.getBeginToken() != null) return lastNode.getBeginToken(); |
- } |
- } |
- return beginToken; |
- } |
-} |
- |
-class Block extends Statement { |
- final NodeList statements; |
- |
- Block(this.statements); |
- |
- Block asBlock() => this; |
- |
- accept(Visitor visitor) => visitor.visitBlock(this); |
- |
- visitChildren(Visitor visitor) { |
- if (statements != null) statements.accept(visitor); |
- } |
- |
- Token getBeginToken() => statements.getBeginToken(); |
- |
- Token getEndToken() => statements.getEndToken(); |
-} |
- |
-class If extends Statement { |
- final ParenthesizedExpression condition; |
- final Statement thenPart; |
- final Statement elsePart; |
- |
- final Token ifToken; |
- final Token elseToken; |
- |
- If(this.condition, this.thenPart, this.elsePart, |
- this.ifToken, this.elseToken); |
- |
- If asIf() => this; |
- |
- bool get hasElsePart => elsePart != null; |
- |
- accept(Visitor visitor) => visitor.visitIf(this); |
- |
- visitChildren(Visitor visitor) { |
- if (condition != null) condition.accept(visitor); |
- if (thenPart != null) thenPart.accept(visitor); |
- if (elsePart != null) elsePart.accept(visitor); |
- } |
- |
- Token getBeginToken() => ifToken; |
- |
- Token getEndToken() { |
- if (elsePart == null) return thenPart.getEndToken(); |
- return elsePart.getEndToken(); |
- } |
-} |
- |
-class Conditional extends Expression { |
- final Expression condition; |
- final Expression thenExpression; |
- final Expression elseExpression; |
- |
- final Token questionToken; |
- final Token colonToken; |
- |
- Conditional(this.condition, this.thenExpression, |
- this.elseExpression, this.questionToken, this.colonToken); |
- |
- Conditional asConditional() => this; |
- |
- accept(Visitor visitor) => visitor.visitConditional(this); |
- |
- visitChildren(Visitor visitor) { |
- condition.accept(visitor); |
- thenExpression.accept(visitor); |
- elseExpression.accept(visitor); |
- } |
- |
- Token getBeginToken() => condition.getBeginToken(); |
- |
- Token getEndToken() => elseExpression.getEndToken(); |
-} |
- |
-class For extends Loop { |
- /** Either a variable declaration or an expression. */ |
- final Node initializer; |
- /** Either an expression statement or an empty statement. */ |
- final Statement conditionStatement; |
- final NodeList update; |
- |
- final Token forToken; |
- |
- For(this.initializer, this.conditionStatement, this.update, body, |
- this.forToken) : super(body); |
- |
- For asFor() => this; |
- |
- Expression get condition { |
- ExpressionStatement expressionStatement = |
- conditionStatement.asExpressionStatement(); |
- if (expressionStatement != null) { |
- return expressionStatement.expression; |
- } else { |
- return null; |
- } |
- } |
- |
- accept(Visitor visitor) => visitor.visitFor(this); |
- |
- visitChildren(Visitor visitor) { |
- if (initializer != null) initializer.accept(visitor); |
- if (conditionStatement != null) conditionStatement.accept(visitor); |
- if (update != null) update.accept(visitor); |
- if (body != null) body.accept(visitor); |
- } |
- |
- Token getBeginToken() => forToken; |
- |
- Token getEndToken() { |
- return body.getEndToken(); |
- } |
-} |
- |
-class FunctionDeclaration extends Statement { |
- final FunctionExpression function; |
- |
- FunctionDeclaration(this.function); |
- |
- FunctionDeclaration asFunctionDeclaration() => this; |
- |
- accept(Visitor visitor) => visitor.visitFunctionDeclaration(this); |
- |
- visitChildren(Visitor visitor) => function.accept(visitor); |
- |
- Token getBeginToken() => function.getBeginToken(); |
- Token getEndToken() => function.getEndToken(); |
-} |
- |
-/// Node representing the method implementation modifiers `sync*`, `async`, and |
-/// `async*` or the invalid modifier `sync`. |
-class AsyncModifier extends Node { |
- /// The `async` or `sync` token. |
- final Token asyncToken; |
- |
- /// The `*` token. |
- final Token starToken; |
- |
- AsyncModifier(this.asyncToken, this.starToken); |
- |
- AsyncModifier asAsyncModifier() => this; |
- |
- accept(Visitor visitor) => visitor.visitAsyncModifier(this); |
- |
- visitChildren(Visitor visitor) {} |
- |
- Token getBeginToken() => asyncToken; |
- |
- Token getEndToken() => starToken != null ? starToken : asyncToken; |
- |
- /// Is `true` if this modifier is either `async` or `async*`. |
- bool get isAsynchronous => asyncToken.value == 'async'; |
- |
- /// Is `true` if this modifier is either `sync*` or `async*`. |
- bool get isYielding => starToken != null; |
-} |
- |
-class FunctionExpression extends Expression with StoredTreeElementMixin { |
- final Node name; |
- |
- /** |
- * List of VariableDefinitions or NodeList. |
- * |
- * A NodeList can only occur at the end and holds named parameters. |
- */ |
- final NodeList parameters; |
- |
- final Statement body; |
- final TypeAnnotation returnType; |
- final Modifiers modifiers; |
- final NodeList initializers; |
- |
- final Token getOrSet; |
- final AsyncModifier asyncModifier; |
- |
- FunctionExpression(this.name, this.parameters, this.body, this.returnType, |
- this.modifiers, this.initializers, this.getOrSet, |
- this.asyncModifier) { |
- assert(modifiers != null); |
- } |
- |
- FunctionExpression asFunctionExpression() => this; |
- |
- accept(Visitor visitor) => visitor.visitFunctionExpression(this); |
- |
- bool get isRedirectingFactory { |
- return body != null && body.asRedirectingFactoryBody() != null; |
- } |
- |
- visitChildren(Visitor visitor) { |
- if (modifiers != null) modifiers.accept(visitor); |
- if (returnType != null) returnType.accept(visitor); |
- if (name != null) name.accept(visitor); |
- if (parameters != null) parameters.accept(visitor); |
- if (initializers != null) initializers.accept(visitor); |
- if (asyncModifier != null) asyncModifier.accept(visitor); |
- if (body != null) body.accept(visitor); |
- } |
- |
- bool hasBody() => body.asEmptyStatement() == null; |
- |
- bool hasEmptyBody() { |
- Block block = body.asBlock(); |
- if (block == null) return false; |
- return block.statements.isEmpty; |
- } |
- |
- Token getBeginToken() { |
- Token token = firstBeginToken(modifiers, returnType); |
- if (token != null) return token; |
- if (getOrSet != null) return getOrSet; |
- return firstBeginToken(name, parameters); |
- } |
- |
- Token getEndToken() { |
- Token token = (body == null) ? null : body.getEndToken(); |
- token = (token == null) ? parameters.getEndToken() : token; |
- return (token == null) ? name.getEndToken() : token; |
- } |
-} |
- |
-typedef void DecodeErrorHandler(Token token, var error); |
- |
-abstract class Literal<T> extends Expression { |
- final Token token; |
- final DecodeErrorHandler handler; |
- |
- Literal(Token this.token, DecodeErrorHandler this.handler); |
- |
- T get value; |
- |
- visitChildren(Visitor visitor) {} |
- |
- Token getBeginToken() => token; |
- |
- Token getEndToken() => token; |
-} |
- |
-class LiteralInt extends Literal<int> { |
- LiteralInt(Token token, DecodeErrorHandler handler) : super(token, handler); |
- |
- LiteralInt asLiteralInt() => this; |
- |
- int get value { |
- try { |
- Token valueToken = token; |
- if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next; |
- return int.parse(valueToken.value); |
- } on FormatException catch (ex) { |
- (this.handler)(token, ex); |
- } |
- } |
- |
- accept(Visitor visitor) => visitor.visitLiteralInt(this); |
-} |
- |
-class LiteralDouble extends Literal<double> { |
- LiteralDouble(Token token, DecodeErrorHandler handler) |
- : super(token, handler); |
- |
- LiteralDouble asLiteralDouble() => this; |
- |
- double get value { |
- try { |
- Token valueToken = token; |
- if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next; |
- return double.parse(valueToken.value); |
- } on FormatException catch (ex) { |
- (this.handler)(token, ex); |
- } |
- } |
- |
- accept(Visitor visitor) => visitor.visitLiteralDouble(this); |
-} |
- |
-class LiteralBool extends Literal<bool> { |
- LiteralBool(Token token, DecodeErrorHandler handler) : super(token, handler); |
- |
- LiteralBool asLiteralBool() => this; |
- |
- bool get value { |
- if (identical(token.stringValue, 'true')) return true; |
- if (identical(token.stringValue, 'false')) return false; |
- (this.handler)(token, "not a bool ${token.value}"); |
- throw false; |
- } |
- |
- accept(Visitor visitor) => visitor.visitLiteralBool(this); |
-} |
- |
- |
-class StringQuoting { |
- |
- /// Cache of common quotings. |
- static const List<StringQuoting> _mapping = const <StringQuoting>[ |
- const StringQuoting($SQ, raw: false, leftQuoteLength: 1), |
- const StringQuoting($SQ, raw: true, leftQuoteLength: 1), |
- const StringQuoting($DQ, raw: false, leftQuoteLength: 1), |
- const StringQuoting($DQ, raw: true, leftQuoteLength: 1), |
- // No string quotes with 2 characters. |
- null, |
- null, |
- null, |
- null, |
- // Multiline quotings. |
- const StringQuoting($SQ, raw: false, leftQuoteLength: 3), |
- const StringQuoting($SQ, raw: true, leftQuoteLength: 3), |
- const StringQuoting($DQ, raw: false, leftQuoteLength: 3), |
- const StringQuoting($DQ, raw: true, leftQuoteLength: 3), |
- // Leading single whitespace or espaped newline. |
- const StringQuoting($SQ, raw: false, leftQuoteLength: 4), |
- const StringQuoting($SQ, raw: true, leftQuoteLength: 4), |
- const StringQuoting($DQ, raw: false, leftQuoteLength: 4), |
- const StringQuoting($DQ, raw: true, leftQuoteLength: 4), |
- // Other combinations of leading whitespace and/or escaped newline. |
- const StringQuoting($SQ, raw: false, leftQuoteLength: 5), |
- const StringQuoting($SQ, raw: true, leftQuoteLength: 5), |
- const StringQuoting($DQ, raw: false, leftQuoteLength: 5), |
- const StringQuoting($DQ, raw: true, leftQuoteLength: 5), |
- const StringQuoting($SQ, raw: false, leftQuoteLength: 6), |
- const StringQuoting($SQ, raw: true, leftQuoteLength: 6), |
- const StringQuoting($DQ, raw: false, leftQuoteLength: 6), |
- const StringQuoting($DQ, raw: true, leftQuoteLength: 6) |
- ]; |
- |
- final bool raw; |
- final int leftQuoteCharCount; |
- final int quote; |
- const StringQuoting(this.quote, { this.raw, int leftQuoteLength }) |
- : this.leftQuoteCharCount = leftQuoteLength; |
- String get quoteChar => identical(quote, $DQ) ? '"' : "'"; |
- |
- int get leftQuoteLength => (raw ? 1 : 0) + leftQuoteCharCount; |
- int get rightQuoteLength => (leftQuoteCharCount > 2) ? 3 : 1; |
- static StringQuoting getQuoting(int quote, bool raw, int leftQuoteLength) { |
- int quoteKindOffset = (quote == $DQ) ? 2 : 0; |
- int rawOffset = raw ? 1 : 0; |
- int index = (leftQuoteLength - 1) * 4 + rawOffset + quoteKindOffset; |
- if (index < _mapping.length) return _mapping[index]; |
- return new StringQuoting(quote, raw: raw, leftQuoteLength: leftQuoteLength); |
- } |
-} |
- |
-/** |
- * Superclass for classes representing string literals. |
- */ |
-abstract class StringNode extends Expression { |
- DartString get dartString; |
- bool get isInterpolation; |
- |
- StringNode asStringNode() => this; |
-} |
- |
-class LiteralString extends StringNode { |
- final Token token; |
- /** Non-null on validated string literals. */ |
- final DartString dartString; |
- |
- LiteralString(this.token, this.dartString); |
- |
- LiteralString asLiteralString() => this; |
- |
- void visitChildren(Visitor visitor) {} |
- |
- bool get isInterpolation => false; |
- |
- Token getBeginToken() => token; |
- Token getEndToken() => token; |
- |
- accept(Visitor visitor) => visitor.visitLiteralString(this); |
-} |
- |
-class LiteralNull extends Literal<String> { |
- LiteralNull(Token token) : super(token, null); |
- |
- LiteralNull asLiteralNull() => this; |
- |
- String get value => null; |
- |
- accept(Visitor visitor) => visitor.visitLiteralNull(this); |
-} |
- |
-class LiteralList extends Expression { |
- final NodeList typeArguments; |
- final NodeList elements; |
- |
- final Token constKeyword; |
- |
- LiteralList(this.typeArguments, this.elements, this.constKeyword); |
- |
- bool get isConst => constKeyword != null; |
- |
- LiteralList asLiteralList() => this; |
- accept(Visitor visitor) => visitor.visitLiteralList(this); |
- |
- visitChildren(Visitor visitor) { |
- if (typeArguments != null) typeArguments.accept(visitor); |
- elements.accept(visitor); |
- } |
- |
- Token getBeginToken() { |
- if (constKeyword != null) return constKeyword; |
- return firstBeginToken(typeArguments, elements); |
- } |
- |
- Token getEndToken() => elements.getEndToken(); |
-} |
- |
-class LiteralSymbol extends Expression { |
- final Token hashToken; |
- final NodeList identifiers; |
- |
- LiteralSymbol(this.hashToken, this.identifiers); |
- |
- LiteralSymbol asLiteralSymbol() => this; |
- |
- void visitChildren(Visitor visitor) { |
- if (identifiers != null) identifiers.accept(visitor); |
- } |
- |
- accept(Visitor visitor) => visitor.visitLiteralSymbol(this); |
- |
- Token getBeginToken() => hashToken; |
- |
- Token getEndToken() => identifiers.getEndToken(); |
- |
- String get slowNameString { |
- Unparser unparser = new Unparser(); |
- unparser.unparseNodeListOfIdentifiers(identifiers); |
- return unparser.result; |
- } |
-} |
- |
-class Identifier extends Expression with StoredTreeElementMixin { |
- final Token token; |
- |
- String get source => token.value; |
- |
- Identifier(Token this.token); |
- |
- bool isThis() => identical(source, 'this'); |
- |
- bool isSuper() => identical(source, 'super'); |
- |
- Identifier asIdentifier() => this; |
- |
- accept(Visitor visitor) => visitor.visitIdentifier(this); |
- |
- visitChildren(Visitor visitor) {} |
- |
- Token getBeginToken() => token; |
- |
- Token getEndToken() => token; |
-} |
- |
-class Operator extends Identifier { |
- static const COMPLEX_OPERATORS = |
- const ["--", "++", '+=', "-=", "*=", "/=", "%=", "&=", "|=", "~/=", "^=", |
- ">>=", "<<="]; |
- |
- static const INCREMENT_OPERATORS = const <String>["++", "--"]; |
- |
- Operator(Token token) : super(token); |
- |
- Operator asOperator() => this; |
- |
- accept(Visitor visitor) => visitor.visitOperator(this); |
-} |
- |
-class Return extends Statement { |
- final Node expression; |
- final Token beginToken; |
- final Token endToken; |
- |
- Return(this.beginToken, this.endToken, this.expression); |
- |
- Return asReturn() => this; |
- |
- bool get hasExpression => expression != null; |
- |
- accept(Visitor visitor) => visitor.visitReturn(this); |
- |
- visitChildren(Visitor visitor) { |
- if (expression != null) expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => beginToken; |
- |
- Token getEndToken() { |
- if (endToken == null) return expression.getEndToken(); |
- return endToken; |
- } |
-} |
- |
-class Yield extends Statement { |
- final Node expression; |
- final Token yieldToken; |
- final Token starToken; |
- final Token endToken; |
- |
- Yield(this.yieldToken, this.starToken, this.expression, this.endToken); |
- |
- Yield asYield() => this; |
- |
- bool get hasStar => starToken != null; |
- |
- accept(Visitor visitor) => visitor.visitYield(this); |
- |
- visitChildren(Visitor visitor) { |
- expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => yieldToken; |
- |
- Token getEndToken() => endToken; |
-} |
- |
-class RedirectingFactoryBody extends Statement with StoredTreeElementMixin { |
- final Node constructorReference; |
- final Token beginToken; |
- final Token endToken; |
- |
- RedirectingFactoryBody(this.beginToken, this.endToken, |
- this.constructorReference); |
- |
- RedirectingFactoryBody asRedirectingFactoryBody() => this; |
- |
- accept(Visitor visitor) => visitor.visitRedirectingFactoryBody(this); |
- |
- visitChildren(Visitor visitor) { |
- constructorReference.accept(visitor); |
- } |
- |
- Token getBeginToken() => beginToken; |
- |
- Token getEndToken() => endToken; |
-} |
- |
-class ExpressionStatement extends Statement { |
- final Expression expression; |
- final Token endToken; |
- |
- ExpressionStatement(this.expression, this.endToken); |
- |
- ExpressionStatement asExpressionStatement() => this; |
- |
- accept(Visitor visitor) => visitor.visitExpressionStatement(this); |
- |
- visitChildren(Visitor visitor) { |
- if (expression != null) expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => expression.getBeginToken(); |
- |
- Token getEndToken() => endToken; |
-} |
- |
-class Throw extends Expression { |
- final Expression expression; |
- |
- final Token throwToken; |
- final Token endToken; |
- |
- Throw(this.expression, this.throwToken, this.endToken); |
- |
- Throw asThrow() => this; |
- |
- accept(Visitor visitor) => visitor.visitThrow(this); |
- |
- visitChildren(Visitor visitor) { |
- expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => throwToken; |
- |
- Token getEndToken() => endToken; |
-} |
- |
-class Await extends Expression { |
- final Expression expression; |
- |
- final Token awaitToken; |
- |
- Await(this.awaitToken, this.expression); |
- |
- Await asAwait() => this; |
- |
- accept(Visitor visitor) => visitor.visitAwait(this); |
- |
- visitChildren(Visitor visitor) { |
- expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => awaitToken; |
- |
- Token getEndToken() => expression.getEndToken(); |
-} |
- |
-class Rethrow extends Statement { |
- final Token throwToken; |
- final Token endToken; |
- |
- Rethrow(this.throwToken, this.endToken); |
- |
- Rethrow asRethrow() => this; |
- |
- accept(Visitor visitor) => visitor.visitRethrow(this); |
- visitChildren(Visitor visitor) { } |
- |
- Token getBeginToken() => throwToken; |
- Token getEndToken() => endToken; |
-} |
- |
-class TypeAnnotation extends Node { |
- final Expression typeName; |
- final NodeList typeArguments; |
- |
- TypeAnnotation(Expression this.typeName, NodeList this.typeArguments); |
- |
- TypeAnnotation asTypeAnnotation() => this; |
- |
- accept(Visitor visitor) => visitor.visitTypeAnnotation(this); |
- |
- visitChildren(Visitor visitor) { |
- typeName.accept(visitor); |
- if (typeArguments != null) typeArguments.accept(visitor); |
- } |
- |
- Token getBeginToken() => typeName.getBeginToken(); |
- |
- Token getEndToken() => typeName.getEndToken(); |
-} |
- |
-class TypeVariable extends Node { |
- final Identifier name; |
- final TypeAnnotation bound; |
- TypeVariable(Identifier this.name, TypeAnnotation this.bound); |
- |
- accept(Visitor visitor) => visitor.visitTypeVariable(this); |
- |
- visitChildren(Visitor visitor) { |
- name.accept(visitor); |
- if (bound != null) { |
- bound.accept(visitor); |
- } |
- } |
- |
- TypeVariable asTypeVariable() => this; |
- |
- Token getBeginToken() => name.getBeginToken(); |
- |
- Token getEndToken() { |
- return (bound != null) ? bound.getEndToken() : name.getEndToken(); |
- } |
-} |
- |
-class VariableDefinitions extends Statement { |
- final NodeList metadata; |
- final TypeAnnotation type; |
- final Modifiers modifiers; |
- final NodeList definitions; |
- |
- VariableDefinitions(this.type, |
- this.modifiers, |
- this.definitions) |
- : this.metadata = null { |
- assert(modifiers != null); |
- } |
- |
- // TODO(johnniwinther): Make this its own node type. |
- VariableDefinitions.forParameter(this.metadata, |
- this.type, |
- this.modifiers, |
- this.definitions) { |
- assert(modifiers != null); |
- } |
- |
- VariableDefinitions asVariableDefinitions() => this; |
- |
- accept(Visitor visitor) => visitor.visitVariableDefinitions(this); |
- |
- visitChildren(Visitor visitor) { |
- if (metadata != null) metadata.accept(visitor); |
- if (type != null) type.accept(visitor); |
- if (definitions != null) definitions.accept(visitor); |
- } |
- |
- Token getBeginToken() { |
- var token = firstBeginToken(modifiers, type); |
- if (token == null) { |
- token = definitions.getBeginToken(); |
- } |
- return token; |
- } |
- |
- Token getEndToken() => definitions.getEndToken(); |
-} |
- |
-abstract class Loop extends Statement { |
- Expression get condition; |
- final Statement body; |
- |
- Loop(this.body); |
- |
- bool isValidContinueTarget() => true; |
-} |
- |
-class DoWhile extends Loop { |
- final Token doKeyword; |
- final Token whileKeyword; |
- final Token endToken; |
- |
- final Expression condition; |
- |
- DoWhile(Statement body, Expression this.condition, |
- Token this.doKeyword, Token this.whileKeyword, Token this.endToken) |
- : super(body); |
- |
- DoWhile asDoWhile() => this; |
- |
- accept(Visitor visitor) => visitor.visitDoWhile(this); |
- |
- visitChildren(Visitor visitor) { |
- if (condition != null) condition.accept(visitor); |
- if (body != null) body.accept(visitor); |
- } |
- |
- Token getBeginToken() => doKeyword; |
- |
- Token getEndToken() => endToken; |
-} |
- |
-class While extends Loop { |
- final Token whileKeyword; |
- final Expression condition; |
- |
- While(Expression this.condition, Statement body, |
- Token this.whileKeyword) : super(body); |
- |
- While asWhile() => this; |
- |
- accept(Visitor visitor) => visitor.visitWhile(this); |
- |
- visitChildren(Visitor visitor) { |
- if (condition != null) condition.accept(visitor); |
- if (body != null) body.accept(visitor); |
- } |
- |
- Token getBeginToken() => whileKeyword; |
- |
- Token getEndToken() => body.getEndToken(); |
-} |
- |
-class ParenthesizedExpression extends Expression { |
- final Expression expression; |
- final BeginGroupToken beginToken; |
- |
- ParenthesizedExpression(Expression this.expression, |
- BeginGroupToken this.beginToken); |
- |
- ParenthesizedExpression asParenthesizedExpression() => this; |
- |
- accept(Visitor visitor) => visitor.visitParenthesizedExpression(this); |
- |
- visitChildren(Visitor visitor) { |
- if (expression != null) expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => beginToken; |
- |
- Token getEndToken() => beginToken.endGroup; |
-} |
- |
-/** Representation of modifiers such as static, abstract, final, etc. */ |
-class Modifiers extends Node { |
- /** |
- * Pseudo-constant for empty modifiers. |
- */ |
- static final Modifiers EMPTY = new Modifiers(new NodeList.empty()); |
- |
- /* TODO(ahe): The following should be validated relating to modifiers: |
- * 1. The nodes must come in a certain order. |
- * 2. The keywords "var" and "final" may not be used at the same time. |
- * 3. The keywords "abstract" and "external" may not be used at the same time. |
- * 4. The type of an element must be null if isVar() is true. |
- */ |
- |
- final NodeList nodes; |
- /** Bit pattern to easy check what modifiers are present. */ |
- final int flags; |
- |
- static const int FLAG_STATIC = 1; |
- static const int FLAG_ABSTRACT = FLAG_STATIC << 1; |
- static const int FLAG_FINAL = FLAG_ABSTRACT << 1; |
- static const int FLAG_VAR = FLAG_FINAL << 1; |
- static const int FLAG_CONST = FLAG_VAR << 1; |
- static const int FLAG_FACTORY = FLAG_CONST << 1; |
- static const int FLAG_EXTERNAL = FLAG_FACTORY << 1; |
- |
- Modifiers(NodeList nodes) : this.withFlags(nodes, computeFlags(nodes.nodes)); |
- |
- Modifiers.withFlags(this.nodes, this.flags); |
- |
- static int computeFlags(Link<Node> nodes) { |
- int flags = 0; |
- for (; !nodes.isEmpty; nodes = nodes.tail) { |
- String value = nodes.head.asIdentifier().source; |
- if (identical(value, 'static')) flags |= FLAG_STATIC; |
- else if (identical(value, 'abstract')) flags |= FLAG_ABSTRACT; |
- else if (identical(value, 'final')) flags |= FLAG_FINAL; |
- else if (identical(value, 'var')) flags |= FLAG_VAR; |
- else if (identical(value, 'const')) flags |= FLAG_CONST; |
- else if (identical(value, 'factory')) flags |= FLAG_FACTORY; |
- else if (identical(value, 'external')) flags |= FLAG_EXTERNAL; |
- else throw 'internal error: ${nodes.head}'; |
- } |
- return flags; |
- } |
- |
- Node findModifier(String modifier) { |
- Link<Node> nodeList = nodes.nodes; |
- for (; !nodeList.isEmpty; nodeList = nodeList.tail) { |
- String value = nodeList.head.asIdentifier().source; |
- if(identical(value, modifier)) { |
- return nodeList.head; |
- } |
- } |
- return null; |
- } |
- |
- Modifiers asModifiers() => this; |
- Token getBeginToken() => nodes.getBeginToken(); |
- Token getEndToken() => nodes.getEndToken(); |
- accept(Visitor visitor) => visitor.visitModifiers(this); |
- visitChildren(Visitor visitor) => nodes.accept(visitor); |
- |
- bool get isStatic => (flags & FLAG_STATIC) != 0; |
- bool get isAbstract => (flags & FLAG_ABSTRACT) != 0; |
- bool get isFinal => (flags & FLAG_FINAL) != 0; |
- bool get isVar => (flags & FLAG_VAR) != 0; |
- bool get isConst => (flags & FLAG_CONST) != 0; |
- bool get isFactory => (flags & FLAG_FACTORY) != 0; |
- bool get isExternal => (flags & FLAG_EXTERNAL) != 0; |
- |
- Node getStatic() => findModifier('static'); |
- |
- /** |
- * Use this to check if the declaration is either explicitly or implicitly |
- * final. |
- */ |
- bool get isFinalOrConst => isFinal || isConst; |
- |
- String toString() { |
- return modifiersToString(isStatic: isStatic, |
- isAbstract: isAbstract, |
- isFinal: isFinal, |
- isVar: isVar, |
- isConst: isConst, |
- isFactory: isFactory, |
- isExternal: isExternal); |
- } |
-} |
- |
-class StringInterpolation extends StringNode { |
- final LiteralString string; |
- final NodeList parts; |
- |
- StringInterpolation(this.string, this.parts); |
- |
- StringInterpolation asStringInterpolation() => this; |
- |
- DartString get dartString => null; |
- bool get isInterpolation => true; |
- |
- accept(Visitor visitor) => visitor.visitStringInterpolation(this); |
- |
- visitChildren(Visitor visitor) { |
- string.accept(visitor); |
- parts.accept(visitor); |
- } |
- |
- Token getBeginToken() => string.getBeginToken(); |
- Token getEndToken() => parts.getEndToken(); |
-} |
- |
-class StringInterpolationPart extends Node { |
- final Expression expression; |
- final LiteralString string; |
- |
- StringInterpolationPart(this.expression, this.string); |
- |
- StringInterpolationPart asStringInterpolationPart() => this; |
- |
- accept(Visitor visitor) => visitor.visitStringInterpolationPart(this); |
- |
- visitChildren(Visitor visitor) { |
- expression.accept(visitor); |
- string.accept(visitor); |
- } |
- |
- Token getBeginToken() => expression.getBeginToken(); |
- |
- Token getEndToken() => string.getEndToken(); |
-} |
- |
-/** |
- * A class representing juxtaposed string literals. |
- * The string literals can be both plain literals and string interpolations. |
- */ |
-class StringJuxtaposition extends StringNode { |
- final Expression first; |
- final Expression second; |
- |
- /** |
- * Caches the check for whether this juxtaposition contains a string |
- * interpolation |
- */ |
- bool isInterpolationCache = null; |
- |
- /** |
- * Caches a Dart string representation of the entire juxtaposition's |
- * content. Only juxtapositions that don't (transitively) contains |
- * interpolations have a static representation. |
- */ |
- DartString dartStringCache = null; |
- |
- StringJuxtaposition(this.first, this.second); |
- |
- StringJuxtaposition asStringJuxtaposition() => this; |
- |
- bool get isInterpolation { |
- if (isInterpolationCache == null) { |
- isInterpolationCache = (first.accept(const IsInterpolationVisitor()) || |
- second.accept(const IsInterpolationVisitor())); |
- } |
- return isInterpolationCache; |
- } |
- |
- /** |
- * Retrieve a single DartString that represents this entire juxtaposition |
- * of string literals. |
- * Should only be called if [isInterpolation] returns false. |
- */ |
- DartString get dartString { |
- if (isInterpolation) { |
- throw new SpannableAssertionFailure( |
- this, "Getting dartString on interpolation;"); |
- } |
- if (dartStringCache == null) { |
- DartString firstString = first.accept(const GetDartStringVisitor()); |
- DartString secondString = second.accept(const GetDartStringVisitor()); |
- if (firstString == null || secondString == null) { |
- return null; |
- } |
- dartStringCache = new DartString.concat(firstString, secondString); |
- } |
- return dartStringCache; |
- } |
- |
- accept(Visitor visitor) => visitor.visitStringJuxtaposition(this); |
- |
- void visitChildren(Visitor visitor) { |
- first.accept(visitor); |
- second.accept(visitor); |
- } |
- |
- Token getBeginToken() => first.getBeginToken(); |
- |
- Token getEndToken() => second.getEndToken(); |
-} |
- |
-class EmptyStatement extends Statement { |
- final Token semicolonToken; |
- |
- EmptyStatement(this.semicolonToken); |
- |
- EmptyStatement asEmptyStatement() => this; |
- |
- accept(Visitor visitor) => visitor.visitEmptyStatement(this); |
- |
- visitChildren(Visitor visitor) {} |
- |
- Token getBeginToken() => semicolonToken; |
- |
- Token getEndToken() => semicolonToken; |
-} |
- |
-class LiteralMap extends Expression { |
- final NodeList typeArguments; |
- final NodeList entries; |
- |
- final Token constKeyword; |
- |
- LiteralMap(this.typeArguments, this.entries, this.constKeyword); |
- |
- bool get isConst => constKeyword != null; |
- |
- LiteralMap asLiteralMap() => this; |
- |
- accept(Visitor visitor) => visitor.visitLiteralMap(this); |
- |
- visitChildren(Visitor visitor) { |
- if (typeArguments != null) typeArguments.accept(visitor); |
- entries.accept(visitor); |
- } |
- |
- Token getBeginToken() { |
- if (constKeyword != null) return constKeyword; |
- return firstBeginToken(typeArguments, entries); |
- } |
- |
- Token getEndToken() => entries.getEndToken(); |
-} |
- |
-class LiteralMapEntry extends Node { |
- final Expression key; |
- final Expression value; |
- |
- final Token colonToken; |
- |
- LiteralMapEntry(this.key, this.colonToken, this.value); |
- |
- LiteralMapEntry asLiteralMapEntry() => this; |
- |
- accept(Visitor visitor) => visitor.visitLiteralMapEntry(this); |
- |
- visitChildren(Visitor visitor) { |
- key.accept(visitor); |
- value.accept(visitor); |
- } |
- |
- Token getBeginToken() => key.getBeginToken(); |
- |
- Token getEndToken() => value.getEndToken(); |
-} |
- |
-class NamedArgument extends Expression { |
- final Identifier name; |
- final Expression expression; |
- |
- final Token colonToken; |
- |
- NamedArgument(this.name, this.colonToken, this.expression); |
- |
- NamedArgument asNamedArgument() => this; |
- |
- accept(Visitor visitor) => visitor.visitNamedArgument(this); |
- |
- visitChildren(Visitor visitor) { |
- name.accept(visitor); |
- expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => name.getBeginToken(); |
- |
- Token getEndToken() => expression.getEndToken(); |
-} |
- |
-class SwitchStatement extends Statement { |
- final ParenthesizedExpression parenthesizedExpression; |
- final NodeList cases; |
- |
- final Token switchKeyword; |
- |
- SwitchStatement(this.parenthesizedExpression, this.cases, |
- this.switchKeyword); |
- |
- SwitchStatement asSwitchStatement() => this; |
- |
- Expression get expression => parenthesizedExpression.expression; |
- |
- accept(Visitor visitor) => visitor.visitSwitchStatement(this); |
- |
- visitChildren(Visitor visitor) { |
- parenthesizedExpression.accept(visitor); |
- cases.accept(visitor); |
- } |
- |
- Token getBeginToken() => switchKeyword; |
- |
- Token getEndToken() => cases.getEndToken(); |
-} |
- |
-class CaseMatch extends Node { |
- final Token caseKeyword; |
- final Expression expression; |
- final Token colonToken; |
- CaseMatch(this.caseKeyword, this.expression, this.colonToken); |
- |
- CaseMatch asCaseMatch() => this; |
- Token getBeginToken() => caseKeyword; |
- Token getEndToken() => colonToken; |
- accept(Visitor visitor) => visitor.visitCaseMatch(this); |
- visitChildren(Visitor visitor) => expression.accept(visitor); |
-} |
- |
-class SwitchCase extends Node { |
- // The labels and case patterns are collected in [labelsAndCases]. |
- // The default keyword, if present, is collected in [defaultKeyword]. |
- // Any actual switch case must have at least one 'case' or 'default' |
- // clause. |
- // Notice: The labels and cases can occur interleaved in the source. |
- // They are separated here, since the order is irrelevant to the meaning |
- // of the switch. |
- |
- /** List of [Label] and [CaseMatch] nodes. */ |
- final NodeList labelsAndCases; |
- /** A "default" keyword token, if applicable. */ |
- final Token defaultKeyword; |
- /** List of statements, the body of the case. */ |
- final NodeList statements; |
- |
- final Token startToken; |
- |
- SwitchCase(this.labelsAndCases, this.defaultKeyword, |
- this.statements, this.startToken); |
- |
- SwitchCase asSwitchCase() => this; |
- |
- bool get isDefaultCase => defaultKeyword != null; |
- |
- bool isValidContinueTarget() => true; |
- |
- accept(Visitor visitor) => visitor.visitSwitchCase(this); |
- |
- visitChildren(Visitor visitor) { |
- labelsAndCases.accept(visitor); |
- statements.accept(visitor); |
- } |
- |
- Token getBeginToken() { |
- return startToken; |
- } |
- |
- Token getEndToken() { |
- if (statements.nodes.isEmpty) { |
- // All cases must have at least one expression or be the default. |
- if (defaultKeyword != null) { |
- // The colon after 'default'. |
- return defaultKeyword.next; |
- } |
- // The colon after the last expression. |
- return labelsAndCases.getEndToken(); |
- } else { |
- return statements.getEndToken(); |
- } |
- } |
-} |
- |
-abstract class GotoStatement extends Statement { |
- final Identifier target; |
- final Token keywordToken; |
- final Token semicolonToken; |
- |
- GotoStatement(this.target, this.keywordToken, this.semicolonToken); |
- |
- visitChildren(Visitor visitor) { |
- if (target != null) target.accept(visitor); |
- } |
- |
- Token getBeginToken() => keywordToken; |
- |
- Token getEndToken() => semicolonToken; |
- |
- // TODO(ahe): make class abstract instead of adding an abstract method. |
- accept(Visitor visitor); |
-} |
- |
-class BreakStatement extends GotoStatement { |
- BreakStatement(Identifier target, Token keywordToken, Token semicolonToken) |
- : super(target, keywordToken, semicolonToken); |
- |
- BreakStatement asBreakStatement() => this; |
- |
- accept(Visitor visitor) => visitor.visitBreakStatement(this); |
-} |
- |
-class ContinueStatement extends GotoStatement { |
- ContinueStatement(Identifier target, Token keywordToken, Token semicolonToken) |
- : super(target, keywordToken, semicolonToken); |
- |
- ContinueStatement asContinueStatement() => this; |
- |
- accept(Visitor visitor) => visitor.visitContinueStatement(this); |
-} |
- |
-class ForIn extends Loop with StoredTreeElementMixin { |
- final Node declaredIdentifier; |
- final Expression expression; |
- |
- final Token awaitToken; |
- final Token forToken; |
- final Token inToken; |
- |
- ForIn(this.declaredIdentifier, this.expression, |
- Statement body, this.awaitToken, this.forToken, this.inToken) |
- : super(body); |
- |
- bool get isAsync => awaitToken != null; |
- |
- Expression get condition => null; |
- |
- ForIn asForIn() => this; |
- |
- accept(Visitor visitor) => visitor.visitForIn(this); |
- |
- visitChildren(Visitor visitor) { |
- declaredIdentifier.accept(visitor); |
- expression.accept(visitor); |
- body.accept(visitor); |
- } |
- |
- Token getBeginToken() => awaitToken != null ? awaitToken : forToken; |
- |
- Token getEndToken() => body.getEndToken(); |
-} |
- |
-class Label extends Node { |
- final Identifier identifier; |
- final Token colonToken; |
- |
- Label(this.identifier, this.colonToken); |
- |
- String get labelName => identifier.source; |
- |
- Label asLabel() => this; |
- |
- accept(Visitor visitor) => visitor.visitLabel(this); |
- |
- void visitChildren(Visitor visitor) { |
- identifier.accept(visitor); |
- } |
- |
- Token getBeginToken() => identifier.token; |
- Token getEndToken() => colonToken; |
-} |
- |
-class LabeledStatement extends Statement { |
- final NodeList labels; |
- final Statement statement; |
- |
- LabeledStatement(this.labels, this.statement); |
- |
- LabeledStatement asLabeledStatement() => this; |
- |
- accept(Visitor visitor) => visitor.visitLabeledStatement(this); |
- |
- visitChildren(Visitor visitor) { |
- labels.accept(visitor); |
- statement.accept(visitor); |
- } |
- |
- Token getBeginToken() => labels.getBeginToken(); |
- |
- Token getEndToken() => statement.getEndToken(); |
- |
- bool isValidContinueTarget() => statement.isValidContinueTarget(); |
-} |
- |
-abstract class LibraryTag extends Node { |
- final Link<MetadataAnnotation> metadata; |
- |
- LibraryTag(this.metadata); |
- |
- bool get isLibraryName => false; |
- bool get isImport => false; |
- bool get isExport => false; |
- bool get isPart => false; |
- bool get isPartOf => false; |
-} |
- |
-class LibraryName extends LibraryTag { |
- final Expression name; |
- |
- final Token libraryKeyword; |
- |
- LibraryName(this.libraryKeyword, |
- this.name, |
- Link<MetadataAnnotation> metadata) |
- : super(metadata); |
- |
- bool get isLibraryName => true; |
- |
- LibraryName asLibraryName() => this; |
- |
- accept(Visitor visitor) => visitor.visitLibraryName(this); |
- |
- visitChildren(Visitor visitor) => name.accept(visitor); |
- |
- Token getBeginToken() => libraryKeyword; |
- |
- Token getEndToken() => name.getEndToken().next; |
-} |
- |
-/** |
- * This tag describes a dependency between one library and the exported |
- * identifiers of another library. The other library is specified by the [uri]. |
- * Combinators filter away some identifiers from the other library. |
- */ |
-abstract class LibraryDependency extends LibraryTag { |
- final StringNode uri; |
- final NodeList combinators; |
- |
- LibraryDependency(this.uri, |
- this.combinators, |
- Link<MetadataAnnotation> metadata) |
- : super(metadata); |
- |
- LibraryDependency asLibraryDependency() => this; |
-} |
- |
-/** |
- * An [:import:] library tag. |
- * |
- * An import tag is dependency on another library where the exported identifiers |
- * are put into the import scope of the importing library. The import scope is |
- * only visible inside the library. |
- */ |
-class Import extends LibraryDependency { |
- final Identifier prefix; |
- final Token importKeyword; |
- final bool isDeferred; |
- |
- Import(this.importKeyword, StringNode uri, |
- this.prefix, NodeList combinators, |
- Link<MetadataAnnotation> metadata, |
- {this.isDeferred}) |
- : super(uri, combinators, metadata); |
- |
- bool get isImport => true; |
- |
- Import asImport() => this; |
- |
- accept(Visitor visitor) => visitor.visitImport(this); |
- |
- visitChildren(Visitor visitor) { |
- uri.accept(visitor); |
- if (prefix != null) prefix.accept(visitor); |
- if (combinators != null) combinators.accept(visitor); |
- } |
- |
- Token getBeginToken() => importKeyword; |
- |
- Token getEndToken() { |
- if (combinators != null) return combinators.getEndToken().next; |
- if (prefix != null) return prefix.getEndToken().next; |
- return uri.getEndToken().next; |
- } |
-} |
- |
-/** |
- * An [:export:] library tag. |
- * |
- * An export tag is dependency on another library where the exported identifiers |
- * are put into the export scope of the exporting library. The export scope is |
- * not visible inside the library. |
- */ |
-class Export extends LibraryDependency { |
- final Token exportKeyword; |
- |
- Export(this.exportKeyword, |
- StringNode uri, |
- NodeList combinators, |
- Link<MetadataAnnotation> metadata) |
- : super(uri, combinators, metadata); |
- |
- bool get isExport => true; |
- |
- Export asExport() => this; |
- |
- accept(Visitor visitor) => visitor.visitExport(this); |
- |
- visitChildren(Visitor visitor) { |
- uri.accept(visitor); |
- if (combinators != null) combinators.accept(visitor); |
- } |
- |
- Token getBeginToken() => exportKeyword; |
- |
- Token getEndToken() { |
- if (combinators != null) return combinators.getEndToken().next; |
- return uri.getEndToken().next; |
- } |
-} |
- |
-class Part extends LibraryTag { |
- final StringNode uri; |
- |
- final Token partKeyword; |
- |
- Part(this.partKeyword, this.uri, Link<MetadataAnnotation> metadata) |
- : super(metadata); |
- |
- bool get isPart => true; |
- |
- Part asPart() => this; |
- |
- accept(Visitor visitor) => visitor.visitPart(this); |
- |
- visitChildren(Visitor visitor) => uri.accept(visitor); |
- |
- Token getBeginToken() => partKeyword; |
- |
- Token getEndToken() => uri.getEndToken().next; |
-} |
- |
-class PartOf extends Node { |
- final Expression name; |
- |
- final Token partKeyword; |
- |
- final Link<MetadataAnnotation> metadata; |
- |
- PartOf(this.partKeyword, this.name, this.metadata); |
- |
- Token get ofKeyword => partKeyword.next; |
- |
- bool get isPartOf => true; |
- |
- PartOf asPartOf() => this; |
- |
- accept(Visitor visitor) => visitor.visitPartOf(this); |
- |
- visitChildren(Visitor visitor) => name.accept(visitor); |
- |
- Token getBeginToken() => partKeyword; |
- |
- Token getEndToken() => name.getEndToken().next; |
-} |
- |
-class Combinator extends Node { |
- final NodeList identifiers; |
- |
- final Token keywordToken; |
- |
- Combinator(this.identifiers, this.keywordToken); |
- |
- bool get isShow => identical(keywordToken.stringValue, 'show'); |
- |
- bool get isHide => identical(keywordToken.stringValue, 'hide'); |
- |
- Combinator asCombinator() => this; |
- |
- accept(Visitor visitor) => visitor.visitCombinator(this); |
- |
- visitChildren(Visitor visitor) => identifiers.accept(visitor); |
- |
- Token getBeginToken() => keywordToken; |
- |
- Token getEndToken() => identifiers.getEndToken(); |
-} |
- |
-class Typedef extends Node { |
- final TypeAnnotation returnType; |
- final Identifier name; |
- final NodeList typeParameters; |
- final NodeList formals; |
- |
- final Token typedefKeyword; |
- final Token endToken; |
- |
- Typedef(this.returnType, this.name, this.typeParameters, this.formals, |
- this.typedefKeyword, this.endToken); |
- |
- Typedef asTypedef() => this; |
- |
- accept(Visitor visitor) => visitor.visitTypedef(this); |
- |
- visitChildren(Visitor visitor) { |
- if (returnType != null) returnType.accept(visitor); |
- name.accept(visitor); |
- if (typeParameters != null) typeParameters.accept(visitor); |
- formals.accept(visitor); |
- } |
- |
- Token getBeginToken() => typedefKeyword; |
- |
- Token getEndToken() => endToken; |
-} |
- |
-class TryStatement extends Statement { |
- final Block tryBlock; |
- final NodeList catchBlocks; |
- final Block finallyBlock; |
- |
- final Token tryKeyword; |
- final Token finallyKeyword; |
- |
- TryStatement(this.tryBlock, this.catchBlocks, this.finallyBlock, |
- this.tryKeyword, this.finallyKeyword); |
- |
- TryStatement asTryStatement() => this; |
- |
- accept(Visitor visitor) => visitor.visitTryStatement(this); |
- |
- visitChildren(Visitor visitor) { |
- tryBlock.accept(visitor); |
- catchBlocks.accept(visitor); |
- if (finallyBlock != null) finallyBlock.accept(visitor); |
- } |
- |
- Token getBeginToken() => tryKeyword; |
- |
- Token getEndToken() { |
- if (finallyBlock != null) return finallyBlock.getEndToken(); |
- if (!catchBlocks.isEmpty) return catchBlocks.getEndToken(); |
- return tryBlock.getEndToken(); |
- } |
-} |
- |
-class Cascade extends Expression { |
- final Expression expression; |
- Cascade(this.expression); |
- |
- Cascade asCascade() => this; |
- accept(Visitor visitor) => visitor.visitCascade(this); |
- |
- void visitChildren(Visitor visitor) { |
- expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => expression.getBeginToken(); |
- |
- Token getEndToken() => expression.getEndToken(); |
-} |
- |
-class CascadeReceiver extends Expression { |
- final Expression expression; |
- final Token cascadeOperator; |
- CascadeReceiver(this.expression, this.cascadeOperator); |
- |
- CascadeReceiver asCascadeReceiver() => this; |
- accept(Visitor visitor) => visitor.visitCascadeReceiver(this); |
- |
- void visitChildren(Visitor visitor) { |
- expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => expression.getBeginToken(); |
- |
- Token getEndToken() => expression.getEndToken(); |
-} |
- |
-class CatchBlock extends Node { |
- final TypeAnnotation type; |
- final NodeList formals; |
- final Block block; |
- |
- final Token onKeyword; |
- final Token catchKeyword; |
- |
- CatchBlock(this.type, this.formals, this.block, |
- this.onKeyword, this.catchKeyword); |
- |
- CatchBlock asCatchBlock() => this; |
- |
- accept(Visitor visitor) => visitor.visitCatchBlock(this); |
- |
- Node get exception { |
- if (formals == null || formals.nodes.isEmpty) return null; |
- VariableDefinitions declarations = formals.nodes.head; |
- return declarations.definitions.nodes.head; |
- } |
- |
- Node get trace { |
- if (formals == null || formals.nodes.isEmpty) return null; |
- Link<Node> declarations = formals.nodes.tail; |
- if (declarations.isEmpty) return null; |
- VariableDefinitions head = declarations.head; |
- return head.definitions.nodes.head; |
- } |
- |
- visitChildren(Visitor visitor) { |
- if (type != null) type.accept(visitor); |
- if (formals != null) formals.accept(visitor); |
- block.accept(visitor); |
- } |
- |
- Token getBeginToken() => onKeyword != null ? onKeyword : catchKeyword; |
- |
- Token getEndToken() => block.getEndToken(); |
-} |
- |
-class Metadata extends Node { |
- final Token token; |
- final Expression expression; |
- |
- Metadata(this.token, this.expression); |
- |
- Metadata asMetadata() => this; |
- |
- accept(Visitor visitor) => visitor.visitMetadata(this); |
- |
- visitChildren(Visitor visitor) { |
- expression.accept(visitor); |
- } |
- |
- Token getBeginToken() => token; |
- |
- Token getEndToken() => expression.getEndToken(); |
-} |
- |
-class Initializers { |
- static bool isSuperConstructorCall(Send node) { |
- return (node.receiver == null && node.selector.isSuper()) || |
- (node.receiver != null && |
- node.receiver.isSuper() && |
- node.selector.asIdentifier() != null); |
- } |
- |
- static bool isConstructorRedirect(Send node) { |
- return (node.receiver == null && node.selector.isThis()) || |
- (node.receiver != null && |
- node.receiver.isThis() && |
- node.selector.asIdentifier() != null); |
- } |
-} |
- |
-class GetDartStringVisitor extends Visitor<DartString> { |
- const GetDartStringVisitor(); |
- DartString visitNode(Node node) => null; |
- DartString visitStringJuxtaposition(StringJuxtaposition node) |
- => node.dartString; |
- DartString visitLiteralString(LiteralString node) => node.dartString; |
-} |
- |
-class IsInterpolationVisitor extends Visitor<bool> { |
- const IsInterpolationVisitor(); |
- bool visitNode(Node node) => false; |
- bool visitStringInterpolation(StringInterpolation node) => true; |
- bool visitStringJuxtaposition(StringJuxtaposition node) |
- => node.isInterpolation; |
-} |
- |
-/// Erroneous node used to recover from parser errors. Implements various |
-/// interfaces and provides bare minimum of implementation to avoid unnecessary |
-/// messages. |
-class ErrorNode |
- extends Node |
- implements FunctionExpression, VariableDefinitions, Typedef { |
- final Token token; |
- final String reason; |
- final Identifier name; |
- final NodeList definitions; |
- |
- ErrorNode.internal(this.token, this.reason, this.name, this.definitions); |
- |
- factory ErrorNode(Token token, String reason) { |
- Identifier name = new Identifier(token); |
- NodeList definitions = new NodeList( |
- null, const Link<Node>().prepend(name), null, null); |
- return new ErrorNode.internal(token, reason, name, definitions); |
- } |
- |
- Token get beginToken => token; |
- Token get endToken => token; |
- |
- Token getBeginToken() => token; |
- |
- Token getEndToken() => token; |
- |
- accept(Visitor visitor) {} |
- |
- visitChildren(Visitor visitor) {} |
- |
- bool get isErroneous => true; |
- |
- // FunctionExpression. |
- get asyncModifier => null; |
- get parameters => null; |
- get body => null; |
- get returnType => null; |
- get modifiers => Modifiers.EMPTY; |
- get initializers => null; |
- get getOrSet => null; |
- get isRedirectingFactory => false; |
- bool hasBody() => false; |
- bool hasEmptyBody() => false; |
- |
- // VariableDefinitions. |
- get metadata => null; |
- get type => null; |
- |
- // Typedef. |
- get typeParameters => null; |
- get formals => null; |
- get typedefKeyword => null; |
-} |