Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "tools/gn/operators.h" | 5 #include "tools/gn/operators.h" |
| 6 | 6 |
| 7 #include "base/strings/string_number_conversions.h" | 7 #include "base/strings/string_number_conversions.h" |
| 8 #include "tools/gn/err.h" | 8 #include "tools/gn/err.h" |
| 9 #include "tools/gn/parse_tree.h" | 9 #include "tools/gn/parse_tree.h" |
| 10 #include "tools/gn/scope.h" | 10 #include "tools/gn/scope.h" |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 | 96 |
| 97 // Assignment ----------------------------------------------------------------- | 97 // Assignment ----------------------------------------------------------------- |
| 98 | 98 |
| 99 Value ExecuteEquals(Scope* scope, | 99 Value ExecuteEquals(Scope* scope, |
| 100 const BinaryOpNode* op_node, | 100 const BinaryOpNode* op_node, |
| 101 const Token& left, | 101 const Token& left, |
| 102 const Value& right, | 102 const Value& right, |
| 103 Err* err) { | 103 Err* err) { |
| 104 const Value* old_value = scope->GetValue(left.value(), false); | 104 const Value* old_value = scope->GetValue(left.value(), false); |
| 105 if (old_value) { | 105 if (old_value) { |
| 106 if (scope->IsSetButUnused(left.value())) { | 106 // Throw an error when overwriting a nonempty list with another nonempty |
| 107 // Throw an error for re-assigning without using the value first. The | 107 // list item. This is to detect the case where you write |
| 108 // exception is that you can overwrite an empty list with another list | 108 // defines = ["FOO"] |
| 109 // since this is the way to get around the "can't overwrite a nonempty | 109 // and you overwrote inherited ones, when instead you mean to append: |
| 110 // list with another nonempty list" restriction. | 110 // defines += ["FOO"] |
| 111 if (old_value->type() != Value::LIST || | 111 if (old_value->type() == Value::LIST && |
| 112 !old_value->list_value().empty()) { | 112 !old_value->list_value().empty() && |
| 113 *err = Err(op_node->left()->GetRange(), "Overwriting unused variable.", | 113 right.type() == Value::LIST && |
| 114 "This overwrites a previous assignment to \"" + | 114 !right.list_value().empty()) { |
| 115 left.value().as_string() + "\" that had no effect."); | 115 *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.", |
| 116 err->AppendSubErr(Err(*scope->GetValue(left.value()), | 116 std::string("This overwrites a previously-defined nonempty list ") + |
| 117 "Previously set here.", | 117 "(length " + |
| 118 "Maybe you wanted \"+=\" to append instead?")); | 118 base::IntToString(static_cast<int>(old_value->list_value().size())) |
| 119 return Value(); | 119 + ")."); |
| 120 } | 120 err->AppendSubErr(Err(*old_value, "for previous definition", |
| 121 } else { | 121 "with another one (length " + |
| 122 // Throw an error when overwriting a nonempty list with another nonempty | 122 base::IntToString(static_cast<int>(right.list_value().size())) + |
| 123 // list item. This is to detect the case where you write | 123 "). Did you mean " + |
| 124 // defines = ["FOO"] | 124 "\"+=\" to append instead? If you\nreally want to do this, do\n " + |
| 125 // and you overwrote inherited ones, when instead you mean to append: | 125 left.value().as_string() + " = []\nbefore reassigning.")); |
| 126 // defines += ["FOO"] | 126 return Value(); |
| 127 if (old_value->type() == Value::LIST && | |
| 128 !old_value->list_value().empty() && | |
| 129 right.type() == Value::LIST && | |
| 130 !right.list_value().empty()) { | |
| 131 *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.", | |
| 132 std::string("This overwrites a previously-defined nonempty list ") + | |
| 133 "(length " + | |
| 134 base::IntToString(static_cast<int>(old_value->list_value().size())) | |
| 135 + ")."); | |
| 136 err->AppendSubErr(Err(*old_value, "for previous definition", | |
| 137 "with another one (length " + | |
| 138 base::IntToString(static_cast<int>(right.list_value().size())) + | |
| 139 "). Did you mean " + | |
| 140 "\"+=\" to append instead? If you\nreally want to do this, do\n " + | |
| 141 left.value().as_string() + " = []\nbefore reassigning.")); | |
| 142 return Value(); | |
| 143 } | |
| 144 } | 127 } |
| 145 } | 128 } |
| 146 if (err->has_error()) | 129 if (err->has_error()) |
| 147 return Value(); | 130 return Value(); |
| 148 | 131 |
| 149 if (right.type() == Value::LIST && left.value() == kSourcesName) { | 132 if (right.type() == Value::LIST && left.value() == kSourcesName) { |
| 150 // Assigning to sources, filter the list. Here we do the filtering and | 133 // Assigning to sources, filter the list. Here we do the filtering and |
| 151 // copying in one step to save an extra list copy (the lists may be | 134 // copying in one step to save an extra list copy (the lists may be |
| 152 // long). | 135 // long). |
| 153 Value* set_value = scope->SetValue(left.value(), | 136 Value* set_value = scope->SetValue(left.value(), |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 203 return; | 186 return; |
| 204 | 187 |
| 205 default: | 188 default: |
| 206 break; | 189 break; |
| 207 } | 190 } |
| 208 break; | 191 break; |
| 209 | 192 |
| 210 // Left-hand-side list. | 193 // Left-hand-side list. |
| 211 case Value::LIST: | 194 case Value::LIST: |
| 212 switch (right.type()) { | 195 switch (right.type()) { |
| 213 case Value::INTEGER: // list + integer -> list append. | |
| 214 case Value::STRING: // list + string -> list append. | |
| 215 if (left_token.value() == kSourcesName) | |
| 216 AppendFilteredSourcesToValue(scope, right, left); | |
| 217 else | |
| 218 left->list_value().push_back(right); | |
| 219 return; | |
| 220 | |
| 221 case Value::LIST: // list + list -> list concat. | 196 case Value::LIST: // list + list -> list concat. |
| 222 if (left_token.value() == kSourcesName) { | 197 if (left_token.value() == kSourcesName) { |
| 223 // Filter additions through the assignment filter. | 198 // Filter additions through the assignment filter. |
| 224 AppendFilteredSourcesToValue(scope, right, left); | 199 AppendFilteredSourcesToValue(scope, right, left); |
| 225 } else { | 200 } else { |
| 226 // Normal list concat. | 201 // Normal list concat. |
| 227 for (size_t i = 0; i < right.list_value().size(); i++) | 202 for (size_t i = 0; i < right.list_value().size(); i++) |
| 228 left->list_value().push_back(right.list_value()[i]); | 203 left->list_value().push_back(right.list_value()[i]); |
| 229 } | 204 } |
| 230 return; | 205 return; |
| 231 | 206 |
| 232 default: | 207 default: |
| 233 break; | 208 *err = Err(op_node->op(), "Incompatible types to add.", |
| 209 "To append a single item to a list do \"foo += [ bar ]\"."); | |
| 210 return; | |
| 234 } | 211 } |
| 235 | 212 |
| 236 default: | 213 default: |
| 237 break; | 214 break; |
| 238 } | 215 } |
| 239 | 216 |
| 240 *err = Err(op_node->op(), "Incompatible types to add.", | 217 *err = Err(op_node->op(), "Incompatible types to add.", |
| 241 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " + | 218 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " + |
| 242 Value::DescribeType(right.type()) + "."); | 219 Value::DescribeType(right.type()) + "."); |
| 243 } | 220 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 break; | 256 break; |
| 280 } | 257 } |
| 281 break; | 258 break; |
| 282 | 259 |
| 283 // Left-hand-side string. | 260 // Left-hand-side string. |
| 284 case Value::STRING: | 261 case Value::STRING: |
| 285 break; // All are errors. | 262 break; // All are errors. |
| 286 | 263 |
| 287 // Left-hand-side list. | 264 // Left-hand-side list. |
| 288 case Value::LIST: | 265 case Value::LIST: |
| 289 RemoveMatchesFromList(op_node, left, right, err); | 266 if (!right.type() != Value::LIST) { |
|
scottmg
2014/01/15 00:32:07
is !right.type() what you meant?
| |
| 267 *err = Err(op_node->op(), "Incompatible types to subtract.", | |
| 268 "To remove a single item from a list do \"foo -= [ bar ]\"."); | |
| 269 } else { | |
| 270 RemoveMatchesFromList(op_node, left, right, err); | |
| 271 } | |
| 290 return; | 272 return; |
| 291 | 273 |
| 292 default: | 274 default: |
| 293 break; | 275 break; |
| 294 } | 276 } |
| 295 | 277 |
| 296 *err = Err(op_node->op(), "Incompatible types to subtract.", | 278 *err = Err(op_node->op(), "Incompatible types to subtract.", |
| 297 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " + | 279 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " + |
| 298 Value::DescribeType(right.type()) + "."); | 280 Value::DescribeType(right.type()) + "."); |
| 299 } | 281 } |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 585 return ExecuteLess(scope, op_node, left_value, right_value, err); | 567 return ExecuteLess(scope, op_node, left_value, right_value, err); |
| 586 | 568 |
| 587 // ||, &&. | 569 // ||, &&. |
| 588 if (op.type() == Token::BOOLEAN_OR) | 570 if (op.type() == Token::BOOLEAN_OR) |
| 589 return ExecuteOr(scope, op_node, left_value, right_value, err); | 571 return ExecuteOr(scope, op_node, left_value, right_value, err); |
| 590 if (op.type() == Token::BOOLEAN_AND) | 572 if (op.type() == Token::BOOLEAN_AND) |
| 591 return ExecuteAnd(scope, op_node, left_value, right_value, err); | 573 return ExecuteAnd(scope, op_node, left_value, right_value, err); |
| 592 | 574 |
| 593 return Value(); | 575 return Value(); |
| 594 } | 576 } |
| OLD | NEW |