blob: 24c111fa26875421ee95af316b80077cac6fce1e [file] [log] [blame]
// Copyright (c) 2019, 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.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:meta/meta.dart';
/// A visitor used to write a source representation of a visited AST node (and
/// all of it's children) to a sink.
class ToSourceVisitor implements AstVisitor<void> {
/// The sink to which the source is to be written.
@protected
final StringSink sink;
/// Initialize a newly created visitor to write source code representing the
/// visited nodes to the given [sink].
ToSourceVisitor(this.sink);
/// Visit the given function [body], printing the [prefix] before if the body
/// is not empty.
@protected
void safelyVisitFunctionWithPrefix(String prefix, FunctionBody body) {
if (body is! EmptyFunctionBody) {
sink.write(prefix);
}
safelyVisitNode(body);
}
/// Safely visit the given [node].
@protected
void safelyVisitNode(AstNode? node) {
if (node != null) {
node.accept(this);
}
}
/// Print a list of [nodes] without any separation.
@protected
void safelyVisitNodeList(NodeList<AstNode> nodes) {
safelyVisitNodeListWithSeparator(nodes, "");
}
/// Print a list of [nodes], separated by the given [separator].
@protected
void safelyVisitNodeListWithSeparator(
NodeList<AstNode> nodes, String separator) {
int size = nodes.length;
for (int i = 0; i < size; i++) {
if (i > 0) {
sink.write(separator);
}
nodes[i].accept(this);
}
}
/// Print a list of [nodes], prefixed by the given [prefix] if the list is not
/// empty, and separated by the given [separator].
@protected
void safelyVisitNodeListWithSeparatorAndPrefix(
String prefix, NodeList<AstNode> nodes, String separator) {
int size = nodes.length;
if (size > 0) {
sink.write(prefix);
for (int i = 0; i < size; i++) {
if (i > 0) {
sink.write(separator);
}
nodes[i].accept(this);
}
}
}
/// Print a list of [nodes], separated by the given [separator], followed by
/// the given [suffix] if the list is not empty.
@protected
void safelyVisitNodeListWithSeparatorAndSuffix(
NodeList<AstNode> nodes, String separator, String suffix) {
int size = nodes.length;
if (size > 0) {
for (int i = 0; i < size; i++) {
if (i > 0) {
sink.write(separator);
}
nodes[i].accept(this);
}
sink.write(suffix);
}
}
/// Safely visit the given [node], printing the [prefix] before the node if it
/// is non-`null`.
@protected
void safelyVisitNodeWithPrefix(String prefix, AstNode? node) {
if (node != null) {
sink.write(prefix);
node.accept(this);
}
}
/// Safely visit the given [node], printing the [suffix] after the node if it
/// is non-`null`.
@protected
void safelyVisitNodeWithSuffix(AstNode? node, String suffix) {
if (node != null) {
node.accept(this);
sink.write(suffix);
}
}
/// Safely visit the given [token].
@protected
void safelyVisitToken(Token? token) {
if (token != null) {
sink.write(token.lexeme);
}
}
/// Safely visit the given [token], printing the [suffix] after the token if
/// it is non-`null`.
@protected
void safelyVisitTokenWithSuffix(Token? token, String suffix) {
if (token != null) {
sink.write(token.lexeme);
sink.write(suffix);
}
}
@override
void visitAdjacentStrings(AdjacentStrings node) {
safelyVisitNodeListWithSeparator(node.strings, " ");
}
@override
void visitAnnotation(Annotation node) {
sink.write('@');
safelyVisitNode(node.name);
safelyVisitNodeWithPrefix(".", node.constructorName);
safelyVisitNode(node.arguments);
}
@override
void visitArgumentList(ArgumentList node) {
sink.write('(');
safelyVisitNodeListWithSeparator(node.arguments, ", ");
sink.write(')');
}
@override
void visitAsExpression(AsExpression node) {
safelyVisitNode(node.expression);
sink.write(" as ");
safelyVisitNode(node.type);
}
@override
void visitAssertInitializer(AssertInitializer node) {
sink.write("assert (");
safelyVisitNode(node.condition);
if (node.message != null) {
sink.write(', ');
safelyVisitNode(node.message);
}
sink.write(");");
}
@override
void visitAssertStatement(AssertStatement node) {
sink.write("assert (");
safelyVisitNode(node.condition);
if (node.message != null) {
sink.write(', ');
safelyVisitNode(node.message);
}
sink.write(");");
}
@override
void visitAssignmentExpression(AssignmentExpression node) {
safelyVisitNode(node.leftHandSide);
sink.write(' ');
sink.write(node.operator.lexeme);
sink.write(' ');
safelyVisitNode(node.rightHandSide);
}
@override
void visitAwaitExpression(AwaitExpression node) {
sink.write("await ");
safelyVisitNode(node.expression);
}
@override
void visitBinaryExpression(BinaryExpression node) {
_writeOperand(node, node.leftOperand);
sink.write(' ');
sink.write(node.operator.lexeme);
sink.write(' ');
_writeOperand(node, node.rightOperand);
}
@override
void visitBlock(Block node) {
sink.write('{');
safelyVisitNodeListWithSeparator(node.statements, " ");
sink.write('}');
}
@override
void visitBlockFunctionBody(BlockFunctionBody node) {
var keyword = node.keyword;
if (keyword != null) {
sink.write(keyword.lexeme);
if (node.star != null) {
sink.write('*');
}
sink.write(' ');
}
safelyVisitNode(node.block);
}
@override
void visitBooleanLiteral(BooleanLiteral node) {
sink.write(node.literal.lexeme);
}
@override
void visitBreakStatement(BreakStatement node) {
sink.write("break");
safelyVisitNodeWithPrefix(" ", node.label);
sink.write(";");
}
@override
void visitCascadeExpression(CascadeExpression node) {
safelyVisitNode(node.target);
safelyVisitNodeList(node.cascadeSections);
}
@override
void visitCatchClause(CatchClause node) {
safelyVisitNodeWithPrefix("on ", node.exceptionType);
if (node.catchKeyword != null) {
if (node.exceptionType != null) {
sink.write(' ');
}
sink.write("catch (");
safelyVisitNode(node.exceptionParameter);
safelyVisitNodeWithPrefix(", ", node.stackTraceParameter);
sink.write(") ");
} else {
sink.write(" ");
}
safelyVisitNode(node.body);
}
@override
void visitClassDeclaration(ClassDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitTokenWithSuffix(node.abstractKeyword, " ");
sink.write("class ");
safelyVisitNode(node.name);
safelyVisitNode(node.typeParameters);
safelyVisitNodeWithPrefix(" ", node.extendsClause);
safelyVisitNodeWithPrefix(" ", node.withClause);
safelyVisitNodeWithPrefix(" ", node.implementsClause);
sink.write(" {");
safelyVisitNodeListWithSeparator(node.members, " ");
sink.write("}");
}
@override
void visitClassTypeAlias(ClassTypeAlias node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
if (node.abstractKeyword != null) {
sink.write("abstract ");
}
sink.write("class ");
safelyVisitNode(node.name);
safelyVisitNode(node.typeParameters);
sink.write(" = ");
safelyVisitNode(node.superclass);
safelyVisitNodeWithPrefix(" ", node.withClause);
safelyVisitNodeWithPrefix(" ", node.implementsClause);
sink.write(";");
}
@override
void visitComment(Comment node) {}
@override
void visitCommentReference(CommentReference node) {}
@override
void visitCompilationUnit(CompilationUnit node) {
var scriptTag = node.scriptTag;
NodeList<Directive> directives = node.directives;
safelyVisitNode(scriptTag);
String prefix = scriptTag == null ? "" : " ";
safelyVisitNodeListWithSeparatorAndPrefix(prefix, directives, " ");
prefix = scriptTag == null && directives.isEmpty ? "" : " ";
safelyVisitNodeListWithSeparatorAndPrefix(prefix, node.declarations, " ");
}
@override
void visitConditionalExpression(ConditionalExpression node) {
safelyVisitNode(node.condition);
sink.write(" ? ");
safelyVisitNode(node.thenExpression);
sink.write(" : ");
safelyVisitNode(node.elseExpression);
}
@override
void visitConfiguration(Configuration node) {
sink.write('if (');
safelyVisitNode(node.name);
safelyVisitNodeWithPrefix(" == ", node.value);
sink.write(') ');
safelyVisitNode(node.uri);
}
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitTokenWithSuffix(node.externalKeyword, " ");
safelyVisitTokenWithSuffix(node.constKeyword, " ");
safelyVisitTokenWithSuffix(node.factoryKeyword, " ");
safelyVisitNode(node.returnType);
safelyVisitNodeWithPrefix(".", node.name);
safelyVisitNode(node.parameters);
safelyVisitNodeListWithSeparatorAndPrefix(" : ", node.initializers, ", ");
safelyVisitNodeWithPrefix(" = ", node.redirectedConstructor);
safelyVisitFunctionWithPrefix(" ", node.body!);
}
@override
void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
safelyVisitTokenWithSuffix(node.thisKeyword, ".");
safelyVisitNode(node.fieldName);
sink.write(" = ");
safelyVisitNode(node.expression);
}
@override
void visitConstructorName(ConstructorName node) {
safelyVisitNode(node.type);
safelyVisitNodeWithPrefix(".", node.name);
}
@override
void visitContinueStatement(ContinueStatement node) {
sink.write("continue");
safelyVisitNodeWithPrefix(" ", node.label);
sink.write(";");
}
@override
void visitDeclaredIdentifier(DeclaredIdentifier node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitTokenWithSuffix(node.keyword, " ");
safelyVisitNodeWithSuffix(node.type, " ");
safelyVisitNode(node.identifier);
}
@override
void visitDefaultFormalParameter(DefaultFormalParameter node) {
if (node.isRequiredNamed) {
sink.write('required ');
}
safelyVisitNode(node.parameter);
if (node.separator != null) {
if (node.separator!.lexeme != ":") {
sink.write(" ");
}
sink.write(node.separator!.lexeme);
safelyVisitNodeWithPrefix(" ", node.defaultValue);
}
}
@override
void visitDoStatement(DoStatement node) {
sink.write("do ");
safelyVisitNode(node.body);
sink.write(" while (");
safelyVisitNode(node.condition);
sink.write(");");
}
@override
void visitDottedName(DottedName node) {
safelyVisitNodeListWithSeparator(node.components, ".");
}
@override
void visitDoubleLiteral(DoubleLiteral node) {
sink.write(node.literal.lexeme);
}
@override
void visitEmptyFunctionBody(EmptyFunctionBody node) {
sink.write(';');
}
@override
void visitEmptyStatement(EmptyStatement node) {
sink.write(';');
}
@override
void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitNode(node.name);
}
@override
void visitEnumDeclaration(EnumDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("enum ");
safelyVisitNode(node.name);
sink.write(" {");
safelyVisitNodeListWithSeparator(node.constants, ", ");
sink.write("}");
}
@override
void visitExportDirective(ExportDirective node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("export ");
safelyVisitNode(node.uri);
safelyVisitNodeListWithSeparatorAndPrefix(" ", node.combinators, " ");
sink.write(';');
}
@override
void visitExpressionFunctionBody(ExpressionFunctionBody node) {
var keyword = node.keyword;
if (keyword != null) {
sink.write(keyword.lexeme);
sink.write(' ');
}
sink.write('${node.functionDefinition.lexeme} ');
safelyVisitNode(node.expression);
if (node.semicolon != null) {
sink.write(';');
}
}
@override
void visitExpressionStatement(ExpressionStatement node) {
safelyVisitNode(node.expression);
sink.write(';');
}
@override
void visitExtendsClause(ExtendsClause node) {
sink.write("extends ");
safelyVisitNode(node.superclass);
}
@override
void visitExtensionDeclaration(ExtensionDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
safelyVisitTokenWithSuffix(node.extensionKeyword, ' ');
safelyVisitNode(node.name);
safelyVisitNode(node.typeParameters);
sink.write(' ');
safelyVisitToken(node.onKeyword);
sink.write(' ');
safelyVisitNodeWithSuffix(node.extendedType, ' ');
safelyVisitToken(node.leftBracket);
safelyVisitNodeListWithSeparator(node.members, ' ');
safelyVisitToken(node.rightBracket);
}
@override
void visitExtensionOverride(ExtensionOverride node) {
safelyVisitNode(node.extensionName);
safelyVisitNode(node.typeArguments);
safelyVisitNode(node.argumentList);
}
@override
void visitFieldDeclaration(FieldDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitTokenWithSuffix(node.abstractKeyword, " ");
safelyVisitTokenWithSuffix(node.externalKeyword, " ");
safelyVisitTokenWithSuffix(node.staticKeyword, " ");
safelyVisitNode(node.fields);
sink.write(";");
}
@override
void visitFieldFormalParameter(FieldFormalParameter node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
safelyVisitTokenWithSuffix(node.covariantKeyword, ' ');
safelyVisitTokenWithSuffix(node.keyword, " ");
safelyVisitNodeWithSuffix(node.type, " ");
sink.write("this.");
safelyVisitNode(node.identifier);
safelyVisitNode(node.typeParameters);
safelyVisitNode(node.parameters);
}
@override
void visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
safelyVisitNode(node.loopVariable);
sink.write(' in ');
safelyVisitNode(node.iterable);
}
@override
void visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
safelyVisitNode(node.identifier);
sink.write(' in ');
safelyVisitNode(node.iterable);
}
@override
void visitForElement(ForElement node) {
safelyVisitTokenWithSuffix(node.awaitKeyword, ' ');
sink.write('for (');
safelyVisitNode(node.forLoopParts);
sink.write(') ');
safelyVisitNode(node.body);
}
@override
void visitFormalParameterList(FormalParameterList node) {
String? groupEnd;
sink.write('(');
NodeList<FormalParameter> parameters = node.parameters;
int size = parameters.length;
for (int i = 0; i < size; i++) {
FormalParameter parameter = parameters[i];
if (i > 0) {
sink.write(", ");
}
if (groupEnd == null && parameter is DefaultFormalParameter) {
if (parameter.isNamed) {
groupEnd = "}";
sink.write('{');
} else {
groupEnd = "]";
sink.write('[');
}
}
parameter.accept(this);
}
if (groupEnd != null) {
sink.write(groupEnd);
}
sink.write(')');
}
@override
void visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
safelyVisitNode(node.variables);
sink.write(';');
safelyVisitNodeWithPrefix(' ', node.condition);
sink.write(';');
safelyVisitNodeListWithSeparatorAndPrefix(' ', node.updaters, ', ');
}
@override
void visitForPartsWithExpression(ForPartsWithExpression node) {
safelyVisitNode(node.initialization);
sink.write(';');
safelyVisitNodeWithPrefix(' ', node.condition);
sink.write(';');
safelyVisitNodeListWithSeparatorAndPrefix(" ", node.updaters, ', ');
}
@override
void visitForStatement(ForStatement node) {
if (node.awaitKeyword != null) {
sink.write('await ');
}
sink.write('for (');
safelyVisitNode(node.forLoopParts);
sink.write(') ');
safelyVisitNode(node.body);
}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitTokenWithSuffix(node.externalKeyword, " ");
safelyVisitNodeWithSuffix(node.returnType, " ");
safelyVisitTokenWithSuffix(node.propertyKeyword, " ");
safelyVisitNode(node.name);
safelyVisitNode(node.functionExpression);
}
@override
void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
safelyVisitNode(node.functionDeclaration);
}
@override
void visitFunctionExpression(FunctionExpression node) {
safelyVisitNode(node.typeParameters);
safelyVisitNode(node.parameters);
if (node.body is! EmptyFunctionBody) {
sink.write(' ');
}
safelyVisitNode(node.body);
}
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
safelyVisitNode(node.function);
safelyVisitNode(node.typeArguments);
safelyVisitNode(node.argumentList);
}
@override
void visitFunctionTypeAlias(FunctionTypeAlias node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("typedef ");
safelyVisitNodeWithSuffix(node.returnType, " ");
safelyVisitNode(node.name);
safelyVisitNode(node.typeParameters);
safelyVisitNode(node.parameters);
sink.write(";");
}
@override
void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
safelyVisitTokenWithSuffix(node.covariantKeyword, ' ');
safelyVisitNodeWithSuffix(node.returnType, " ");
safelyVisitNode(node.identifier);
safelyVisitNode(node.typeParameters);
safelyVisitNode(node.parameters);
if (node.question != null) {
sink.write('?');
}
}
@override
void visitGenericFunctionType(GenericFunctionType node) {
safelyVisitNode(node.returnType);
sink.write(' Function');
safelyVisitNode(node.typeParameters);
safelyVisitNode(node.parameters);
if (node.question != null) {
sink.write('?');
}
}
@override
void visitGenericTypeAlias(GenericTypeAlias node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("typedef ");
safelyVisitNode(node.name);
safelyVisitNode(node.typeParameters);
sink.write(" = ");
safelyVisitNode(node.type);
}
@override
void visitHideCombinator(HideCombinator node) {
sink.write("hide ");
safelyVisitNodeListWithSeparator(node.hiddenNames, ", ");
}
@override
void visitIfElement(IfElement node) {
sink.write('if (');
safelyVisitNode(node.condition);
sink.write(') ');
safelyVisitNode(node.thenElement);
safelyVisitNodeWithPrefix(' else ', node.elseElement);
}
@override
void visitIfStatement(IfStatement node) {
sink.write("if (");
safelyVisitNode(node.condition);
sink.write(") ");
safelyVisitNode(node.thenStatement);
safelyVisitNodeWithPrefix(" else ", node.elseStatement);
}
@override
void visitImplementsClause(ImplementsClause node) {
sink.write("implements ");
safelyVisitNodeListWithSeparator(node.interfaces, ", ");
}
@override
void visitImportDirective(ImportDirective node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("import ");
safelyVisitNode(node.uri);
if (node.deferredKeyword != null) {
sink.write(" deferred");
}
safelyVisitNodeWithPrefix(" as ", node.prefix);
safelyVisitNodeListWithSeparatorAndPrefix(" ", node.combinators, " ");
sink.write(';');
}
@override
void visitIndexExpression(IndexExpression node) {
if (node.isCascaded) {
safelyVisitToken(node.period);
} else {
safelyVisitNode(node.target);
}
safelyVisitToken(node.question);
safelyVisitToken(node.leftBracket);
safelyVisitNode(node.index);
safelyVisitToken(node.rightBracket);
}
@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
safelyVisitTokenWithSuffix(node.keyword, " ");
safelyVisitNode(node.constructorName);
safelyVisitNode(node.argumentList);
}
@override
void visitIntegerLiteral(IntegerLiteral node) {
sink.write(node.literal.lexeme);
}
@override
void visitInterpolationExpression(InterpolationExpression node) {
if (node.rightBracket != null) {
sink.write("\${");
safelyVisitNode(node.expression);
sink.write("}");
} else {
sink.write("\$");
safelyVisitNode(node.expression);
}
}
@override
void visitInterpolationString(InterpolationString node) {
sink.write(node.contents.lexeme);
}
@override
void visitIsExpression(IsExpression node) {
safelyVisitNode(node.expression);
if (node.notOperator == null) {
sink.write(" is ");
} else {
sink.write(" is! ");
}
safelyVisitNode(node.type);
}
@override
void visitLabel(Label node) {
safelyVisitNode(node.label);
sink.write(":");
}
@override
void visitLabeledStatement(LabeledStatement node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.labels, " ", " ");
safelyVisitNode(node.statement);
}
@override
void visitLibraryDirective(LibraryDirective node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("library ");
safelyVisitNode(node.name);
sink.write(';');
}
@override
void visitLibraryIdentifier(LibraryIdentifier node) {
sink.write(node.name);
}
@override
void visitListLiteral(ListLiteral node) {
safelyVisitTokenWithSuffix(node.constKeyword, ' ');
safelyVisitNode(node.typeArguments);
sink.write('[');
safelyVisitNodeListWithSeparator(node.elements, ', ');
sink.write(']');
}
@override
void visitMapLiteralEntry(MapLiteralEntry node) {
safelyVisitNode(node.key);
sink.write(" : ");
safelyVisitNode(node.value);
}
@override
void visitMethodDeclaration(MethodDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitTokenWithSuffix(node.externalKeyword, " ");
safelyVisitTokenWithSuffix(node.modifierKeyword, " ");
safelyVisitNodeWithSuffix(node.returnType, " ");
safelyVisitTokenWithSuffix(node.propertyKeyword, " ");
safelyVisitTokenWithSuffix(node.operatorKeyword, " ");
safelyVisitNode(node.name);
if (!node.isGetter) {
safelyVisitNode(node.typeParameters);
safelyVisitNode(node.parameters);
}
safelyVisitFunctionWithPrefix(" ", node.body);
}
@override
void visitMethodInvocation(MethodInvocation node) {
if (node.isCascaded) {
sink.write(node.operator!.lexeme);
} else {
if (node.target != null) {
node.target!.accept(this);
sink.write(node.operator!.lexeme);
}
}
safelyVisitNode(node.methodName);
safelyVisitNode(node.typeArguments);
safelyVisitNode(node.argumentList);
}
@override
void visitMixinDeclaration(MixinDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("mixin ");
safelyVisitNode(node.name);
safelyVisitNode(node.typeParameters);
safelyVisitNodeWithPrefix(" ", node.onClause);
safelyVisitNodeWithPrefix(" ", node.implementsClause);
sink.write(" {");
safelyVisitNodeListWithSeparator(node.members, " ");
sink.write("}");
}
@override
void visitNamedExpression(NamedExpression node) {
safelyVisitNode(node.name);
safelyVisitNodeWithPrefix(" ", node.expression);
}
@override
void visitNativeClause(NativeClause node) {
sink.write("native ");
safelyVisitNode(node.name);
}
@override
void visitNativeFunctionBody(NativeFunctionBody node) {
sink.write("native ");
safelyVisitNode(node.stringLiteral);
sink.write(';');
}
@override
void visitNullLiteral(NullLiteral node) {
sink.write("null");
}
@override
void visitOnClause(OnClause node) {
sink.write('on ');
safelyVisitNodeListWithSeparator(node.superclassConstraints, ", ");
}
@override
void visitParenthesizedExpression(ParenthesizedExpression node) {
sink.write('(');
safelyVisitNode(node.expression);
sink.write(')');
}
@override
void visitPartDirective(PartDirective node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("part ");
safelyVisitNode(node.uri);
sink.write(';');
}
@override
void visitPartOfDirective(PartOfDirective node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
sink.write("part of ");
safelyVisitNode(node.libraryName);
safelyVisitNode(node.uri);
sink.write(';');
}
@override
void visitPostfixExpression(PostfixExpression node) {
_writeOperand(node, node.operand);
sink.write(node.operator.lexeme);
}
@override
void visitPrefixedIdentifier(PrefixedIdentifier node) {
safelyVisitNode(node.prefix);
sink.write('.');
safelyVisitNode(node.identifier);
}
@override
void visitPrefixExpression(PrefixExpression node) {
sink.write(node.operator.lexeme);
_writeOperand(node, node.operand);
}
@override
void visitPropertyAccess(PropertyAccess node) {
if (node.isCascaded) {
sink.write(node.operator.lexeme);
} else {
safelyVisitNode(node.target);
sink.write(node.operator.lexeme);
}
safelyVisitNode(node.propertyName);
}
@override
void visitRedirectingConstructorInvocation(
RedirectingConstructorInvocation node) {
sink.write("this");
safelyVisitNodeWithPrefix(".", node.constructorName);
safelyVisitNode(node.argumentList);
}
@override
void visitRethrowExpression(RethrowExpression node) {
sink.write("rethrow");
}
@override
void visitReturnStatement(ReturnStatement node) {
var expression = node.expression;
if (expression == null) {
sink.write("return;");
} else {
sink.write("return ");
expression.accept(this);
sink.write(";");
}
}
@override
void visitScriptTag(ScriptTag node) {
sink.write(node.scriptTag.lexeme);
}
@override
void visitSetOrMapLiteral(SetOrMapLiteral node) {
safelyVisitTokenWithSuffix(node.constKeyword, ' ');
safelyVisitNode(node.typeArguments);
sink.write('{');
safelyVisitNodeListWithSeparator(node.elements, ', ');
sink.write('}');
}
@override
void visitShowCombinator(ShowCombinator node) {
sink.write("show ");
safelyVisitNodeListWithSeparator(node.shownNames, ", ");
}
@override
void visitSimpleFormalParameter(SimpleFormalParameter node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, ' ', ' ');
safelyVisitTokenWithSuffix(node.covariantKeyword, ' ');
safelyVisitTokenWithSuffix(node.keyword, " ");
safelyVisitNode(node.type);
if (node.type != null && node.identifier != null) {
sink.write(' ');
}
safelyVisitNode(node.identifier);
}
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
sink.write(node.token.lexeme);
}
@override
void visitSimpleStringLiteral(SimpleStringLiteral node) {
sink.write(node.literal.lexeme);
}
@override
void visitSpreadElement(SpreadElement node) {
sink.write(node.spreadOperator.lexeme);
safelyVisitNode(node.expression);
}
@override
void visitStringInterpolation(StringInterpolation node) {
safelyVisitNodeList(node.elements);
}
@override
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
sink.write("super");
safelyVisitNodeWithPrefix(".", node.constructorName);
safelyVisitNode(node.argumentList);
}
@override
void visitSuperExpression(SuperExpression node) {
sink.write("super");
}
@override
void visitSwitchCase(SwitchCase node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.labels, " ", " ");
sink.write("case ");
safelyVisitNode(node.expression);
sink.write(": ");
safelyVisitNodeListWithSeparator(node.statements, " ");
}
@override
void visitSwitchDefault(SwitchDefault node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.labels, " ", " ");
sink.write("default: ");
safelyVisitNodeListWithSeparator(node.statements, " ");
}
@override
void visitSwitchStatement(SwitchStatement node) {
sink.write("switch (");
safelyVisitNode(node.expression);
sink.write(") {");
safelyVisitNodeListWithSeparator(node.members, " ");
sink.write("}");
}
@override
void visitSymbolLiteral(SymbolLiteral node) {
sink.write("#");
List<Token> components = node.components;
for (int i = 0; i < components.length; i++) {
if (i > 0) {
sink.write(".");
}
sink.write(components[i].lexeme);
}
}
@override
void visitThisExpression(ThisExpression node) {
sink.write("this");
}
@override
void visitThrowExpression(ThrowExpression node) {
sink.write("throw ");
safelyVisitNode(node.expression);
}
@override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
safelyVisitTokenWithSuffix(node.externalKeyword, " ");
safelyVisitNodeWithSuffix(node.variables, ";");
}
@override
void visitTryStatement(TryStatement node) {
sink.write("try ");
safelyVisitNode(node.body);
safelyVisitNodeListWithSeparatorAndPrefix(" ", node.catchClauses, " ");
safelyVisitNodeWithPrefix(" finally ", node.finallyBlock);
}
@override
void visitTypeArgumentList(TypeArgumentList node) {
sink.write('<');
safelyVisitNodeListWithSeparator(node.arguments, ", ");
sink.write('>');
}
@override
void visitTypeName(TypeName node) {
safelyVisitNode(node.name);
safelyVisitNode(node.typeArguments);
if (node.question != null) {
sink.write('?');
}
}
@override
void visitTypeParameter(TypeParameter node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
// TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
// added to the interface.
var varianceKeyword = (node as TypeParameterImpl).varianceKeyword;
if (varianceKeyword != null) {
sink.write(varianceKeyword.lexeme + ' ');
}
safelyVisitNode(node.name);
safelyVisitNodeWithPrefix(" extends ", node.bound);
}
@override
void visitTypeParameterList(TypeParameterList node) {
sink.write('<');
safelyVisitNodeListWithSeparator(node.typeParameters, ", ");
sink.write('>');
}
@override
void visitVariableDeclaration(VariableDeclaration node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitNode(node.name);
safelyVisitNodeWithPrefix(" = ", node.initializer);
}
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
safelyVisitTokenWithSuffix(node.lateKeyword, " ");
safelyVisitTokenWithSuffix(node.keyword, " ");
safelyVisitNodeWithSuffix(node.type, " ");
safelyVisitNodeListWithSeparator(node.variables, ", ");
}
@override
void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
safelyVisitNode(node.variables);
sink.write(";");
}
@override
void visitWhileStatement(WhileStatement node) {
sink.write("while (");
safelyVisitNode(node.condition);
sink.write(") ");
safelyVisitNode(node.body);
}
@override
void visitWithClause(WithClause node) {
sink.write("with ");
safelyVisitNodeListWithSeparator(node.mixinTypes, ", ");
}
@override
void visitYieldStatement(YieldStatement node) {
if (node.star != null) {
sink.write("yield* ");
} else {
sink.write("yield ");
}
safelyVisitNode(node.expression);
sink.write(";");
}
void _writeOperand(Expression node, Expression operand) {
bool needsParenthesis = operand.precedence < node.precedence;
if (needsParenthesis) {
sink.write('(');
}
operand.accept(this);
if (needsParenthesis) {
sink.write(')');
}
}
}