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

Side by Side Diff: tools/gn/command_format.cc

Issue 772663002: gn format: Make parenthesizing better (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years 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 unified diff | Download patch
« no previous file with comments | « no previous file | tools/gn/command_format_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <sstream> 5 #include <sstream>
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/files/file_util.h" 8 #include "base/files/file_util.h"
9 #include "base/strings/string_split.h" 9 #include "base/strings/string_split.h"
10 #include "tools/gn/commands.h" 10 #include "tools/gn/commands.h"
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 const int kPenaltyExcess = 10000; 61 const int kPenaltyExcess = 10000;
62 const int kPenaltyBrokenLineOnOneLiner = 5000; 62 const int kPenaltyBrokenLineOnOneLiner = 5000;
63 63
64 enum Precedence { 64 enum Precedence {
65 kPrecedenceLowest, 65 kPrecedenceLowest,
66 kPrecedenceAssign, 66 kPrecedenceAssign,
67 kPrecedenceOr, 67 kPrecedenceOr,
68 kPrecedenceAnd, 68 kPrecedenceAnd,
69 kPrecedenceCompare, 69 kPrecedenceCompare,
70 kPrecedenceAdd, 70 kPrecedenceAdd,
71 kPrecedenceUnary,
71 kPrecedenceSuffix, 72 kPrecedenceSuffix,
72 kPrecedenceUnary,
73 }; 73 };
74 74
75 int CountLines(const std::string& str) { 75 int CountLines(const std::string& str) {
76 std::vector<std::string> lines; 76 std::vector<std::string> lines;
77 base::SplitStringDontTrim(str, '\n', &lines); 77 base::SplitStringDontTrim(str, '\n', &lines);
78 return static_cast<int>(lines.size()); 78 return static_cast<int>(lines.size());
79 } 79 }
80 80
81 class Printer { 81 class Printer {
82 public: 82 public:
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 std::string output_; // Output buffer. 171 std::string output_; // Output buffer.
172 std::vector<Token> comments_; // Pending end-of-line comments. 172 std::vector<Token> comments_; // Pending end-of-line comments.
173 int margin() const { return stack_.back().margin; } 173 int margin() const { return stack_.back().margin; }
174 174
175 int penalty_depth_; 175 int penalty_depth_;
176 int GetPenaltyForLineBreak() const { 176 int GetPenaltyForLineBreak() const {
177 return penalty_depth_ * kPenaltyLineBreak; 177 return penalty_depth_ * kPenaltyLineBreak;
178 } 178 }
179 179
180 struct IndentState { 180 struct IndentState {
181 IndentState() : margin(0), continuation_requires_indent(false) {} 181 IndentState()
182 IndentState(int margin, bool continuation_requires_indent) 182 : margin(0),
183 continuation_requires_indent(false),
184 parent_is_boolean_or(false) {}
185 IndentState(int margin,
186 bool continuation_requires_indent,
187 bool parent_is_boolean_or)
183 : margin(margin), 188 : margin(margin),
184 continuation_requires_indent(continuation_requires_indent) {} 189 continuation_requires_indent(continuation_requires_indent),
190 parent_is_boolean_or(parent_is_boolean_or) {}
185 191
186 // The left margin (number of spaces). 192 // The left margin (number of spaces).
187 int margin; 193 int margin;
188 194
189 bool continuation_requires_indent; 195 bool continuation_requires_indent;
196
197 bool parent_is_boolean_or;
190 }; 198 };
191 // Stack used to track 199 // Stack used to track
192 std::vector<IndentState> stack_; 200 std::vector<IndentState> stack_;
193 201
194 // Gives the precedence for operators in a BinaryOpNode. 202 // Gives the precedence for operators in a BinaryOpNode.
195 std::map<base::StringPiece, Precedence> precedence_; 203 std::map<base::StringPiece, Precedence> precedence_;
196 204
197 DISALLOW_COPY_AND_ASSIGN(Printer); 205 DISALLOW_COPY_AND_ASSIGN(Printer);
198 }; 206 };
199 207
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 TrimWhitespaceASCII(token.value().as_string(), base::TRIM_ALL, &trimmed); 240 TrimWhitespaceASCII(token.value().as_string(), base::TRIM_ALL, &trimmed);
233 Print(trimmed); 241 Print(trimmed);
234 } 242 }
235 243
236 void Printer::Newline() { 244 void Printer::Newline() {
237 if (!comments_.empty()) { 245 if (!comments_.empty()) {
238 Print(" "); 246 Print(" ");
239 // Save the margin, and temporarily set it to where the first comment 247 // Save the margin, and temporarily set it to where the first comment
240 // starts so that multiple suffix comments are vertically aligned. This 248 // starts so that multiple suffix comments are vertically aligned. This
241 // will need to be fancier once we enforce 80 col. 249 // will need to be fancier once we enforce 80 col.
242 stack_.push_back(IndentState(CurrentColumn(), false)); 250 stack_.push_back(IndentState(CurrentColumn(), false, false));
243 int i = 0; 251 int i = 0;
244 for (const auto& c : comments_) { 252 for (const auto& c : comments_) {
245 if (i > 0) { 253 if (i > 0) {
246 Trim(); 254 Trim();
247 Print("\n"); 255 Print("\n");
248 PrintMargin(); 256 PrintMargin();
249 } 257 }
250 TrimAndPrintToken(c); 258 TrimAndPrintToken(c);
251 ++i; 259 ++i;
252 } 260 }
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 Print("."); 414 Print(".");
407 Expr(accessor->member(), kPrecedenceLowest, std::string()); 415 Expr(accessor->member(), kPrecedenceLowest, std::string());
408 } else { 416 } else {
409 CHECK(accessor->index()); 417 CHECK(accessor->index());
410 Print("["); 418 Print("[");
411 Expr(accessor->index(), kPrecedenceLowest, "]"); 419 Expr(accessor->index(), kPrecedenceLowest, "]");
412 } 420 }
413 } else if (const BinaryOpNode* binop = root->AsBinaryOp()) { 421 } else if (const BinaryOpNode* binop = root->AsBinaryOp()) {
414 CHECK(precedence_.find(binop->op().value()) != precedence_.end()); 422 CHECK(precedence_.find(binop->op().value()) != precedence_.end());
415 AnnotatePreferedMultilineAssignment(binop); 423 AnnotatePreferedMultilineAssignment(binop);
424
416 Precedence prec = precedence_[binop->op().value()]; 425 Precedence prec = precedence_[binop->op().value()];
417 AddParen(prec, outer_prec, &parenthesized); 426
427 // Since binary operators format left-to-right, it is ok for the left side
428 // use the same operator without parentheses, so the left uses prec. For the
429 // same reason, the right side cannot reuse the same operator, or else "x +
430 // (y + z)" would format as "x + y + z" which means "(x + y) + z". So, treat
431 // the right expression as appearing one precedence level higher.
432 // However, because the source parens are not in the parse tree, as a
433 // special case for && and || we insert strictly-redundant-but-helpful-for-
434 // human-readers parentheses.
435 int prec_left = prec;
436 int prec_right = prec + 1;
437 if (binop->op().value() == "&&" && stack_.back().parent_is_boolean_or) {
438 Print("(");
439 parenthesized = true;
440 } else {
441 AddParen(prec_left, outer_prec, &parenthesized);
442 }
443
418 int start_line = CurrentLine(); 444 int start_line = CurrentLine();
419 int start_column = CurrentColumn(); 445 int start_column = CurrentColumn();
420 bool is_assignment = binop->op().value() == "=" || 446 bool is_assignment = binop->op().value() == "=" ||
421 binop->op().value() == "+=" || 447 binop->op().value() == "+=" ||
422 binop->op().value() == "-="; 448 binop->op().value() == "-=";
423 // A sort of funny special case for the long lists that are common in .gn 449 // A sort of funny special case for the long lists that are common in .gn
424 // files, don't indent them + 4, even though they're just continuations when 450 // files, don't indent them + 4, even though they're just continuations when
425 // they're simple lists like "x = [ a, b, c, ... ]" 451 // they're simple lists like "x = [ a, b, c, ... ]"
426 const ListNode* right_as_list = binop->right()->AsList(); 452 const ListNode* right_as_list = binop->right()->AsList();
427 int indent_column = 453 int indent_column =
428 (is_assignment && 454 (is_assignment &&
429 (!right_as_list || (!right_as_list->prefer_multiline() && 455 (!right_as_list || (!right_as_list->prefer_multiline() &&
430 !ListWillBeMultiline(right_as_list->contents(), 456 !ListWillBeMultiline(right_as_list->contents(),
431 right_as_list->End())))) 457 right_as_list->End()))))
432 ? margin() + kIndentSize * 2 458 ? margin() + kIndentSize * 2
433 : start_column; 459 : start_column;
434 if (stack_.back().continuation_requires_indent) 460 if (stack_.back().continuation_requires_indent)
435 indent_column += kIndentSize * 2; 461 indent_column += kIndentSize * 2;
436 462
437 stack_.push_back(IndentState(indent_column, false)); 463 stack_.push_back(
464 IndentState(indent_column, false, binop->op().value() == "||"));
438 Printer sub_left; 465 Printer sub_left;
439 InitializeSub(&sub_left); 466 InitializeSub(&sub_left);
440 sub_left.Expr(binop->left(), 467 sub_left.Expr(binop->left(),
441 prec, 468 prec_left,
442 std::string(" ") + binop->op().value().as_string()); 469 std::string(" ") + binop->op().value().as_string());
443 bool left_is_multiline = CountLines(sub_left.String()) > 1; 470 bool left_is_multiline = CountLines(sub_left.String()) > 1;
444 // Avoid walking the whole left redundantly times (see timing of Format.046) 471 // Avoid walking the whole left redundantly times (see timing of Format.046)
445 // so pull the output and comments from subprinter. 472 // so pull the output and comments from subprinter.
446 Print(sub_left.String().substr(start_column)); 473 Print(sub_left.String().substr(start_column));
447 std::copy(sub_left.comments_.begin(), 474 std::copy(sub_left.comments_.begin(),
448 sub_left.comments_.end(), 475 sub_left.comments_.end(),
449 std::back_inserter(comments_)); 476 std::back_inserter(comments_));
450 477
451 // Single line. 478 // Single line.
452 Printer sub1; 479 Printer sub1;
453 InitializeSub(&sub1); 480 InitializeSub(&sub1);
454 sub1.Print(" "); 481 sub1.Print(" ");
455 int penalty_current_line = 482 int penalty_current_line =
456 sub1.Expr(binop->right(), prec + 1, std::string()); 483 sub1.Expr(binop->right(), prec_right, std::string());
457 sub1.Print(suffix); 484 sub1.Print(suffix);
458 penalty_current_line += AssessPenalty(sub1.String()); 485 penalty_current_line += AssessPenalty(sub1.String());
459 if (!is_assignment && left_is_multiline) { 486 if (!is_assignment && left_is_multiline) {
460 // In e.g. xxx + yyy, if xxx is already multiline, then we want a penalty 487 // In e.g. xxx + yyy, if xxx is already multiline, then we want a penalty
461 // for trying to continue as if this were one line. 488 // for trying to continue as if this were one line.
462 penalty_current_line += 489 penalty_current_line +=
463 (CountLines(sub1.String()) - 1) * kPenaltyBrokenLineOnOneLiner; 490 (CountLines(sub1.String()) - 1) * kPenaltyBrokenLineOnOneLiner;
464 } 491 }
465 492
466 // Break after operator. 493 // Break after operator.
467 Printer sub2; 494 Printer sub2;
468 InitializeSub(&sub2); 495 InitializeSub(&sub2);
469 sub2.Newline(); 496 sub2.Newline();
470 int penalty_next_line = sub2.Expr(binop->right(), prec + 1, std::string()); 497 int penalty_next_line =
498 sub2.Expr(binop->right(), prec_right, std::string());
471 sub2.Print(suffix); 499 sub2.Print(suffix);
472 penalty_next_line += AssessPenalty(sub2.String()); 500 penalty_next_line += AssessPenalty(sub2.String());
473 501
474 if (penalty_current_line < penalty_next_line) { 502 if (penalty_current_line < penalty_next_line) {
475 Print(" "); 503 Print(" ");
476 Expr(binop->right(), prec + 1, std::string()); 504 Expr(binop->right(), prec_right, std::string());
477 } else { 505 } else {
478 // Otherwise, put first argument and op, and indent next. 506 // Otherwise, put first argument and op, and indent next.
479 Newline(); 507 Newline();
480 penalty += std::abs(CurrentColumn() - start_column) * 508 penalty += std::abs(CurrentColumn() - start_column) *
481 kPenaltyHorizontalSeparation; 509 kPenaltyHorizontalSeparation;
482 Expr(binop->right(), prec + 1, std::string()); 510 Expr(binop->right(), prec_right, std::string());
483 } 511 }
484 stack_.pop_back(); 512 stack_.pop_back();
485 penalty += (CurrentLine() - start_line) * GetPenaltyForLineBreak(); 513 penalty += (CurrentLine() - start_line) * GetPenaltyForLineBreak();
486 } else if (const BlockNode* block = root->AsBlock()) { 514 } else if (const BlockNode* block = root->AsBlock()) {
487 Sequence( 515 Sequence(
488 kSequenceStyleBracedBlock, block->statements(), block->End(), false); 516 kSequenceStyleBracedBlock, block->statements(), block->End(), false);
489 } else if (const ConditionNode* condition = root->AsConditionNode()) { 517 } else if (const ConditionNode* condition = root->AsConditionNode()) {
490 Print("if ("); 518 Print("if (");
491 // TODO(scottmg): The { needs to be included in the suffix here. 519 // TODO(scottmg): The { needs to be included in the suffix here.
492 Expr(condition->condition(), kPrecedenceLowest, ") "); 520 Expr(condition->condition(), kPrecedenceLowest, ") ");
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 force_multiline |= ListWillBeMultiline(list, end); 591 force_multiline |= ListWillBeMultiline(list, end);
564 592
565 if (list.size() == 0 && !force_multiline) { 593 if (list.size() == 0 && !force_multiline) {
566 // No elements, and not forcing newlines, print nothing. 594 // No elements, and not forcing newlines, print nothing.
567 } else if (list.size() == 1 && !force_multiline) { 595 } else if (list.size() == 1 && !force_multiline) {
568 Print(" "); 596 Print(" ");
569 Expr(list[0], kPrecedenceLowest, std::string()); 597 Expr(list[0], kPrecedenceLowest, std::string());
570 CHECK(!list[0]->comments() || list[0]->comments()->after().empty()); 598 CHECK(!list[0]->comments() || list[0]->comments()->after().empty());
571 Print(" "); 599 Print(" ");
572 } else { 600 } else {
573 stack_.push_back( 601 stack_.push_back(IndentState(margin() + kIndentSize,
574 IndentState(margin() + kIndentSize, style == kSequenceStyleList)); 602 style == kSequenceStyleList,
603 false));
575 size_t i = 0; 604 size_t i = 0;
576 for (const auto& x : list) { 605 for (const auto& x : list) {
577 Newline(); 606 Newline();
578 // If: 607 // If:
579 // - we're going to output some comments, and; 608 // - we're going to output some comments, and;
580 // - we haven't just started this multiline list, and; 609 // - we haven't just started this multiline list, and;
581 // - there isn't already a blank line here; 610 // - there isn't already a blank line here;
582 // Then: insert one. 611 // Then: insert one.
583 if (i != 0 && x->comments() && !x->comments()->before().empty() && 612 if (i != 0 && x->comments() && !x->comments()->before().empty() &&
584 !HaveBlankLine()) { 613 !HaveBlankLine()) {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 // 2. starting on same line, broken at each comma but paren aligned; 682 // 2. starting on same line, broken at each comma but paren aligned;
654 // 3. broken to next line + 4, broken at each comma. 683 // 3. broken to next line + 4, broken at each comma.
655 std::string terminator = ")"; 684 std::string terminator = ")";
656 if (have_block) 685 if (have_block)
657 terminator += " {"; 686 terminator += " {";
658 terminator += suffix; 687 terminator += suffix;
659 688
660 // 1: Same line. 689 // 1: Same line.
661 Printer sub1; 690 Printer sub1;
662 InitializeSub(&sub1); 691 InitializeSub(&sub1);
663 sub1.stack_.push_back(IndentState(CurrentColumn(), true)); 692 sub1.stack_.push_back(IndentState(CurrentColumn(), true, false));
664 int penalty_one_line = 0; 693 int penalty_one_line = 0;
665 for (size_t i = 0; i < list.size(); ++i) { 694 for (size_t i = 0; i < list.size(); ++i) {
666 penalty_one_line += sub1.Expr(list[i], kPrecedenceLowest, 695 penalty_one_line += sub1.Expr(list[i], kPrecedenceLowest,
667 i < list.size() - 1 ? ", " : std::string()); 696 i < list.size() - 1 ? ", " : std::string());
668 } 697 }
669 sub1.Print(terminator); 698 sub1.Print(terminator);
670 penalty_one_line += AssessPenalty(sub1.String()); 699 penalty_one_line += AssessPenalty(sub1.String());
671 // This extra penalty prevents a short second argument from being squeezed in 700 // This extra penalty prevents a short second argument from being squeezed in
672 // after a first argument that went multiline (and instead preferring a 701 // after a first argument that went multiline (and instead preferring a
673 // variant below). 702 // variant below).
674 penalty_one_line += 703 penalty_one_line +=
675 (CountLines(sub1.String()) - 1) * kPenaltyBrokenLineOnOneLiner; 704 (CountLines(sub1.String()) - 1) * kPenaltyBrokenLineOnOneLiner;
676 705
677 // 2: Starting on same line, broken at commas. 706 // 2: Starting on same line, broken at commas.
678 Printer sub2; 707 Printer sub2;
679 InitializeSub(&sub2); 708 InitializeSub(&sub2);
680 sub2.stack_.push_back(IndentState(CurrentColumn(), true)); 709 sub2.stack_.push_back(IndentState(CurrentColumn(), true, false));
681 int penalty_multiline_start_same_line = 0; 710 int penalty_multiline_start_same_line = 0;
682 for (size_t i = 0; i < list.size(); ++i) { 711 for (size_t i = 0; i < list.size(); ++i) {
683 penalty_multiline_start_same_line += sub2.Expr( 712 penalty_multiline_start_same_line += sub2.Expr(
684 list[i], kPrecedenceLowest, i < list.size() - 1 ? "," : std::string()); 713 list[i], kPrecedenceLowest, i < list.size() - 1 ? "," : std::string());
685 if (i < list.size() - 1) { 714 if (i < list.size() - 1) {
686 sub2.Newline(); 715 sub2.Newline();
687 } 716 }
688 } 717 }
689 sub2.Print(terminator); 718 sub2.Print(terminator);
690 penalty_multiline_start_same_line += AssessPenalty(sub2.String()); 719 penalty_multiline_start_same_line += AssessPenalty(sub2.String());
691 720
692 // 3: Starting on next line, broken at commas. 721 // 3: Starting on next line, broken at commas.
693 Printer sub3; 722 Printer sub3;
694 InitializeSub(&sub3); 723 InitializeSub(&sub3);
695 sub3.stack_.push_back(IndentState(margin() + kIndentSize * 2, true)); 724 sub3.stack_.push_back(IndentState(margin() + kIndentSize * 2, true, false));
696 sub3.Newline(); 725 sub3.Newline();
697 int penalty_multiline_start_next_line = 0; 726 int penalty_multiline_start_next_line = 0;
698 for (size_t i = 0; i < list.size(); ++i) { 727 for (size_t i = 0; i < list.size(); ++i) {
699 if (i == 0) { 728 if (i == 0) {
700 penalty_multiline_start_next_line += 729 penalty_multiline_start_next_line +=
701 std::abs(sub3.CurrentColumn() - start_column) * 730 std::abs(sub3.CurrentColumn() - start_column) *
702 kPenaltyHorizontalSeparation; 731 kPenaltyHorizontalSeparation;
703 } 732 }
704 penalty_multiline_start_next_line += sub3.Expr( 733 penalty_multiline_start_next_line += sub3.Expr(
705 list[i], kPrecedenceLowest, i < list.size() - 1 ? "," : std::string()); 734 list[i], kPrecedenceLowest, i < list.size() - 1 ? "," : std::string());
(...skipping 15 matching lines...) Expand all
721 force_multiline = true; 750 force_multiline = true;
722 } 751 }
723 } else { 752 } else {
724 force_multiline = true; 753 force_multiline = true;
725 } 754 }
726 755
727 if (list.size() == 0 && !force_multiline) { 756 if (list.size() == 0 && !force_multiline) {
728 // No elements, and not forcing newlines, print nothing. 757 // No elements, and not forcing newlines, print nothing.
729 } else { 758 } else {
730 if (penalty_multiline_start_next_line < penalty_multiline_start_same_line) { 759 if (penalty_multiline_start_next_line < penalty_multiline_start_same_line) {
731 stack_.push_back(IndentState(margin() + kIndentSize * 2, true)); 760 stack_.push_back(IndentState(margin() + kIndentSize * 2, true, false));
732 Newline(); 761 Newline();
733 } else { 762 } else {
734 stack_.push_back(IndentState(CurrentColumn(), true)); 763 stack_.push_back(IndentState(CurrentColumn(), true, false));
735 } 764 }
736 765
737 for (size_t i = 0; i < list.size(); ++i) { 766 for (size_t i = 0; i < list.size(); ++i) {
738 const auto& x = list[i]; 767 const auto& x = list[i];
739 if (i > 0) { 768 if (i > 0) {
740 if (fits_on_current_line && !force_multiline) 769 if (fits_on_current_line && !force_multiline)
741 Print(" "); 770 Print(" ");
742 else 771 else
743 Newline(); 772 Newline();
744 } 773 }
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 printf("Wrote formatted to '%s'.\n", to_write.AsUTF8Unsafe().c_str()); 964 printf("Wrote formatted to '%s'.\n", to_write.AsUTF8Unsafe().c_str());
936 } else { 965 } else {
937 printf("%s", output_string.c_str()); 966 printf("%s", output_string.c_str());
938 } 967 }
939 } 968 }
940 969
941 return 0; 970 return 0;
942 } 971 }
943 972
944 } // namespace commands 973 } // namespace commands
OLDNEW
« no previous file with comments | « no previous file | tools/gn/command_format_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698