Fix click-to-play positioning.
[chromium-blink-merge.git] / tools / gn / operators.cc
blob3a815ea34fc31bd33dba7ed0e442f3878586e2a1
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"
14 namespace {
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
20 // match.
21 void AppendFilteredSourcesToValue(const Scope* scope,
22 const Value& source,
23 Value* dest) {
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);
30 return;
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);
36 return;
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]);
44 return;
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
49 // additions.
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,
58 const char* name,
59 Scope* scope,
60 Err* err) {
61 Value value = node->Execute(scope, err);
62 if (err->has_error())
63 return Value();
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());
70 return Value();
72 return value;
75 void RemoveMatchesFromList(const BinaryOpNode* op_node,
76 Value* list,
77 const Value& to_remove,
78 Err* err) {
79 std::vector<Value>& v = list->list_value();
80 switch (to_remove.type()) {
81 case Value::BOOLEAN:
82 case Value::INTEGER: // Filter out the individual int/string.
83 case Value::STRING: {
84 bool found_match = false;
85 for (size_t i = 0; i < v.size(); /* nothing */) {
86 if (v[i] == to_remove) {
87 found_match = true;
88 v.erase(v.begin() + i);
89 } else {
90 i++;
93 if (!found_match) {
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.");
98 break;
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())
107 return;
109 break;
111 default:
112 break;
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,
122 const Token& left,
123 const Value& right,
124 Err* err) {
125 const Value* old_value = scope->GetValue(left.value(), false);
126 if (old_value) {
127 // Throw an error when overwriting a nonempty list with another nonempty
128 // list item. This is to detect the case where you write
129 // defines = ["FOO"]
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 ") +
138 "(length " +
139 base::IntToString(static_cast<int>(old_value->list_value().size()))
140 + ").");
141 err->AppendSubErr(Err(*old_value, "for previous definition",
142 "with another one (length " +
143 base::IntToString(static_cast<int>(right.list_value().size())) +
144 "). Did you mean " +
145 "\"+=\" to append instead? If you\nreally want to do this, do\n " +
146 left.value().as_string() + " = []\nbefore reassigning."));
147 return Value();
150 if (err->has_error())
151 return Value();
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
156 // long).
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);
161 } else {
162 // Normal value set, just copy it.
163 scope->SetValue(left.value(), right, op_node->right());
165 return Value();
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
177 // is very wasteful.
178 void ValuePlusEquals(const Scope* scope,
179 const BinaryOpNode* op_node,
180 const Token& left_token,
181 Value* left,
182 const Value& right,
183 bool allow_type_conversion,
184 Err* err) {
185 switch (left->type()) {
186 // Left-hand-side int.
187 case Value::INTEGER:
188 switch (right.type()) {
189 case Value::INTEGER: // int + int -> addition.
190 left->int_value() += right.int_value();
191 return;
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());
197 return;
199 break;
201 default:
202 break;
204 break;
206 // Left-hand-side string.
207 case Value::STRING:
208 switch (right.type()) {
209 case Value::INTEGER: // string + int -> string concat.
210 left->string_value().append(base::Int64ToString(right.int_value()));
211 return;
213 case Value::STRING: // string + string -> string contat.
214 left->string_value().append(right.string_value());
215 return;
217 default:
218 break;
220 break;
222 // Left-hand-side list.
223 case Value::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);
229 } else {
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]);
234 return;
236 default:
237 *err = Err(op_node->op(), "Incompatible types to add.",
238 "To append a single item to a list do \"foo += [ bar ]\".");
239 return;
242 default:
243 break;
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,
253 const Token& left,
254 const Value& right,
255 Err* err) {
256 // We modify in-place rather than doing read-modify-write to avoid
257 // copying large lists.
258 Value* left_value =
259 scope->GetValueForcedToCurrentScope(left.value(), op_node);
260 if (!left_value) {
261 *err = Err(left, "Undefined variable for +=.",
262 "I don't have something with this name in scope now.");
263 return Value();
265 ValuePlusEquals(scope, op_node, left, left_value, right, false, err);
266 left_value->set_origin(op_node);
267 scope->MarkUnused(left.value());
268 return 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,
274 Value* left,
275 const Value& right,
276 bool allow_type_conversion,
277 Err* err) {
278 switch (left->type()) {
279 // Left-hand-side int.
280 case Value::INTEGER:
281 switch (right.type()) {
282 case Value::INTEGER: // int - int -> subtraction.
283 left->int_value() -= right.int_value();
284 return;
286 default:
287 break;
289 break;
291 // Left-hand-side string.
292 case Value::STRING:
293 break; // All are errors.
295 // Left-hand-side list.
296 case Value::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 ]\".");
300 } else {
301 RemoveMatchesFromList(op_node, left, right, err);
303 return;
305 default:
306 break;
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,
316 const Token& left,
317 const Value& right,
318 Err* err) {
319 Value* left_value =
320 scope->GetValueForcedToCurrentScope(left.value(), op_node);
321 if (!left_value) {
322 *err = Err(left, "Undefined variable for -=.",
323 "I don't have something with this name in scope now.");
324 return Value();
326 ValueMinusEquals(op_node, left_value, right, false, err);
327 left_value->set_origin(op_node);
328 scope->MarkUnused(left.value());
329 return Value();
332 // Plus/Minus -----------------------------------------------------------------
334 Value ExecutePlus(Scope* scope,
335 const BinaryOpNode* op_node,
336 const Value& left,
337 const Value& right,
338 Err* err) {
339 Value ret = left;
340 ValuePlusEquals(scope, op_node, Token(), &ret, right, true, err);
341 ret.set_origin(op_node);
342 return ret;
345 Value ExecuteMinus(Scope* scope,
346 const BinaryOpNode* op_node,
347 const Value& left,
348 const Value& right,
349 Err* err) {
350 Value ret = left;
351 ValueMinusEquals(op_node, &ret, right, true, err);
352 ret.set_origin(op_node);
353 return ret;
356 // Comparison -----------------------------------------------------------------
358 Value ExecuteEqualsEquals(Scope* scope,
359 const BinaryOpNode* op_node,
360 const Value& left,
361 const Value& right,
362 Err* err) {
363 if (left == right)
364 return Value(op_node, true);
365 return Value(op_node, false);
368 Value ExecuteNotEquals(Scope* scope,
369 const BinaryOpNode* op_node,
370 const Value& left,
371 const Value& right,
372 Err* err) {
373 // Evaluate in terms of ==.
374 Value result = ExecuteEqualsEquals(scope, op_node, left, right, err);
375 result.boolean_value() = !result.boolean_value();
376 return result;
379 Value FillNeedsTwoIntegersError(const BinaryOpNode* op_node,
380 const Value& left,
381 const Value& right,
382 Err* err) {
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());
387 return Value();
390 Value ExecuteLessEquals(Scope* scope,
391 const BinaryOpNode* op_node,
392 const Value& left,
393 const Value& right,
394 Err* err) {
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,
402 const Value& left,
403 const Value& right,
404 Err* err) {
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,
412 const Value& left,
413 const Value& right,
414 Err* err) {
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,
422 const Value& left,
423 const Value& right,
424 Err* err) {
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,
436 Err* err) {
437 Value left = GetValueOrFillError(op_node, left_node, "left", scope, err);
438 if (err->has_error())
439 return Value();
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())) +
443 "\" instead.");
444 return Value();
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())
451 return Value();
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())) +
455 "\" instead.");
456 return Value();
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,
466 Err* err) {
467 Value left = GetValueOrFillError(op_node, left_node, "left", scope, err);
468 if (err->has_error())
469 return Value();
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())) +
473 "\" instead.");
474 return Value();
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())
481 return Value();
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())) +
485 "\" instead.");
486 return Value();
488 return Value(op_node, left.boolean_value() && right.boolean_value());
491 } // namespace
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,
533 const Value& expr,
534 Err* err) {
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())) +
540 "\" instead.");
541 return Value();
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,
551 Err* err) {
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();
559 if (!left_id) {
560 *err = Err(op, "Operator requires a lvalue.",
561 "This thing on the left is not an identifier.");
562 err->AppendRange(left->GetRange());
563 return Value();
565 const Token& dest = left_id->value();
567 Value right_value = right->Execute(scope, err);
568 if (err->has_error())
569 return Value();
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());
574 return Value();
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);
583 NOTREACHED();
584 return Value();
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())
596 return Value();
597 Value right_value = GetValueOrFillError(op_node, right, "right", scope, err);
598 if (err->has_error())
599 return Value();
601 // +, -.
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);
607 // Comparisons.
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);
621 return Value();