| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library formatter_impl; | 5 library formatter_impl; |
| 6 | 6 |
| 7 import 'dart:math'; |
| 7 | 8 |
| 8 import 'package:analyzer_experimental/analyzer.dart'; | 9 import 'package:analyzer_experimental/analyzer.dart'; |
| 9 import 'package:analyzer_experimental/src/generated/parser.dart'; | 10 import 'package:analyzer_experimental/src/generated/parser.dart'; |
| 10 import 'package:analyzer_experimental/src/generated/scanner.dart'; | 11 import 'package:analyzer_experimental/src/generated/scanner.dart'; |
| 11 import 'package:analyzer_experimental/src/generated/source.dart'; | 12 import 'package:analyzer_experimental/src/generated/source.dart'; |
| 12 import 'package:analyzer_experimental/src/services/writer.dart'; | 13 import 'package:analyzer_experimental/src/services/writer.dart'; |
| 13 | 14 |
| 14 /// OS line separator. --- TODO(pquitslund): may not be necessary | 15 /// OS line separator. --- TODO(pquitslund): may not be necessary |
| 15 const NEW_LINE = '\n' ; //Platform.pathSeparator; | 16 const NEW_LINE = '\n' ; //Platform.pathSeparator; |
| 16 | 17 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 | 69 |
| 69 /// Dart source code formatter. | 70 /// Dart source code formatter. |
| 70 abstract class CodeFormatter { | 71 abstract class CodeFormatter { |
| 71 | 72 |
| 72 factory CodeFormatter([FormatterOptions options = const FormatterOptions()]) | 73 factory CodeFormatter([FormatterOptions options = const FormatterOptions()]) |
| 73 => new CodeFormatterImpl(options); | 74 => new CodeFormatterImpl(options); |
| 74 | 75 |
| 75 /// Format the specified portion (from [offset] with [length]) of the given | 76 /// Format the specified portion (from [offset] with [length]) of the given |
| 76 /// [source] string, optionally providing an [indentationLevel]. | 77 /// [source] string, optionally providing an [indentationLevel]. |
| 77 String format(CodeKind kind, String source, {int offset, int end, | 78 String format(CodeKind kind, String source, {int offset, int end, |
| 78 int indentationLevel:0}); | 79 int indentationLevel: 0}); |
| 79 | 80 |
| 80 } | 81 } |
| 81 | 82 |
| 82 class CodeFormatterImpl implements CodeFormatter, AnalysisErrorListener { | 83 class CodeFormatterImpl implements CodeFormatter, AnalysisErrorListener { |
| 83 | 84 |
| 84 final FormatterOptions options; | 85 final FormatterOptions options; |
| 85 final errors = <AnalysisError>[]; | 86 final errors = <AnalysisError>[]; |
| 86 | 87 |
| 87 LineInfo lineInfo; | 88 LineInfo lineInfo; |
| 88 | 89 |
| 89 CodeFormatterImpl(this.options); | 90 CodeFormatterImpl(this.options); |
| 90 | 91 |
| 91 String format(CodeKind kind, String source, {int offset, int end, | 92 String format(CodeKind kind, String source, {int offset, int end, |
| 92 int indentationLevel:0}) { | 93 int indentationLevel: 0}) { |
| 93 | 94 |
| 94 var start = tokenize(source); | 95 var start = tokenize(source); |
| 95 checkForErrors(); | 96 checkForErrors(); |
| 96 | 97 |
| 97 var node = parse(kind, start); | 98 var node = parse(kind, start); |
| 98 checkForErrors(); | 99 checkForErrors(); |
| 99 | 100 |
| 100 var formatter = new SourceVisitor(options, lineInfo); | 101 var formatter = new SourceVisitor(options, lineInfo); |
| 101 node.accept(formatter); | 102 node.accept(formatter); |
| 102 | 103 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 130 Token tokenize(String source) { | 131 Token tokenize(String source) { |
| 131 var scanner = new StringScanner(null, source, this); | 132 var scanner = new StringScanner(null, source, this); |
| 132 var token = scanner.tokenize(); | 133 var token = scanner.tokenize(); |
| 133 lineInfo = new LineInfo(scanner.lineStarts); | 134 lineInfo = new LineInfo(scanner.lineStarts); |
| 134 return token; | 135 return token; |
| 135 } | 136 } |
| 136 | 137 |
| 137 } | 138 } |
| 138 | 139 |
| 139 | 140 |
| 140 | |
| 141 /// An AST visitor that drives formatting heuristics. | 141 /// An AST visitor that drives formatting heuristics. |
| 142 class SourceVisitor implements ASTVisitor { | 142 class SourceVisitor implements ASTVisitor { |
| 143 | 143 |
| 144 /// The writer to which the source is to be written. | 144 /// The writer to which the source is to be written. |
| 145 SourceWriter writer; | 145 SourceWriter writer; |
| 146 | 146 |
| 147 /// Cached line info for calculating blank lines. |
| 147 LineInfo lineInfo; | 148 LineInfo lineInfo; |
| 148 | 149 |
| 150 /// Cached previous token for calculating preceding whitespace. |
| 151 Token previousToken; |
| 152 |
| 149 /// Initialize a newly created visitor to write source code representing | 153 /// Initialize a newly created visitor to write source code representing |
| 150 /// the visited nodes to the given [writer]. | 154 /// the visited nodes to the given [writer]. |
| 151 SourceVisitor(FormatterOptions options, this.lineInfo) : | 155 SourceVisitor(FormatterOptions options, this.lineInfo) : |
| 152 writer = new SourceWriter(indentCount: options.initialIndentationLevel, | 156 writer = new SourceWriter(indentCount: options.initialIndentationLevel, |
| 153 lineSeparator: options.lineSeparator); | 157 lineSeparator: options.lineSeparator); |
| 154 | 158 |
| 155 visitAdjacentStrings(AdjacentStrings node) { | 159 visitAdjacentStrings(AdjacentStrings node) { |
| 156 visitList(node.strings, ' '); | 160 visitList(node.strings, ' '); |
| 157 } | 161 } |
| 158 | 162 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 writer.indent(); | 211 writer.indent(); |
| 208 | 212 |
| 209 for (var stmt in node.statements) { | 213 for (var stmt in node.statements) { |
| 210 writer.newline(); | 214 writer.newline(); |
| 211 visit(stmt); | 215 visit(stmt); |
| 212 } | 216 } |
| 213 | 217 |
| 214 writer.unindent(); | 218 writer.unindent(); |
| 215 writer.newline(); | 219 writer.newline(); |
| 216 writer.print('}'); | 220 writer.print('}'); |
| 221 previousToken = node.rightBracket; |
| 217 } | 222 } |
| 218 | 223 |
| 219 visitBlockFunctionBody(BlockFunctionBody node) { | 224 visitBlockFunctionBody(BlockFunctionBody node) { |
| 220 visit(node.block); | 225 visit(node.block); |
| 221 } | 226 } |
| 222 | 227 |
| 223 visitBooleanLiteral(BooleanLiteral node) { | 228 visitBooleanLiteral(BooleanLiteral node) { |
| 224 writer.print(node.literal.lexeme); | 229 writer.print(node.literal.lexeme); |
| 225 } | 230 } |
| 226 | 231 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 245 visit(node.exceptionParameter); | 250 visit(node.exceptionParameter); |
| 246 visitPrefixed(', ', node.stackTraceParameter); | 251 visitPrefixed(', ', node.stackTraceParameter); |
| 247 writer.print(') '); | 252 writer.print(') '); |
| 248 } else { | 253 } else { |
| 249 writer.print(' '); | 254 writer.print(' '); |
| 250 } | 255 } |
| 251 visit(node.body); | 256 visit(node.body); |
| 252 } | 257 } |
| 253 | 258 |
| 254 visitClassDeclaration(ClassDeclaration node) { | 259 visitClassDeclaration(ClassDeclaration node) { |
| 255 visitToken(node.abstractKeyword, ' '); | 260 emitToken(node.abstractKeyword, ' '); |
| 256 writer.print('class '); | 261 emitToken(node.classKeyword, ' '); |
| 257 visit(node.name); | 262 visit(node.name); |
| 258 visit(node.typeParameters); | 263 visit(node.typeParameters); |
| 259 visitPrefixed(' ', node.extendsClause); | 264 visitPrefixed(' ', node.extendsClause); |
| 260 visitPrefixed(' ', node.withClause); | 265 visitPrefixed(' ', node.withClause); |
| 261 visitPrefixed(' ', node.implementsClause); | 266 visitPrefixed(' ', node.implementsClause); |
| 262 writer.print(' {'); | 267 // writer.print(' {'); |
| 268 // writer.print(' '); |
| 269 // emit(node.leftBracket); |
| 270 emitPrefixedToken(' ', node.leftBracket); |
| 263 writer.indent(); | 271 writer.indent(); |
| 264 for (var member in node.members) { | 272 |
| 265 writer.newline(); | 273 for (var i = 0; i < node.members.length; i++) { |
| 266 visit(member); | 274 visit(node.members[i]); |
| 267 } | 275 } |
| 268 | 276 |
| 269 writer.unindent(); | 277 writer.unindent(); |
| 270 writer.newline(); | 278 |
| 271 writer.print('}'); | 279 emit(node.rightBracket, min: 1); |
| 272 } | 280 } |
| 273 | 281 |
| 274 visitClassTypeAlias(ClassTypeAlias node) { | 282 visitClassTypeAlias(ClassTypeAlias node) { |
| 275 writer.print('typedef '); | 283 writer.print('typedef '); |
| 276 visit(node.name); | 284 visit(node.name); |
| 277 visit(node.typeParameters); | 285 visit(node.typeParameters); |
| 278 writer.print(' = '); | 286 writer.print(' = '); |
| 279 if (node.abstractKeyword != null) { | 287 if (node.abstractKeyword != null) { |
| 280 writer.print('abstract '); | 288 writer.print('abstract '); |
| 281 } | 289 } |
| 282 visit(node.superclass); | 290 visit(node.superclass); |
| 283 visitPrefixed(' ', node.withClause); | 291 visitPrefixed(' ', node.withClause); |
| 284 visitPrefixed(' ', node.implementsClause); | 292 visitPrefixed(' ', node.implementsClause); |
| 285 writer.print(';'); | 293 writer.print(';'); |
| 286 } | 294 } |
| 287 | 295 |
| 288 visitComment(Comment node) => null; | 296 visitComment(Comment node) => null; |
| 289 | 297 |
| 290 visitCommentReference(CommentReference node) => null; | 298 visitCommentReference(CommentReference node) => null; |
| 291 | 299 |
| 292 visitCompilationUnit(CompilationUnit node) { | 300 visitCompilationUnit(CompilationUnit node) { |
| 293 var scriptTag = node.scriptTag; | 301 var scriptTag = node.scriptTag; |
| 294 var directives = node.directives; | 302 var directives = node.directives; |
| 295 visit(scriptTag); | 303 visit(scriptTag); |
| 296 var prefix = scriptTag == null ? '' : ' '; | 304 var prefix = scriptTag == null ? '' : ' '; |
| 297 visitPrefixedList(prefix, directives, ' '); | 305 visitPrefixedList(prefix, directives, ' '); |
| 298 prefix = scriptTag == null && directives.isEmpty ? '' : ' '; | 306 //prefix = scriptTag == null && directives.isEmpty ? '' : ' '; |
| 299 visitPrefixedListWithBlanks(prefix, node.declarations); | 307 prefix = ''; |
| 308 visitPrefixedList(prefix, node.declarations); |
| 300 | 309 |
| 301 //TODO(pquitslund): move this? | 310 //TODO(pquitslund): move this? |
| 302 writer.newline(); | 311 writer.newline(); |
| 303 } | 312 } |
| 304 | 313 |
| 305 visitConditionalExpression(ConditionalExpression node) { | 314 visitConditionalExpression(ConditionalExpression node) { |
| 306 visit(node.condition); | 315 visit(node.condition); |
| 307 writer.print(' ? '); | 316 writer.print(' ? '); |
| 308 visit(node.thenExpression); | 317 visit(node.thenExpression); |
| 309 writer.print(' : '); | 318 writer.print(' : '); |
| 310 visit(node.elseExpression); | 319 visit(node.elseExpression); |
| 311 } | 320 } |
| 312 | 321 |
| 313 visitConstructorDeclaration(ConstructorDeclaration node) { | 322 visitConstructorDeclaration(ConstructorDeclaration node) { |
| 314 visitToken(node.externalKeyword, ' '); | 323 emitToken(node.externalKeyword, ' '); |
| 315 visitToken(node.constKeyword, ' '); | 324 emitToken(node.constKeyword, ' '); |
| 316 visitToken(node.factoryKeyword, ' '); | 325 emitToken(node.factoryKeyword, ' '); |
| 317 visit(node.returnType); | 326 visit(node.returnType); |
| 318 visitPrefixed('.', node.name); | 327 visitPrefixed('.', node.name); |
| 319 visit(node.parameters); | 328 visit(node.parameters); |
| 320 visitPrefixedList(' : ', node.initializers, ', '); | 329 visitPrefixedList(' : ', node.initializers, ', '); |
| 321 visitPrefixed(' = ', node.redirectedConstructor); | 330 visitPrefixed(' = ', node.redirectedConstructor); |
| 322 visitPrefixedBody(' ', node.body); | 331 visitPrefixedBody(' ', node.body); |
| 323 } | 332 } |
| 324 | 333 |
| 325 visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | 334 visitConstructorFieldInitializer(ConstructorFieldInitializer node) { |
| 326 visitToken(node.keyword, '.'); | 335 emitToken(node.keyword, '.'); |
| 327 visit(node.fieldName); | 336 visit(node.fieldName); |
| 328 writer.print(' = '); | 337 writer.print(' = '); |
| 329 visit(node.expression); | 338 visit(node.expression); |
| 330 } | 339 } |
| 331 | 340 |
| 332 visitConstructorName(ConstructorName node) { | 341 visitConstructorName(ConstructorName node) { |
| 333 visit(node.type); | 342 visit(node.type); |
| 334 visitPrefixed('.', node.name); | 343 visitPrefixed('.', node.name); |
| 335 } | 344 } |
| 336 | 345 |
| 337 visitContinueStatement(ContinueStatement node) { | 346 visitContinueStatement(ContinueStatement node) { |
| 338 writer.print('continue'); | 347 writer.print('continue'); |
| 339 visitPrefixed(' ', node.label); | 348 visitPrefixed(' ', node.label); |
| 340 writer.print(';'); | 349 writer.print(';'); |
| 341 } | 350 } |
| 342 | 351 |
| 343 visitDeclaredIdentifier(DeclaredIdentifier node) { | 352 visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 344 visitToken(node.keyword, ' '); | 353 emitToken(node.keyword, ' '); |
| 345 visitSuffixed(node.type, ' '); | 354 visitSuffixed(node.type, ' '); |
| 346 visit(node.identifier); | 355 visit(node.identifier); |
| 347 } | 356 } |
| 348 | 357 |
| 349 visitDefaultFormalParameter(DefaultFormalParameter node) { | 358 visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 350 visit(node.parameter); | 359 visit(node.parameter); |
| 351 if (node.separator != null) { | 360 if (node.separator != null) { |
| 352 writer.print(' '); | 361 writer.print(' '); |
| 353 writer.print(node.separator.lexeme); | 362 writer.print(node.separator.lexeme); |
| 354 visitPrefixed(' ', node.defaultValue); | 363 visitPrefixed(' ', node.defaultValue); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 visit(node.expression); | 403 visit(node.expression); |
| 395 writer.print(';'); | 404 writer.print(';'); |
| 396 } | 405 } |
| 397 | 406 |
| 398 visitExtendsClause(ExtendsClause node) { | 407 visitExtendsClause(ExtendsClause node) { |
| 399 writer.print('extends '); | 408 writer.print('extends '); |
| 400 visit(node.superclass); | 409 visit(node.superclass); |
| 401 } | 410 } |
| 402 | 411 |
| 403 visitFieldDeclaration(FieldDeclaration node) { | 412 visitFieldDeclaration(FieldDeclaration node) { |
| 404 visitToken(node.keyword, ' '); | 413 emitToken(node.keyword, ' '); |
| 405 visit(node.fields); | 414 visit(node.fields); |
| 406 writer.print(';'); | 415 writer.print(';'); |
| 407 } | 416 } |
| 408 | 417 |
| 409 visitFieldFormalParameter(FieldFormalParameter node) { | 418 visitFieldFormalParameter(FieldFormalParameter node) { |
| 410 visitToken(node.keyword, ' '); | 419 emitToken(node.keyword, ' '); |
| 411 visitSuffixed(node.type, ' '); | 420 visitSuffixed(node.type, ' '); |
| 412 writer.print('this.'); | 421 writer.print('this.'); |
| 413 visit(node.identifier); | 422 visit(node.identifier); |
| 414 visit(node.parameters); | 423 visit(node.parameters); |
| 415 } | 424 } |
| 416 | 425 |
| 417 visitForEachStatement(ForEachStatement node) { | 426 visitForEachStatement(ForEachStatement node) { |
| 418 writer.print('for ('); | 427 writer.print('for ('); |
| 419 visit(node.loopVariable); | 428 visit(node.loopVariable); |
| 420 writer.print(' in '); | 429 writer.print(' in '); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 writer.print(';'); | 470 writer.print(';'); |
| 462 visitPrefixed(' ', node.condition); | 471 visitPrefixed(' ', node.condition); |
| 463 writer.print(';'); | 472 writer.print(';'); |
| 464 visitPrefixedList(' ', node.updaters, ', '); | 473 visitPrefixedList(' ', node.updaters, ', '); |
| 465 writer.print(') '); | 474 writer.print(') '); |
| 466 visit(node.body); | 475 visit(node.body); |
| 467 } | 476 } |
| 468 | 477 |
| 469 visitFunctionDeclaration(FunctionDeclaration node) { | 478 visitFunctionDeclaration(FunctionDeclaration node) { |
| 470 visitSuffixed(node.returnType, ' '); | 479 visitSuffixed(node.returnType, ' '); |
| 471 visitToken(node.propertyKeyword, ' '); | 480 emitToken(node.propertyKeyword, ' '); |
| 472 visit(node.name); | 481 visit(node.name); |
| 473 visit(node.functionExpression); | 482 visit(node.functionExpression); |
| 474 } | 483 } |
| 475 | 484 |
| 476 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | 485 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { |
| 477 visit(node.functionDeclaration); | 486 visit(node.functionDeclaration); |
| 478 writer.print(';'); | 487 writer.print(';'); |
| 479 } | 488 } |
| 480 | 489 |
| 481 visitFunctionExpression(FunctionExpression node) { | 490 visitFunctionExpression(FunctionExpression node) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 visitImplementsClause(ImplementsClause node) { | 529 visitImplementsClause(ImplementsClause node) { |
| 521 writer.print('implements '); | 530 writer.print('implements '); |
| 522 visitList(node.interfaces, ', '); | 531 visitList(node.interfaces, ', '); |
| 523 } | 532 } |
| 524 | 533 |
| 525 visitImportDirective(ImportDirective node) { | 534 visitImportDirective(ImportDirective node) { |
| 526 writer.print('import '); | 535 writer.print('import '); |
| 527 visit(node.uri); | 536 visit(node.uri); |
| 528 visitPrefixed(' as ', node.prefix); | 537 visitPrefixed(' as ', node.prefix); |
| 529 visitPrefixedList(' ', node.combinators, ' '); | 538 visitPrefixedList(' ', node.combinators, ' '); |
| 530 writer.print(';'); | 539 // writer.print(';'); |
| 540 emit(node.semicolon); |
| 541 // writer.newline(); |
| 531 } | 542 } |
| 532 | 543 |
| 533 visitIndexExpression(IndexExpression node) { | 544 visitIndexExpression(IndexExpression node) { |
| 534 if (node.isCascaded) { | 545 if (node.isCascaded) { |
| 535 writer.print('..'); | 546 writer.print('..'); |
| 536 } else { | 547 } else { |
| 537 visit(node.target); | 548 visit(node.target); |
| 538 } | 549 } |
| 539 writer.print('['); | 550 writer.print('['); |
| 540 visit(node.index); | 551 visit(node.index); |
| 541 writer.print(']'); | 552 writer.print(']'); |
| 542 } | 553 } |
| 543 | 554 |
| 544 visitInstanceCreationExpression(InstanceCreationExpression node) { | 555 visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 545 visitToken(node.keyword, ' '); | 556 emitToken(node.keyword, ' '); |
| 546 visit(node.constructorName); | 557 visit(node.constructorName); |
| 547 visit(node.argumentList); | 558 visit(node.argumentList); |
| 548 } | 559 } |
| 549 | 560 |
| 550 visitIntegerLiteral(IntegerLiteral node) { | 561 visitIntegerLiteral(IntegerLiteral node) { |
| 551 writer.print(node.literal.lexeme); | 562 writer.print(node.literal.lexeme); |
| 552 } | 563 } |
| 553 | 564 |
| 554 visitInterpolationExpression(InterpolationExpression node) { | 565 visitInterpolationExpression(InterpolationExpression node) { |
| 555 if (node.rightBracket != null) { | 566 if (node.rightBracket != null) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 618 writer.print('}'); | 629 writer.print('}'); |
| 619 } | 630 } |
| 620 | 631 |
| 621 visitMapLiteralEntry(MapLiteralEntry node) { | 632 visitMapLiteralEntry(MapLiteralEntry node) { |
| 622 visit(node.key); | 633 visit(node.key); |
| 623 writer.print(' : '); | 634 writer.print(' : '); |
| 624 visit(node.value); | 635 visit(node.value); |
| 625 } | 636 } |
| 626 | 637 |
| 627 visitMethodDeclaration(MethodDeclaration node) { | 638 visitMethodDeclaration(MethodDeclaration node) { |
| 628 visitToken(node.externalKeyword, ' '); | 639 emitToken(node.externalKeyword, ' '); |
| 629 visitToken(node.modifierKeyword, ' '); | 640 emitToken(node.modifierKeyword, ' '); |
| 630 visitSuffixed(node.returnType, ' '); | 641 visitSuffixed(node.returnType, ' '); |
| 631 visitToken(node.propertyKeyword, ' '); | 642 emitToken(node.propertyKeyword, ' '); |
| 632 visitToken(node.operatorKeyword, ' '); | 643 emitToken(node.operatorKeyword, ' '); |
| 633 visit(node.name); | 644 visit(node.name); |
| 634 if (!node.isGetter) { | 645 if (!node.isGetter) { |
| 635 visit(node.parameters); | 646 visit(node.parameters); |
| 636 } | 647 } |
| 637 visitPrefixedBody(' ', node.body); | 648 visitPrefixedBody(' ', node.body); |
| 638 } | 649 } |
| 639 | 650 |
| 640 visitMethodInvocation(MethodInvocation node) { | 651 visitMethodInvocation(MethodInvocation node) { |
| 641 if (node.isCascaded) { | 652 if (node.isCascaded) { |
| 642 writer.print('..'); | 653 writer.print('..'); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 visitScriptTag(ScriptTag node) { | 746 visitScriptTag(ScriptTag node) { |
| 736 writer.print(node.scriptTag.lexeme); | 747 writer.print(node.scriptTag.lexeme); |
| 737 } | 748 } |
| 738 | 749 |
| 739 visitShowCombinator(ShowCombinator node) { | 750 visitShowCombinator(ShowCombinator node) { |
| 740 writer.print('show '); | 751 writer.print('show '); |
| 741 visitList(node.shownNames, ', '); | 752 visitList(node.shownNames, ', '); |
| 742 } | 753 } |
| 743 | 754 |
| 744 visitSimpleFormalParameter(SimpleFormalParameter node) { | 755 visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 745 visitToken(node.keyword, ' '); | 756 emitToken(node.keyword, ' '); |
| 746 visitSuffixed(node.type, ' '); | 757 visitSuffixed(node.type, ' '); |
| 747 visit(node.identifier); | 758 visit(node.identifier); |
| 748 } | 759 } |
| 749 | 760 |
| 750 visitSimpleIdentifier(SimpleIdentifier node) { | 761 visitSimpleIdentifier(SimpleIdentifier node) { |
| 751 writer.print(node.token.lexeme); | 762 emit(node.token); |
| 763 // writer.print(node.token.lexeme); |
| 752 } | 764 } |
| 753 | 765 |
| 754 visitSimpleStringLiteral(SimpleStringLiteral node) { | 766 visitSimpleStringLiteral(SimpleStringLiteral node) { |
| 755 writer.print(node.literal.lexeme); | 767 writer.print(node.literal.lexeme); |
| 756 } | 768 } |
| 757 | 769 |
| 758 visitStringInterpolation(StringInterpolation node) { | 770 visitStringInterpolation(StringInterpolation node) { |
| 759 visitList(node.elements); | 771 visitList(node.elements); |
| 760 } | 772 } |
| 761 | 773 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 836 visitList(node.typeParameters, ', '); | 848 visitList(node.typeParameters, ', '); |
| 837 writer.print('>'); | 849 writer.print('>'); |
| 838 } | 850 } |
| 839 | 851 |
| 840 visitVariableDeclaration(VariableDeclaration node) { | 852 visitVariableDeclaration(VariableDeclaration node) { |
| 841 visit(node.name); | 853 visit(node.name); |
| 842 visitPrefixed(' = ', node.initializer); | 854 visitPrefixed(' = ', node.initializer); |
| 843 } | 855 } |
| 844 | 856 |
| 845 visitVariableDeclarationList(VariableDeclarationList node) { | 857 visitVariableDeclarationList(VariableDeclarationList node) { |
| 846 visitToken(node.keyword, ' '); | 858 emitToken(node.keyword, ' '); |
| 847 visitSuffixed(node.type, ' '); | 859 visitSuffixed(node.type, ' '); |
| 848 visitList(node.variables, ', '); | 860 visitList(node.variables, ', '); |
| 849 } | 861 } |
| 850 | 862 |
| 851 visitVariableDeclarationStatement(VariableDeclarationStatement node) { | 863 visitVariableDeclarationStatement(VariableDeclarationStatement node) { |
| 852 visit(node.variables); | 864 visit(node.variables); |
| 853 writer.print(';'); | 865 writer.print(';'); |
| 854 } | 866 } |
| 855 | 867 |
| 856 visitWhileStatement(WhileStatement node) { | 868 visitWhileStatement(WhileStatement node) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 892 | 904 |
| 893 /// Visit the given function [body], printing the [prefix] before if given | 905 /// Visit the given function [body], printing the [prefix] before if given |
| 894 /// body is not empty. | 906 /// body is not empty. |
| 895 visitPrefixedBody(String prefix, FunctionBody body) { | 907 visitPrefixedBody(String prefix, FunctionBody body) { |
| 896 if (body is! EmptyFunctionBody) { | 908 if (body is! EmptyFunctionBody) { |
| 897 writer.print(prefix); | 909 writer.print(prefix); |
| 898 } | 910 } |
| 899 visit(body); | 911 visit(body); |
| 900 } | 912 } |
| 901 | 913 |
| 902 /// Safely visit the given [token], printing the suffix after the [token] | 914 /// Emit the given [token], printing the prefix before the [token] |
| 915 /// if it is non-null. |
| 916 emitPrefixedToken(String prefix, Token token) { |
| 917 if (token != null) { |
| 918 writer.print(prefix); |
| 919 emit(token); |
| 920 } |
| 921 } |
| 922 |
| 923 /// Emit the given [token], printing the suffix after the [token] |
| 903 /// node if it is non-null. | 924 /// node if it is non-null. |
| 904 visitToken(Token token, String suffix) { | 925 emitToken(Token token, String suffix) { |
| 905 if (token != null) { | 926 if (token != null) { |
| 906 writer.print(token.lexeme); | 927 emit(token); |
| 907 writer.print(suffix); | 928 writer.print(suffix); |
| 908 } | 929 } |
| 909 } | 930 } |
| 910 | 931 |
| 911 /// Print a list of [nodes], separated by the given [separator]. | 932 /// Print a list of [nodes], separated by the given [separator]. |
| 912 visitList(NodeList<ASTNode> nodes, [String separator = '']) { | 933 visitList(NodeList<ASTNode> nodes, [String separator = '']) { |
| 913 if (nodes != null) { | 934 if (nodes != null) { |
| 914 var size = nodes.length; | 935 var size = nodes.length; |
| 915 for (var i = 0; i < size; i++) { | 936 for (var i = 0; i < size; i++) { |
| 916 if (i > 0) { | 937 if (i > 0) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 931 writer.print(separator); | 952 writer.print(separator); |
| 932 } | 953 } |
| 933 nodes[i].accept(this); | 954 nodes[i].accept(this); |
| 934 } | 955 } |
| 935 writer.print(suffix); | 956 writer.print(suffix); |
| 936 } | 957 } |
| 937 } | 958 } |
| 938 } | 959 } |
| 939 | 960 |
| 940 /// Print a list of [nodes], separated by the given [separator]. | 961 /// Print a list of [nodes], separated by the given [separator]. |
| 941 visitPrefixedList(String prefix, NodeList<ASTNode> nodes, String separator) { | 962 visitPrefixedList(String prefix, NodeList<ASTNode> nodes, |
| 963 [String separator = null]) { |
| 942 if (nodes != null) { | 964 if (nodes != null) { |
| 943 var size = nodes.length; | 965 var size = nodes.length; |
| 944 if (size > 0) { | 966 if (size > 0) { |
| 945 writer.print(prefix); | 967 writer.print(prefix); |
| 946 for (var i = 0; i < size; i++) { | 968 for (var i = 0; i < size; i++) { |
| 947 if (i > 0) { | 969 if (i > 0 && separator != null) { |
| 948 writer.print(separator); | 970 writer.print(separator); |
| 949 } | 971 } |
| 950 nodes[i].accept(this); | 972 nodes[i].accept(this); |
| 951 } | 973 } |
| 952 } | 974 } |
| 953 } | 975 } |
| 954 } | 976 } |
| 955 | 977 |
| 956 /// Print a list of [nodes], preserving blank lines between nodes. | 978 /// Emit the given [token], preceeded by any detected newlines or a minimum |
| 957 visitPrefixedListWithBlanks(String prefix, | 979 /// as specified by [min]. |
| 958 NodeList<ASTNode> nodes) { | 980 emit(Token token, {min: 0}) { |
| 959 if (nodes != null) { | 981 var comment = token.precedingComments; |
| 960 var size = nodes.length; | 982 var currentToken = comment != null ? comment : token; |
| 961 if (size > 0) { | 983 var newlines = max(min, countNewlinesBetween(previousToken, currentToken)); |
| 962 writer.print(prefix); | 984 writer.newlines(newlines); |
| 963 for (var i = 0; i < size; i++) { | 985 while (comment != null) { |
| 964 if (i > 0) { | 986 writer.print(comment.toString().trim()); |
| 965 // Emit blanks lines | 987 writer.newline(); |
| 966 var lastLine = | 988 comment = comment.next; |
| 967 lineInfo.getLocation(nodes[i-1].endToken.offset).lineNumber; | |
| 968 var currentLine = | |
| 969 lineInfo.getLocation(nodes[i].beginToken.offset).lineNumber; | |
| 970 var blanks = currentLine - lastLine; | |
| 971 for (var i = 0; i < blanks; i++) { | |
| 972 writer.newline(); | |
| 973 } | |
| 974 } | |
| 975 nodes[i].accept(this); | |
| 976 } | |
| 977 } | |
| 978 } | 989 } |
| 990 |
| 991 previousToken = token; |
| 992 writer.print(token.lexeme); |
| 993 } |
| 994 |
| 995 /// Count the blanks between these two nodes. |
| 996 int countBlankLinesBetween(ASTNode lastNode, ASTNode currentNode) => |
| 997 countNewlinesBetween(lastNode.endToken, currentNode.beginToken); |
| 998 |
| 999 /// Count newlines preceeding this [node]. |
| 1000 int countPrecedingNewlines(ASTNode node) => |
| 1001 countNewlinesBetween(node.beginToken.previous, node.beginToken); |
| 1002 |
| 1003 /// Count newlines succeeding this [node]. |
| 1004 int countSucceedingNewlines(ASTNode node) => node == null ? 0 : |
| 1005 countNewlinesBetween(node.endToken, node.endToken.next); |
| 1006 |
| 1007 /// Count the blanks between these two nodes. |
| 1008 int countNewlinesBetween(Token last, Token current) { |
| 1009 if (last == null || current == null) { |
| 1010 return 0; |
| 1011 } |
| 1012 var lastLine = |
| 1013 lineInfo.getLocation(last.offset).lineNumber; |
| 1014 var currentLine = |
| 1015 lineInfo.getLocation(current.offset).lineNumber; |
| 1016 return currentLine - lastLine; |
| 979 } | 1017 } |
| 980 | 1018 |
| 981 } | 1019 } |
| OLD | NEW |