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