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