operators.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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  if (source.type() == Value::STRING) {
27    if (!filter || filter->is_empty() ||
28        !filter->MatchesValue(source))
29      dest->list_value().push_back(source);
30    return;
31  }
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;
37  }
38
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;
45  }
46
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]);
53  }
54}
55
56void RemoveMatchesFromList(const BinaryOpNode* op_node,
57                           Value* list,
58                           const Value& to_remove,
59                           Err* err) {
60  std::vector<Value>& v = list->list_value();
61  switch (to_remove.type()) {
62    case Value::BOOLEAN:
63    case Value::INTEGER:  // Filter out the individual int/string.
64    case Value::STRING: {
65      bool found_match = false;
66      for (size_t i = 0; i < v.size(); /* nothing */) {
67        if (v[i] == to_remove) {
68          found_match = true;
69          v.erase(v.begin() + i);
70        } else {
71          i++;
72        }
73      }
74      if (!found_match) {
75        *err = Err(to_remove.origin()->GetRange(), "Item not found",
76            "You were trying to remove " + to_remove.ToString(true) +
77            "\nfrom the list but it wasn't there.");
78      }
79      break;
80    }
81
82    case Value::LIST:  // Filter out each individual thing.
83      for (size_t i = 0; i < to_remove.list_value().size(); i++) {
84        // TODO(brettw) if the nested item is a list, we may want to search
85        // for the literal list rather than remote the items in it.
86        RemoveMatchesFromList(op_node, list, to_remove.list_value()[i], err);
87        if (err->has_error())
88          return;
89      }
90      break;
91
92    default:
93      break;
94  }
95}
96
97// Assignment -----------------------------------------------------------------
98
99// We return a null value from this rather than the result of doing the append.
100// See ValuePlusEquals for rationale.
101Value ExecuteEquals(Scope* scope,
102                    const BinaryOpNode* op_node,
103                    const Token& left,
104                    const Value& right,
105                    Err* err) {
106  const Value* old_value = scope->GetValue(left.value(), false);
107  if (old_value) {
108    // Throw an error when overwriting a nonempty list with another nonempty
109    // list item. This is to detect the case where you write
110    //   defines = ["FOO"]
111    // and you overwrote inherited ones, when instead you mean to append:
112    //   defines += ["FOO"]
113    if (old_value->type() == Value::LIST &&
114        !old_value->list_value().empty() &&
115        right.type() == Value::LIST &&
116        !right.list_value().empty()) {
117      *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.",
118          std::string("This overwrites a previously-defined nonempty list ") +
119          "(length " +
120          base::IntToString(static_cast<int>(old_value->list_value().size()))
121          + ").");
122      err->AppendSubErr(Err(*old_value, "for previous definition",
123          "with another one (length " +
124          base::IntToString(static_cast<int>(right.list_value().size())) +
125          "). Did you mean " +
126          "\"+=\" to append instead? If you\nreally want to do this, do\n  " +
127          left.value().as_string() + " = []\nbefore reassigning."));
128      return Value();
129    }
130  }
131  if (err->has_error())
132    return Value();
133
134  if (right.type() == Value::LIST && left.value() == kSourcesName) {
135    // Assigning to sources, filter the list. Here we do the filtering and
136    // copying in one step to save an extra list copy (the lists may be
137    // long).
138    Value* set_value = scope->SetValue(left.value(),
139                                       Value(op_node, Value::LIST), op_node);
140    set_value->list_value().reserve(right.list_value().size());
141    AppendFilteredSourcesToValue(scope, right, set_value);
142  } else {
143    // Normal value set, just copy it.
144    scope->SetValue(left.value(), right, op_node->right());
145  }
146  return Value();
147}
148
149// allow_type_conversion indicates if we're allowed to change the type of the
150// left value. This is set to true when doing +, and false when doing +=.
151//
152// Note that we return Value() from here, which is different than C++. This
153// means you can't do clever things like foo = [ bar += baz ] to simultaneously
154// append to and use a value. This is basically never needed in out build
155// scripts and is just as likely an error as the intended behavior, and it also
156// involves a copy of the value when it's returned. Many times we're appending
157// to large lists, and copying the value to discard it for the next statement
158// is very wasteful.
159void ValuePlusEquals(const Scope* scope,
160                     const BinaryOpNode* op_node,
161                     const Token& left_token,
162                     Value* left,
163                     const Value& right,
164                     bool allow_type_conversion,
165                     Err* err) {
166  switch (left->type()) {
167    // Left-hand-side int.
168    case Value::INTEGER:
169      switch (right.type()) {
170        case Value::INTEGER:  // int + int -> addition.
171          left->int_value() += right.int_value();
172          return;
173
174        case Value::STRING:  // int + string -> string concat.
175          if (allow_type_conversion) {
176            *left = Value(op_node,
177                base::Int64ToString(left->int_value()) + right.string_value());
178            return;
179          }
180          break;
181
182        default:
183          break;
184      }
185      break;
186
187    // Left-hand-side string.
188    case Value::STRING:
189      switch (right.type()) {
190        case Value::INTEGER:  // string + int -> string concat.
191          left->string_value().append(base::Int64ToString(right.int_value()));
192          return;
193
194        case Value::STRING:  // string + string -> string contat.
195          left->string_value().append(right.string_value());
196          return;
197
198        default:
199          break;
200      }
201      break;
202
203    // Left-hand-side list.
204    case Value::LIST:
205      switch (right.type()) {
206        case Value::LIST:  // list + list -> list concat.
207          if (left_token.value() == kSourcesName) {
208            // Filter additions through the assignment filter.
209            AppendFilteredSourcesToValue(scope, right, left);
210          } else {
211            // Normal list concat.
212            for (size_t i = 0; i < right.list_value().size(); i++)
213              left->list_value().push_back(right.list_value()[i]);
214          }
215          return;
216
217        default:
218          *err = Err(op_node->op(), "Incompatible types to add.",
219              "To append a single item to a list do \"foo += [ bar ]\".");
220          return;
221      }
222
223    default:
224      break;
225  }
226
227  *err = Err(op_node->op(), "Incompatible types to add.",
228      std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
229      Value::DescribeType(right.type()) + ".");
230}
231
232Value ExecutePlusEquals(Scope* scope,
233                        const BinaryOpNode* op_node,
234                        const Token& left,
235                        const Value& right,
236                        Err* err) {
237  // We modify in-place rather than doing read-modify-write to avoid
238  // copying large lists.
239  Value* left_value =
240      scope->GetValueForcedToCurrentScope(left.value(), op_node);
241  if (!left_value) {
242    *err = Err(left, "Undefined variable for +=.",
243        "I don't have something with this name in scope now.");
244    return Value();
245  }
246  ValuePlusEquals(scope, op_node, left, left_value, right, false, err);
247  left_value->set_origin(op_node);
248  scope->MarkUnused(left.value());
249  return Value();
250}
251
252// We return a null value from this rather than the result of doing the append.
253// See ValuePlusEquals for rationale.
254void ValueMinusEquals(const BinaryOpNode* op_node,
255                      Value* left,
256                      const Value& right,
257                      bool allow_type_conversion,
258                      Err* err) {
259  switch (left->type()) {
260    // Left-hand-side int.
261    case Value::INTEGER:
262      switch (right.type()) {
263        case Value::INTEGER:  // int - int -> subtraction.
264          left->int_value() -= right.int_value();
265          return;
266
267        default:
268          break;
269      }
270      break;
271
272    // Left-hand-side string.
273    case Value::STRING:
274      break;  // All are errors.
275
276    // Left-hand-side list.
277    case Value::LIST:
278      if (right.type() != Value::LIST) {
279        *err = Err(op_node->op(), "Incompatible types to subtract.",
280            "To remove a single item from a list do \"foo -= [ bar ]\".");
281      } else {
282        RemoveMatchesFromList(op_node, left, right, err);
283      }
284      return;
285
286    default:
287      break;
288  }
289
290  *err = Err(op_node->op(), "Incompatible types to subtract.",
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, true);
346  return Value(op_node, false);
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.boolean_value() = !result.boolean_value();
357  return result;
358}
359
360Value FillNeedsTwoIntegersError(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 FillNeedsTwoIntegersError(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 FillNeedsTwoIntegersError(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 FillNeedsTwoIntegersError(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 FillNeedsTwoIntegersError(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  if (left.type() != Value::BOOLEAN) {
419    *err = Err(left, "Left side of || operator is not a boolean.");
420    err->AppendRange(op_node->GetRange());
421  } else if (right.type() != Value::BOOLEAN) {
422    *err = Err(right, "Right side of || operator is not a boolean.");
423    err->AppendRange(op_node->GetRange());
424  }
425  return Value(op_node, left.boolean_value() || right.boolean_value());
426}
427
428Value ExecuteAnd(Scope* scope,
429                 const BinaryOpNode* op_node,
430                 const Value& left,
431                 const Value& right,
432                 Err* err) {
433  if (left.type() != Value::BOOLEAN) {
434    *err = Err(left, "Left side of && operator is not a boolean.");
435    err->AppendRange(op_node->GetRange());
436  } else if (right.type() != Value::BOOLEAN) {
437    *err = Err(right, "Right side of && operator is not a boolean.");
438    err->AppendRange(op_node->GetRange());
439  }
440  return Value(op_node, left.boolean_value() && right.boolean_value());
441}
442
443}  // namespace
444
445// ----------------------------------------------------------------------------
446
447bool IsUnaryOperator(const Token& token) {
448  return token.type() == Token::BANG;
449}
450
451bool IsBinaryOperator(const Token& token) {
452  return token.type() == Token::EQUAL ||
453         token.type() == Token::PLUS ||
454         token.type() == Token::MINUS ||
455         token.type() == Token::PLUS_EQUALS ||
456         token.type() == Token::MINUS_EQUALS ||
457         token.type() == Token::EQUAL_EQUAL ||
458         token.type() == Token::NOT_EQUAL ||
459         token.type() == Token::LESS_EQUAL ||
460         token.type() == Token::GREATER_EQUAL ||
461         token.type() == Token::LESS_THAN ||
462         token.type() == Token::GREATER_THAN ||
463         token.type() == Token::BOOLEAN_AND ||
464         token.type() == Token::BOOLEAN_OR;
465}
466
467bool IsFunctionCallArgBeginScoper(const Token& token) {
468  return token.type() == Token::LEFT_PAREN;
469}
470
471bool IsFunctionCallArgEndScoper(const Token& token) {
472  return token.type() == Token::RIGHT_PAREN;
473}
474
475bool IsScopeBeginScoper(const Token& token) {
476  return token.type() == Token::LEFT_BRACE;
477}
478
479bool IsScopeEndScoper(const Token& token) {
480  return token.type() == Token::RIGHT_BRACE;
481}
482
483Value ExecuteUnaryOperator(Scope* scope,
484                           const UnaryOpNode* op_node,
485                           const Value& expr,
486                           Err* err) {
487  DCHECK(op_node->op().type() == Token::BANG);
488
489  if (expr.type() != Value::BOOLEAN) {
490    *err = Err(expr, "Operand of ! operator is not a boolean.");
491    err->AppendRange(op_node->GetRange());
492    return Value();
493  }
494  // TODO(scottmg): Why no unary minus?
495  return Value(op_node, !expr.boolean_value());
496}
497
498Value ExecuteBinaryOperator(Scope* scope,
499                            const BinaryOpNode* op_node,
500                            const ParseNode* left,
501                            const ParseNode* right,
502                            Err* err) {
503  const Token& op = op_node->op();
504
505  // First handle the ones that take an lvalue.
506  if (op.type() == Token::EQUAL ||
507      op.type() == Token::PLUS_EQUALS ||
508      op.type() == Token::MINUS_EQUALS) {
509    const IdentifierNode* left_id = left->AsIdentifier();
510    if (!left_id) {
511      *err = Err(op, "Operator requires a lvalue.",
512                 "This thing on the left is not an identifier.");
513      err->AppendRange(left->GetRange());
514      return Value();
515    }
516    const Token& dest = left_id->value();
517
518    Value right_value = right->Execute(scope, err);
519    if (err->has_error())
520      return Value();
521    if (right_value.type() == Value::NONE) {
522      *err = Err(op, "Operator requires a rvalue.",
523                 "This thing on the right does not evaluate to a value.");
524      err->AppendRange(right->GetRange());
525      return Value();
526    }
527
528    if (op.type() == Token::EQUAL)
529      return ExecuteEquals(scope, op_node, dest, right_value, err);
530    if (op.type() == Token::PLUS_EQUALS)
531      return ExecutePlusEquals(scope, op_node, dest, right_value, err);
532    if (op.type() == Token::MINUS_EQUALS)
533      return ExecuteMinusEquals(scope, op_node, dest, right_value, err);
534    NOTREACHED();
535    return Value();
536  }
537
538  // Left value.
539  Value left_value = left->Execute(scope, err);
540  if (err->has_error())
541    return Value();
542  if (left_value.type() == Value::NONE) {
543    *err = Err(op, "Operator requires a value.",
544               "This thing on the left does not evaluate to a value.");
545    err->AppendRange(left->GetRange());
546    return Value();
547  }
548
549  // Right value. Note: don't move this above to share code with the lvalue
550  // version since in this case we want to execute the left side first.
551  Value right_value = right->Execute(scope, err);
552  if (err->has_error())
553    return Value();
554  if (right_value.type() == Value::NONE) {
555    *err = Err(op, "Operator requires a value.",
556               "This thing on the right does not evaluate to a value.");
557    err->AppendRange(right->GetRange());
558    return Value();
559  }
560
561  // +, -.
562  if (op.type() == Token::MINUS)
563    return ExecuteMinus(scope, op_node, left_value, right_value, err);
564  if (op.type() == Token::PLUS)
565    return ExecutePlus(scope, op_node, left_value, right_value, err);
566
567  // Comparisons.
568  if (op.type() == Token::EQUAL_EQUAL)
569    return ExecuteEqualsEquals(scope, op_node, left_value, right_value, err);
570  if (op.type() == Token::NOT_EQUAL)
571    return ExecuteNotEquals(scope, op_node, left_value, right_value, err);
572  if (op.type() == Token::GREATER_EQUAL)
573    return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err);
574  if (op.type() == Token::LESS_EQUAL)
575    return ExecuteLessEquals(scope, op_node, left_value, right_value, err);
576  if (op.type() == Token::GREATER_THAN)
577    return ExecuteGreater(scope, op_node, left_value, right_value, err);
578  if (op.type() == Token::LESS_THAN)
579    return ExecuteLess(scope, op_node, left_value, right_value, err);
580
581  // ||, &&.
582  if (op.type() == Token::BOOLEAN_OR)
583    return ExecuteOr(scope, op_node, left_value, right_value, err);
584  if (op.type() == Token::BOOLEAN_AND)
585    return ExecuteAnd(scope, op_node, left_value, right_value, err);
586
587  return Value();
588}
589