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::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 
     96 Value 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 +=.
    163 void 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 
    242 Value 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 
    262 void 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 
    298 Value 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 
    318 Value 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 
    329 Value 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 
    342 Value 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 
    352 Value 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.boolean_value() = !result.boolean_value();
    360   return result;
    361 }
    362 
    363 Value 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 
    374 Value 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 
    384 Value 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 
    394 Value 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 
    404 Value 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 
    416 Value 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 
    431 Value 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 
    450 bool IsUnaryOperator(const Token& token) {
    451   return token.type() == Token::BANG;
    452 }
    453 
    454 bool 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 
    470 bool IsFunctionCallArgBeginScoper(const Token& token) {
    471   return token.type() == Token::LEFT_PAREN;
    472 }
    473 
    474 bool IsFunctionCallArgEndScoper(const Token& token) {
    475   return token.type() == Token::RIGHT_PAREN;
    476 }
    477 
    478 bool IsScopeBeginScoper(const Token& token) {
    479   return token.type() == Token::LEFT_BRACE;
    480 }
    481 
    482 bool IsScopeEndScoper(const Token& token) {
    483   return token.type() == Token::RIGHT_BRACE;
    484 }
    485 
    486 Value 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 
    501 Value 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