Chromium Code Reviews| 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 import 'dart:math'; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
| 10 import 'package:analyzer/src/generated/java_core.dart' show CharSequence; | 10 import 'package:analyzer/src/generated/java_core.dart' show CharSequence; |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 345 | 345 |
| 346 /// Cached line info for calculating blank lines. | 346 /// Cached line info for calculating blank lines. |
| 347 LineInfo lineInfo; | 347 LineInfo lineInfo; |
| 348 | 348 |
| 349 /// Cached previous token for calculating preceding whitespace. | 349 /// Cached previous token for calculating preceding whitespace. |
| 350 Token previousToken; | 350 Token previousToken; |
| 351 | 351 |
| 352 /// A flag to indicate that a newline should be emitted before the next token. | 352 /// A flag to indicate that a newline should be emitted before the next token. |
| 353 bool needsNewline = false; | 353 bool needsNewline = false; |
| 354 | 354 |
| 355 /// A flag to indicate that user introduced newlines should be emitted before | |
| 356 /// the next token. | |
| 357 bool preserveNewlines = false; | |
| 358 | |
| 355 /// A counter for spaces that should be emitted preceding the next token. | 359 /// A counter for spaces that should be emitted preceding the next token. |
| 356 int leadingSpaces = 0; | 360 int leadingSpaces = 0; |
| 357 | 361 |
| 358 /// A flag to specify whether line-leading spaces should be preserved (and | 362 /// A flag to specify whether line-leading spaces should be preserved (and |
| 359 /// addded to the indent level). | 363 /// addded to the indent level). |
| 360 bool allowLineLeadingSpaces; | 364 bool allowLineLeadingSpaces; |
| 361 | 365 |
| 362 /// Used for matching EOL comments | 366 /// Used for matching EOL comments |
| 363 final twoSlashes = new RegExp(r'//[^/]'); | 367 final twoSlashes = new RegExp(r'//[^/]'); |
| 364 | 368 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 455 | 459 |
| 456 visitBreakStatement(BreakStatement node) { | 460 visitBreakStatement(BreakStatement node) { |
| 457 token(node.keyword); | 461 token(node.keyword); |
| 458 visitNode(node.label, precededBy: space); | 462 visitNode(node.label, precededBy: space); |
| 459 token(node.semicolon); | 463 token(node.semicolon); |
| 460 } | 464 } |
| 461 | 465 |
| 462 visitCascadeExpression(CascadeExpression node) { | 466 visitCascadeExpression(CascadeExpression node) { |
| 463 visit(node.target); | 467 visit(node.target); |
| 464 indent(2); | 468 indent(2); |
| 465 visitNodes(node.cascadeSections); | 469 newlines(); |
| 470 visitNodes(node.cascadeSections, separatedBy: newlines); | |
| 466 unindent(2); | 471 unindent(2); |
| 467 } | 472 } |
| 468 | 473 |
| 469 visitCatchClause(CatchClause node) { | 474 visitCatchClause(CatchClause node) { |
| 470 | 475 |
| 471 token(node.onKeyword, followedBy: space); | 476 token(node.onKeyword, followedBy: space); |
| 472 visit(node.exceptionType); | 477 visit(node.exceptionType); |
| 473 | 478 |
| 474 if (node.catchKeyword != null) { | 479 if (node.catchKeyword != null) { |
| 475 if (node.exceptionType != null) { | 480 if (node.exceptionType != null) { |
| 476 space(); | 481 space(); |
| 477 } | 482 } |
| 478 token(node.catchKeyword); | 483 token(node.catchKeyword); |
| 479 space(); | 484 space(); |
| 480 token(node.leftParenthesis); | 485 token(node.leftParenthesis); |
| 481 visit(node.exceptionParameter); | 486 visit(node.exceptionParameter); |
| 482 token(node.comma, followedBy: space); | 487 token(node.comma, followedBy: space); |
| 483 visit(node.stackTraceParameter); | 488 visit(node.stackTraceParameter); |
| 484 token(node.rightParenthesis); | 489 token(node.rightParenthesis); |
| 485 space(); | 490 space(); |
| 486 } else { | 491 } else { |
| 487 space(); | 492 space(); |
| 488 } | 493 } |
| 489 visit(node.body); | 494 visit(node.body); |
| 490 } | 495 } |
| 491 | 496 |
| 492 visitClassDeclaration(ClassDeclaration node) { | 497 visitClassDeclaration(ClassDeclaration node) { |
| 498 preserveLeadingNewlines(); | |
| 493 modifier(node.abstractKeyword); | 499 modifier(node.abstractKeyword); |
| 494 token(node.classKeyword); | 500 token(node.classKeyword); |
| 495 space(); | 501 space(); |
| 496 visit(node.name); | 502 visit(node.name); |
| 497 allowContinuedLines((){ | 503 allowContinuedLines((){ |
| 498 visit(node.typeParameters); | 504 visit(node.typeParameters); |
| 499 visitNode(node.extendsClause, precededBy: space); | 505 visitNode(node.extendsClause, precededBy: space); |
| 500 visitNode(node.withClause, precededBy: space); | 506 visitNode(node.withClause, precededBy: space); |
| 501 visitNode(node.implementsClause, precededBy: space); | 507 visitNode(node.implementsClause, precededBy: space); |
| 502 space(); | 508 space(); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 540 } | 546 } |
| 541 | 547 |
| 542 var scriptTag = node.scriptTag; | 548 var scriptTag = node.scriptTag; |
| 543 var directives = node.directives; | 549 var directives = node.directives; |
| 544 visit(scriptTag); | 550 visit(scriptTag); |
| 545 | 551 |
| 546 visitNodes(directives, separatedBy: newlines, followedBy: newlines); | 552 visitNodes(directives, separatedBy: newlines, followedBy: newlines); |
| 547 | 553 |
| 548 visitNodes(node.declarations, separatedBy: newlines); | 554 visitNodes(node.declarations, separatedBy: newlines); |
| 549 | 555 |
| 556 preserveLeadingNewlines(); | |
| 557 | |
| 550 // Handle trailing whitespace | 558 // Handle trailing whitespace |
| 551 token(node.endToken /* EOF */); | 559 token(node.endToken /* EOF */); |
| 552 | 560 |
| 553 // Be a good citizen, end with a NL | 561 // Be a good citizen, end with a NL |
| 554 ensureTrailingNewline(); | 562 ensureTrailingNewline(); |
| 555 } | 563 } |
| 556 | 564 |
| 557 visitConditionalExpression(ConditionalExpression node) { | 565 visitConditionalExpression(ConditionalExpression node) { |
| 558 visit(node.condition); | 566 visit(node.condition); |
| 559 space(); | 567 space(); |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 794 visitCommaSeparatedNodes(node.updaters); | 802 visitCommaSeparatedNodes(node.updaters); |
| 795 } | 803 } |
| 796 token(node.rightParenthesis); | 804 token(node.rightParenthesis); |
| 797 if (node.body is! EmptyStatement) { | 805 if (node.body is! EmptyStatement) { |
| 798 space(); | 806 space(); |
| 799 } | 807 } |
| 800 visit(node.body); | 808 visit(node.body); |
| 801 } | 809 } |
| 802 | 810 |
| 803 visitFunctionDeclaration(FunctionDeclaration node) { | 811 visitFunctionDeclaration(FunctionDeclaration node) { |
| 812 preserveLeadingNewlines(); | |
| 804 visitNode(node.returnType, followedBy: space); | 813 visitNode(node.returnType, followedBy: space); |
| 805 token(node.propertyKeyword, followedBy: space); | 814 token(node.propertyKeyword, followedBy: space); |
| 806 visit(node.name); | 815 visit(node.name); |
| 807 visit(node.functionExpression); | 816 visit(node.functionExpression); |
| 808 } | 817 } |
| 809 | 818 |
| 810 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | 819 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { |
| 811 visit(node.functionDeclaration); | 820 visit(node.functionDeclaration); |
| 812 } | 821 } |
| 813 | 822 |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 958 visitCommaSeparatedNodes(node.elements); | 967 visitCommaSeparatedNodes(node.elements); |
| 959 optionalTrailingComma(node.rightBracket); | 968 optionalTrailingComma(node.rightBracket); |
| 960 unindent(); | 969 unindent(); |
| 961 token(node.rightBracket); | 970 token(node.rightBracket); |
| 962 } | 971 } |
| 963 | 972 |
| 964 visitMapLiteral(MapLiteral node) { | 973 visitMapLiteral(MapLiteral node) { |
| 965 modifier(node.constKeyword); | 974 modifier(node.constKeyword); |
| 966 visitNode(node.typeArguments, followedBy: space); | 975 visitNode(node.typeArguments, followedBy: space); |
| 967 token(node.leftBracket); | 976 token(node.leftBracket); |
| 977 newlines(); | |
| 968 indent(); | 978 indent(); |
| 969 visitCommaSeparatedNodes(node.entries); | 979 visitCommaSeparatedNodes(node.entries, followedBy: newlines); |
| 970 optionalTrailingComma(node.rightBracket); | 980 optionalTrailingComma(node.rightBracket); |
| 971 unindent(); | 981 unindent(); |
| 982 newlines(); | |
| 972 token(node.rightBracket); | 983 token(node.rightBracket); |
| 973 } | 984 } |
| 974 | 985 |
| 975 visitMapLiteralEntry(MapLiteralEntry node) { | 986 visitMapLiteralEntry(MapLiteralEntry node) { |
| 976 visit(node.key); | 987 visit(node.key); |
| 977 token(node.separator); | 988 token(node.separator); |
| 978 space(); | 989 space(); |
| 979 visit(node.value); | 990 visit(node.value); |
| 980 } | 991 } |
| 981 | 992 |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1302 nodes[i].accept(this); | 1313 nodes[i].accept(this); |
| 1303 } | 1314 } |
| 1304 if (followedBy != null) { | 1315 if (followedBy != null) { |
| 1305 followedBy(); | 1316 followedBy(); |
| 1306 } | 1317 } |
| 1307 } | 1318 } |
| 1308 } | 1319 } |
| 1309 } | 1320 } |
| 1310 | 1321 |
| 1311 /// Visit a comma-separated list of [nodes] if not null. | 1322 /// Visit a comma-separated list of [nodes] if not null. |
| 1312 visitCommaSeparatedNodes(NodeList<ASTNode> nodes) { | 1323 visitCommaSeparatedNodes(NodeList<ASTNode> nodes, {followedBy(): null}) { |
| 1324 //TODO(pquitslund): handle this more neatly | |
|
pquitslund
2013/12/18 17:16:47
EG: by introducing a const pointer to the space fu
Brian Wilkerson
2013/12/18 17:53:07
In order to do that, the space function will have
| |
| 1325 if (followedBy == null) { | |
| 1326 followedBy = space; | |
| 1327 } | |
| 1313 if (nodes != null) { | 1328 if (nodes != null) { |
| 1314 var size = nodes.length; | 1329 var size = nodes.length; |
| 1315 if (size > 0) { | 1330 if (size > 0) { |
| 1316 var node; | 1331 var node; |
| 1317 for (var i = 0; i < size; i++) { | 1332 for (var i = 0; i < size; i++) { |
| 1318 node = nodes[i]; | 1333 node = nodes[i]; |
| 1319 if (i > 0) { | 1334 if (i > 0) { |
| 1320 var comma = node.beginToken.previous; | 1335 var comma = node.beginToken.previous; |
| 1321 token(comma); | 1336 token(comma); |
| 1322 space(); | 1337 followedBy(); |
| 1323 } | 1338 } |
| 1324 node.accept(this); | 1339 node.accept(this); |
| 1325 } | 1340 } |
| 1326 } | 1341 } |
| 1327 } | 1342 } |
| 1328 } | 1343 } |
| 1329 | 1344 |
| 1330 | 1345 |
| 1331 /// Visit a [node], and if not null, optionally preceded or followed by the | 1346 /// Visit a [node], and if not null, optionally preceded or followed by the |
| 1332 /// specified functions. | 1347 /// specified functions. |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1361 needsNewline = true; | 1376 needsNewline = true; |
| 1362 } | 1377 } |
| 1363 | 1378 |
| 1364 /// Optionally emit a trailing comma. | 1379 /// Optionally emit a trailing comma. |
| 1365 optionalTrailingComma(Token rightBracket) { | 1380 optionalTrailingComma(Token rightBracket) { |
| 1366 if (rightBracket.previous.lexeme == ',') { | 1381 if (rightBracket.previous.lexeme == ',') { |
| 1367 token(rightBracket.previous); | 1382 token(rightBracket.previous); |
| 1368 } | 1383 } |
| 1369 } | 1384 } |
| 1370 | 1385 |
| 1386 /// Indicate that user introduced newlines should be emitted before the next | |
| 1387 /// token. | |
| 1388 preserveLeadingNewlines() { | |
| 1389 preserveNewlines = true; | |
| 1390 } | |
| 1391 | |
| 1371 token(Token token, {precededBy(), followedBy(), int minNewlines: 0}) { | 1392 token(Token token, {precededBy(), followedBy(), int minNewlines: 0}) { |
| 1372 if (token != null) { | 1393 if (token != null) { |
| 1373 if (needsNewline) { | 1394 if (needsNewline) { |
| 1374 minNewlines = max(1, minNewlines); | 1395 minNewlines = max(1, minNewlines); |
| 1375 } | 1396 } |
| 1376 var emitted = emitPrecedingCommentsAndNewlines(token, min: minNewlines); | 1397 var emitted = emitPrecedingCommentsAndNewlines(token, min: minNewlines); |
| 1377 if (emitted > 0) { | 1398 if (emitted > 0) { |
| 1378 needsNewline = false; | 1399 needsNewline = false; |
| 1379 } | 1400 } |
| 1380 if (precededBy != null) { | 1401 if (precededBy != null) { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1471 var comment = token.precedingComments; | 1492 var comment = token.precedingComments; |
| 1472 var currentToken = comment != null ? comment : token; | 1493 var currentToken = comment != null ? comment : token; |
| 1473 | 1494 |
| 1474 //Handle EOLs before newlines | 1495 //Handle EOLs before newlines |
| 1475 if (isAtEOL(comment)) { | 1496 if (isAtEOL(comment)) { |
| 1476 emitComment(comment, previousToken); | 1497 emitComment(comment, previousToken); |
| 1477 comment = comment.next; | 1498 comment = comment.next; |
| 1478 currentToken = comment != null ? comment : token; | 1499 currentToken = comment != null ? comment : token; |
| 1479 } | 1500 } |
| 1480 | 1501 |
| 1481 var lines = max(min, countNewlinesBetween(previousToken, currentToken)); | 1502 var lines = 0; |
| 1503 if (needsNewline || preserveNewlines) { | |
| 1504 lines = max(min, countNewlinesBetween(previousToken, currentToken)); | |
| 1505 preserveNewlines = false; | |
| 1506 } | |
| 1482 emitNewlines(lines); | 1507 emitNewlines(lines); |
| 1483 | 1508 |
| 1484 previousToken = | 1509 previousToken = |
| 1485 currentToken.previous != null ? currentToken.previous : token.previous; | 1510 currentToken.previous != null ? currentToken.previous : token.previous; |
| 1486 | 1511 |
| 1487 while (comment != null) { | 1512 while (comment != null) { |
| 1488 | 1513 |
| 1489 emitComment(comment, previousToken); | 1514 emitComment(comment, previousToken); |
| 1490 | 1515 |
| 1491 var nextToken = comment.next != null ? comment.next : token; | 1516 var nextToken = comment.next != null ? comment.next : token; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1601 var lastLine = | 1626 var lastLine = |
| 1602 lineInfo.getLocation(lastOffset).lineNumber; | 1627 lineInfo.getLocation(lastOffset).lineNumber; |
| 1603 var currentLine = | 1628 var currentLine = |
| 1604 lineInfo.getLocation(currentOffset).lineNumber; | 1629 lineInfo.getLocation(currentOffset).lineNumber; |
| 1605 return currentLine - lastLine; | 1630 return currentLine - lastLine; |
| 1606 } | 1631 } |
| 1607 | 1632 |
| 1608 String toString() => writer.toString(); | 1633 String toString() => writer.toString(); |
| 1609 | 1634 |
| 1610 } | 1635 } |
| OLD | NEW |