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

Unified Diff: pkg/analyzer_experimental/lib/src/services/formatter_impl.dart

Issue 18346013: Formatter re-think/updates. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analyzer_experimental/lib/src/services/writer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
===================================================================
--- pkg/analyzer_experimental/lib/src/services/formatter_impl.dart (revision 24755)
+++ pkg/analyzer_experimental/lib/src/services/formatter_impl.dart (working copy)
@@ -11,8 +11,8 @@
import 'package:analyzer_experimental/src/generated/parser.dart';
import 'package:analyzer_experimental/src/generated/scanner.dart';
import 'package:analyzer_experimental/src/generated/source.dart';
+import 'package:analyzer_experimental/src/services/writer.dart';
-
/// OS line separator. --- TODO(pquitslund): may not be necessary
const NEW_LINE = '\n' ; //Platform.pathSeparator;
@@ -22,15 +22,17 @@
/// Create formatter options with defaults derived (where defined) from
/// the style guide: <http://www.dartlang.org/articles/style-guide/>.
const FormatterOptions({this.initialIndentationLevel: 0,
- this.indentPerLevel: 2,
+ this.spacesPerIndent: 2,
this.lineSeparator: NEW_LINE,
this.pageWidth: 80,
+ this.tabsForIndent: false,
this.tabSize: 2});
final String lineSeparator;
final int initialIndentationLevel;
- final int indentPerLevel;
+ final int spacesPerIndent;
final int tabSize;
+ final bool tabsForIndent;
final int pageWidth;
}
@@ -83,11 +85,9 @@
class CodeFormatterImpl implements CodeFormatter, AnalysisErrorListener {
final FormatterOptions options;
- final EditRecorder recorder;
final errors = <AnalysisError>[];
- CodeFormatterImpl(FormatterOptions options) : this.options = options,
- recorder = new EditRecorder(options);
+ CodeFormatterImpl(this.options);
String format(CodeKind kind, String source, {int offset, int end,
int indentationLevel:0}) {
@@ -98,8 +98,10 @@
var node = parse(kind, start);
checkForErrors();
- var formatter = new FormattingEngine(options);
- return formatter.format(source, node, start, kind, recorder);
+ var formatter = new SourceVisitor(options);
+ node.accept(formatter);
+
+ return formatter.writer.toString();
}
ASTNode parse(CodeKind kind, Token start) {
@@ -134,454 +136,810 @@
}
-/// Records a sequence of edits to a source string that will cause the string
-/// to be formatted when applied.
-class EditRecorder {
- final FormatterOptions options;
- final EditStore editStore;
+/// An AST visitor that drives formatting heuristics.
+class SourceVisitor implements ASTVisitor {
- int column = 0;
+ /// The writer to which the source is to be written.
+ SourceWriter writer;
- int sourceIndex = 0;
- String source = '';
+ /// Initialize a newly created visitor to write source code representing
+ /// the visited nodes to the given [writer].
+ SourceVisitor(FormatterOptions options) :
+ writer = new SourceWriter(initialIndent: options.initialIndentationLevel,
Brian Wilkerson 2013/07/03 22:03:02 This seems weird. Why not just pass in the options
pquitslund 2013/07/03 22:21:39 I was on the fence. Leaning towards doing just th
+ lineSeparator: options.lineSeparator);
- Token currentToken;
+ visitAdjacentStrings(AdjacentStrings node) {
+ visitList(node.strings, ' ');
+ }
- int numberOfIndentations = 0;
+ visitAnnotation(Annotation node) {
+ writer.print('@');
+ visit(node.name);
+ visitPrefixed('.', node.constructorName);
+ visit(node.arguments);
+ }
- bool needsIndent = false;
+ visitArgumentDefinitionTest(ArgumentDefinitionTest node) {
+ writer.print('?');
+ visit(node.identifier);
+ }
- EditRecorder(this.options): editStore = new EditStore();
+ visitArgumentList(ArgumentList node) {
+ writer.print('(');
+ visitList(node.arguments, ', ');
+ writer.print(')');
+ }
- /// Add an [Edit] that describes a textual [replacement] of a text
- /// interval starting at the given [offset] spanning the given [length].
- void addEdit(int offset, int length, String replacement) {
- editStore.addEdit(offset, length, replacement);
+ visitAsExpression(AsExpression node) {
+ visit(node.expression);
+ writer.print(' as ');
+ visit(node.type);
}
- /// Advance past the given expected [token] (or fail if not matched).
- void advance(Token token) {
- if (currentToken.lexeme == token.lexeme) {
+ visitAssertStatement(AssertStatement node) {
+ writer.print('assert (');
+ visit(node.condition);
+ writer.print(');');
+ }
- // TODO(pquitslund) emit comments
-// if (needsIndent) {
-// advanceIndent();
-// needsIndent = false;
-// }
- // Record writing a token at the current edit location
- advanceChars(token.length);
- currentToken = currentToken.next;
- } else {
- wrongToken(token.lexeme);
- }
+ visitAssignmentExpression(AssignmentExpression node) {
+ visit(node.leftHandSide);
+ writer.print(' ');
+ writer.print(node.operator.lexeme);
+ writer.print(' ');
+ visit(node.rightHandSide);
}
- /// Move indices past indent, adding an edit if needed to adjust indentation
- void advanceIndent() {
-// var indentWidth = options.indentPerLevel * indentationLevel;
-// var indentString = getIndentString(indentWidth);
-// var sourceIndentWidth = 0;
-// for (var i = 0; i < source.length; i++) {
-// if (isIndentChar(source[sourceIndex + i])) {
-// sourceIndentWidth += 1;
-// } else {
-// break;
-// }
-// }
-// var hasSameIndent = sourceIndentWidth == indentWidth;
-// if (hasSameIndent) {
-// for (var i = 0; i < indentWidth; i++) {
-// if (source[sourceIndex + i] != indentString[i]) {
-// hasSameIndent = false;
-// break;
-// }
-// }
-// if (hasSameIndent) {
-// advanceChars(indentWidth);
-// return;
-// }
-// }
-// addEdit(sourceIndex, sourceIndentWidth, indentString);
-// column += indentWidth;
-// sourceIndex += sourceIndentWidth;
-
- var indent = options.indentPerLevel * numberOfIndentations;
-
- spaces(indent);
+ visitBinaryExpression(BinaryExpression node) {
+ visit(node.leftOperand);
+ writer.print(' ');
+ writer.print(node.operator.lexeme);
+ writer.print(' ');
+ visit(node.rightOperand);
}
- String getIndentString(int indentWidth) {
+ visitBlock(Block node) {
+ writer.print('{');
+ writer.indent();
- // TODO(pquitslund) a temporary workaround
- if (indentWidth < 0) {
- return '';
+ for (var stmt in node.statements) {
+ writer.newline();
+ visit(stmt);
}
- // TODO(pquitslund) allow indent with tab chars
+ writer.unindent();
+ writer.newline();
+ writer.print('}');
+ }
- // Fetch a precomputed indent string
- if (indentWidth < SPACES.length) {
- return SPACES[indentWidth];
- }
+ visitBlockFunctionBody(BlockFunctionBody node) {
+ visit(node.block);
+ }
- // Build un-precomputed strings dynamically
- var sb = new StringBuffer();
- for (var i = 0; i < indentWidth; ++i) {
- sb.write(' ');
- }
- return sb.toString();
+ visitBooleanLiteral(BooleanLiteral node) {
+ writer.print(node.literal.lexeme);
}
- /// Advance past the given expected [token] (or fail if not matched).
- void advanceToken(String token) {
- if (currentToken.lexeme == token) {
- advance(currentToken);
- } else {
- wrongToken(token);
- }
+ visitBreakStatement(BreakStatement node) {
+ writer.print('break');
+ visitPrefixed(' ', node.label);
+ writer.print(';');
}
- /// Advance [column] and [sourceIndex] indices by [len] characters.
- void advanceChars(int len) {
- column += len;
- sourceIndex += len;
+ visitCascadeExpression(CascadeExpression node) {
+ visit(node.target);
+ visitList(node.cascadeSections);
}
- /// Count the number of whitespace chars beginning at the current
- /// [sourceIndex].
- int countWhitespace() {
- var count = 0;
- for (var i = sourceIndex; i < source.length; ++i) {
- if (isIndentChar(source[i])) {
- ++count;
- } else {
- break;
+ visitCatchClause(CatchClause node) {
+ visitPrefixed('on ', node.exceptionType);
+ if (node.catchKeyword != null) {
+ if (node.exceptionType != null) {
+ writer.print(' ');
}
+ writer.print('catch (');
+ visit(node.exceptionParameter);
+ visitPrefixed(', ', node.stackTraceParameter);
+ writer.print(') ');
+ } else {
+ writer.print(' ');
}
- return count;
+ visit(node.body);
}
- /// Update indent indices.
- void indent() {
- numberOfIndentations++;
+ visitClassDeclaration(ClassDeclaration node) {
+ visitToken(node.abstractKeyword, ' ');
+ writer.print('class ');
+ visit(node.name);
+ visit(node.typeParameters);
+ visitPrefixed(' ', node.extendsClause);
+ visitPrefixed(' ', node.withClause);
+ visitPrefixed(' ', node.implementsClause);
+ writer.print(' {');
+ writer.indent();
+ for (var member in node.members) {
+ writer.newline();
+ visit(member);
+ }
+
+ writer.unindent();
+ writer.newline();
+ writer.print('}');
}
- /// Test if there is a newline at the given source [index].
- bool isNewlineAt(int index) {
- if (index < 0 || index + NEW_LINE.length > source.length) {
- return false;
+ visitClassTypeAlias(ClassTypeAlias node) {
+ writer.print('typedef ');
+ visit(node.name);
+ visit(node.typeParameters);
+ writer.print(' = ');
+ if (node.abstractKeyword != null) {
+ writer.print('abstract ');
}
- for (var i = 0; i < NEW_LINE.length; i++) {
- if (source[index] != NEW_LINE[i]) {
- return false;
- }
- }
- return true;
+ visit(node.superclass);
+ visitPrefixed(' ', node.withClause);
+ visitPrefixed(' ', node.implementsClause);
+ writer.print(';');
}
- /// Newline.
- void newline() {
- // TODO(pquitslund) emit comments
- needsIndent = true;
- // If there is a newline before the edit location, do nothing.
- if (isNewlineAt(sourceIndex - NEW_LINE.length)) {
- return;
- }
- // If there is a newline after the edit location, advance over it.
- if (isNewlineAt(sourceIndex)) {
- advanceChars(NEW_LINE.length);
- return;
- }
- // Otherwise, replace whitespace with a newline.
- var charsToReplace = countWhitespace();
- if (isNewlineAt(sourceIndex + charsToReplace)) {
- charsToReplace += NEW_LINE.length;
- }
- addEdit(sourceIndex, charsToReplace, NEW_LINE);
- advanceChars(charsToReplace);
+ visitComment(Comment node) => null;
+
+ visitCommentReference(CommentReference node) => null;
+
+ visitCompilationUnit(CompilationUnit node) {
+ var scriptTag = node.scriptTag;
+ var directives = node.directives;
+ visit(scriptTag);
+ var prefix = scriptTag == null ? '' : ' ';
+ visitPrefixedList(prefix, directives, ' ');
+ prefix = scriptTag == null && directives.isEmpty ? '' : ' ';
+ visitPrefixedList(prefix, node.declarations, ' ');
}
+ visitConditionalExpression(ConditionalExpression node) {
+ visit(node.condition);
+ writer.print(' ? ');
+ visit(node.thenExpression);
+ writer.print(' : ');
+ visit(node.elseExpression);
+ }
- /// Un-indent.
- void unindent() {
- numberOfIndentations--;
+ visitConstructorDeclaration(ConstructorDeclaration node) {
+ visitToken(node.externalKeyword, ' ');
+ visitToken(node.constKeyword, ' ');
+ visitToken(node.factoryKeyword, ' ');
+ visit(node.returnType);
+ visitPrefixed('.', node.name);
+ visit(node.parameters);
+ visitPrefixedList(' : ', node.initializers, ', ');
+ visitPrefixed(' = ', node.redirectedConstructor);
+ visitPrefixedBody(' ', node.body);
}
- /// Space.
- void space() {
- // TODO(pquitslund) emit comments
-// // If there is a space before the edit location, do nothing.
-// if (isSpaceAt(sourceIndex - 1)) {
-// return;
-// }
-// // If there is a space after the edit location, advance over it.
-// if (isSpaceAt(sourceIndex)) {
-// advance(1);
-// return;
-// }
- // Otherwise, replace spaces with a single space.
- spaces(1);
+ visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+ visitToken(node.keyword, '.');
+ visit(node.fieldName);
+ writer.print(' = ');
+ visit(node.expression);
}
- /// Spaces.
- void spaces(int num) {
- var charsToReplace = countWhitespace();
- addEdit(sourceIndex, charsToReplace, SPACES[num]);
- advanceChars(charsToReplace);
+ visitConstructorName(ConstructorName node) {
+ visit(node.type);
+ visitPrefixed('.', node.name);
}
- wrongToken(String token) {
- throw new FormatterException('expected token: "${token}", '
- 'actual: "${currentToken}"');
+ visitContinueStatement(ContinueStatement node) {
+ writer.print('continue');
+ visitPrefixed(' ', node.label);
+ writer.print(';');
}
- String toString() =>
- new EditOperation().apply(editStore.edits,
- source.substring(0, sourceIndex));
+ visitDeclaredIdentifier(DeclaredIdentifier node) {
+ visitToken(node.keyword, ' ');
+ visitSuffixed(node.type, ' ');
+ visit(node.identifier);
+ }
-}
+ visitDefaultFormalParameter(DefaultFormalParameter node) {
+ visit(node.parameter);
+ if (node.separator != null) {
+ writer.print(' ');
+ writer.print(node.separator.lexeme);
+ visitPrefixed(' ', node.defaultValue);
+ }
+ }
-const SPACE = ' ';
-final SPACES = [
- '',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
-];
+ visitDoStatement(DoStatement node) {
+ writer.print('do ');
+ visit(node.body);
+ writer.print(' while (');
+ visit(node.condition);
+ writer.print(');');
+ }
+ visitDoubleLiteral(DoubleLiteral node) {
+ writer.print(node.literal.lexeme);
+ }
-bool isIndentChar(String ch) => ch == SPACE; // TODO(pquitslund) also check tab
+ visitEmptyFunctionBody(EmptyFunctionBody node) {
+ writer.print(';');
+ }
+ visitEmptyStatement(EmptyStatement node) {
+ writer.print(';');
+ }
-/// Manages stored [Edit]s.
-class EditStore {
+ visitExportDirective(ExportDirective node) {
+ writer.print('export ');
+ visit(node.uri);
+ visitPrefixedList(' ', node.combinators, ' ');
+ writer.print(';');
+ }
- const EditStore();
+ visitExpressionFunctionBody(ExpressionFunctionBody node) {
+ writer.print('=> ');
+ visit(node.expression);
+ if (node.semicolon != null) {
+ writer.print(';');
+ }
+ }
- /// The underlying sequence of [Edit]s.
- final edits = <Edit>[];
+ visitExpressionStatement(ExpressionStatement node) {
+ visit(node.expression);
+ writer.print(';');
+ }
- /// Add the given [Edit] to the end of the edit sequence.
- void add(Edit edit) {
- edits.add(edit);
+ visitExtendsClause(ExtendsClause node) {
+ writer.print('extends ');
+ visit(node.superclass);
}
- /// Add an [Edit] that describes a textual [replacement] of a text interval
- /// starting at the given [offset] spanning the given [length].
- void addEdit(int offset, int length, String replacement) {
- add(new Edit(offset, length, replacement));
+ visitFieldDeclaration(FieldDeclaration node) {
+ visitToken(node.keyword, ' ');
+ visit(node.fields);
+ writer.print(';');
}
- /// Get the index of the current edit (for use in caching location
- /// information).
- int getCurrentEditIndex() => edits.length - 1;
+ visitFieldFormalParameter(FieldFormalParameter node) {
+ visitToken(node.keyword, ' ');
+ visitSuffixed(node.type, ' ');
+ writer.print('this.');
+ visit(node.identifier);
+ visit(node.parameters);
+ }
- /// Get the last edit.
- Edit getLastEdit() => edits.isEmpty ? null : edits.last;
+ visitForEachStatement(ForEachStatement node) {
+ writer.print('for (');
+ visit(node.loopVariable);
+ writer.print(' in ');
+ visit(node.iterator);
+ writer.print(') ');
+ visit(node.body);
+ }
- /// Add an [Edit] that describes an insertion of text starting at the given
- /// [offset].
- void insert(int offset, String insertedString) {
- addEdit(offset, 0, insertedString);
+ visitFormalParameterList(FormalParameterList node) {
+ var groupEnd = null;
+ writer.print('(');
+ var parameters = node.parameters;
+ var size = parameters.length;
+ for (var i = 0; i < size; i++) {
+ var parameter = parameters[i];
+ if (i > 0) {
+ writer.print(', ');
+ }
+ if (groupEnd == null && parameter is DefaultFormalParameter) {
+ if (identical(parameter.kind, ParameterKind.NAMED)) {
+ groupEnd = '}';
+ writer.print('{');
+ } else {
+ groupEnd = ']';
+ writer.print('[');
+ }
+ }
+ parameter.accept(this);
+ }
+ if (groupEnd != null) {
+ writer.print(groupEnd);
+ }
+ writer.print(')');
}
- /// Reset cached state.
- void reset() {
- edits.clear();
+ visitForStatement(ForStatement node) {
+ var initialization = node.initialization;
+ writer.print('for (');
+ if (initialization != null) {
+ visit(initialization);
+ } else {
+ visit(node.variables);
+ }
+ writer.print(';');
+ visitPrefixed(' ', node.condition);
+ writer.print(';');
+ visitPrefixedList(' ', node.updaters, ', ');
+ writer.print(') ');
+ visit(node.body);
}
- String toString() => 'EditStore( ${edits.toString()} )';
+ visitFunctionDeclaration(FunctionDeclaration node) {
+ visitSuffixed(node.returnType, ' ');
+ visitToken(node.propertyKeyword, ' ');
+ visit(node.name);
+ visit(node.functionExpression);
+ }
-}
+ visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
+ visit(node.functionDeclaration);
+ writer.print(';');
+ }
+ visitFunctionExpression(FunctionExpression node) {
+ visit(node.parameters);
+ writer.print(' ');
+ visit(node.body);
+ }
-/// Describes a text edit.
-class Edit {
+ visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+ visit(node.function);
+ visit(node.argumentList);
+ }
- /// The offset at which to apply the edit.
- final int offset;
+ visitFunctionTypeAlias(FunctionTypeAlias node) {
+ writer.print('typedef ');
+ visitSuffixed(node.returnType, ' ');
+ visit(node.name);
+ visit(node.typeParameters);
+ visit(node.parameters);
+ writer.print(';');
+ }
- /// The length of the text interval to replace.
- final int length;
+ visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+ visitSuffixed(node.returnType, ' ');
+ visit(node.identifier);
+ visit(node.parameters);
+ }
- /// The replacement text.
- final String replacement;
+ visitHideCombinator(HideCombinator node) {
+ writer.print('hide ');
+ visitList(node.hiddenNames, ', ');
+ }
- /// Create an edit.
- const Edit(this.offset, this.length, this.replacement);
+ visitIfStatement(IfStatement node) {
+ writer.print('if (');
+ visit(node.condition);
+ writer.print(') ');
+ visit(node.thenStatement);
+ visitPrefixed(' else ', node.elseStatement);
+ }
- /// Create an edit for the given [range].
- Edit.forRange(SourceRange range, String replacement):
- this(range.offset, range.length, replacement);
+ visitImplementsClause(ImplementsClause node) {
+ writer.print('implements ');
+ visitList(node.interfaces, ', ');
+ }
- String toString() => '${offset < 0 ? '(' : 'X('} offset: ${offset} , '
- 'length ${length}, replacement :> ${replacement} <:)';
+ visitImportDirective(ImportDirective node) {
+ writer.print('import ');
+ visit(node.uri);
+ visitPrefixed(' as ', node.prefix);
+ visitPrefixedList(' ', node.combinators, ' ');
+ writer.print(';');
+ }
-}
+ visitIndexExpression(IndexExpression node) {
+ if (node.isCascaded) {
+ writer.print('..');
+ } else {
+ visit(node.array);
+ }
+ writer.print('[');
+ visit(node.index);
+ writer.print(']');
+ }
-/// Applies a sequence of [edits] to a [document].
-class EditOperation {
+ visitInstanceCreationExpression(InstanceCreationExpression node) {
+ visitToken(node.keyword, ' ');
+ visit(node.constructorName);
+ visit(node.argumentList);
+ }
- String apply(List<Edit> edits, String document) {
+ visitIntegerLiteral(IntegerLiteral node) {
+ writer.print(node.literal.lexeme);
+ }
- var edit;
- for (var i = edits.length - 1; i >= 0; --i) {
- edit = edits[i];
- document = replace(document, edit.offset,
- edit.offset + edit.length, edit.replacement);
+ visitInterpolationExpression(InterpolationExpression node) {
+ if (node.rightBracket != null) {
+ writer.print('\${');
+ visit(node.expression);
+ writer.print('}');
+ } else {
+ writer.print('\$');
+ visit(node.expression);
}
+ }
- return document;
+ visitInterpolationString(InterpolationString node) {
+ writer.print(node.contents.lexeme);
}
-}
+ visitIsExpression(IsExpression node) {
+ visit(node.expression);
+ if (node.notOperator == null) {
+ writer.print(' is ');
+ } else {
+ writer.print(' is! ');
+ }
+ visit(node.type);
+ }
+ visitLabel(Label node) {
+ visit(node.label);
+ writer.print(':');
+ }
-String replace(String str, int start, int end, String replacement) =>
- str.substring(0, start) + replacement + str.substring(end);
+ visitLabeledStatement(LabeledStatement node) {
+ visitSuffixedList(node.labels, ' ', ' ');
+ visit(node.statement);
+ }
+ visitLibraryDirective(LibraryDirective node) {
+ writer.print('library ');
+ visit(node.name);
+ writer.print(';');
+ }
-/// An AST visitor that drives formatting heuristics.
-class FormattingEngine extends RecursiveASTVisitor {
+ visitLibraryIdentifier(LibraryIdentifier node) {
+ writer.print(node.name);
+ }
- final FormatterOptions options;
+ visitListLiteral(ListLiteral node) {
+ if (node.modifier != null) {
+ writer.print(node.modifier.lexeme);
+ writer.print(' ');
+ }
+ visitSuffixed(node.typeArguments, ' ');
+ writer.print('[');
+ visitList(node.elements, ', ');
+ writer.print(']');
+ }
- CodeKind kind;
- EditRecorder recorder;
+ visitMapLiteral(MapLiteral node) {
+ if (node.modifier != null) {
+ writer.print(node.modifier.lexeme);
+ writer.print(' ');
+ }
+ visitSuffixed(node.typeArguments, ' ');
+ writer.print('{');
+ visitList(node.entries, ', ');
+ writer.print('}');
+ }
- FormattingEngine(this.options);
+ visitMapLiteralEntry(MapLiteralEntry node) {
+ visit(node.key);
+ writer.print(' : ');
+ visit(node.value);
+ }
- String format(String source, ASTNode node, Token start, CodeKind kind,
- EditRecorder recorder) {
+ visitMethodDeclaration(MethodDeclaration node) {
+ visitToken(node.externalKeyword, ' ');
+ visitToken(node.modifierKeyword, ' ');
+ visitSuffixed(node.returnType, ' ');
+ visitToken(node.propertyKeyword, ' ');
+ visitToken(node.operatorKeyword, ' ');
+ visit(node.name);
+ if (!node.isGetter) {
+ visit(node.parameters);
+ }
+ visitPrefixedBody(' ', node.body);
+ }
- this.kind = kind;
- this.recorder = recorder;
+ visitMethodInvocation(MethodInvocation node) {
+ if (node.isCascaded) {
+ writer.print('..');
+ } else {
+ visitSuffixed(node.target, '.');
+ }
+ visit(node.methodName);
+ visit(node.argumentList);
+ }
- recorder..source = source
- ..currentToken = start;
+ visitNamedExpression(NamedExpression node) {
+ visit(node.name);
+ visitPrefixed(' ', node.expression);
+ }
- node.accept(this);
+ visitNativeFunctionBody(NativeFunctionBody node) {
+ writer.print('native ');
+ visit(node.stringLiteral);
+ writer.print(';');
+ }
- var editor = new EditOperation();
- return editor.apply(recorder.editStore.edits, source);
+ visitNullLiteral(NullLiteral node) {
+ writer.print('null');
}
+ visitParenthesizedExpression(ParenthesizedExpression node) {
+ writer.print('(');
+ visit(node.expression);
+ writer.print(')');
+ }
- visitClassDeclaration(ClassDeclaration node) {
+ visitPartDirective(PartDirective node) {
+ writer.print('part ');
+ visit(node.uri);
+ writer.print(';');
+ }
- recorder.advanceIndent();
+ visitPartOfDirective(PartOfDirective node) {
+ writer.print('part of ');
+ visit(node.libraryName);
+ writer.print(';');
+ }
- if (node.documentationComment != null) {
- node.documentationComment.accept(this);
- }
+ visitPostfixExpression(PostfixExpression node) {
+ visit(node.operand);
+ writer.print(node.operator.lexeme);
+ }
- recorder..advance(node.classKeyword)..space();
+ visitPrefixedIdentifier(PrefixedIdentifier node) {
+ visit(node.prefix);
+ writer.print('.');
+ visit(node.identifier);
+ }
- node.name.accept(this);
+ visitPrefixExpression(PrefixExpression node) {
+ writer.print(node.operator.lexeme);
+ visit(node.operand);
+ }
- if (node.typeParameters != null) {
- node.typeParameters.accept(this);
+ visitPropertyAccess(PropertyAccess node) {
+ if (node.isCascaded) {
+ writer.print('..');
+ } else {
+ visit(node.target);
+ writer.print('.');
}
- recorder.space();
+ visit(node.propertyName);
+ }
- if (node.extendsClause != null) {
- node.extendsClause.accept(this);
- recorder.space();
- }
+ visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+ writer.print('this');
+ visitPrefixed('.', node.constructorName);
+ visit(node.argumentList);
+ }
- if (node.implementsClause != null) {
- node.implementsClause.accept(this);
- recorder.space();
+ visitRethrowExpression(RethrowExpression node) {
+ writer.print('rethrow');
+ }
+
+ visitReturnStatement(ReturnStatement node) {
+ var expression = node.expression;
+ if (expression == null) {
+ writer.print('return;');
+ } else {
+ writer.print('return ');
+ expression.accept(this);
+ writer.print(';');
}
+ }
- recorder..advance(node.leftBracket)
- ..indent();
+ visitScriptTag(ScriptTag node) {
+ writer.print(node.scriptTag.lexeme);
+ }
- for (var member in node.members) {
- recorder..newline()
- ..advanceIndent();
- member.accept(this);
- }
+ visitShowCombinator(ShowCombinator node) {
+ writer.print('show ');
+ visitList(node.shownNames, ', ');
+ }
- recorder..unindent()
- ..newline()
- ..advanceIndent()
- ..advance(node.rightBracket);
+ visitSimpleFormalParameter(SimpleFormalParameter node) {
+ visitToken(node.keyword, ' ');
+ visitSuffixed(node.type, ' ');
+ visit(node.identifier);
}
+ visitSimpleIdentifier(SimpleIdentifier node) {
+ writer.print(node.token.lexeme);
+ }
- visitBlockFunctionBody(BlockFunctionBody node) {
- node.block.accept(this);
+ visitSimpleStringLiteral(SimpleStringLiteral node) {
+ writer.print(node.literal.lexeme);
}
+ visitStringInterpolation(StringInterpolation node) {
+ visitList(node.elements);
+ }
- visitBlock(Block block) {
- recorder..advance(block.leftBracket)
- ..indent()
- ..newline();
- // ...
- recorder..unindent()
- ..advanceIndent()
- ..advance(block.rightBracket);
+ visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+ writer.print('super');
+ visitPrefixed('.', node.constructorName);
+ visit(node.argumentList);
}
+ visitSuperExpression(SuperExpression node) {
+ writer.print('super');
+ }
- visitExpressionFunctionBody(ExpressionFunctionBody node) {
- recorder..advance(node.functionDefinition)
- ..indent()
- ..newline();
- node.expression.accept(this);
- recorder..unindent()
- ..advanceIndent()
- ..advance(node.semicolon);
+ visitSwitchCase(SwitchCase node) {
+ visitSuffixedList(node.labels, ' ', ' ');
+ writer.print('case ');
+ visit(node.expression);
+ writer.print(': ');
+ visitList(node.statements, ' ');
}
+ visitSwitchDefault(SwitchDefault node) {
+ visitSuffixedList(node.labels, ' ', ' ');
+ writer.print('default: ');
+ visitList(node.statements, ' ');
+ }
- visitMethodDeclaration(MethodDeclaration node) {
+ visitSwitchStatement(SwitchStatement node) {
+ writer.print('switch (');
+ visit(node.expression);
+ writer.print(') {');
+ visitList(node.members, ' ');
+ writer.print('}');
+ }
- if (node.modifierKeyword != null) {
- recorder.advance(node.modifierKeyword);
- recorder.space();
- }
+ visitSymbolLiteral(SymbolLiteral node) {
+ // No-op ?
+ }
- if (node.returnType != null) {
- node.returnType.accept(this);
- recorder.space();
- }
+ visitThisExpression(ThisExpression node) {
+ writer.print('this');
+ }
- recorder.advance(node.name.beginToken);
+ visitThrowExpression(ThrowExpression node) {
+ writer.print('throw ');
+ visit(node.expression);
+ }
- node.parameters.accept(this);
+ visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+ visitSuffixed(node.variables, ';');
+ }
- recorder.space();
+ visitTryStatement(TryStatement node) {
+ writer.print('try ');
+ visit(node.body);
+ visitPrefixedList(' ', node.catchClauses, ' ');
+ visitPrefixed(' finally ', node.finallyClause);
+ }
- node.body.accept(this);
+ visitTypeArgumentList(TypeArgumentList node) {
+ writer.print('<');
+ visitList(node.arguments, ', ');
+ writer.print('>');
}
+ visitTypeName(TypeName node) {
+ visit(node.name);
+ visit(node.typeArguments);
+ }
- visitFormalParameterList(FormalParameterList node) {
- recorder.advance(node.beginToken);
- //...
- recorder.advance(node.endToken);
+ visitTypeParameter(TypeParameter node) {
+ visit(node.name);
+ visitPrefixed(' extends ', node.bound);
}
+ visitTypeParameterList(TypeParameterList node) {
+ writer.print('<');
+ visitList(node.typeParameters, ', ');
+ writer.print('>');
+ }
- visitSimpleIdentifier(SimpleIdentifier node) {
- recorder.advance(node.token);
+ visitVariableDeclaration(VariableDeclaration node) {
+ visit(node.name);
+ visitPrefixed(' = ', node.initializer);
}
-}
+ visitVariableDeclarationList(VariableDeclarationList node) {
+ visitToken(node.keyword, ' ');
+ visitSuffixed(node.type, ' ');
+ visitList(node.variables, ', ');
+ }
+
+ visitVariableDeclarationStatement(VariableDeclarationStatement node) {
+ visit(node.variables);
+ writer.print(';');
+ }
+
+ visitWhileStatement(WhileStatement node) {
+ writer.print('while (');
+ visit(node.condition);
+ writer.print(') ');
+ visit(node.body);
+ }
+
+ visitWithClause(WithClause node) {
+ writer.print('with ');
+ visitList(node.mixinTypes, ', ');
+ }
+
+ /// Safely visit the given [node].
+ visit(ASTNode node) {
+ if (node != null) {
+ node.accept(this);
+ }
+ }
+
+ /// Safely visit the given [node], printing the [suffix] after the node if it
+ /// is non-null.
+ visitSuffixed(ASTNode node, String suffix) {
+ if (node != null) {
+ node.accept(this);
+ writer.print(suffix);
+ }
+ }
+
+ /// Safely visit the given [node], printing the [prefix] before the node if
+ /// it is non-null.
+ visitPrefixed(String prefix, ASTNode node) {
+ if (node != null) {
+ writer.print(prefix);
+ node.accept(this);
+ }
+ }
+
+ /// Visit the given function [body], printing the [prefix] before if given
+ /// body is not empty.
+ visitPrefixedBody(String prefix, FunctionBody body) {
+ if (body is! EmptyFunctionBody) {
+ writer.print(prefix);
+ }
+ visit(body);
+ }
+
+ /// Safely visit the given [token], printing the suffix after the [token]
+ /// node if it is non-null.
+ visitToken(Token token, String suffix) {
+ if (token != null) {
+ writer.print(token.lexeme);
+ writer.print(suffix);
+ }
+ }
+
+ /// Print a list of [nodes], separated by the given [separator].
+ visitList(NodeList<ASTNode> nodes, [String separator = '']) {
+ if (nodes != null) {
+ var size = nodes.length;
+ for (var i = 0; i < size; i++) {
+ if (i > 0) {
+ writer.print(separator);
+ }
+ nodes[i].accept(this);
+ }
+ }
+ }
+
+ /// Print a list of [nodes], separated by the given [separator].
+ visitSuffixedList(NodeList<ASTNode> nodes, String separator, String suffix) {
+ if (nodes != null) {
+ var size = nodes.length;
+ if (size > 0) {
+ for (var i = 0; i < size; i++) {
+ if (i > 0) {
+ writer.print(separator);
+ }
+ nodes[i].accept(this);
+ }
+ writer.print(suffix);
+ }
+ }
+ }
+
+ /// Print a list of [nodes], separated by the given [separator].
+ visitPrefixedList(String prefix, NodeList<ASTNode> nodes, String separator) {
+ if (nodes != null) {
+ var size = nodes.length;
+ if (size > 0) {
+ writer.print(prefix);
+ for (var i = 0; i < size; i++) {
+ if (i > 0) {
+ writer.print(separator);
+ }
+ nodes[i].accept(this);
+ }
+ }
+ }
+ }
+
+}
« no previous file with comments | « no previous file | pkg/analyzer_experimental/lib/src/services/writer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698