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/operators.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "tools/gn/err.h"
9 #include "tools/gn/parse_tree.h"
10 #include "tools/gn/scope.h"
11 #include "tools/gn/token.h"
12 #include "tools/gn/value.h"
16 const char kSourcesName
[] = "sources";
18 // Applies the sources assignment filter from the given scope to each element
19 // of source (can be a list or a string), appending it to dest if it doesn't
21 void AppendFilteredSourcesToValue(const Scope
* scope
,
24 const PatternList
* filter
= scope
->GetSourcesAssignmentFilter();
26 if (source
.type() == Value::STRING
) {
27 if (!filter
|| filter
->is_empty() ||
28 !filter
->MatchesValue(source
))
29 dest
->list_value().push_back(source
);
32 if (source
.type() != Value::LIST
) {
33 // Any non-list and non-string being added to a list can just get appended,
34 // we're not going to filter it.
35 dest
->list_value().push_back(source
);
39 const std::vector
<Value
>& source_list
= source
.list_value();
40 if (!filter
|| filter
->is_empty()) {
41 // No filter, append everything.
42 for (size_t i
= 0; i
< source_list
.size(); i
++)
43 dest
->list_value().push_back(source_list
[i
]);
47 // Note: don't reserve() the dest vector here since that actually hurts
48 // the allocation pattern when the build script is doing multiple small
50 for (size_t i
= 0; i
< source_list
.size(); i
++) {
51 if (!filter
->MatchesValue(source_list
[i
]))
52 dest
->list_value().push_back(source_list
[i
]);
56 Value
GetValueOrFillError(const BinaryOpNode
* op_node
,
57 const ParseNode
* node
,
61 Value value
= node
->Execute(scope
, err
);
64 if (value
.type() == Value::NONE
) {
65 *err
= Err(op_node
->op(),
66 "Operator requires a value.",
67 "This thing on the " + std::string(name
) +
68 " does not evaluate to a value.");
69 err
->AppendRange(node
->GetRange());
75 void RemoveMatchesFromList(const BinaryOpNode
* op_node
,
77 const Value
& to_remove
,
79 std::vector
<Value
>& v
= list
->list_value();
80 switch (to_remove
.type()) {
82 case Value::INTEGER
: // Filter out the individual int/string.
84 bool found_match
= false;
85 for (size_t i
= 0; i
< v
.size(); /* nothing */) {
86 if (v
[i
] == to_remove
) {
88 v
.erase(v
.begin() + i
);
94 *err
= Err(to_remove
.origin()->GetRange(), "Item not found",
95 "You were trying to remove " + to_remove
.ToString(true) +
96 "\nfrom the list but it wasn't there.");
101 case Value::LIST
: // Filter out each individual thing.
102 for (size_t i
= 0; i
< to_remove
.list_value().size(); i
++) {
103 // TODO(brettw) if the nested item is a list, we may want to search
104 // for the literal list rather than remote the items in it.
105 RemoveMatchesFromList(op_node
, list
, to_remove
.list_value()[i
], err
);
106 if (err
->has_error())
116 // Assignment -----------------------------------------------------------------
118 // We return a null value from this rather than the result of doing the append.
119 // See ValuePlusEquals for rationale.
120 Value
ExecuteEquals(Scope
* scope
,
121 const BinaryOpNode
* op_node
,
125 const Value
* old_value
= scope
->GetValue(left
.value(), false);
127 // Throw an error when overwriting a nonempty list with another nonempty
128 // list item. This is to detect the case where you write
130 // and you overwrote inherited ones, when instead you mean to append:
131 // defines += ["FOO"]
132 if (old_value
->type() == Value::LIST
&&
133 !old_value
->list_value().empty() &&
134 right
.type() == Value::LIST
&&
135 !right
.list_value().empty()) {
136 *err
= Err(op_node
->left()->GetRange(), "Replacing nonempty list.",
137 std::string("This overwrites a previously-defined nonempty list ") +
139 base::IntToString(static_cast<int>(old_value
->list_value().size()))
141 err
->AppendSubErr(Err(*old_value
, "for previous definition",
142 "with another one (length " +
143 base::IntToString(static_cast<int>(right
.list_value().size())) +
145 "\"+=\" to append instead? If you\nreally want to do this, do\n " +
146 left
.value().as_string() + " = []\nbefore reassigning."));
150 if (err
->has_error())
153 if (right
.type() == Value::LIST
&& left
.value() == kSourcesName
) {
154 // Assigning to sources, filter the list. Here we do the filtering and
155 // copying in one step to save an extra list copy (the lists may be
157 Value
* set_value
= scope
->SetValue(left
.value(),
158 Value(op_node
, Value::LIST
), op_node
);
159 set_value
->list_value().reserve(right
.list_value().size());
160 AppendFilteredSourcesToValue(scope
, right
, set_value
);
162 // Normal value set, just copy it.
163 scope
->SetValue(left
.value(), right
, op_node
->right());
168 // allow_type_conversion indicates if we're allowed to change the type of the
169 // left value. This is set to true when doing +, and false when doing +=.
171 // Note that we return Value() from here, which is different than C++. This
172 // means you can't do clever things like foo = [ bar += baz ] to simultaneously
173 // append to and use a value. This is basically never needed in out build
174 // scripts and is just as likely an error as the intended behavior, and it also
175 // involves a copy of the value when it's returned. Many times we're appending
176 // to large lists, and copying the value to discard it for the next statement
178 void ValuePlusEquals(const Scope
* scope
,
179 const BinaryOpNode
* op_node
,
180 const Token
& left_token
,
183 bool allow_type_conversion
,
185 switch (left
->type()) {
186 // Left-hand-side int.
188 switch (right
.type()) {
189 case Value::INTEGER
: // int + int -> addition.
190 left
->int_value() += right
.int_value();
193 case Value::STRING
: // int + string -> string concat.
194 if (allow_type_conversion
) {
195 *left
= Value(op_node
,
196 base::Int64ToString(left
->int_value()) + right
.string_value());
206 // Left-hand-side string.
208 switch (right
.type()) {
209 case Value::INTEGER
: // string + int -> string concat.
210 left
->string_value().append(base::Int64ToString(right
.int_value()));
213 case Value::STRING
: // string + string -> string contat.
214 left
->string_value().append(right
.string_value());
222 // Left-hand-side list.
224 switch (right
.type()) {
225 case Value::LIST
: // list + list -> list concat.
226 if (left_token
.value() == kSourcesName
) {
227 // Filter additions through the assignment filter.
228 AppendFilteredSourcesToValue(scope
, right
, left
);
230 // Normal list concat.
231 for (size_t i
= 0; i
< right
.list_value().size(); i
++)
232 left
->list_value().push_back(right
.list_value()[i
]);
237 *err
= Err(op_node
->op(), "Incompatible types to add.",
238 "To append a single item to a list do \"foo += [ bar ]\".");
246 *err
= Err(op_node
->op(), "Incompatible types to add.",
247 std::string("I see a ") + Value::DescribeType(left
->type()) + " and a " +
248 Value::DescribeType(right
.type()) + ".");
251 Value
ExecutePlusEquals(Scope
* scope
,
252 const BinaryOpNode
* op_node
,
256 // We modify in-place rather than doing read-modify-write to avoid
257 // copying large lists.
259 scope
->GetValueForcedToCurrentScope(left
.value(), op_node
);
261 *err
= Err(left
, "Undefined variable for +=.",
262 "I don't have something with this name in scope now.");
265 ValuePlusEquals(scope
, op_node
, left
, left_value
, right
, false, err
);
266 left_value
->set_origin(op_node
);
267 scope
->MarkUnused(left
.value());
271 // We return a null value from this rather than the result of doing the append.
272 // See ValuePlusEquals for rationale.
273 void ValueMinusEquals(const BinaryOpNode
* op_node
,
276 bool allow_type_conversion
,
278 switch (left
->type()) {
279 // Left-hand-side int.
281 switch (right
.type()) {
282 case Value::INTEGER
: // int - int -> subtraction.
283 left
->int_value() -= right
.int_value();
291 // Left-hand-side string.
293 break; // All are errors.
295 // Left-hand-side list.
297 if (right
.type() != Value::LIST
) {
298 *err
= Err(op_node
->op(), "Incompatible types to subtract.",
299 "To remove a single item from a list do \"foo -= [ bar ]\".");
301 RemoveMatchesFromList(op_node
, left
, right
, err
);
309 *err
= Err(op_node
->op(), "Incompatible types to subtract.",
310 std::string("I see a ") + Value::DescribeType(left
->type()) + " and a " +
311 Value::DescribeType(right
.type()) + ".");
314 Value
ExecuteMinusEquals(Scope
* scope
,
315 const BinaryOpNode
* op_node
,
320 scope
->GetValueForcedToCurrentScope(left
.value(), op_node
);
322 *err
= Err(left
, "Undefined variable for -=.",
323 "I don't have something with this name in scope now.");
326 ValueMinusEquals(op_node
, left_value
, right
, false, err
);
327 left_value
->set_origin(op_node
);
328 scope
->MarkUnused(left
.value());
332 // Plus/Minus -----------------------------------------------------------------
334 Value
ExecutePlus(Scope
* scope
,
335 const BinaryOpNode
* op_node
,
340 ValuePlusEquals(scope
, op_node
, Token(), &ret
, right
, true, err
);
341 ret
.set_origin(op_node
);
345 Value
ExecuteMinus(Scope
* scope
,
346 const BinaryOpNode
* op_node
,
351 ValueMinusEquals(op_node
, &ret
, right
, true, err
);
352 ret
.set_origin(op_node
);
356 // Comparison -----------------------------------------------------------------
358 Value
ExecuteEqualsEquals(Scope
* scope
,
359 const BinaryOpNode
* op_node
,
364 return Value(op_node
, true);
365 return Value(op_node
, false);
368 Value
ExecuteNotEquals(Scope
* scope
,
369 const BinaryOpNode
* op_node
,
373 // Evaluate in terms of ==.
374 Value result
= ExecuteEqualsEquals(scope
, op_node
, left
, right
, err
);
375 result
.boolean_value() = !result
.boolean_value();
379 Value
FillNeedsTwoIntegersError(const BinaryOpNode
* op_node
,
383 *err
= Err(op_node
, "Comparison requires two integers.",
384 "This operator can only compare two integers.");
385 err
->AppendRange(left
.origin()->GetRange());
386 err
->AppendRange(right
.origin()->GetRange());
390 Value
ExecuteLessEquals(Scope
* scope
,
391 const BinaryOpNode
* op_node
,
395 if (left
.type() != Value::INTEGER
|| right
.type() != Value::INTEGER
)
396 return FillNeedsTwoIntegersError(op_node
, left
, right
, err
);
397 return Value(op_node
, left
.int_value() <= right
.int_value());
400 Value
ExecuteGreaterEquals(Scope
* scope
,
401 const BinaryOpNode
* op_node
,
405 if (left
.type() != Value::INTEGER
|| right
.type() != Value::INTEGER
)
406 return FillNeedsTwoIntegersError(op_node
, left
, right
, err
);
407 return Value(op_node
, left
.int_value() >= right
.int_value());
410 Value
ExecuteGreater(Scope
* scope
,
411 const BinaryOpNode
* op_node
,
415 if (left
.type() != Value::INTEGER
|| right
.type() != Value::INTEGER
)
416 return FillNeedsTwoIntegersError(op_node
, left
, right
, err
);
417 return Value(op_node
, left
.int_value() > right
.int_value());
420 Value
ExecuteLess(Scope
* scope
,
421 const BinaryOpNode
* op_node
,
425 if (left
.type() != Value::INTEGER
|| right
.type() != Value::INTEGER
)
426 return FillNeedsTwoIntegersError(op_node
, left
, right
, err
);
427 return Value(op_node
, left
.int_value() < right
.int_value());
430 // Binary ----------------------------------------------------------------------
432 Value
ExecuteOr(Scope
* scope
,
433 const BinaryOpNode
* op_node
,
434 const ParseNode
* left_node
,
435 const ParseNode
* right_node
,
437 Value left
= GetValueOrFillError(op_node
, left_node
, "left", scope
, err
);
438 if (err
->has_error())
440 if (left
.type() != Value::BOOLEAN
) {
441 *err
= Err(op_node
->left(), "Left side of || operator is not a boolean.",
442 "Type is \"" + std::string(Value::DescribeType(left
.type())) +
446 if (left
.boolean_value())
447 return Value(op_node
, left
.boolean_value());
449 Value right
= GetValueOrFillError(op_node
, right_node
, "right", scope
, err
);
450 if (err
->has_error())
452 if (right
.type() != Value::BOOLEAN
) {
453 *err
= Err(op_node
->right(), "Right side of || operator is not a boolean.",
454 "Type is \"" + std::string(Value::DescribeType(right
.type())) +
459 return Value(op_node
, left
.boolean_value() || right
.boolean_value());
462 Value
ExecuteAnd(Scope
* scope
,
463 const BinaryOpNode
* op_node
,
464 const ParseNode
* left_node
,
465 const ParseNode
* right_node
,
467 Value left
= GetValueOrFillError(op_node
, left_node
, "left", scope
, err
);
468 if (err
->has_error())
470 if (left
.type() != Value::BOOLEAN
) {
471 *err
= Err(op_node
->left(), "Left side of && operator is not a boolean.",
472 "Type is \"" + std::string(Value::DescribeType(left
.type())) +
476 if (!left
.boolean_value())
477 return Value(op_node
, left
.boolean_value());
479 Value right
= GetValueOrFillError(op_node
, right_node
, "right", scope
, err
);
480 if (err
->has_error())
482 if (right
.type() != Value::BOOLEAN
) {
483 *err
= Err(op_node
->right(), "Right side of && operator is not a boolean.",
484 "Type is \"" + std::string(Value::DescribeType(right
.type())) +
488 return Value(op_node
, left
.boolean_value() && right
.boolean_value());
493 // ----------------------------------------------------------------------------
495 bool IsUnaryOperator(const Token
& token
) {
496 return token
.type() == Token::BANG
;
499 bool IsBinaryOperator(const Token
& token
) {
500 return token
.type() == Token::EQUAL
||
501 token
.type() == Token::PLUS
||
502 token
.type() == Token::MINUS
||
503 token
.type() == Token::PLUS_EQUALS
||
504 token
.type() == Token::MINUS_EQUALS
||
505 token
.type() == Token::EQUAL_EQUAL
||
506 token
.type() == Token::NOT_EQUAL
||
507 token
.type() == Token::LESS_EQUAL
||
508 token
.type() == Token::GREATER_EQUAL
||
509 token
.type() == Token::LESS_THAN
||
510 token
.type() == Token::GREATER_THAN
||
511 token
.type() == Token::BOOLEAN_AND
||
512 token
.type() == Token::BOOLEAN_OR
;
515 bool IsFunctionCallArgBeginScoper(const Token
& token
) {
516 return token
.type() == Token::LEFT_PAREN
;
519 bool IsFunctionCallArgEndScoper(const Token
& token
) {
520 return token
.type() == Token::RIGHT_PAREN
;
523 bool IsScopeBeginScoper(const Token
& token
) {
524 return token
.type() == Token::LEFT_BRACE
;
527 bool IsScopeEndScoper(const Token
& token
) {
528 return token
.type() == Token::RIGHT_BRACE
;
531 Value
ExecuteUnaryOperator(Scope
* scope
,
532 const UnaryOpNode
* op_node
,
535 DCHECK(op_node
->op().type() == Token::BANG
);
537 if (expr
.type() != Value::BOOLEAN
) {
538 *err
= Err(op_node
, "Operand of ! operator is not a boolean.",
539 "Type is \"" + std::string(Value::DescribeType(expr
.type())) +
543 // TODO(scottmg): Why no unary minus?
544 return Value(op_node
, !expr
.boolean_value());
547 Value
ExecuteBinaryOperator(Scope
* scope
,
548 const BinaryOpNode
* op_node
,
549 const ParseNode
* left
,
550 const ParseNode
* right
,
552 const Token
& op
= op_node
->op();
554 // First handle the ones that take an lvalue.
555 if (op
.type() == Token::EQUAL
||
556 op
.type() == Token::PLUS_EQUALS
||
557 op
.type() == Token::MINUS_EQUALS
) {
558 const IdentifierNode
* left_id
= left
->AsIdentifier();
560 *err
= Err(op
, "Operator requires a lvalue.",
561 "This thing on the left is not an identifier.");
562 err
->AppendRange(left
->GetRange());
565 const Token
& dest
= left_id
->value();
567 Value right_value
= right
->Execute(scope
, err
);
568 if (err
->has_error())
570 if (right_value
.type() == Value::NONE
) {
571 *err
= Err(op
, "Operator requires a rvalue.",
572 "This thing on the right does not evaluate to a value.");
573 err
->AppendRange(right
->GetRange());
577 if (op
.type() == Token::EQUAL
)
578 return ExecuteEquals(scope
, op_node
, dest
, right_value
, err
);
579 if (op
.type() == Token::PLUS_EQUALS
)
580 return ExecutePlusEquals(scope
, op_node
, dest
, right_value
, err
);
581 if (op
.type() == Token::MINUS_EQUALS
)
582 return ExecuteMinusEquals(scope
, op_node
, dest
, right_value
, err
);
587 // ||, &&. Passed the node instead of the value so that they can avoid
588 // evaluating the RHS on early-out.
589 if (op
.type() == Token::BOOLEAN_OR
)
590 return ExecuteOr(scope
, op_node
, left
, right
, err
);
591 if (op
.type() == Token::BOOLEAN_AND
)
592 return ExecuteAnd(scope
, op_node
, left
, right
, err
);
594 Value left_value
= GetValueOrFillError(op_node
, left
, "left", scope
, err
);
595 if (err
->has_error())
597 Value right_value
= GetValueOrFillError(op_node
, right
, "right", scope
, err
);
598 if (err
->has_error())
602 if (op
.type() == Token::MINUS
)
603 return ExecuteMinus(scope
, op_node
, left_value
, right_value
, err
);
604 if (op
.type() == Token::PLUS
)
605 return ExecutePlus(scope
, op_node
, left_value
, right_value
, err
);
608 if (op
.type() == Token::EQUAL_EQUAL
)
609 return ExecuteEqualsEquals(scope
, op_node
, left_value
, right_value
, err
);
610 if (op
.type() == Token::NOT_EQUAL
)
611 return ExecuteNotEquals(scope
, op_node
, left_value
, right_value
, err
);
612 if (op
.type() == Token::GREATER_EQUAL
)
613 return ExecuteGreaterEquals(scope
, op_node
, left_value
, right_value
, err
);
614 if (op
.type() == Token::LESS_EQUAL
)
615 return ExecuteLessEquals(scope
, op_node
, left_value
, right_value
, err
);
616 if (op
.type() == Token::GREATER_THAN
)
617 return ExecuteGreater(scope
, op_node
, left_value
, right_value
, err
);
618 if (op
.type() == Token::LESS_THAN
)
619 return ExecuteLess(scope
, op_node
, left_value
, right_value
, err
);