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