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 | 8 |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
11 #include "tools/gn/functions.h" | 11 #include "tools/gn/functions.h" |
12 #include "tools/gn/operators.h" | 12 #include "tools/gn/operators.h" |
13 #include "tools/gn/scope.h" | 13 #include "tools/gn/scope.h" |
14 #include "tools/gn/string_utils.h" | 14 #include "tools/gn/string_utils.h" |
15 | 15 |
16 namespace { | 16 namespace { |
17 | 17 |
18 std::string IndentFor(int value) { | 18 std::string IndentFor(int value) { |
19 return std::string(value, ' '); | 19 return std::string(value, ' '); |
20 } | 20 } |
21 | 21 |
| 22 bool IsSortRangeSeparator(const ParseNode* node, const ParseNode* prev) { |
| 23 // 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. |
| 25 return node->AsBlockComment() != nullptr || |
| 26 (prev && node->comments() && !node->comments()->before().empty() && |
| 27 (node->GetRange().begin().line_number() > |
| 28 prev->GetRange().end().line_number() + |
| 29 static_cast<int>(node->comments()->before().size() + 1))); |
| 30 } |
| 31 |
| 32 base::StringPiece GetStringRepresentation(const ParseNode* node) { |
| 33 DCHECK(node->AsLiteral() || node->AsIdentifier() || node->AsAccessor()); |
| 34 if (node->AsLiteral()) |
| 35 return node->AsLiteral()->value().value(); |
| 36 else if (node->AsIdentifier()) |
| 37 return node->AsIdentifier()->value().value(); |
| 38 else if (node->AsAccessor()) |
| 39 return node->AsAccessor()->base().value(); |
| 40 return base::StringPiece(); |
| 41 } |
| 42 |
22 } // namespace | 43 } // namespace |
23 | 44 |
24 Comments::Comments() { | 45 Comments::Comments() { |
25 } | 46 } |
26 | 47 |
27 Comments::~Comments() { | 48 Comments::~Comments() { |
28 } | 49 } |
29 | 50 |
30 void Comments::ReverseSuffix() { | 51 void Comments::ReverseSuffix() { |
31 for (int i = 0, j = static_cast<int>(suffix_.size() - 1); i < j; ++i, --j) | 52 for (int i = 0, j = static_cast<int>(suffix_.size() - 1); i < j; ++i, --j) |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 } | 208 } |
188 | 209 |
189 if (!result) { | 210 if (!result) { |
190 *err = Err(member_.get(), "No value named \"" + | 211 *err = Err(member_.get(), "No value named \"" + |
191 member_->value().value() + "\" in scope \"" + base_.value() + "\""); | 212 member_->value().value() + "\" in scope \"" + base_.value() + "\""); |
192 return Value(); | 213 return Value(); |
193 } | 214 } |
194 return *result; | 215 return *result; |
195 } | 216 } |
196 | 217 |
| 218 void AccessorNode::SetNewLocation(int line_number) { |
| 219 Location old = base_.location(); |
| 220 base_.set_location( |
| 221 Location(old.file(), line_number, old.char_offset(), old.byte())); |
| 222 } |
| 223 |
197 // BinaryOpNode --------------------------------------------------------------- | 224 // BinaryOpNode --------------------------------------------------------------- |
198 | 225 |
199 BinaryOpNode::BinaryOpNode() { | 226 BinaryOpNode::BinaryOpNode() { |
200 } | 227 } |
201 | 228 |
202 BinaryOpNode::~BinaryOpNode() { | 229 BinaryOpNode::~BinaryOpNode() { |
203 } | 230 } |
204 | 231 |
205 const BinaryOpNode* BinaryOpNode::AsBinaryOp() const { | 232 const BinaryOpNode* BinaryOpNode::AsBinaryOp() const { |
206 return this; | 233 return this; |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
429 Err IdentifierNode::MakeErrorDescribing(const std::string& msg, | 456 Err IdentifierNode::MakeErrorDescribing(const std::string& msg, |
430 const std::string& help) const { | 457 const std::string& help) const { |
431 return Err(value_, msg, help); | 458 return Err(value_, msg, help); |
432 } | 459 } |
433 | 460 |
434 void IdentifierNode::Print(std::ostream& out, int indent) const { | 461 void IdentifierNode::Print(std::ostream& out, int indent) const { |
435 out << IndentFor(indent) << "IDENTIFIER(" << value_.value() << ")\n"; | 462 out << IndentFor(indent) << "IDENTIFIER(" << value_.value() << ")\n"; |
436 PrintComments(out, indent); | 463 PrintComments(out, indent); |
437 } | 464 } |
438 | 465 |
| 466 void IdentifierNode::SetNewLocation(int line_number) { |
| 467 Location old = value_.location(); |
| 468 value_.set_location( |
| 469 Location(old.file(), line_number, old.char_offset(), old.byte())); |
| 470 } |
| 471 |
439 // ListNode ------------------------------------------------------------------- | 472 // ListNode ------------------------------------------------------------------- |
440 | 473 |
441 ListNode::ListNode() : prefer_multiline_(false) { | 474 ListNode::ListNode() : prefer_multiline_(false) { |
442 } | 475 } |
443 | 476 |
444 ListNode::~ListNode() { | 477 ListNode::~ListNode() { |
445 STLDeleteContainerPointers(contents_.begin(), contents_.end()); | 478 STLDeleteContainerPointers(contents_.begin(), contents_.end()); |
446 } | 479 } |
447 | 480 |
448 const ListNode* ListNode::AsList() const { | 481 const ListNode* ListNode::AsList() const { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 void ListNode::Print(std::ostream& out, int indent) const { | 516 void ListNode::Print(std::ostream& out, int indent) const { |
484 out << IndentFor(indent) << "LIST" << (prefer_multiline_ ? " multiline" : "") | 517 out << IndentFor(indent) << "LIST" << (prefer_multiline_ ? " multiline" : "") |
485 << "\n"; | 518 << "\n"; |
486 PrintComments(out, indent); | 519 PrintComments(out, indent); |
487 for (const auto& cur : contents_) | 520 for (const auto& cur : contents_) |
488 cur->Print(out, indent + 1); | 521 cur->Print(out, indent + 1); |
489 if (end_ && end_->comments()) | 522 if (end_ && end_->comments()) |
490 end_->Print(out, indent + 1); | 523 end_->Print(out, indent + 1); |
491 } | 524 } |
492 | 525 |
| 526 void ListNode::SortAsStringsList() { |
| 527 // Sorts alphabetically. Partitions first on BlockCommentNodes and sorts each |
| 528 // partition separately. |
| 529 for (auto sr : GetSortRanges()) { |
| 530 // Save the original line number so that we can re-assign ranges. We assume |
| 531 // they're contiguous lines because GetSortRanges() does so above. We need |
| 532 // to re-assign these line numbers primiarily because `gn format` uses them |
| 533 // to determine whether two nodes were initially separated by a blank line |
| 534 // or not. |
| 535 int start_line = contents_[sr.begin]->GetRange().begin().line_number(); |
| 536 const ParseNode* original_first = contents_[sr.begin]; |
| 537 std::sort(contents_.begin() + sr.begin, contents_.begin() + sr.end, |
| 538 [](const ParseNode* a, const ParseNode* b) { |
| 539 base::StringPiece astr = GetStringRepresentation(a); |
| 540 base::StringPiece bstr = GetStringRepresentation(b); |
| 541 return astr < bstr; |
| 542 }); |
| 543 // If the beginning of the range had before comments, and the first node |
| 544 // moved during the sort, then move its comments to the new head of the |
| 545 // range. |
| 546 if (original_first->comments() && contents_[sr.begin] != original_first) { |
| 547 for (const auto& hc : original_first->comments()->before()) { |
| 548 const_cast<ParseNode*>(contents_[sr.begin]) |
| 549 ->comments_mutable() |
| 550 ->append_before(hc); |
| 551 } |
| 552 const_cast<ParseNode*>(original_first) |
| 553 ->comments_mutable() |
| 554 ->clear_before(); |
| 555 } |
| 556 const ParseNode* prev = nullptr; |
| 557 for (size_t i = sr.begin; i != sr.end; ++i) { |
| 558 const ParseNode* node = contents_[i]; |
| 559 DCHECK(node->AsLiteral() || node->AsIdentifier() || node->AsAccessor()); |
| 560 int line_number = |
| 561 prev ? prev->GetRange().end().line_number() + 1 : start_line; |
| 562 if (node->AsLiteral()) { |
| 563 const_cast<LiteralNode*>(node->AsLiteral()) |
| 564 ->SetNewLocation(line_number); |
| 565 } else if (node->AsIdentifier()) { |
| 566 const_cast<IdentifierNode*>(node->AsIdentifier()) |
| 567 ->SetNewLocation(line_number); |
| 568 } else if (node->AsAccessor()) { |
| 569 const_cast<AccessorNode*>(node->AsAccessor()) |
| 570 ->SetNewLocation(line_number); |
| 571 } |
| 572 prev = node; |
| 573 } |
| 574 } |
| 575 } |
| 576 |
| 577 // Breaks the ParseNodes of |contents| up by ranges that should be separately |
| 578 // sorted. In particular, we break at a block comment, or an item that has an |
| 579 // attached "before" comment and is separated by a blank line from the item |
| 580 // before it. The assumption is that both of these indicate a separate 'section' |
| 581 // of a sources block across which items should not be inter-sorted. |
| 582 std::vector<ListNode::SortRange> ListNode::GetSortRanges() const { |
| 583 std::vector<SortRange> ranges; |
| 584 const ParseNode* prev = nullptr; |
| 585 size_t begin = 0; |
| 586 for (size_t i = begin; i < contents_.size(); prev = contents_[i++]) { |
| 587 if (IsSortRangeSeparator(contents_[i], prev)) { |
| 588 if (i > begin) { |
| 589 ranges.push_back(SortRange(begin, i)); |
| 590 // If |i| is an item with an attached comment, then we start the next |
| 591 // range at that point, because we want to include it in the sort. |
| 592 // Otherwise, it's a block comment which we skip over entirely because |
| 593 // we don't want to move or include it in the sort. The two cases are: |
| 594 // |
| 595 // sources = [ |
| 596 // "a", |
| 597 // "b", |
| 598 // |
| 599 // # |
| 600 // # This is a block comment. |
| 601 // # |
| 602 // |
| 603 // "c", |
| 604 // "d", |
| 605 // ] |
| 606 // |
| 607 // which contains 5 elements, and for which the ranges would be { [0, |
| 608 // 2), [3, 5) } (notably excluding 2, the block comment), and: |
| 609 // |
| 610 // sources = [ |
| 611 // "a", |
| 612 // "b", |
| 613 // |
| 614 // # This is a header comment. |
| 615 // "c", |
| 616 // "d", |
| 617 // ] |
| 618 // |
| 619 // which contains 4 elements, index 2 containing an attached 'before' |
| 620 // comments, and the ranges should be { [0, 2), [2, 4) }. |
| 621 if (!contents_[i]->AsBlockComment()) |
| 622 begin = i; |
| 623 else |
| 624 begin = i + 1; |
| 625 } else { |
| 626 // If it was a one item range, just skip over it. |
| 627 begin = i + 1; |
| 628 } |
| 629 } |
| 630 } |
| 631 if (begin != contents_.size()) |
| 632 ranges.push_back(SortRange(begin, contents_.size())); |
| 633 return ranges; |
| 634 } |
| 635 |
493 // LiteralNode ----------------------------------------------------------------- | 636 // LiteralNode ----------------------------------------------------------------- |
494 | 637 |
495 LiteralNode::LiteralNode() { | 638 LiteralNode::LiteralNode() { |
496 } | 639 } |
497 | 640 |
498 LiteralNode::LiteralNode(const Token& token) : value_(token) { | 641 LiteralNode::LiteralNode(const Token& token) : value_(token) { |
499 } | 642 } |
500 | 643 |
501 LiteralNode::~LiteralNode() { | 644 LiteralNode::~LiteralNode() { |
502 } | 645 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 Err LiteralNode::MakeErrorDescribing(const std::string& msg, | 680 Err LiteralNode::MakeErrorDescribing(const std::string& msg, |
538 const std::string& help) const { | 681 const std::string& help) const { |
539 return Err(value_, msg, help); | 682 return Err(value_, msg, help); |
540 } | 683 } |
541 | 684 |
542 void LiteralNode::Print(std::ostream& out, int indent) const { | 685 void LiteralNode::Print(std::ostream& out, int indent) const { |
543 out << IndentFor(indent) << "LITERAL(" << value_.value() << ")\n"; | 686 out << IndentFor(indent) << "LITERAL(" << value_.value() << ")\n"; |
544 PrintComments(out, indent); | 687 PrintComments(out, indent); |
545 } | 688 } |
546 | 689 |
| 690 void LiteralNode::SetNewLocation(int line_number) { |
| 691 Location old = value_.location(); |
| 692 value_.set_location( |
| 693 Location(old.file(), line_number, old.char_offset(), old.byte())); |
| 694 } |
| 695 |
547 // UnaryOpNode ---------------------------------------------------------------- | 696 // UnaryOpNode ---------------------------------------------------------------- |
548 | 697 |
549 UnaryOpNode::UnaryOpNode() { | 698 UnaryOpNode::UnaryOpNode() { |
550 } | 699 } |
551 | 700 |
552 UnaryOpNode::~UnaryOpNode() { | 701 UnaryOpNode::~UnaryOpNode() { |
553 } | 702 } |
554 | 703 |
555 const UnaryOpNode* UnaryOpNode::AsUnaryOp() const { | 704 const UnaryOpNode* UnaryOpNode::AsUnaryOp() const { |
556 return this; | 705 return this; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
601 Err BlockCommentNode::MakeErrorDescribing(const std::string& msg, | 750 Err BlockCommentNode::MakeErrorDescribing(const std::string& msg, |
602 const std::string& help) const { | 751 const std::string& help) const { |
603 return Err(comment_, msg, help); | 752 return Err(comment_, msg, help); |
604 } | 753 } |
605 | 754 |
606 void BlockCommentNode::Print(std::ostream& out, int indent) const { | 755 void BlockCommentNode::Print(std::ostream& out, int indent) const { |
607 out << IndentFor(indent) << "BLOCK_COMMENT(" << comment_.value() << ")\n"; | 756 out << IndentFor(indent) << "BLOCK_COMMENT(" << comment_.value() << ")\n"; |
608 PrintComments(out, indent); | 757 PrintComments(out, indent); |
609 } | 758 } |
610 | 759 |
611 | |
612 // EndNode --------------------------------------------------------------------- | 760 // EndNode --------------------------------------------------------------------- |
613 | 761 |
614 EndNode::EndNode(const Token& token) : value_(token) { | 762 EndNode::EndNode(const Token& token) : value_(token) { |
615 } | 763 } |
616 | 764 |
617 EndNode::~EndNode() { | 765 EndNode::~EndNode() { |
618 } | 766 } |
619 | 767 |
620 const EndNode* EndNode::AsEnd() const { | 768 const EndNode* EndNode::AsEnd() const { |
621 return this; | 769 return this; |
622 } | 770 } |
623 | 771 |
624 Value EndNode::Execute(Scope* scope, Err* err) const { | 772 Value EndNode::Execute(Scope* scope, Err* err) const { |
625 return Value(); | 773 return Value(); |
626 } | 774 } |
627 | 775 |
628 LocationRange EndNode::GetRange() const { | 776 LocationRange EndNode::GetRange() const { |
629 return value_.range(); | 777 return value_.range(); |
630 } | 778 } |
631 | 779 |
632 Err EndNode::MakeErrorDescribing(const std::string& msg, | 780 Err EndNode::MakeErrorDescribing(const std::string& msg, |
633 const std::string& help) const { | 781 const std::string& help) const { |
634 return Err(value_, msg, help); | 782 return Err(value_, msg, help); |
635 } | 783 } |
636 | 784 |
637 void EndNode::Print(std::ostream& out, int indent) const { | 785 void EndNode::Print(std::ostream& out, int indent) const { |
638 out << IndentFor(indent) << "END(" << value_.value() << ")\n"; | 786 out << IndentFor(indent) << "END(" << value_.value() << ")\n"; |
639 PrintComments(out, indent); | 787 PrintComments(out, indent); |
640 } | 788 } |
OLD | NEW |