1d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// found in the LICENSE file.
4d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
5d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/operators.h"
6d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
7d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "base/strings/string_number_conversions.h"
8d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/err.h"
9d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/parse_tree.h"
10d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/scope.h"
11d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/token.h"
12d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "tools/gn/value.h"
13d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
14d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochnamespace {
15d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
16d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochconst char kSourcesName[] = "sources";
17d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
18d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Applies the sources assignment filter from the given scope to each element
19d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// of source (can be a list or a string), appending it to dest if it doesn't
20d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// match.
21d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid AppendFilteredSourcesToValue(const Scope* scope,
22d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                  const Value& source,
23d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                  Value* dest) {
24d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const PatternList* filter = scope->GetSourcesAssignmentFilter();
25d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
26d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (source.type() == Value::STRING) {
27d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (!filter || filter->is_empty() ||
28d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        !filter->MatchesValue(source))
29d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      dest->list_value().push_back(source);
30d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return;
31d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (source.type() != Value::LIST) {
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Any non-list and non-string being added to a list can just get appended,
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // we're not going to filter it.
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dest->list_value().push_back(source);
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
38d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::vector<Value>& source_list = source.list_value();
40d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!filter || filter->is_empty()) {
41d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // No filter, append everything.
42d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    for (size_t i = 0; i < source_list.size(); i++)
43d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      dest->list_value().push_back(source_list[i]);
44d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return;
45d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
46d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
47d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Note: don't reserve() the dest vector here since that actually hurts
48d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // the allocation pattern when the build script is doing multiple small
49d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // additions.
50d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  for (size_t i = 0; i < source_list.size(); i++) {
51d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (!filter->MatchesValue(source_list[i]))
52d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      dest->list_value().push_back(source_list[i]);
53d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
54d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
55d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
560529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochValue GetValueOrFillError(const BinaryOpNode* op_node,
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          const ParseNode* node,
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          const char* name,
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          Scope* scope,
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          Err* err) {
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Value value = node->Execute(scope, err);
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (err->has_error())
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return Value();
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (value.type() == Value::NONE) {
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    *err = Err(op_node->op(),
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch               "Operator requires a value.",
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch               "This thing on the " + std::string(name) +
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   " does not evaluate to a value.");
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    err->AppendRange(node->GetRange());
700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return Value();
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return value;
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
75d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid RemoveMatchesFromList(const BinaryOpNode* op_node,
76d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           Value* list,
77d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           const Value& to_remove,
78d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           Err* err) {
79d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  std::vector<Value>& v = list->list_value();
80d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  switch (to_remove.type()) {
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case Value::BOOLEAN:
82d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::INTEGER:  // Filter out the individual int/string.
83d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::STRING: {
84d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      bool found_match = false;
85d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      for (size_t i = 0; i < v.size(); /* nothing */) {
86d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        if (v[i] == to_remove) {
87d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          found_match = true;
88d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          v.erase(v.begin() + i);
89d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        } else {
90d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          i++;
91d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        }
92d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
93d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (!found_match) {
94d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        *err = Err(to_remove.origin()->GetRange(), "Item not found",
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "You were trying to remove " + to_remove.ToString(true) +
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            "\nfrom the list but it wasn't there.");
97d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
98d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
99d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
100d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
101d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::LIST:  // Filter out each individual thing.
102d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      for (size_t i = 0; i < to_remove.list_value().size(); i++) {
103d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // TODO(brettw) if the nested item is a list, we may want to search
104d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        // for the literal list rather than remote the items in it.
105d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        RemoveMatchesFromList(op_node, list, to_remove.list_value()[i], err);
106d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        if (err->has_error())
107d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return;
108d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
109d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
110d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
111d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    default:
112d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
113d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
114d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
115d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
116d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Assignment -----------------------------------------------------------------
117d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// We return a null value from this rather than the result of doing the append.
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// See ValuePlusEquals for rationale.
120d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteEquals(Scope* scope,
121d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                    const BinaryOpNode* op_node,
122d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                    const Token& left,
123d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                    const Value& right,
124d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                    Err* err) {
125d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const Value* old_value = scope->GetValue(left.value(), false);
126d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (old_value) {
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Throw an error when overwriting a nonempty list with another nonempty
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // list item. This is to detect the case where you write
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    //   defines = ["FOO"]
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // and you overwrote inherited ones, when instead you mean to append:
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    //   defines += ["FOO"]
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (old_value->type() == Value::LIST &&
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !old_value->list_value().empty() &&
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        right.type() == Value::LIST &&
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !right.list_value().empty()) {
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.",
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          std::string("This overwrites a previously-defined nonempty list ") +
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "(length " +
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::IntToString(static_cast<int>(old_value->list_value().size()))
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          + ").");
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      err->AppendSubErr(Err(*old_value, "for previous definition",
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "with another one (length " +
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::IntToString(static_cast<int>(right.list_value().size())) +
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "). Did you mean " +
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "\"+=\" to append instead? If you\nreally want to do this, do\n  " +
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          left.value().as_string() + " = []\nbefore reassigning."));
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return Value();
148d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
149d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
150d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (err->has_error())
151d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return Value();
152d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
153d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (right.type() == Value::LIST && left.value() == kSourcesName) {
154d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Assigning to sources, filter the list. Here we do the filtering and
155d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // copying in one step to save an extra list copy (the lists may be
156d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // long).
157d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    Value* set_value = scope->SetValue(left.value(),
158d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                       Value(op_node, Value::LIST), op_node);
159d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    set_value->list_value().reserve(right.list_value().size());
160d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    AppendFilteredSourcesToValue(scope, right, set_value);
161d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  } else {
162d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Normal value set, just copy it.
163d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    scope->SetValue(left.value(), right, op_node->right());
164d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
165d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value();
166d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
167d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
168d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// allow_type_conversion indicates if we're allowed to change the type of the
169d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// left value. This is set to true when doing +, and false when doing +=.
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Note that we return Value() from here, which is different than C++. This
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// means you can't do clever things like foo = [ bar += baz ] to simultaneously
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// append to and use a value. This is basically never needed in out build
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// scripts and is just as likely an error as the intended behavior, and it also
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// involves a copy of the value when it's returned. Many times we're appending
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// to large lists, and copying the value to discard it for the next statement
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// is very wasteful.
178d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid ValuePlusEquals(const Scope* scope,
179d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     const BinaryOpNode* op_node,
180d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     const Token& left_token,
181d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     Value* left,
182d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     const Value& right,
183d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     bool allow_type_conversion,
184d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     Err* err) {
185d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  switch (left->type()) {
186d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Left-hand-side int.
187d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::INTEGER:
188d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      switch (right.type()) {
189d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Value::INTEGER:  // int + int -> addition.
190d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          left->int_value() += right.int_value();
191d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return;
192d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
193d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Value::STRING:  // int + string -> string concat.
194d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          if (allow_type_conversion) {
195d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            *left = Value(op_node,
196d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                base::Int64ToString(left->int_value()) + right.string_value());
197d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            return;
198d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          }
199d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          break;
200d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
201d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        default:
202d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          break;
203d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
204d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
205d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
206d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Left-hand-side string.
207d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::STRING:
208d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      switch (right.type()) {
209d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Value::INTEGER:  // string + int -> string concat.
210d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          left->string_value().append(base::Int64ToString(right.int_value()));
211d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return;
212d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
213d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Value::STRING:  // string + string -> string contat.
214d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          left->string_value().append(right.string_value());
215d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return;
216d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
217d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        default:
218d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          break;
219d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
220d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
221d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
222d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Left-hand-side list.
223d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::LIST:
224d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      switch (right.type()) {
225d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Value::LIST:  // list + list -> list concat.
226d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          if (left_token.value() == kSourcesName) {
227d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // Filter additions through the assignment filter.
228d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            AppendFilteredSourcesToValue(scope, right, left);
229d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          } else {
230d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            // Normal list concat.
231d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch            for (size_t i = 0; i < right.list_value().size(); i++)
232d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch              left->list_value().push_back(right.list_value()[i]);
233d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          }
234d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return;
235d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
236d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        default:
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          *err = Err(op_node->op(), "Incompatible types to add.",
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              "To append a single item to a list do \"foo += [ bar ]\".");
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          return;
240d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
241d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
242d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    default:
243d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
244d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
245d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
246d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  *err = Err(op_node->op(), "Incompatible types to add.",
247d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
248d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      Value::DescribeType(right.type()) + ".");
249d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
250d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
251d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecutePlusEquals(Scope* scope,
252d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                        const BinaryOpNode* op_node,
253d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                        const Token& left,
254d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                        const Value& right,
255d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                        Err* err) {
256d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // We modify in-place rather than doing read-modify-write to avoid
257d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // copying large lists.
258d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  Value* left_value =
259d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      scope->GetValueForcedToCurrentScope(left.value(), op_node);
260d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!left_value) {
261d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    *err = Err(left, "Undefined variable for +=.",
262d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        "I don't have something with this name in scope now.");
263d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return Value();
264d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
265d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ValuePlusEquals(scope, op_node, left, left_value, right, false, err);
266d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  left_value->set_origin(op_node);
267d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  scope->MarkUnused(left.value());
268d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value();
269d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
270d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// We return a null value from this rather than the result of doing the append.
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// See ValuePlusEquals for rationale.
273d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochvoid ValueMinusEquals(const BinaryOpNode* op_node,
274d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                      Value* left,
275d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                      const Value& right,
276d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                      bool allow_type_conversion,
277d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                      Err* err) {
278d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  switch (left->type()) {
279d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Left-hand-side int.
280d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::INTEGER:
281d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      switch (right.type()) {
282d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        case Value::INTEGER:  // int - int -> subtraction.
283d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          left->int_value() -= right.int_value();
284d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          return;
285d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
286d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        default:
287d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch          break;
288d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      }
289d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
290d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
291d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Left-hand-side string.
292d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::STRING:
293d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;  // All are errors.
294d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
295d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    // Left-hand-side list.
296d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case Value::LIST:
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (right.type() != Value::LIST) {
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *err = Err(op_node->op(), "Incompatible types to subtract.",
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "To remove a single item from a list do \"foo -= [ bar ]\".");
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else {
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        RemoveMatchesFromList(op_node, left, right, err);
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
303d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return;
304d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
305d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    default:
306d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      break;
307d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
308d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *err = Err(op_node->op(), "Incompatible types to subtract.",
310d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
311d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      Value::DescribeType(right.type()) + ".");
312d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
313d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
314d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteMinusEquals(Scope* scope,
315d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                         const BinaryOpNode* op_node,
316d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                         const Token& left,
317d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                         const Value& right,
318d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                         Err* err) {
319d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  Value* left_value =
320d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      scope->GetValueForcedToCurrentScope(left.value(), op_node);
321d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (!left_value) {
322d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    *err = Err(left, "Undefined variable for -=.",
323d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        "I don't have something with this name in scope now.");
324d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return Value();
325d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
326d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ValueMinusEquals(op_node, left_value, right, false, err);
327d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  left_value->set_origin(op_node);
328d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  scope->MarkUnused(left.value());
329d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value();
330d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
331d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
332d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Plus/Minus -----------------------------------------------------------------
333d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
334d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecutePlus(Scope* scope,
335d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  const BinaryOpNode* op_node,
336d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  const Value& left,
337d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  const Value& right,
338d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  Err* err) {
339d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  Value ret = left;
340d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ValuePlusEquals(scope, op_node, Token(), &ret, right, true, err);
341d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ret.set_origin(op_node);
342d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return ret;
343d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
344d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
345d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteMinus(Scope* scope,
346d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                   const BinaryOpNode* op_node,
347d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                   const Value& left,
348d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                   const Value& right,
349d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                   Err* err) {
350d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  Value ret = left;
351d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ValueMinusEquals(op_node, &ret, right, true, err);
352d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  ret.set_origin(op_node);
353d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return ret;
354d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
355d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
356d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Comparison -----------------------------------------------------------------
357d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
358d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteEqualsEquals(Scope* scope,
359d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                          const BinaryOpNode* op_node,
360d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                          const Value& left,
361d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                          const Value& right,
362d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                          Err* err) {
363d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (left == right)
3643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return Value(op_node, true);
3653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return Value(op_node, false);
366d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
367d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
368d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteNotEquals(Scope* scope,
369d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                       const BinaryOpNode* op_node,
370d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                       const Value& left,
371d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                       const Value& right,
372d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                       Err* err) {
373d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Evaluate in terms of ==.
374d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  Value result = ExecuteEqualsEquals(scope, op_node, left, right, err);
3758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  result.boolean_value() = !result.boolean_value();
376d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return result;
377d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
378d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
3793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Value FillNeedsTwoIntegersError(const BinaryOpNode* op_node,
3803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                const Value& left,
3813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                const Value& right,
3823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                Err* err) {
383d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  *err = Err(op_node, "Comparison requires two integers.",
384d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch             "This operator can only compare two integers.");
385d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  err->AppendRange(left.origin()->GetRange());
386d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  err->AppendRange(right.origin()->GetRange());
387d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value();
388d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
389d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
390d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteLessEquals(Scope* scope,
391d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                        const BinaryOpNode* op_node,
392d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                        const Value& left,
393d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                        const Value& right,
394d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                        Err* err) {
395d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
3963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return FillNeedsTwoIntegersError(op_node, left, right, err);
397d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value(op_node, left.int_value() <= right.int_value());
398d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
399d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
400d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteGreaterEquals(Scope* scope,
401d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           const BinaryOpNode* op_node,
402d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           const Value& left,
403d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           const Value& right,
404d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           Err* err) {
405d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
4063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return FillNeedsTwoIntegersError(op_node, left, right, err);
407d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value(op_node, left.int_value() >= right.int_value());
408d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
409d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
410d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteGreater(Scope* scope,
411d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     const BinaryOpNode* op_node,
412d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     const Value& left,
413d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     const Value& right,
414d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                     Err* err) {
415d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
4163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return FillNeedsTwoIntegersError(op_node, left, right, err);
417d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value(op_node, left.int_value() > right.int_value());
418d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
419d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
420d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteLess(Scope* scope,
421d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  const BinaryOpNode* op_node,
422d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  const Value& left,
423d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  const Value& right,
424d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                  Err* err) {
425d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
4263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return FillNeedsTwoIntegersError(op_node, left, right, err);
427d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value(op_node, left.int_value() < right.int_value());
428d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
429d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
430d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// Binary ----------------------------------------------------------------------
431d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
432d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteOr(Scope* scope,
433d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                const BinaryOpNode* op_node,
4340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                const ParseNode* left_node,
4350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                const ParseNode* right_node,
436d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                Err* err) {
4370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Value left = GetValueOrFillError(op_node, left_node, "left", scope, err);
4380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (err->has_error())
4390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return Value();
4403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (left.type() != Value::BOOLEAN) {
441c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    *err = Err(op_node->left(), "Left side of || operator is not a boolean.",
442c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Type is \"" + std::string(Value::DescribeType(left.type())) +
443c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "\" instead.");
444c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return Value();
4450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
4460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (left.boolean_value())
4470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return Value(op_node, left.boolean_value());
4480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Value right = GetValueOrFillError(op_node, right_node, "right", scope, err);
4500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (err->has_error())
4510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return Value();
4520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (right.type() != Value::BOOLEAN) {
453c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    *err = Err(op_node->right(), "Right side of || operator is not a boolean.",
454c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Type is \"" + std::string(Value::DescribeType(right.type())) +
455c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "\" instead.");
456c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return Value();
4573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return Value(op_node, left.boolean_value() || right.boolean_value());
460d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
461d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
462d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteAnd(Scope* scope,
463d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                 const BinaryOpNode* op_node,
4640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 const ParseNode* left_node,
4650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 const ParseNode* right_node,
466d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                 Err* err) {
4670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Value left = GetValueOrFillError(op_node, left_node, "left", scope, err);
4680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (err->has_error())
4690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return Value();
4703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (left.type() != Value::BOOLEAN) {
471c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    *err = Err(op_node->left(), "Left side of && operator is not a boolean.",
472c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Type is \"" + std::string(Value::DescribeType(left.type())) +
473c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "\" instead.");
474c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return Value();
4750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
4760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!left.boolean_value())
4770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return Value(op_node, left.boolean_value());
4780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Value right = GetValueOrFillError(op_node, right_node, "right", scope, err);
4800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (err->has_error())
4810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return Value();
4820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (right.type() != Value::BOOLEAN) {
483c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    *err = Err(op_node->right(), "Right side of && operator is not a boolean.",
484c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Type is \"" + std::string(Value::DescribeType(right.type())) +
485c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "\" instead.");
486c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return Value();
4873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return Value(op_node, left.boolean_value() && right.boolean_value());
489d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
490d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
491d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}  // namespace
492d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
493d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch// ----------------------------------------------------------------------------
494d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
495d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool IsUnaryOperator(const Token& token) {
4963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return token.type() == Token::BANG;
497d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
498d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
499d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool IsBinaryOperator(const Token& token) {
5003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return token.type() == Token::EQUAL ||
5013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::PLUS ||
5023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::MINUS ||
5033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::PLUS_EQUALS ||
5043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::MINUS_EQUALS ||
5053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::EQUAL_EQUAL ||
5063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::NOT_EQUAL ||
5073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::LESS_EQUAL ||
5083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::GREATER_EQUAL ||
5093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::LESS_THAN ||
5103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::GREATER_THAN ||
5113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::BOOLEAN_AND ||
5123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         token.type() == Token::BOOLEAN_OR;
513d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
514d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
515d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool IsFunctionCallArgBeginScoper(const Token& token) {
5163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return token.type() == Token::LEFT_PAREN;
517d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
518d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
519d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool IsFunctionCallArgEndScoper(const Token& token) {
5203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return token.type() == Token::RIGHT_PAREN;
521d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
522d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
523d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool IsScopeBeginScoper(const Token& token) {
5243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return token.type() == Token::LEFT_BRACE;
525d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
526d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
527d3868032626d59662ff73b372b5d584c1d144c53Ben Murdochbool IsScopeEndScoper(const Token& token) {
5283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return token.type() == Token::RIGHT_BRACE;
529d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
530d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
531d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteUnaryOperator(Scope* scope,
532d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           const UnaryOpNode* op_node,
533d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           const Value& expr,
534d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                           Err* err) {
5353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(op_node->op().type() == Token::BANG);
5363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (expr.type() != Value::BOOLEAN) {
538c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    *err = Err(op_node, "Operand of ! operator is not a boolean.",
539c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Type is \"" + std::string(Value::DescribeType(expr.type())) +
540c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "\" instead.");
5413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return Value();
5423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(scottmg): Why no unary minus?
5443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return Value(op_node, !expr.boolean_value());
545d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
546d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
547d3868032626d59662ff73b372b5d584c1d144c53Ben MurdochValue ExecuteBinaryOperator(Scope* scope,
548d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                            const BinaryOpNode* op_node,
549d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                            const ParseNode* left,
550d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                            const ParseNode* right,
551d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                            Err* err) {
552d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  const Token& op = op_node->op();
553d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
554d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // First handle the ones that take an lvalue.
5553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::EQUAL ||
5563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      op.type() == Token::PLUS_EQUALS ||
5573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      op.type() == Token::MINUS_EQUALS) {
558d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const IdentifierNode* left_id = left->AsIdentifier();
559d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (!left_id) {
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *err = Err(op, "Operator requires a lvalue.",
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 "This thing on the left is not an identifier.");
562d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      err->AppendRange(left->GetRange());
563d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return Value();
564d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
565d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const Token& dest = left_id->value();
566d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
567d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    Value right_value = right->Execute(scope, err);
568d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (err->has_error())
569d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return Value();
570d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (right_value.type() == Value::NONE) {
5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *err = Err(op, "Operator requires a rvalue.",
572d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                 "This thing on the right does not evaluate to a value.");
573d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      err->AppendRange(right->GetRange());
574d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return Value();
575d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
576d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
5773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (op.type() == Token::EQUAL)
578d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return ExecuteEquals(scope, op_node, dest, right_value, err);
5793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (op.type() == Token::PLUS_EQUALS)
580d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return ExecutePlusEquals(scope, op_node, dest, right_value, err);
5813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (op.type() == Token::MINUS_EQUALS)
582d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      return ExecuteMinusEquals(scope, op_node, dest, right_value, err);
583d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    NOTREACHED();
584d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return Value();
585d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
586d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
5870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // ||, &&. Passed the node instead of the value so that they can avoid
5880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // evaluating the RHS on early-out.
5890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (op.type() == Token::BOOLEAN_OR)
5900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return ExecuteOr(scope, op_node, left, right, err);
5910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (op.type() == Token::BOOLEAN_AND)
5920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return ExecuteAnd(scope, op_node, left, right, err);
593d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
5940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Value left_value = GetValueOrFillError(op_node, left, "left", scope, err);
595010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (err->has_error())
596010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return Value();
5970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Value right_value = GetValueOrFillError(op_node, right, "right", scope, err);
598010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (err->has_error())
599010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return Value();
600d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
601d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // +, -.
6023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::MINUS)
603d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return ExecuteMinus(scope, op_node, left_value, right_value, err);
6043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::PLUS)
605d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return ExecutePlus(scope, op_node, left_value, right_value, err);
606d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
607d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  // Comparisons.
6083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::EQUAL_EQUAL)
609d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return ExecuteEqualsEquals(scope, op_node, left_value, right_value, err);
6103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::NOT_EQUAL)
611d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return ExecuteNotEquals(scope, op_node, left_value, right_value, err);
6123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::GREATER_EQUAL)
613d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err);
6143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::LESS_EQUAL)
615d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return ExecuteLessEquals(scope, op_node, left_value, right_value, err);
6163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::GREATER_THAN)
617d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return ExecuteGreater(scope, op_node, left_value, right_value, err);
6183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (op.type() == Token::LESS_THAN)
619d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    return ExecuteLess(scope, op_node, left_value, right_value, err);
620d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
621d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  return Value();
622d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}
623