OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "tools/gn/parse_tree.h" | 5 #include "tools/gn/parse_tree.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
| 8 #include <tuple> |
8 | 9 |
9 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
10 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
11 #include "tools/gn/functions.h" | 12 #include "tools/gn/functions.h" |
12 #include "tools/gn/operators.h" | 13 #include "tools/gn/operators.h" |
13 #include "tools/gn/scope.h" | 14 #include "tools/gn/scope.h" |
14 #include "tools/gn/string_utils.h" | 15 #include "tools/gn/string_utils.h" |
15 | 16 |
16 namespace { | 17 namespace { |
17 | 18 |
| 19 std::tuple<base::StringPiece, base::StringPiece> SplitAtFirst( |
| 20 base::StringPiece str, |
| 21 char c) { |
| 22 if (!str.starts_with("\"") || !str.ends_with("\"")) |
| 23 return std::make_tuple(str, base::StringPiece()); |
| 24 |
| 25 str = str.substr(1, str.length() - 2); |
| 26 size_t index_of_first = str.find(c); |
| 27 return std::make_tuple(str.substr(0, index_of_first), |
| 28 index_of_first != base::StringPiece::npos |
| 29 ? str.substr(index_of_first + 1) |
| 30 : base::StringPiece()); |
| 31 } |
| 32 |
18 std::string IndentFor(int value) { | 33 std::string IndentFor(int value) { |
19 return std::string(value, ' '); | 34 return std::string(value, ' '); |
20 } | 35 } |
21 | 36 |
22 bool IsSortRangeSeparator(const ParseNode* node, const ParseNode* prev) { | 37 bool IsSortRangeSeparator(const ParseNode* node, const ParseNode* prev) { |
23 // If it's a block comment, or has an attached comment with a blank line | 38 // If it's a block comment, or has an attached comment with a blank line |
24 // before it, then we break the range at this point. | 39 // before it, then we break the range at this point. |
25 return node->AsBlockComment() != nullptr || | 40 return node->AsBlockComment() != nullptr || |
26 (prev && node->comments() && !node->comments()->before().empty() && | 41 (prev && node->comments() && !node->comments()->before().empty() && |
27 (node->GetRange().begin().line_number() > | 42 (node->GetRange().begin().line_number() > |
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 void ListNode::Print(std::ostream& out, int indent) const { | 510 void ListNode::Print(std::ostream& out, int indent) const { |
496 out << IndentFor(indent) << "LIST" << (prefer_multiline_ ? " multiline" : "") | 511 out << IndentFor(indent) << "LIST" << (prefer_multiline_ ? " multiline" : "") |
497 << "\n"; | 512 << "\n"; |
498 PrintComments(out, indent); | 513 PrintComments(out, indent); |
499 for (const auto& cur : contents_) | 514 for (const auto& cur : contents_) |
500 cur->Print(out, indent + 1); | 515 cur->Print(out, indent + 1); |
501 if (end_ && end_->comments()) | 516 if (end_ && end_->comments()) |
502 end_->Print(out, indent + 1); | 517 end_->Print(out, indent + 1); |
503 } | 518 } |
504 | 519 |
505 void ListNode::SortAsStringsList() { | 520 template <typename Comparator> |
506 // Sorts alphabetically. Partitions first on BlockCommentNodes and sorts each | 521 void ListNode::SortList(Comparator comparator) { |
507 // partition separately. | 522 // Partitions first on BlockCommentNodes and sorts each partition separately. |
508 for (auto sr : GetSortRanges()) { | 523 for (auto sr : GetSortRanges()) { |
| 524 bool skip = false; |
| 525 for (size_t i = sr.begin; i != sr.end; ++i) { |
| 526 // Bails out if any of the nodes are unsupported. |
| 527 const ParseNode* node = contents_[i]; |
| 528 if (!node->AsLiteral() && !node->AsIdentifier() && !node->AsAccessor()) { |
| 529 skip = true; |
| 530 continue; |
| 531 } |
| 532 } |
| 533 if (skip) |
| 534 continue; |
509 // Save the original line number so that we can re-assign ranges. We assume | 535 // Save the original line number so that we can re-assign ranges. We assume |
510 // they're contiguous lines because GetSortRanges() does so above. We need | 536 // they're contiguous lines because GetSortRanges() does so above. We need |
511 // to re-assign these line numbers primiarily because `gn format` uses them | 537 // to re-assign these line numbers primiarily because `gn format` uses them |
512 // to determine whether two nodes were initially separated by a blank line | 538 // to determine whether two nodes were initially separated by a blank line |
513 // or not. | 539 // or not. |
514 int start_line = contents_[sr.begin]->GetRange().begin().line_number(); | 540 int start_line = contents_[sr.begin]->GetRange().begin().line_number(); |
515 const ParseNode* original_first = contents_[sr.begin]; | 541 const ParseNode* original_first = contents_[sr.begin]; |
516 std::sort(contents_.begin() + sr.begin, contents_.begin() + sr.end, | 542 std::sort(contents_.begin() + sr.begin, contents_.begin() + sr.end, |
517 [](const ParseNode* a, const ParseNode* b) { | 543 comparator); |
518 base::StringPiece astr = GetStringRepresentation(a); | |
519 base::StringPiece bstr = GetStringRepresentation(b); | |
520 return astr < bstr; | |
521 }); | |
522 // If the beginning of the range had before comments, and the first node | 544 // If the beginning of the range had before comments, and the first node |
523 // moved during the sort, then move its comments to the new head of the | 545 // moved during the sort, then move its comments to the new head of the |
524 // range. | 546 // range. |
525 if (original_first->comments() && contents_[sr.begin] != original_first) { | 547 if (original_first->comments() && contents_[sr.begin] != original_first) { |
526 for (const auto& hc : original_first->comments()->before()) { | 548 for (const auto& hc : original_first->comments()->before()) { |
527 const_cast<ParseNode*>(contents_[sr.begin]) | 549 const_cast<ParseNode*>(contents_[sr.begin]) |
528 ->comments_mutable() | 550 ->comments_mutable() |
529 ->append_before(hc); | 551 ->append_before(hc); |
530 } | 552 } |
531 const_cast<ParseNode*>(original_first) | 553 const_cast<ParseNode*>(original_first) |
(...skipping 14 matching lines...) Expand all Loading... |
546 ->SetNewLocation(line_number); | 568 ->SetNewLocation(line_number); |
547 } else if (node->AsAccessor()) { | 569 } else if (node->AsAccessor()) { |
548 const_cast<AccessorNode*>(node->AsAccessor()) | 570 const_cast<AccessorNode*>(node->AsAccessor()) |
549 ->SetNewLocation(line_number); | 571 ->SetNewLocation(line_number); |
550 } | 572 } |
551 prev = node; | 573 prev = node; |
552 } | 574 } |
553 } | 575 } |
554 } | 576 } |
555 | 577 |
| 578 void ListNode::SortAsStringsList() { |
| 579 // Sorts alphabetically. |
| 580 SortList([](const ParseNode* a, const ParseNode* b) { |
| 581 base::StringPiece astr = GetStringRepresentation(a); |
| 582 base::StringPiece bstr = GetStringRepresentation(b); |
| 583 return astr < bstr; |
| 584 }); |
| 585 } |
| 586 |
| 587 void ListNode::SortAsDepsList() { |
| 588 // Sorts first relative targets, then absolute, each group is sorted |
| 589 // alphabetically. |
| 590 SortList([](const ParseNode* a, const ParseNode* b) { |
| 591 base::StringPiece astr = GetStringRepresentation(a); |
| 592 base::StringPiece bstr = GetStringRepresentation(b); |
| 593 return SplitAtFirst(astr, ':') < SplitAtFirst(bstr, ':'); |
| 594 }); |
| 595 } |
| 596 |
556 // Breaks the ParseNodes of |contents| up by ranges that should be separately | 597 // Breaks the ParseNodes of |contents| up by ranges that should be separately |
557 // sorted. In particular, we break at a block comment, or an item that has an | 598 // sorted. In particular, we break at a block comment, or an item that has an |
558 // attached "before" comment and is separated by a blank line from the item | 599 // attached "before" comment and is separated by a blank line from the item |
559 // before it. The assumption is that both of these indicate a separate 'section' | 600 // before it. The assumption is that both of these indicate a separate 'section' |
560 // of a sources block across which items should not be inter-sorted. | 601 // of a sources block across which items should not be inter-sorted. |
561 std::vector<ListNode::SortRange> ListNode::GetSortRanges() const { | 602 std::vector<ListNode::SortRange> ListNode::GetSortRanges() const { |
562 std::vector<SortRange> ranges; | 603 std::vector<SortRange> ranges; |
563 const ParseNode* prev = nullptr; | 604 const ParseNode* prev = nullptr; |
564 size_t begin = 0; | 605 size_t begin = 0; |
565 for (size_t i = begin; i < contents_.size(); prev = contents_[i++]) { | 606 for (size_t i = begin; i < contents_.size(); prev = contents_[i++]) { |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 | 807 |
767 Err EndNode::MakeErrorDescribing(const std::string& msg, | 808 Err EndNode::MakeErrorDescribing(const std::string& msg, |
768 const std::string& help) const { | 809 const std::string& help) const { |
769 return Err(value_, msg, help); | 810 return Err(value_, msg, help); |
770 } | 811 } |
771 | 812 |
772 void EndNode::Print(std::ostream& out, int indent) const { | 813 void EndNode::Print(std::ostream& out, int indent) const { |
773 out << IndentFor(indent) << "END(" << value_.value() << ")\n"; | 814 out << IndentFor(indent) << "END(" << value_.value() << ")\n"; |
774 PrintComments(out, indent); | 815 PrintComments(out, indent); |
775 } | 816 } |
OLD | NEW |