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
3 // found in the LICENSE file.
5 #include "tools/gn/parse_tree.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "tools/gn/functions.h"
12 #include "tools/gn/operators.h"
13 #include "tools/gn/scope.h"
14 #include "tools/gn/string_utils.h"
18 std::string
IndentFor(int value
) {
19 return std::string(value
, ' ');
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)));
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();
45 Comments::Comments() {
48 Comments::~Comments() {
51 void Comments::ReverseSuffix() {
52 for (int i
= 0, j
= static_cast<int>(suffix_
.size() - 1); i
< j
; ++i
, --j
)
53 std::swap(suffix_
[i
], suffix_
[j
]);
56 ParseNode::ParseNode() {
59 ParseNode::~ParseNode() {
62 const AccessorNode
* ParseNode::AsAccessor() const { return nullptr; }
63 const BinaryOpNode
* ParseNode::AsBinaryOp() const { return nullptr; }
64 const BlockCommentNode
* ParseNode::AsBlockComment() const { return nullptr; }
65 const BlockNode
* ParseNode::AsBlock() const { return nullptr; }
66 const ConditionNode
* ParseNode::AsConditionNode() const { return nullptr; }
67 const EndNode
* ParseNode::AsEnd() const { return nullptr; }
68 const FunctionCallNode
* ParseNode::AsFunctionCall() const { return nullptr; }
69 const IdentifierNode
* ParseNode::AsIdentifier() const { return nullptr; }
70 const ListNode
* ParseNode::AsList() const { return nullptr; }
71 const LiteralNode
* ParseNode::AsLiteral() const { return nullptr; }
72 const UnaryOpNode
* ParseNode::AsUnaryOp() const { return nullptr; }
74 Comments
* ParseNode::comments_mutable() {
76 comments_
.reset(new Comments
);
77 return comments_
.get();
80 void ParseNode::PrintComments(std::ostream
& out
, int indent
) const {
82 std::string ind
= IndentFor(indent
+ 1);
83 for (const auto& token
: comments_
->before())
84 out
<< ind
<< "+BEFORE_COMMENT(\"" << token
.value() << "\")\n";
85 for (const auto& token
: comments_
->suffix())
86 out
<< ind
<< "+SUFFIX_COMMENT(\"" << token
.value() << "\")\n";
87 for (const auto& token
: comments_
->after())
88 out
<< ind
<< "+AFTER_COMMENT(\"" << token
.value() << "\")\n";
92 // AccessorNode ---------------------------------------------------------------
94 AccessorNode::AccessorNode() {
97 AccessorNode::~AccessorNode() {
100 const AccessorNode
* AccessorNode::AsAccessor() const {
104 Value
AccessorNode::Execute(Scope
* scope
, Err
* err
) const {
106 return ExecuteArrayAccess(scope
, err
);
108 return ExecuteScopeAccess(scope
, err
);
113 LocationRange
AccessorNode::GetRange() const {
115 return LocationRange(base_
.location(), index_
->GetRange().end());
117 return LocationRange(base_
.location(), member_
->GetRange().end());
119 return LocationRange();
122 Err
AccessorNode::MakeErrorDescribing(const std::string
& msg
,
123 const std::string
& help
) const {
124 return Err(GetRange(), msg
, help
);
127 void AccessorNode::Print(std::ostream
& out
, int indent
) const {
128 out
<< IndentFor(indent
) << "ACCESSOR\n";
129 PrintComments(out
, indent
);
130 out
<< IndentFor(indent
+ 1) << base_
.value() << "\n";
132 index_
->Print(out
, indent
+ 1);
134 member_
->Print(out
, indent
+ 1);
137 Value
AccessorNode::ExecuteArrayAccess(Scope
* scope
, Err
* err
) const {
138 Value index_value
= index_
->Execute(scope
, err
);
139 if (err
->has_error())
141 if (!index_value
.VerifyTypeIs(Value::INTEGER
, err
))
144 const Value
* base_value
= scope
->GetValue(base_
.value(), true);
146 *err
= MakeErrorDescribing("Undefined identifier.");
149 if (!base_value
->VerifyTypeIs(Value::LIST
, err
))
152 int64 index_int
= index_value
.int_value();
154 *err
= Err(index_
->GetRange(), "Negative array subscript.",
155 "You gave me " + base::Int64ToString(index_int
) + ".");
158 size_t index_sizet
= static_cast<size_t>(index_int
);
159 if (index_sizet
>= base_value
->list_value().size()) {
160 *err
= Err(index_
->GetRange(), "Array subscript out of range.",
161 "You gave me " + base::Int64ToString(index_int
) +
162 " but I was expecting something from 0 to " +
164 static_cast<int64
>(base_value
->list_value().size()) - 1) +
169 // Doing this assumes that there's no way in the language to do anything
170 // between the time the reference is created and the time that the reference
171 // is used. If there is, this will crash! Currently, this is just used for
172 // array accesses where this "shouldn't" happen.
173 return base_value
->list_value()[index_sizet
];
176 Value
AccessorNode::ExecuteScopeAccess(Scope
* scope
, Err
* err
) const {
177 // We jump through some hoops here since ideally a.b will count "b" as
178 // accessed in the given scope. The value "a" might be in some normal nested
179 // scope and we can modify it, but it might also be inherited from the
180 // readonly root scope and we can't do used variable tracking on it. (It's
181 // not legal to const cast it away since the root scope will be in readonly
182 // mode and being accessed from multiple threads without locking.) So this
183 // code handles both cases.
184 const Value
* result
= nullptr;
186 // Look up the value in the scope named by "base_".
187 Value
* mutable_base_value
= scope
->GetMutableValue(base_
.value(), true);
188 if (mutable_base_value
) {
189 // Common case: base value is mutable so we can track variable accesses
190 // for unused value warnings.
191 if (!mutable_base_value
->VerifyTypeIs(Value::SCOPE
, err
))
193 result
= mutable_base_value
->scope_value()->GetValue(
194 member_
->value().value(), true);
196 // Fall back to see if the value is on a read-only scope.
197 const Value
* const_base_value
= scope
->GetValue(base_
.value(), true);
198 if (const_base_value
) {
199 // Read only value, don't try to mark the value access as a "used" one.
200 if (!const_base_value
->VerifyTypeIs(Value::SCOPE
, err
))
203 const_base_value
->scope_value()->GetValue(member_
->value().value());
205 *err
= Err(base_
, "Undefined identifier.");
211 *err
= Err(member_
.get(), "No value named \"" +
212 member_
->value().value() + "\" in scope \"" + base_
.value() + "\"");
218 void AccessorNode::SetNewLocation(int line_number
) {
219 Location old
= base_
.location();
221 Location(old
.file(), line_number
, old
.char_offset(), old
.byte()));
224 // BinaryOpNode ---------------------------------------------------------------
226 BinaryOpNode::BinaryOpNode() {
229 BinaryOpNode::~BinaryOpNode() {
232 const BinaryOpNode
* BinaryOpNode::AsBinaryOp() const {
236 Value
BinaryOpNode::Execute(Scope
* scope
, Err
* err
) const {
237 return ExecuteBinaryOperator(scope
, this, left_
.get(), right_
.get(), err
);
240 LocationRange
BinaryOpNode::GetRange() const {
241 return left_
->GetRange().Union(right_
->GetRange());
244 Err
BinaryOpNode::MakeErrorDescribing(const std::string
& msg
,
245 const std::string
& help
) const {
246 return Err(op_
, msg
, help
);
249 void BinaryOpNode::Print(std::ostream
& out
, int indent
) const {
250 out
<< IndentFor(indent
) << "BINARY(" << op_
.value() << ")\n";
251 PrintComments(out
, indent
);
252 left_
->Print(out
, indent
+ 1);
253 right_
->Print(out
, indent
+ 1);
256 // BlockNode ------------------------------------------------------------------
258 BlockNode::BlockNode(bool has_scope
) : has_scope_(has_scope
) {
261 BlockNode::~BlockNode() {
262 STLDeleteContainerPointers(statements_
.begin(), statements_
.end());
265 const BlockNode
* BlockNode::AsBlock() const {
269 Value
BlockNode::Execute(Scope
* containing_scope
, Err
* err
) const {
271 Scope
our_scope(containing_scope
);
272 Value ret
= ExecuteBlockInScope(&our_scope
, err
);
273 if (err
->has_error())
276 // Check for unused vars in the scope.
277 our_scope
.CheckForUnusedVars(err
);
280 return ExecuteBlockInScope(containing_scope
, err
);
283 LocationRange
BlockNode::GetRange() const {
284 if (begin_token_
.type() != Token::INVALID
&&
285 end_
->value().type() != Token::INVALID
) {
286 return begin_token_
.range().Union(end_
->value().range());
287 } else if (!statements_
.empty()) {
288 return statements_
[0]->GetRange().Union(
289 statements_
[statements_
.size() - 1]->GetRange());
291 return LocationRange();
294 Err
BlockNode::MakeErrorDescribing(const std::string
& msg
,
295 const std::string
& help
) const {
296 return Err(GetRange(), msg
, help
);
299 void BlockNode::Print(std::ostream
& out
, int indent
) const {
300 out
<< IndentFor(indent
) << "BLOCK\n";
301 PrintComments(out
, indent
);
302 for (const auto& statement
: statements_
)
303 statement
->Print(out
, indent
+ 1);
304 if (end_
&& end_
->comments())
305 end_
->Print(out
, indent
+ 1);
308 Value
BlockNode::ExecuteBlockInScope(Scope
* our_scope
, Err
* err
) const {
309 for (size_t i
= 0; i
< statements_
.size() && !err
->has_error(); i
++) {
310 // Check for trying to execute things with no side effects in a block.
311 const ParseNode
* cur
= statements_
[i
];
312 if (cur
->AsList() || cur
->AsLiteral() || cur
->AsUnaryOp() ||
313 cur
->AsIdentifier()) {
314 *err
= cur
->MakeErrorDescribing(
315 "This statement has no effect.",
316 "Either delete it or do something with the result.");
319 cur
->Execute(our_scope
, err
);
324 // ConditionNode --------------------------------------------------------------
326 ConditionNode::ConditionNode() {
329 ConditionNode::~ConditionNode() {
332 const ConditionNode
* ConditionNode::AsConditionNode() const {
336 Value
ConditionNode::Execute(Scope
* scope
, Err
* err
) const {
337 Value condition_result
= condition_
->Execute(scope
, err
);
338 if (err
->has_error())
340 if (condition_result
.type() != Value::BOOLEAN
) {
341 *err
= condition_
->MakeErrorDescribing(
342 "Condition does not evaluate to a boolean value.",
343 std::string("This is a value of type \"") +
344 Value::DescribeType(condition_result
.type()) +
346 err
->AppendRange(if_token_
.range());
350 if (condition_result
.boolean_value()) {
351 if_true_
->ExecuteBlockInScope(scope
, err
);
352 } else if (if_false_
) {
353 // The else block is optional. It's either another condition (for an
354 // "else if" and we can just Execute it and the condition will handle
355 // the scoping) or it's a block indicating an "else" in which ase we
356 // need to be sure it inherits our scope.
357 const BlockNode
* if_false_block
= if_false_
->AsBlock();
359 if_false_block
->ExecuteBlockInScope(scope
, err
);
361 if_false_
->Execute(scope
, err
);
367 LocationRange
ConditionNode::GetRange() const {
369 return if_token_
.range().Union(if_false_
->GetRange());
370 return if_token_
.range().Union(if_true_
->GetRange());
373 Err
ConditionNode::MakeErrorDescribing(const std::string
& msg
,
374 const std::string
& help
) const {
375 return Err(if_token_
, msg
, help
);
378 void ConditionNode::Print(std::ostream
& out
, int indent
) const {
379 out
<< IndentFor(indent
) << "CONDITION\n";
380 PrintComments(out
, indent
);
381 condition_
->Print(out
, indent
+ 1);
382 if_true_
->Print(out
, indent
+ 1);
384 if_false_
->Print(out
, indent
+ 1);
387 // FunctionCallNode -----------------------------------------------------------
389 FunctionCallNode::FunctionCallNode() {
392 FunctionCallNode::~FunctionCallNode() {
395 const FunctionCallNode
* FunctionCallNode::AsFunctionCall() const {
399 Value
FunctionCallNode::Execute(Scope
* scope
, Err
* err
) const {
400 return functions::RunFunction(scope
, this, args_
.get(), block_
.get(), err
);
403 LocationRange
FunctionCallNode::GetRange() const {
404 if (function_
.type() == Token::INVALID
)
405 return LocationRange(); // This will be null in some tests.
407 return function_
.range().Union(block_
->GetRange());
408 return function_
.range().Union(args_
->GetRange());
411 Err
FunctionCallNode::MakeErrorDescribing(const std::string
& msg
,
412 const std::string
& help
) const {
413 return Err(function_
, msg
, help
);
416 void FunctionCallNode::Print(std::ostream
& out
, int indent
) const {
417 out
<< IndentFor(indent
) << "FUNCTION(" << function_
.value() << ")\n";
418 PrintComments(out
, indent
);
419 args_
->Print(out
, indent
+ 1);
421 block_
->Print(out
, indent
+ 1);
424 // IdentifierNode --------------------------------------------------------------
426 IdentifierNode::IdentifierNode() {
429 IdentifierNode::IdentifierNode(const Token
& token
) : value_(token
) {
432 IdentifierNode::~IdentifierNode() {
435 const IdentifierNode
* IdentifierNode::AsIdentifier() const {
439 Value
IdentifierNode::Execute(Scope
* scope
, Err
* err
) const {
440 const Value
* value
= scope
->GetValue(value_
.value(), true);
443 *err
= MakeErrorDescribing("Undefined identifier");
448 result
.set_origin(this);
452 LocationRange
IdentifierNode::GetRange() const {
453 return value_
.range();
456 Err
IdentifierNode::MakeErrorDescribing(const std::string
& msg
,
457 const std::string
& help
) const {
458 return Err(value_
, msg
, help
);
461 void IdentifierNode::Print(std::ostream
& out
, int indent
) const {
462 out
<< IndentFor(indent
) << "IDENTIFIER(" << value_
.value() << ")\n";
463 PrintComments(out
, indent
);
466 void IdentifierNode::SetNewLocation(int line_number
) {
467 Location old
= value_
.location();
469 Location(old
.file(), line_number
, old
.char_offset(), old
.byte()));
472 // ListNode -------------------------------------------------------------------
474 ListNode::ListNode() : prefer_multiline_(false) {
477 ListNode::~ListNode() {
478 STLDeleteContainerPointers(contents_
.begin(), contents_
.end());
481 const ListNode
* ListNode::AsList() const {
485 Value
ListNode::Execute(Scope
* scope
, Err
* err
) const {
486 Value
result_value(this, Value::LIST
);
487 std::vector
<Value
>& results
= result_value
.list_value();
488 results
.reserve(contents_
.size());
490 for (const auto& cur
: contents_
) {
491 if (cur
->AsBlockComment())
493 results
.push_back(cur
->Execute(scope
, err
));
494 if (err
->has_error())
496 if (results
.back().type() == Value::NONE
) {
497 *err
= cur
->MakeErrorDescribing(
498 "This does not evaluate to a value.",
499 "I can't do something with nothing.");
506 LocationRange
ListNode::GetRange() const {
507 return LocationRange(begin_token_
.location(),
508 end_
->value().location());
511 Err
ListNode::MakeErrorDescribing(const std::string
& msg
,
512 const std::string
& help
) const {
513 return Err(begin_token_
, msg
, help
);
516 void ListNode::Print(std::ostream
& out
, int indent
) const {
517 out
<< IndentFor(indent
) << "LIST" << (prefer_multiline_
? " multiline" : "")
519 PrintComments(out
, indent
);
520 for (const auto& cur
: contents_
)
521 cur
->Print(out
, indent
+ 1);
522 if (end_
&& end_
->comments())
523 end_
->Print(out
, indent
+ 1);
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
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
);
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
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
])
552 const_cast<ParseNode
*>(original_first
)
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());
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
);
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;
586 for (size_t i
= begin
; i
< contents_
.size(); prev
= contents_
[i
++]) {
587 if (IsSortRangeSeparator(contents_
[i
], prev
)) {
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:
600 // # This is a block comment.
607 // which contains 5 elements, and for which the ranges would be { [0,
608 // 2), [3, 5) } (notably excluding 2, the block comment), and:
614 // # This is a header comment.
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())
626 // If it was a one item range, just skip over it.
631 if (begin
!= contents_
.size())
632 ranges
.push_back(SortRange(begin
, contents_
.size()));
636 // LiteralNode -----------------------------------------------------------------
638 LiteralNode::LiteralNode() {
641 LiteralNode::LiteralNode(const Token
& token
) : value_(token
) {
644 LiteralNode::~LiteralNode() {
647 const LiteralNode
* LiteralNode::AsLiteral() const {
651 Value
LiteralNode::Execute(Scope
* scope
, Err
* err
) const {
652 switch (value_
.type()) {
653 case Token::TRUE_TOKEN
:
654 return Value(this, true);
655 case Token::FALSE_TOKEN
:
656 return Value(this, false);
657 case Token::INTEGER
: {
659 if (!base::StringToInt64(value_
.value(), &result_int
)) {
660 *err
= MakeErrorDescribing("This does not look like an integer");
663 return Value(this, result_int
);
665 case Token::STRING
: {
666 Value
v(this, Value::STRING
);
667 ExpandStringLiteral(scope
, value_
, &v
, err
);
676 LocationRange
LiteralNode::GetRange() const {
677 return value_
.range();
680 Err
LiteralNode::MakeErrorDescribing(const std::string
& msg
,
681 const std::string
& help
) const {
682 return Err(value_
, msg
, help
);
685 void LiteralNode::Print(std::ostream
& out
, int indent
) const {
686 out
<< IndentFor(indent
) << "LITERAL(" << value_
.value() << ")\n";
687 PrintComments(out
, indent
);
690 void LiteralNode::SetNewLocation(int line_number
) {
691 Location old
= value_
.location();
693 Location(old
.file(), line_number
, old
.char_offset(), old
.byte()));
696 // UnaryOpNode ----------------------------------------------------------------
698 UnaryOpNode::UnaryOpNode() {
701 UnaryOpNode::~UnaryOpNode() {
704 const UnaryOpNode
* UnaryOpNode::AsUnaryOp() const {
708 Value
UnaryOpNode::Execute(Scope
* scope
, Err
* err
) const {
709 Value operand_value
= operand_
->Execute(scope
, err
);
710 if (err
->has_error())
712 return ExecuteUnaryOperator(scope
, this, operand_value
, err
);
715 LocationRange
UnaryOpNode::GetRange() const {
716 return op_
.range().Union(operand_
->GetRange());
719 Err
UnaryOpNode::MakeErrorDescribing(const std::string
& msg
,
720 const std::string
& help
) const {
721 return Err(op_
, msg
, help
);
724 void UnaryOpNode::Print(std::ostream
& out
, int indent
) const {
725 out
<< IndentFor(indent
) << "UNARY(" << op_
.value() << ")\n";
726 PrintComments(out
, indent
);
727 operand_
->Print(out
, indent
+ 1);
730 // BlockCommentNode ------------------------------------------------------------
732 BlockCommentNode::BlockCommentNode() {
735 BlockCommentNode::~BlockCommentNode() {
738 const BlockCommentNode
* BlockCommentNode::AsBlockComment() const {
742 Value
BlockCommentNode::Execute(Scope
* scope
, Err
* err
) const {
746 LocationRange
BlockCommentNode::GetRange() const {
747 return comment_
.range();
750 Err
BlockCommentNode::MakeErrorDescribing(const std::string
& msg
,
751 const std::string
& help
) const {
752 return Err(comment_
, msg
, help
);
755 void BlockCommentNode::Print(std::ostream
& out
, int indent
) const {
756 out
<< IndentFor(indent
) << "BLOCK_COMMENT(" << comment_
.value() << ")\n";
757 PrintComments(out
, indent
);
760 // EndNode ---------------------------------------------------------------------
762 EndNode::EndNode(const Token
& token
) : value_(token
) {
765 EndNode::~EndNode() {
768 const EndNode
* EndNode::AsEnd() const {
772 Value
EndNode::Execute(Scope
* scope
, Err
* err
) const {
776 LocationRange
EndNode::GetRange() const {
777 return value_
.range();
780 Err
EndNode::MakeErrorDescribing(const std::string
& msg
,
781 const std::string
& help
) const {
782 return Err(value_
, msg
, help
);
785 void EndNode::Print(std::ostream
& out
, int indent
) const {
786 out
<< IndentFor(indent
) << "END(" << value_
.value() << ")\n";
787 PrintComments(out
, indent
);