• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "gn/parse_tree.h"
6 
7 #include <stdint.h>
8 
9 #include <memory>
10 #include <string>
11 #include <tuple>
12 
13 #include "base/json/string_escape.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "gn/functions.h"
18 #include "gn/operators.h"
19 #include "gn/scope.h"
20 #include "gn/string_utils.h"
21 
22 // Dictionary keys used for JSON-formatted tree dump.
23 const char kJsonNodeChild[] = "child";
24 const char kJsonNodeType[] = "type";
25 const char kJsonNodeValue[] = "value";
26 const char kJsonBeforeComment[] = "before_comment";
27 const char kJsonSuffixComment[] = "suffix_comment";
28 const char kJsonAfterComment[] = "after_comment";
29 
30 namespace {
31 
32 enum DepsCategory {
33   DEPS_CATEGORY_LOCAL,
34   DEPS_CATEGORY_RELATIVE,
35   DEPS_CATEGORY_ABSOLUTE,
36   DEPS_CATEGORY_OTHER,
37 };
38 
GetDepsCategory(std::string_view deps)39 DepsCategory GetDepsCategory(std::string_view deps) {
40   if (deps.length() < 2 || deps[0] != '"' || deps[deps.size() - 1] != '"')
41     return DEPS_CATEGORY_OTHER;
42 
43   if (deps[1] == ':')
44     return DEPS_CATEGORY_LOCAL;
45 
46   if (deps[1] == '/')
47     return DEPS_CATEGORY_ABSOLUTE;
48 
49   return DEPS_CATEGORY_RELATIVE;
50 }
51 
SplitAtFirst(std::string_view str,char c)52 std::tuple<std::string_view, std::string_view> SplitAtFirst(
53     std::string_view str,
54     char c) {
55   if (!base::StartsWith(str, "\"", base::CompareCase::SENSITIVE) ||
56       !base::EndsWith(str, "\"", base::CompareCase::SENSITIVE))
57     return std::make_tuple(str, std::string_view());
58 
59   str = str.substr(1, str.length() - 2);
60   size_t index_of_first = str.find(c);
61   return std::make_tuple(str.substr(0, index_of_first),
62                          index_of_first != std::string_view::npos
63                              ? str.substr(index_of_first + 1)
64                              : std::string_view());
65 }
66 
IsSortRangeSeparator(const ParseNode * node,const ParseNode * prev)67 bool IsSortRangeSeparator(const ParseNode* node, const ParseNode* prev) {
68   // If it's a block comment, or has an attached comment with a blank line
69   // before it, then we break the range at this point.
70   return node->AsBlockComment() != nullptr ||
71          (prev && node->comments() && !node->comments()->before().empty() &&
72           (node->GetRange().begin().line_number() >
73            prev->GetRange().end().line_number() +
74                static_cast<int>(node->comments()->before().size() + 1)));
75 }
76 
GetStringRepresentation(const ParseNode * node)77 std::string_view GetStringRepresentation(const ParseNode* node) {
78   DCHECK(node->AsLiteral() || node->AsIdentifier() || node->AsAccessor());
79   if (node->AsLiteral())
80     return node->AsLiteral()->value().value();
81   else if (node->AsIdentifier())
82     return node->AsIdentifier()->value().value();
83   else if (node->AsAccessor())
84     return node->AsAccessor()->base().value();
85   return std::string_view();
86 }
87 
88 }  // namespace
89 
90 Comments::Comments() = default;
91 
92 Comments::~Comments() = default;
93 
ReverseSuffix()94 void Comments::ReverseSuffix() {
95   for (int i = 0, j = static_cast<int>(suffix_.size() - 1); i < j; ++i, --j)
96     std::swap(suffix_[i], suffix_[j]);
97 }
98 
99 ParseNode::ParseNode() = default;
100 
101 ParseNode::~ParseNode() = default;
102 
AsAccessor() const103 const AccessorNode* ParseNode::AsAccessor() const {
104   return nullptr;
105 }
AsBinaryOp() const106 const BinaryOpNode* ParseNode::AsBinaryOp() const {
107   return nullptr;
108 }
AsBlockComment() const109 const BlockCommentNode* ParseNode::AsBlockComment() const {
110   return nullptr;
111 }
AsBlock() const112 const BlockNode* ParseNode::AsBlock() const {
113   return nullptr;
114 }
AsConditionNode() const115 const ConditionNode* ParseNode::AsConditionNode() const {
116   return nullptr;
117 }
AsEnd() const118 const EndNode* ParseNode::AsEnd() const {
119   return nullptr;
120 }
AsFunctionCall() const121 const FunctionCallNode* ParseNode::AsFunctionCall() const {
122   return nullptr;
123 }
AsIdentifier() const124 const IdentifierNode* ParseNode::AsIdentifier() const {
125   return nullptr;
126 }
AsList() const127 const ListNode* ParseNode::AsList() const {
128   return nullptr;
129 }
AsLiteral() const130 const LiteralNode* ParseNode::AsLiteral() const {
131   return nullptr;
132 }
AsUnaryOp() const133 const UnaryOpNode* ParseNode::AsUnaryOp() const {
134   return nullptr;
135 }
136 
comments_mutable()137 Comments* ParseNode::comments_mutable() {
138   if (!comments_)
139     comments_ = std::make_unique<Comments>();
140   return comments_.get();
141 }
142 
CreateJSONNode(const char * type) const143 base::Value ParseNode::CreateJSONNode(const char* type) const {
144   base::Value dict(base::Value::Type::DICTIONARY);
145   dict.SetKey(kJsonNodeType, base::Value(type));
146   AddCommentsJSONNodes(&dict);
147   return dict;
148 }
149 
CreateJSONNode(const char * type,const std::string_view & value) const150 base::Value ParseNode::CreateJSONNode(const char* type,
151                                       const std::string_view& value) const {
152   base::Value dict(base::Value::Type::DICTIONARY);
153   dict.SetKey(kJsonNodeType, base::Value(type));
154   dict.SetKey(kJsonNodeValue, base::Value(value));
155   AddCommentsJSONNodes(&dict);
156   return dict;
157 }
158 
AddCommentsJSONNodes(base::Value * out_value) const159 void ParseNode::AddCommentsJSONNodes(base::Value* out_value) const {
160   if (comments_) {
161     if (comments_->before().size()) {
162       base::Value comment_values(base::Value::Type::LIST);
163       for (const auto& token : comments_->before())
164         comment_values.GetList().push_back(base::Value(token.value()));
165       out_value->SetKey(kJsonBeforeComment, std::move(comment_values));
166     }
167     if (comments_->suffix().size()) {
168       base::Value comment_values(base::Value::Type::LIST);
169       for (const auto& token : comments_->suffix())
170         comment_values.GetList().push_back(base::Value(token.value()));
171       out_value->SetKey(kJsonSuffixComment, std::move(comment_values));
172     }
173     if (comments_->after().size()) {
174       base::Value comment_values(base::Value::Type::LIST);
175       for (const auto& token : comments_->after())
176         comment_values.GetList().push_back(base::Value(token.value()));
177       out_value->SetKey(kJsonAfterComment, std::move(comment_values));
178     }
179   }
180 }
181 
182 // AccessorNode ---------------------------------------------------------------
183 
184 AccessorNode::AccessorNode() = default;
185 
186 AccessorNode::~AccessorNode() = default;
187 
AsAccessor() const188 const AccessorNode* AccessorNode::AsAccessor() const {
189   return this;
190 }
191 
Execute(Scope * scope,Err * err) const192 Value AccessorNode::Execute(Scope* scope, Err* err) const {
193   if (subscript_)
194     return ExecuteSubscriptAccess(scope, err);
195   else if (member_)
196     return ExecuteScopeAccess(scope, err);
197   NOTREACHED();
198   return Value();
199 }
200 
GetRange() const201 LocationRange AccessorNode::GetRange() const {
202   if (subscript_)
203     return LocationRange(base_.location(), subscript_->GetRange().end());
204   else if (member_)
205     return LocationRange(base_.location(), member_->GetRange().end());
206   NOTREACHED();
207   return LocationRange();
208 }
209 
MakeErrorDescribing(const std::string & msg,const std::string & help) const210 Err AccessorNode::MakeErrorDescribing(const std::string& msg,
211                                       const std::string& help) const {
212   return Err(GetRange(), msg, help);
213 }
214 
GetJSONNode() const215 base::Value AccessorNode::GetJSONNode() const {
216   base::Value dict(CreateJSONNode("ACCESSOR", base_.value()));
217   base::Value child(base::Value::Type::LIST);
218   if (subscript_)
219     child.GetList().push_back(subscript_->GetJSONNode());
220   else if (member_)
221     child.GetList().push_back(member_->GetJSONNode());
222   dict.SetKey(kJsonNodeChild, std::move(child));
223   return dict;
224 }
225 
ExecuteSubscriptAccess(Scope * scope,Err * err) const226 Value AccessorNode::ExecuteSubscriptAccess(Scope* scope, Err* err) const {
227   const Value* base_value = scope->GetValue(base_.value(), true);
228   if (!base_value) {
229     *err = MakeErrorDescribing("Undefined identifier.");
230     return Value();
231   }
232   if (base_value->type() == Value::LIST) {
233     return ExecuteArrayAccess(scope, base_value, err);
234   } else if (base_value->type() == Value::SCOPE) {
235     return ExecuteScopeSubscriptAccess(scope, base_value, err);
236   } else {
237     *err = MakeErrorDescribing(
238         std::string("Expecting either a list or a scope for subscript, got ") +
239         Value::DescribeType(base_value->type()) + ".");
240     return Value();
241   }
242 }
243 
ExecuteArrayAccess(Scope * scope,const Value * base_value,Err * err) const244 Value AccessorNode::ExecuteArrayAccess(Scope* scope,
245                                        const Value* base_value,
246                                        Err* err) const {
247   size_t index = 0;
248   if (!ComputeAndValidateListIndex(scope, base_value->list_value().size(),
249                                    &index, err))
250     return Value();
251   return base_value->list_value()[index];
252 }
253 
ExecuteScopeSubscriptAccess(Scope * scope,const Value * base_value,Err * err) const254 Value AccessorNode::ExecuteScopeSubscriptAccess(Scope* scope,
255                                                 const Value* base_value,
256                                                 Err* err) const {
257   Value key_value = subscript_->Execute(scope, err);
258   if (err->has_error())
259     return Value();
260   if (!key_value.VerifyTypeIs(Value::STRING, err))
261     return Value();
262   const Value* result =
263       base_value->scope_value()->GetValue(key_value.string_value());
264   if (!result) {
265     *err =
266         Err(subscript_.get(), "No value named \"" + key_value.string_value() +
267                                   "\" in scope \"" + base_.value() + "\"");
268   }
269   return *result;
270 }
271 
ExecuteScopeAccess(Scope * scope,Err * err) const272 Value AccessorNode::ExecuteScopeAccess(Scope* scope, Err* err) const {
273   // We jump through some hoops here since ideally a.b will count "b" as
274   // accessed in the given scope. The value "a" might be in some normal nested
275   // scope and we can modify it, but it might also be inherited from the
276   // readonly root scope and we can't do used variable tracking on it. (It's
277   // not legal to const cast it away since the root scope will be in readonly
278   // mode and being accessed from multiple threads without locking.) So this
279   // code handles both cases.
280   const Value* result = nullptr;
281 
282   // Look up the value in the scope named by "base_".
283   Value* mutable_base_value =
284       scope->GetMutableValue(base_.value(), Scope::SEARCH_NESTED, true);
285   if (mutable_base_value) {
286     // Common case: base value is mutable so we can track variable accesses
287     // for unused value warnings.
288     if (!mutable_base_value->VerifyTypeIs(Value::SCOPE, err))
289       return Value();
290     result = mutable_base_value->scope_value()->GetValue(
291         member_->value().value(), true);
292   } else {
293     // Fall back to see if the value is on a read-only scope.
294     const Value* const_base_value = scope->GetValue(base_.value(), true);
295     if (const_base_value) {
296       // Read only value, don't try to mark the value access as a "used" one.
297       if (!const_base_value->VerifyTypeIs(Value::SCOPE, err))
298         return Value();
299       result =
300           const_base_value->scope_value()->GetValue(member_->value().value());
301     } else {
302       *err = Err(base_, "Undefined identifier.");
303       return Value();
304     }
305   }
306 
307   if (!result) {
308     *err = Err(member_.get(), "No value named \"" + member_->value().value() +
309                                   "\" in scope \"" + base_.value() + "\"");
310     return Value();
311   }
312   return *result;
313 }
314 
SetNewLocation(int line_number)315 void AccessorNode::SetNewLocation(int line_number) {
316   Location old = base_.location();
317   base_.set_location(
318       Location(old.file(), line_number, old.column_number(), old.byte()));
319 }
320 
ComputeAndValidateListIndex(Scope * scope,size_t max_len,size_t * computed_index,Err * err) const321 bool AccessorNode::ComputeAndValidateListIndex(Scope* scope,
322                                                size_t max_len,
323                                                size_t* computed_index,
324                                                Err* err) const {
325   Value index_value = subscript_->Execute(scope, err);
326   if (err->has_error())
327     return false;
328   if (!index_value.VerifyTypeIs(Value::INTEGER, err))
329     return false;
330 
331   int64_t index_int = index_value.int_value();
332   if (index_int < 0) {
333     *err = Err(subscript_->GetRange(), "Negative array subscript.",
334                "You gave me " + base::Int64ToString(index_int) + ".");
335     return false;
336   }
337   if (max_len == 0) {
338     *err = Err(subscript_->GetRange(), "Array subscript out of range.",
339                "You gave me " + base::Int64ToString(index_int) + " but the " +
340                    "array has no elements.");
341     return false;
342   }
343   size_t index_sizet = static_cast<size_t>(index_int);
344   if (index_sizet >= max_len) {
345     *err = Err(subscript_->GetRange(), "Array subscript out of range.",
346                "You gave me " + base::Int64ToString(index_int) +
347                    " but I was expecting something from 0 to " +
348                    base::NumberToString(max_len - 1) + ", inclusive.");
349     return false;
350   }
351 
352   *computed_index = index_sizet;
353   return true;
354 }
355 
356 // BinaryOpNode ---------------------------------------------------------------
357 
358 BinaryOpNode::BinaryOpNode() = default;
359 
360 BinaryOpNode::~BinaryOpNode() = default;
361 
AsBinaryOp() const362 const BinaryOpNode* BinaryOpNode::AsBinaryOp() const {
363   return this;
364 }
365 
Execute(Scope * scope,Err * err) const366 Value BinaryOpNode::Execute(Scope* scope, Err* err) const {
367   return ExecuteBinaryOperator(scope, this, left_.get(), right_.get(), err);
368 }
369 
GetRange() const370 LocationRange BinaryOpNode::GetRange() const {
371   return left_->GetRange().Union(right_->GetRange());
372 }
373 
MakeErrorDescribing(const std::string & msg,const std::string & help) const374 Err BinaryOpNode::MakeErrorDescribing(const std::string& msg,
375                                       const std::string& help) const {
376   return Err(op_, msg, help);
377 }
378 
GetJSONNode() const379 base::Value BinaryOpNode::GetJSONNode() const {
380   base::Value dict(CreateJSONNode("BINARY", op_.value()));
381   base::Value child(base::Value::Type::LIST);
382   child.GetList().push_back(left_->GetJSONNode());
383   child.GetList().push_back(right_->GetJSONNode());
384   dict.SetKey(kJsonNodeChild, std::move(child));
385   return dict;
386 }
387 
388 // BlockNode ------------------------------------------------------------------
389 
BlockNode(ResultMode result_mode)390 BlockNode::BlockNode(ResultMode result_mode) : result_mode_(result_mode) {}
391 
392 BlockNode::~BlockNode() = default;
393 
AsBlock() const394 const BlockNode* BlockNode::AsBlock() const {
395   return this;
396 }
397 
Execute(Scope * enclosing_scope,Err * err) const398 Value BlockNode::Execute(Scope* enclosing_scope, Err* err) const {
399   std::unique_ptr<Scope> nested_scope;  // May be null.
400 
401   Scope* execution_scope;  // Either the enclosing_scope or nested_scope.
402   if (result_mode_ == RETURNS_SCOPE) {
403     // Create a nested scope to save the values for returning.
404     nested_scope = std::make_unique<Scope>(enclosing_scope);
405     execution_scope = nested_scope.get();
406   } else {
407     // Use the enclosing scope. Modifications will go into this also (for
408     // example, if conditions and loops).
409     execution_scope = enclosing_scope;
410   }
411 
412   for (size_t i = 0; i < statements_.size() && !err->has_error(); i++) {
413     // Check for trying to execute things with no side effects in a block.
414     //
415     // A BlockNode here means that somebody has a free-floating { }.
416     // Technically this can have side effects since it could generated targets,
417     // but we don't want to allow this since it creates ambiguity when
418     // immediately following a function call that takes no block. By not
419     // allowing free-floating blocks that aren't passed anywhere or assigned to
420     // anything, this ambiguity is resolved.
421     const ParseNode* cur = statements_[i].get();
422     if (cur->AsList() || cur->AsLiteral() || cur->AsUnaryOp() ||
423         cur->AsIdentifier() || cur->AsBlock()) {
424       *err = cur->MakeErrorDescribing(
425           "This statement has no effect.",
426           "Either delete it or do something with the result.");
427       return Value();
428     }
429     cur->Execute(execution_scope, err);
430   }
431 
432   if (result_mode_ == RETURNS_SCOPE) {
433     // Clear the reference to the containing scope. This will be passed in
434     // a value whose lifetime will not be related to the enclosing_scope passed
435     // to this function.
436     nested_scope->DetachFromContaining();
437     return Value(this, std::move(nested_scope));
438   }
439   return Value();
440 }
441 
GetRange() const442 LocationRange BlockNode::GetRange() const {
443   if (begin_token_.type() != Token::INVALID &&
444       end_->value().type() != Token::INVALID) {
445     return begin_token_.range().Union(end_->value().range());
446   } else if (!statements_.empty()) {
447     return statements_[0]->GetRange().Union(
448         statements_[statements_.size() - 1]->GetRange());
449   }
450   return LocationRange();
451 }
452 
MakeErrorDescribing(const std::string & msg,const std::string & help) const453 Err BlockNode::MakeErrorDescribing(const std::string& msg,
454                                    const std::string& help) const {
455   return Err(GetRange(), msg, help);
456 }
457 
GetJSONNode() const458 base::Value BlockNode::GetJSONNode() const {
459   base::Value dict(CreateJSONNode("BLOCK"));
460   base::Value statements(base::Value::Type::LIST);
461   for (const auto& statement : statements_)
462     statements.GetList().push_back(statement->GetJSONNode());
463   if (end_ && end_->comments())
464     statements.GetList().push_back(end_->GetJSONNode());
465 
466   dict.SetKey("child", std::move(statements));
467   return dict;
468 }
469 
470 // ConditionNode --------------------------------------------------------------
471 
472 ConditionNode::ConditionNode() = default;
473 
474 ConditionNode::~ConditionNode() = default;
475 
AsConditionNode() const476 const ConditionNode* ConditionNode::AsConditionNode() const {
477   return this;
478 }
479 
Execute(Scope * scope,Err * err) const480 Value ConditionNode::Execute(Scope* scope, Err* err) const {
481   Value condition_result = condition_->Execute(scope, err);
482   if (err->has_error())
483     return Value();
484   if (condition_result.type() != Value::BOOLEAN) {
485     *err = condition_->MakeErrorDescribing(
486         "Condition does not evaluate to a boolean value.",
487         std::string("This is a value of type \"") +
488             Value::DescribeType(condition_result.type()) + "\" instead.");
489     err->AppendRange(if_token_.range());
490     return Value();
491   }
492 
493   if (condition_result.boolean_value()) {
494     if_true_->Execute(scope, err);
495   } else if (if_false_) {
496     // The else block is optional.
497     if_false_->Execute(scope, err);
498   }
499 
500   return Value();
501 }
502 
GetRange() const503 LocationRange ConditionNode::GetRange() const {
504   if (if_false_)
505     return if_token_.range().Union(if_false_->GetRange());
506   return if_token_.range().Union(if_true_->GetRange());
507 }
508 
MakeErrorDescribing(const std::string & msg,const std::string & help) const509 Err ConditionNode::MakeErrorDescribing(const std::string& msg,
510                                        const std::string& help) const {
511   return Err(if_token_, msg, help);
512 }
513 
GetJSONNode() const514 base::Value ConditionNode::GetJSONNode() const {
515   base::Value dict = CreateJSONNode("CONDITION");
516   base::Value child(base::Value::Type::LIST);
517   child.GetList().push_back(condition_->GetJSONNode());
518   child.GetList().push_back(if_true_->GetJSONNode());
519   if (if_false_) {
520     child.GetList().push_back(if_false_->GetJSONNode());
521   }
522   dict.SetKey(kJsonNodeChild, std::move(child));
523   return dict;
524 }
525 
526 // FunctionCallNode -----------------------------------------------------------
527 
528 FunctionCallNode::FunctionCallNode() = default;
529 
530 FunctionCallNode::~FunctionCallNode() = default;
531 
AsFunctionCall() const532 const FunctionCallNode* FunctionCallNode::AsFunctionCall() const {
533   return this;
534 }
535 
Execute(Scope * scope,Err * err) const536 Value FunctionCallNode::Execute(Scope* scope, Err* err) const {
537   return functions::RunFunction(scope, this, args_.get(), block_.get(), err);
538 }
539 
GetRange() const540 LocationRange FunctionCallNode::GetRange() const {
541   if (function_.type() == Token::INVALID)
542     return LocationRange();  // This will be null in some tests.
543   if (block_)
544     return function_.range().Union(block_->GetRange());
545   return function_.range().Union(args_->GetRange());
546 }
547 
MakeErrorDescribing(const std::string & msg,const std::string & help) const548 Err FunctionCallNode::MakeErrorDescribing(const std::string& msg,
549                                           const std::string& help) const {
550   return Err(function_, msg, help);
551 }
552 
GetJSONNode() const553 base::Value FunctionCallNode::GetJSONNode() const {
554   base::Value dict = CreateJSONNode("FUNCTION", function_.value());
555   base::Value child(base::Value::Type::LIST);
556   child.GetList().push_back(args_->GetJSONNode());
557   if (block_) {
558     child.GetList().push_back(block_->GetJSONNode());
559   }
560   dict.SetKey(kJsonNodeChild, std::move(child));
561   return dict;
562 }
563 
SetNewLocation(int line_number)564 void FunctionCallNode::SetNewLocation(int line_number) {
565   Location func_old_loc = function_.location();
566   Location func_new_loc =
567       Location(func_old_loc.file(), line_number, func_old_loc.column_number(),
568                func_old_loc.byte());
569   function_.set_location(func_new_loc);
570 
571   Location args_old_loc = args_->Begin().location();
572   Location args_new_loc =
573       Location(args_old_loc.file(), line_number, args_old_loc.column_number(),
574                args_old_loc.byte());
575   const_cast<Token&>(args_->Begin()).set_location(args_new_loc);
576   const_cast<Token&>(args_->End()->value()).set_location(args_new_loc);
577 }
578 
579 // IdentifierNode --------------------------------------------------------------
580 
581 IdentifierNode::IdentifierNode() = default;
582 
IdentifierNode(const Token & token)583 IdentifierNode::IdentifierNode(const Token& token) : value_(token) {}
584 
585 IdentifierNode::~IdentifierNode() = default;
586 
AsIdentifier() const587 const IdentifierNode* IdentifierNode::AsIdentifier() const {
588   return this;
589 }
590 
Execute(Scope * scope,Err * err) const591 Value IdentifierNode::Execute(Scope* scope, Err* err) const {
592   const Scope* found_in_scope = nullptr;
593   const Value* value =
594       scope->GetValueWithScope(value_.value(), true, &found_in_scope);
595   Value result;
596   if (!value) {
597     *err = MakeErrorDescribing("Undefined identifier");
598     return result;
599   }
600 
601   if (!EnsureNotReadingFromSameDeclareArgs(this, scope, found_in_scope, err))
602     return result;
603 
604   result = *value;
605   result.set_origin(this);
606   return result;
607 }
608 
GetRange() const609 LocationRange IdentifierNode::GetRange() const {
610   return value_.range();
611 }
612 
MakeErrorDescribing(const std::string & msg,const std::string & help) const613 Err IdentifierNode::MakeErrorDescribing(const std::string& msg,
614                                         const std::string& help) const {
615   return Err(value_, msg, help);
616 }
617 
GetJSONNode() const618 base::Value IdentifierNode::GetJSONNode() const {
619   return CreateJSONNode("IDENTIFIER", value_.value());
620 }
621 
SetNewLocation(int line_number)622 void IdentifierNode::SetNewLocation(int line_number) {
623   Location old = value_.location();
624   value_.set_location(
625       Location(old.file(), line_number, old.column_number(), old.byte()));
626 }
627 
628 // ListNode -------------------------------------------------------------------
629 
ListNode()630 ListNode::ListNode() {}
631 
632 ListNode::~ListNode() = default;
633 
AsList() const634 const ListNode* ListNode::AsList() const {
635   return this;
636 }
637 
Execute(Scope * scope,Err * err) const638 Value ListNode::Execute(Scope* scope, Err* err) const {
639   Value result_value(this, Value::LIST);
640   std::vector<Value>& results = result_value.list_value();
641   results.reserve(contents_.size());
642 
643   for (const auto& cur : contents_) {
644     if (cur->AsBlockComment())
645       continue;
646     results.push_back(cur->Execute(scope, err));
647     if (err->has_error())
648       return Value();
649     if (results.back().type() == Value::NONE) {
650       *err = cur->MakeErrorDescribing("This does not evaluate to a value.",
651                                       "I can't do something with nothing.");
652       return Value();
653     }
654   }
655   return result_value;
656 }
657 
GetRange() const658 LocationRange ListNode::GetRange() const {
659   return LocationRange(begin_token_.location(), end_->value().location());
660 }
661 
MakeErrorDescribing(const std::string & msg,const std::string & help) const662 Err ListNode::MakeErrorDescribing(const std::string& msg,
663                                   const std::string& help) const {
664   return Err(begin_token_, msg, help);
665 }
666 
GetJSONNode() const667 base::Value ListNode::GetJSONNode() const {
668   base::Value dict(CreateJSONNode("LIST"));
669   base::Value child(base::Value::Type::LIST);
670   for (const auto& cur : contents_) {
671     child.GetList().push_back(cur->GetJSONNode());
672   }
673   if (end_ && end_->comments()) {
674     child.GetList().push_back(end_->GetJSONNode());
675   }
676   dict.SetKey(kJsonNodeChild, std::move(child));
677   return dict;
678 }
679 
680 template <typename Comparator>
SortList(Comparator comparator)681 void ListNode::SortList(Comparator comparator) {
682   // Partitions first on BlockCommentNodes and sorts each partition separately.
683   for (auto sr : GetSortRanges()) {
684     bool skip = false;
685     for (size_t i = sr.begin; i != sr.end; ++i) {
686       // Bails out if any of the nodes are unsupported.
687       const ParseNode* node = contents_[i].get();
688       if (!node->AsLiteral() && !node->AsIdentifier() && !node->AsAccessor()) {
689         skip = true;
690         continue;
691       }
692     }
693     if (skip)
694       continue;
695     // Save the original line number so that we can re-assign ranges. We assume
696     // they're contiguous lines because GetSortRanges() does so above. We need
697     // to re-assign these line numbers primiarily because `gn format` uses them
698     // to determine whether two nodes were initially separated by a blank line
699     // or not.
700     int start_line = contents_[sr.begin]->GetRange().begin().line_number();
701     const ParseNode* original_first = contents_[sr.begin].get();
702     std::sort(contents_.begin() + sr.begin, contents_.begin() + sr.end,
703               [&comparator](const std::unique_ptr<const ParseNode>& a,
704                             const std::unique_ptr<const ParseNode>& b) {
705                 return comparator(a.get(), b.get());
706               });
707     // If the beginning of the range had before comments, and the first node
708     // moved during the sort, then move its comments to the new head of the
709     // range.
710     if (original_first->comments() &&
711         contents_[sr.begin].get() != original_first) {
712       for (const auto& hc : original_first->comments()->before()) {
713         const_cast<ParseNode*>(contents_[sr.begin].get())
714             ->comments_mutable()
715             ->append_before(hc);
716       }
717       const_cast<ParseNode*>(original_first)
718           ->comments_mutable()
719           ->clear_before();
720     }
721     const ParseNode* prev = nullptr;
722     for (size_t i = sr.begin; i != sr.end; ++i) {
723       const ParseNode* node = contents_[i].get();
724       DCHECK(node->AsLiteral() || node->AsIdentifier() || node->AsAccessor());
725       int line_number =
726           prev ? prev->GetRange().end().line_number() + 1 : start_line;
727       if (node->AsLiteral()) {
728         const_cast<LiteralNode*>(node->AsLiteral())
729             ->SetNewLocation(line_number);
730       } else if (node->AsIdentifier()) {
731         const_cast<IdentifierNode*>(node->AsIdentifier())
732             ->SetNewLocation(line_number);
733       } else if (node->AsAccessor()) {
734         const_cast<AccessorNode*>(node->AsAccessor())
735             ->SetNewLocation(line_number);
736       }
737       prev = node;
738     }
739   }
740 }
741 
SortAsStringsList()742 void ListNode::SortAsStringsList() {
743   // Sorts alphabetically.
744   SortList([](const ParseNode* a, const ParseNode* b) {
745     std::string_view astr = GetStringRepresentation(a);
746     std::string_view bstr = GetStringRepresentation(b);
747     return astr < bstr;
748   });
749 }
750 
SortAsDepsList()751 void ListNode::SortAsDepsList() {
752   // Sorts first relative targets, then absolute, each group is sorted
753   // alphabetically.
754   SortList([](const ParseNode* a, const ParseNode* b) {
755     std::string_view astr = GetStringRepresentation(a);
756     std::string_view bstr = GetStringRepresentation(b);
757     return std::make_pair(GetDepsCategory(astr), SplitAtFirst(astr, ':')) <
758            std::make_pair(GetDepsCategory(bstr), SplitAtFirst(bstr, ':'));
759   });
760 }
761 
762 // Breaks the ParseNodes of |contents| up by ranges that should be separately
763 // sorted. In particular, we break at a block comment, or an item that has an
764 // attached "before" comment and is separated by a blank line from the item
765 // before it. The assumption is that both of these indicate a separate 'section'
766 // of a sources block across which items should not be inter-sorted.
GetSortRanges() const767 std::vector<ListNode::SortRange> ListNode::GetSortRanges() const {
768   std::vector<SortRange> ranges;
769   const ParseNode* prev = nullptr;
770   size_t begin = 0;
771   for (size_t i = begin; i < contents_.size(); prev = contents_[i++].get()) {
772     if (IsSortRangeSeparator(contents_[i].get(), prev)) {
773       if (i > begin) {
774         ranges.push_back(SortRange(begin, i));
775         // If |i| is an item with an attached comment, then we start the next
776         // range at that point, because we want to include it in the sort.
777         // Otherwise, it's a block comment which we skip over entirely because
778         // we don't want to move or include it in the sort. The two cases are:
779         //
780         // sources = [
781         //   "a",
782         //   "b",
783         //
784         //   #
785         //   # This is a block comment.
786         //   #
787         //
788         //   "c",
789         //   "d",
790         // ]
791         //
792         // which contains 5 elements, and for which the ranges would be { [0,
793         // 2), [3, 5) } (notably excluding 2, the block comment), and:
794         //
795         // sources = [
796         //   "a",
797         //   "b",
798         //
799         //   # This is a header comment.
800         //   "c",
801         //   "d",
802         // ]
803         //
804         // which contains 4 elements, index 2 containing an attached 'before'
805         // comments, and the ranges should be { [0, 2), [2, 4) }.
806         if (!contents_[i]->AsBlockComment())
807           begin = i;
808         else
809           begin = i + 1;
810       } else {
811         // If it was a one item range, just skip over it.
812         begin = i + 1;
813       }
814     }
815   }
816   if (begin != contents_.size())
817     ranges.push_back(SortRange(begin, contents_.size()));
818   return ranges;
819 }
820 
821 // LiteralNode -----------------------------------------------------------------
822 
823 LiteralNode::LiteralNode() = default;
824 
LiteralNode(const Token & token)825 LiteralNode::LiteralNode(const Token& token) : value_(token) {}
826 
827 LiteralNode::~LiteralNode() = default;
828 
AsLiteral() const829 const LiteralNode* LiteralNode::AsLiteral() const {
830   return this;
831 }
832 
Execute(Scope * scope,Err * err) const833 Value LiteralNode::Execute(Scope* scope, Err* err) const {
834   switch (value_.type()) {
835     case Token::TRUE_TOKEN:
836       return Value(this, true);
837     case Token::FALSE_TOKEN:
838       return Value(this, false);
839     case Token::INTEGER: {
840       std::string_view s = value_.value();
841       if ((base::StartsWith(s, "0", base::CompareCase::SENSITIVE) &&
842            s.size() > 1) ||
843           base::StartsWith(s, "-0", base::CompareCase::SENSITIVE)) {
844         if (s == "-0")
845           *err = MakeErrorDescribing("Negative zero doesn't make sense");
846         else
847           *err = MakeErrorDescribing("Leading zeros not allowed");
848         return Value();
849       }
850       int64_t result_int;
851       if (!base::StringToInt64(s, &result_int)) {
852         *err = MakeErrorDescribing("This does not look like an integer");
853         return Value();
854       }
855       return Value(this, result_int);
856     }
857     case Token::STRING: {
858       Value v(this, Value::STRING);
859       ExpandStringLiteral(scope, value_, &v, err);
860       return v;
861     }
862     default:
863       NOTREACHED();
864       return Value();
865   }
866 }
867 
GetRange() const868 LocationRange LiteralNode::GetRange() const {
869   return value_.range();
870 }
871 
MakeErrorDescribing(const std::string & msg,const std::string & help) const872 Err LiteralNode::MakeErrorDescribing(const std::string& msg,
873                                      const std::string& help) const {
874   return Err(value_, msg, help);
875 }
876 
GetJSONNode() const877 base::Value LiteralNode::GetJSONNode() const {
878   return CreateJSONNode("LITERAL", value_.value());
879 }
880 
SetNewLocation(int line_number)881 void LiteralNode::SetNewLocation(int line_number) {
882   Location old = value_.location();
883   value_.set_location(
884       Location(old.file(), line_number, old.column_number(), old.byte()));
885 }
886 
887 // UnaryOpNode ----------------------------------------------------------------
888 
889 UnaryOpNode::UnaryOpNode() = default;
890 
891 UnaryOpNode::~UnaryOpNode() = default;
892 
AsUnaryOp() const893 const UnaryOpNode* UnaryOpNode::AsUnaryOp() const {
894   return this;
895 }
896 
Execute(Scope * scope,Err * err) const897 Value UnaryOpNode::Execute(Scope* scope, Err* err) const {
898   Value operand_value = operand_->Execute(scope, err);
899   if (err->has_error())
900     return Value();
901   return ExecuteUnaryOperator(scope, this, operand_value, err);
902 }
903 
GetRange() const904 LocationRange UnaryOpNode::GetRange() const {
905   return op_.range().Union(operand_->GetRange());
906 }
907 
MakeErrorDescribing(const std::string & msg,const std::string & help) const908 Err UnaryOpNode::MakeErrorDescribing(const std::string& msg,
909                                      const std::string& help) const {
910   return Err(op_, msg, help);
911 }
912 
GetJSONNode() const913 base::Value UnaryOpNode::GetJSONNode() const {
914   base::Value dict = CreateJSONNode("UNARY", op_.value());
915   base::Value child(base::Value::Type::LIST);
916   child.GetList().push_back(operand_->GetJSONNode());
917   dict.SetKey(kJsonNodeChild, std::move(child));
918   return dict;
919 }
920 
921 // BlockCommentNode ------------------------------------------------------------
922 
923 BlockCommentNode::BlockCommentNode() = default;
924 
925 BlockCommentNode::~BlockCommentNode() = default;
926 
AsBlockComment() const927 const BlockCommentNode* BlockCommentNode::AsBlockComment() const {
928   return this;
929 }
930 
Execute(Scope * scope,Err * err) const931 Value BlockCommentNode::Execute(Scope* scope, Err* err) const {
932   return Value();
933 }
934 
GetRange() const935 LocationRange BlockCommentNode::GetRange() const {
936   return comment_.range();
937 }
938 
MakeErrorDescribing(const std::string & msg,const std::string & help) const939 Err BlockCommentNode::MakeErrorDescribing(const std::string& msg,
940                                           const std::string& help) const {
941   return Err(comment_, msg, help);
942 }
943 
GetJSONNode() const944 base::Value BlockCommentNode::GetJSONNode() const {
945   std::string escaped;
946   base::EscapeJSONString(std::string(comment_.value()), false, &escaped);
947   return CreateJSONNode("BLOCK_COMMENT", escaped);
948 }
949 
950 // EndNode ---------------------------------------------------------------------
951 
EndNode(const Token & token)952 EndNode::EndNode(const Token& token) : value_(token) {}
953 
954 EndNode::~EndNode() = default;
955 
AsEnd() const956 const EndNode* EndNode::AsEnd() const {
957   return this;
958 }
959 
Execute(Scope * scope,Err * err) const960 Value EndNode::Execute(Scope* scope, Err* err) const {
961   return Value();
962 }
963 
GetRange() const964 LocationRange EndNode::GetRange() const {
965   return value_.range();
966 }
967 
MakeErrorDescribing(const std::string & msg,const std::string & help) const968 Err EndNode::MakeErrorDescribing(const std::string& msg,
969                                  const std::string& help) const {
970   return Err(value_, msg, help);
971 }
972 
GetJSONNode() const973 base::Value EndNode::GetJSONNode() const {
974   return CreateJSONNode("END", value_.value());
975 }
976