Home | History | Annotate | Download | only in gn
      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 
     14 namespace {
     15 
     16 const 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.
     21 void 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 
     53 void 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 
     95 Value 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 +=.
    160 void 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 
    239 Value 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 
    259 void 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 
    295 Value 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 
    315 Value 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 
    326 Value 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 
    339 Value 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 
    349 Value 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 
    360 Value 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 
    371 Value 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 
    381 Value 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 
    391 Value 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 
    401 Value 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 
    413 Value 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 
    422 Value 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 
    435 bool IsUnaryOperator(const Token& token) {
    436   if (token.type() != Token::OPERATOR)
    437     return false;
    438   return token.value() == "!";
    439 }
    440 
    441 bool 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 
    459 bool IsFunctionCallArgBeginScoper(const Token& token) {
    460   return token.IsScoperEqualTo("(");
    461 }
    462 
    463 bool IsFunctionCallArgEndScoper(const Token& token) {
    464   return token.IsScoperEqualTo(")");
    465 }
    466 
    467 bool IsScopeBeginScoper(const Token& token) {
    468   return token.IsScoperEqualTo("{");
    469 }
    470 
    471 bool IsScopeEndScoper(const Token& token) {
    472   return token.IsScoperEqualTo("}");
    473 }
    474 
    475 Value 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 
    483 Value 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