operators.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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 "tools/gn/operators.h"
6
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"
13
14namespace {
15
16const char kSourcesName[] = "sources";
17
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.
21void AppendFilteredSourcesToValue(const Scope* scope,
22                                  const Value& source,
23                                  Value* dest) {
24  const PatternList* filter = scope->GetSourcesAssignmentFilter();
25
26  const std::vector<Value>& source_list = source.list_value();
27
28  if (source.type() == Value::STRING) {
29    if (!filter || filter->is_empty() ||
30        !filter->MatchesValue(source))
31      dest->list_value().push_back(source);
32    return;
33  }
34
35  // Otherwise source is a list.
36  DCHECK(source.type() == Value::LIST);
37  if (!filter || filter->is_empty()) {
38    // No filter, append everything.
39    for (size_t i = 0; i < source_list.size(); i++)
40      dest->list_value().push_back(source_list[i]);
41    return;
42  }
43
44  // Note: don't reserve() the dest vector here since that actually hurts
45  // the allocation pattern when the build script is doing multiple small
46  // additions.
47  for (size_t i = 0; i < source_list.size(); i++) {
48    if (!filter->MatchesValue(source_list[i]))
49      dest->list_value().push_back(source_list[i]);
50  }
51}
52
53void RemoveMatchesFromList(const BinaryOpNode* op_node,
54                           Value* list,
55                           const Value& to_remove,
56                           Err* err) {
57  std::vector<Value>& v = list->list_value();
58  switch (to_remove.type()) {
59    case Value::BOOLEAN:
60    case Value::INTEGER:  // Filter out the individual int/string.
61    case Value::STRING: {
62      bool found_match = false;
63      for (size_t i = 0; i < v.size(); /* nothing */) {
64        if (v[i] == to_remove) {
65          found_match = true;
66          v.erase(v.begin() + i);
67        } else {
68          i++;
69        }
70      }
71      if (!found_match) {
72        *err = Err(to_remove.origin()->GetRange(), "Item not found",
73            "You were trying to remove " + to_remove.ToString(true) +
74            "\nfrom the list but it wasn't there.");
75      }
76      break;
77    }
78
79    case Value::LIST:  // Filter out each individual thing.
80      for (size_t i = 0; i < to_remove.list_value().size(); i++) {
81        // TODO(brettw) if the nested item is a list, we may want to search
82        // for the literal list rather than remote the items in it.
83        RemoveMatchesFromList(op_node, list, to_remove.list_value()[i], err);
84        if (err->has_error())
85          return;
86      }
87      break;
88
89    default:
90      break;
91  }
92}
93
94// Assignment -----------------------------------------------------------------
95
96Value ExecuteEquals(Scope* scope,
97                    const BinaryOpNode* op_node,
98                    const Token& left,
99                    const Value& right,
100                    Err* err) {
101  const Value* old_value = scope->GetValue(left.value(), false);
102  if (old_value) {
103    if (scope->IsSetButUnused(left.value())) {
104      // Throw an error for re-assigning without using the value first. The
105      // exception is that you can overwrite an empty list with another list
106      // since this is the way to get around the "can't overwrite a nonempty
107      // list with another nonempty list" restriction.
108      if (old_value->type() != Value::LIST ||
109          !old_value->list_value().empty()) {
110        *err = Err(op_node->left()->GetRange(), "Overwriting unused variable.",
111            "This overwrites a previous assignment to \"" +
112            left.value().as_string() + "\" that had no effect.");
113        err->AppendSubErr(Err(*scope->GetValue(left.value()),
114                              "Previously set here.",
115                              "Maybe you wanted \"+=\" to append instead?"));
116        return Value();
117      }
118    } else {
119      // Throw an error when overwriting a nonempty list with another nonempty
120      // list item. This is to detect the case where you write
121      //   defines = ["FOO"]
122      // and you overwrote inherited ones, when instead you mean to append:
123      //   defines += ["FOO"]
124      if (old_value->type() == Value::LIST &&
125          !old_value->list_value().empty() &&
126          right.type() == Value::LIST &&
127          !right.list_value().empty()) {
128        *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.",
129            std::string("This overwrites a previously-defined nonempty list ") +
130            "(length " +
131            base::IntToString(static_cast<int>(old_value->list_value().size()))
132            + ").");
133        err->AppendSubErr(Err(*old_value, "for previous definition",
134            "with another one (length " +
135            base::IntToString(static_cast<int>(right.list_value().size())) +
136            "). Did you mean " +
137            "\"+=\" to append instead? If you\nreally want to do this, do\n  " +
138            left.value().as_string() + " = []\nbefore reassigning."));
139        return Value();
140      }
141    }
142  }
143  if (err->has_error())
144    return Value();
145
146  if (right.type() == Value::LIST && left.value() == kSourcesName) {
147    // Assigning to sources, filter the list. Here we do the filtering and
148    // copying in one step to save an extra list copy (the lists may be
149    // long).
150    Value* set_value = scope->SetValue(left.value(),
151                                       Value(op_node, Value::LIST), op_node);
152    set_value->list_value().reserve(right.list_value().size());
153    AppendFilteredSourcesToValue(scope, right, set_value);
154  } else {
155    // Normal value set, just copy it.
156    scope->SetValue(left.value(), right, op_node->right());
157  }
158  return Value();
159}
160
161// allow_type_conversion indicates if we're allowed to change the type of the
162// left value. This is set to true when doing +, and false when doing +=.
163void ValuePlusEquals(const Scope* scope,
164                     const BinaryOpNode* op_node,
165                     const Token& left_token,
166                     Value* left,
167                     const Value& right,
168                     bool allow_type_conversion,
169                     Err* err) {
170  switch (left->type()) {
171    // Left-hand-side int.
172    case Value::INTEGER:
173      switch (right.type()) {
174        case Value::INTEGER:  // int + int -> addition.
175          left->int_value() += right.int_value();
176          return;
177
178        case Value::STRING:  // int + string -> string concat.
179          if (allow_type_conversion) {
180            *left = Value(op_node,
181                base::Int64ToString(left->int_value()) + right.string_value());
182            return;
183          }
184          break;
185
186        default:
187          break;
188      }
189      break;
190
191    // Left-hand-side string.
192    case Value::STRING:
193      switch (right.type()) {
194        case Value::INTEGER:  // string + int -> string concat.
195          left->string_value().append(base::Int64ToString(right.int_value()));
196          return;
197
198        case Value::STRING:  // string + string -> string contat.
199          left->string_value().append(right.string_value());
200          return;
201
202        default:
203          break;
204      }
205      break;
206
207    // Left-hand-side list.
208    case Value::LIST:
209      switch (right.type()) {
210        case Value::INTEGER:  // list + integer -> list append.
211        case Value::STRING:  // list + string -> list append.
212          if (left_token.value() == kSourcesName)
213            AppendFilteredSourcesToValue(scope, right, left);
214          else
215            left->list_value().push_back(right);
216          return;
217
218        case Value::LIST:  // list + list -> list concat.
219          if (left_token.value() == kSourcesName) {
220            // Filter additions through the assignment filter.
221            AppendFilteredSourcesToValue(scope, right, left);
222          } else {
223            // Normal list concat.
224            for (size_t i = 0; i < right.list_value().size(); i++)
225              left->list_value().push_back(right.list_value()[i]);
226          }
227          return;
228
229        default:
230          break;
231      }
232
233    default:
234      break;
235  }
236
237  *err = Err(op_node->op(), "Incompatible types to add.",
238      std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
239      Value::DescribeType(right.type()) + ".");
240}
241
242Value ExecutePlusEquals(Scope* scope,
243                        const BinaryOpNode* op_node,
244                        const Token& left,
245                        const Value& right,
246                        Err* err) {
247  // We modify in-place rather than doing read-modify-write to avoid
248  // copying large lists.
249  Value* left_value =
250      scope->GetValueForcedToCurrentScope(left.value(), op_node);
251  if (!left_value) {
252    *err = Err(left, "Undefined variable for +=.",
253        "I don't have something with this name in scope now.");
254    return Value();
255  }
256  ValuePlusEquals(scope, op_node, left, left_value, right, false, err);
257  left_value->set_origin(op_node);
258  scope->MarkUnused(left.value());
259  return Value();
260}
261
262void ValueMinusEquals(const BinaryOpNode* op_node,
263                      Value* left,
264                      const Value& right,
265                      bool allow_type_conversion,
266                      Err* err) {
267  switch (left->type()) {
268    // Left-hand-side int.
269    case Value::INTEGER:
270      switch (right.type()) {
271        case Value::INTEGER:  // int - int -> subtraction.
272          left->int_value() -= right.int_value();
273          return;
274
275        default:
276          break;
277      }
278      break;
279
280    // Left-hand-side string.
281    case Value::STRING:
282      break;  // All are errors.
283
284    // Left-hand-side list.
285    case Value::LIST:
286      RemoveMatchesFromList(op_node, left, right, err);
287      return;
288
289    default:
290      break;
291  }
292
293  *err = Err(op_node->op(), "Incompatible types to add.",
294      std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
295      Value::DescribeType(right.type()) + ".");
296}
297
298Value ExecuteMinusEquals(Scope* scope,
299                         const BinaryOpNode* op_node,
300                         const Token& left,
301                         const Value& right,
302                         Err* err) {
303  Value* left_value =
304      scope->GetValueForcedToCurrentScope(left.value(), op_node);
305  if (!left_value) {
306    *err = Err(left, "Undefined variable for -=.",
307        "I don't have something with this name in scope now.");
308    return Value();
309  }
310  ValueMinusEquals(op_node, left_value, right, false, err);
311  left_value->set_origin(op_node);
312  scope->MarkUnused(left.value());
313  return Value();
314}
315
316// Plus/Minus -----------------------------------------------------------------
317
318Value ExecutePlus(Scope* scope,
319                  const BinaryOpNode* op_node,
320                  const Value& left,
321                  const Value& right,
322                  Err* err) {
323  Value ret = left;
324  ValuePlusEquals(scope, op_node, Token(), &ret, right, true, err);
325  ret.set_origin(op_node);
326  return ret;
327}
328
329Value ExecuteMinus(Scope* scope,
330                   const BinaryOpNode* op_node,
331                   const Value& left,
332                   const Value& right,
333                   Err* err) {
334  Value ret = left;
335  ValueMinusEquals(op_node, &ret, right, true, err);
336  ret.set_origin(op_node);
337  return ret;
338}
339
340// Comparison -----------------------------------------------------------------
341
342Value ExecuteEqualsEquals(Scope* scope,
343                          const BinaryOpNode* op_node,
344                          const Value& left,
345                          const Value& right,
346                          Err* err) {
347  if (left == right)
348    return Value(op_node, true);
349  return Value(op_node, false);
350}
351
352Value ExecuteNotEquals(Scope* scope,
353                       const BinaryOpNode* op_node,
354                       const Value& left,
355                       const Value& right,
356                       Err* err) {
357  // Evaluate in terms of ==.
358  Value result = ExecuteEqualsEquals(scope, op_node, left, right, err);
359  result.int_value() = static_cast<int64>(!result.int_value());
360  return result;
361}
362
363Value FillNeedsTwoIntegersError(const BinaryOpNode* op_node,
364                                const Value& left,
365                                const Value& right,
366                                Err* err) {
367  *err = Err(op_node, "Comparison requires two integers.",
368             "This operator can only compare two integers.");
369  err->AppendRange(left.origin()->GetRange());
370  err->AppendRange(right.origin()->GetRange());
371  return Value();
372}
373
374Value ExecuteLessEquals(Scope* scope,
375                        const BinaryOpNode* op_node,
376                        const Value& left,
377                        const Value& right,
378                        Err* err) {
379  if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
380    return FillNeedsTwoIntegersError(op_node, left, right, err);
381  return Value(op_node, left.int_value() <= right.int_value());
382}
383
384Value ExecuteGreaterEquals(Scope* scope,
385                           const BinaryOpNode* op_node,
386                           const Value& left,
387                           const Value& right,
388                           Err* err) {
389  if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
390    return FillNeedsTwoIntegersError(op_node, left, right, err);
391  return Value(op_node, left.int_value() >= right.int_value());
392}
393
394Value ExecuteGreater(Scope* scope,
395                     const BinaryOpNode* op_node,
396                     const Value& left,
397                     const Value& right,
398                     Err* err) {
399  if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
400    return FillNeedsTwoIntegersError(op_node, left, right, err);
401  return Value(op_node, left.int_value() > right.int_value());
402}
403
404Value ExecuteLess(Scope* scope,
405                  const BinaryOpNode* op_node,
406                  const Value& left,
407                  const Value& right,
408                  Err* err) {
409  if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
410    return FillNeedsTwoIntegersError(op_node, left, right, err);
411  return Value(op_node, left.int_value() < right.int_value());
412}
413
414// Binary ----------------------------------------------------------------------
415
416Value ExecuteOr(Scope* scope,
417                const BinaryOpNode* op_node,
418                const Value& left,
419                const Value& right,
420                Err* err) {
421  if (left.type() != Value::BOOLEAN) {
422    *err = Err(left, "Left side of || operator is not a boolean.");
423    err->AppendRange(op_node->GetRange());
424  } else if (right.type() != Value::BOOLEAN) {
425    *err = Err(right, "Right side of || operator is not a boolean.");
426    err->AppendRange(op_node->GetRange());
427  }
428  return Value(op_node, left.boolean_value() || right.boolean_value());
429}
430
431Value ExecuteAnd(Scope* scope,
432                 const BinaryOpNode* op_node,
433                 const Value& left,
434                 const Value& right,
435                 Err* err) {
436  if (left.type() != Value::BOOLEAN) {
437    *err = Err(left, "Left side of && operator is not a boolean.");
438    err->AppendRange(op_node->GetRange());
439  } else if (right.type() != Value::BOOLEAN) {
440    *err = Err(right, "Right side of && operator is not a boolean.");
441    err->AppendRange(op_node->GetRange());
442  }
443  return Value(op_node, left.boolean_value() && right.boolean_value());
444}
445
446}  // namespace
447
448// ----------------------------------------------------------------------------
449
450bool IsUnaryOperator(const Token& token) {
451  return token.type() == Token::BANG;
452}
453
454bool IsBinaryOperator(const Token& token) {
455  return token.type() == Token::EQUAL ||
456         token.type() == Token::PLUS ||
457         token.type() == Token::MINUS ||
458         token.type() == Token::PLUS_EQUALS ||
459         token.type() == Token::MINUS_EQUALS ||
460         token.type() == Token::EQUAL_EQUAL ||
461         token.type() == Token::NOT_EQUAL ||
462         token.type() == Token::LESS_EQUAL ||
463         token.type() == Token::GREATER_EQUAL ||
464         token.type() == Token::LESS_THAN ||
465         token.type() == Token::GREATER_THAN ||
466         token.type() == Token::BOOLEAN_AND ||
467         token.type() == Token::BOOLEAN_OR;
468}
469
470bool IsFunctionCallArgBeginScoper(const Token& token) {
471  return token.type() == Token::LEFT_PAREN;
472}
473
474bool IsFunctionCallArgEndScoper(const Token& token) {
475  return token.type() == Token::RIGHT_PAREN;
476}
477
478bool IsScopeBeginScoper(const Token& token) {
479  return token.type() == Token::LEFT_BRACE;
480}
481
482bool IsScopeEndScoper(const Token& token) {
483  return token.type() == Token::RIGHT_BRACE;
484}
485
486Value ExecuteUnaryOperator(Scope* scope,
487                           const UnaryOpNode* op_node,
488                           const Value& expr,
489                           Err* err) {
490  DCHECK(op_node->op().type() == Token::BANG);
491
492  if (expr.type() != Value::BOOLEAN) {
493    *err = Err(expr, "Operand of ! operator is not a boolean.");
494    err->AppendRange(op_node->GetRange());
495    return Value();
496  }
497  // TODO(scottmg): Why no unary minus?
498  return Value(op_node, !expr.boolean_value());
499}
500
501Value ExecuteBinaryOperator(Scope* scope,
502                            const BinaryOpNode* op_node,
503                            const ParseNode* left,
504                            const ParseNode* right,
505                            Err* err) {
506  const Token& op = op_node->op();
507
508  // First handle the ones that take an lvalue.
509  if (op.type() == Token::EQUAL ||
510      op.type() == Token::PLUS_EQUALS ||
511      op.type() == Token::MINUS_EQUALS) {
512    const IdentifierNode* left_id = left->AsIdentifier();
513    if (!left_id) {
514      *err = Err(op, "Operator requires an lvalue.",
515                 "This thing on the left is not an idenfitier.");
516      err->AppendRange(left->GetRange());
517      return Value();
518    }
519    const Token& dest = left_id->value();
520
521    Value right_value = right->Execute(scope, err);
522    if (err->has_error())
523      return Value();
524    if (right_value.type() == Value::NONE) {
525      *err = Err(op, "Operator requires an rvalue.",
526                 "This thing on the right does not evaluate to a value.");
527      err->AppendRange(right->GetRange());
528      return Value();
529    }
530
531    if (op.type() == Token::EQUAL)
532      return ExecuteEquals(scope, op_node, dest, right_value, err);
533    if (op.type() == Token::PLUS_EQUALS)
534      return ExecutePlusEquals(scope, op_node, dest, right_value, err);
535    if (op.type() == Token::MINUS_EQUALS)
536      return ExecuteMinusEquals(scope, op_node, dest, right_value, err);
537    NOTREACHED();
538    return Value();
539  }
540
541  // Left value.
542  Value left_value = left->Execute(scope, err);
543  if (err->has_error())
544    return Value();
545  if (left_value.type() == Value::NONE) {
546    *err = Err(op, "Operator requires an value.",
547               "This thing on the left does not evaluate to a value.");
548    err->AppendRange(left->GetRange());
549    return Value();
550  }
551
552  // Right value. Note: don't move this above to share code with the lvalue
553  // version since in this case we want to execute the left side first.
554  Value right_value = right->Execute(scope, err);
555  if (err->has_error())
556    return Value();
557  if (right_value.type() == Value::NONE) {
558    *err = Err(op, "Operator requires an value.",
559               "This thing on the right does not evaluate to a value.");
560    err->AppendRange(right->GetRange());
561    return Value();
562  }
563
564  // +, -.
565  if (op.type() == Token::MINUS)
566    return ExecuteMinus(scope, op_node, left_value, right_value, err);
567  if (op.type() == Token::PLUS)
568    return ExecutePlus(scope, op_node, left_value, right_value, err);
569
570  // Comparisons.
571  if (op.type() == Token::EQUAL_EQUAL)
572    return ExecuteEqualsEquals(scope, op_node, left_value, right_value, err);
573  if (op.type() == Token::NOT_EQUAL)
574    return ExecuteNotEquals(scope, op_node, left_value, right_value, err);
575  if (op.type() == Token::GREATER_EQUAL)
576    return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err);
577  if (op.type() == Token::LESS_EQUAL)
578    return ExecuteLessEquals(scope, op_node, left_value, right_value, err);
579  if (op.type() == Token::GREATER_THAN)
580    return ExecuteGreater(scope, op_node, left_value, right_value, err);
581  if (op.type() == Token::LESS_THAN)
582    return ExecuteLess(scope, op_node, left_value, right_value, err);
583
584  // ||, &&.
585  if (op.type() == Token::BOOLEAN_OR)
586    return ExecuteOr(scope, op_node, left_value, right_value, err);
587  if (op.type() == Token::BOOLEAN_AND)
588    return ExecuteAnd(scope, op_node, left_value, right_value, err);
589
590  return Value();
591}
592