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 <stddef.h> | 7 #include <stddef.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 | 9 |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
202 } | 202 } |
203 | 203 |
204 void ValueDestination::MakeUndefinedIdentifierForModifyError(Err* err) { | 204 void ValueDestination::MakeUndefinedIdentifierForModifyError(Err* err) { |
205 // When Init() succeeds, the base of any accessor has already been resolved | 205 // When Init() succeeds, the base of any accessor has already been resolved |
206 // and that list indices are in-range. This means any undefined identifiers | 206 // and that list indices are in-range. This means any undefined identifiers |
207 // are for scope accesses. | 207 // are for scope accesses. |
208 DCHECK(type_ == SCOPE); | 208 DCHECK(type_ == SCOPE); |
209 *err = Err(*name_token_, "Undefined identifier."); | 209 *err = Err(*name_token_, "Undefined identifier."); |
210 } | 210 } |
211 | 211 |
212 // Computes an error message for overwriting a nonempty list/scope with another. | |
213 Err MakeOverwriteError(const BinaryOpNode* op_node, | |
214 const Value& old_value) { | |
215 std::string type_name; | |
216 std::string empty_def; | |
217 | |
218 if (old_value.type() == Value::LIST) { | |
219 type_name = "list"; | |
220 empty_def = "[]"; | |
221 } else if (old_value.type() == Value::SCOPE) { | |
222 type_name = "scope"; | |
223 empty_def = "{}"; | |
224 } else { | |
225 NOTREACHED(); | |
226 } | |
227 | |
228 Err result(op_node->left()->GetRange(), | |
229 "Replacing nonempty " + type_name + ".", | |
230 "This overwrites a previously-defined nonempty " + type_name + | |
231 "with another nonempty " + type_name + "."); | |
232 result.AppendSubErr(Err(old_value, "for previous definition", | |
233 "Did you mean to append/modify instead? If you really want to overwrite, " | |
234 "do:\n" | |
235 " foo = " + empty_def + "\nbefore reassigning.")); | |
236 return result; | |
237 } | |
238 | |
212 // ----------------------------------------------------------------------------- | 239 // ----------------------------------------------------------------------------- |
213 | 240 |
214 Err MakeIncompatibleTypeError(const BinaryOpNode* op_node, | 241 Err MakeIncompatibleTypeError(const BinaryOpNode* op_node, |
215 const Value& left, | 242 const Value& left, |
216 const Value& right) { | 243 const Value& right) { |
217 std::string msg = | 244 std::string msg = |
218 std::string("You can't do <") + Value::DescribeType(left.type()) + "> " + | 245 std::string("You can't do <") + Value::DescribeType(left.type()) + "> " + |
219 op_node->op().value().as_string() + | 246 op_node->op().value().as_string() + |
220 " <" + Value::DescribeType(right.type()) + ">."; | 247 " <" + Value::DescribeType(right.type()) + ">."; |
221 if (left.type() == Value::LIST) { | 248 if (left.type() == Value::LIST) { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
290 | 317 |
291 // We return a null value from this rather than the result of doing the append. | 318 // We return a null value from this rather than the result of doing the append. |
292 // See ValuePlusEquals for rationale. | 319 // See ValuePlusEquals for rationale. |
293 Value ExecuteEquals(Scope* exec_scope, | 320 Value ExecuteEquals(Scope* exec_scope, |
294 const BinaryOpNode* op_node, | 321 const BinaryOpNode* op_node, |
295 ValueDestination* dest, | 322 ValueDestination* dest, |
296 Value right, | 323 Value right, |
297 Err* err) { | 324 Err* err) { |
298 const Value* old_value = dest->GetExistingValue(); | 325 const Value* old_value = dest->GetExistingValue(); |
299 if (old_value) { | 326 if (old_value) { |
300 // Throw an error when overwriting a nonempty list with another nonempty | 327 // Check for overwriting nonempty scopes or lists with other nonempty |
301 // list item. This is to detect the case where you write | 328 // scopes or lists. This prevents mistakes that clobber a value rather than |
302 // defines = ["FOO"] | 329 // appending to it. For cases where a user meant to clear a value, allow |
303 // and you overwrote inherited ones, when instead you mean to append: | 330 // overwriting a nonempty list/scope with an empty one, which can then be |
304 // defines += ["FOO"] | 331 // modified. |
305 if (old_value->type() == Value::LIST && | 332 if (old_value->type() == Value::LIST && right.type() == Value::LIST && |
scottmg
2016/08/09 22:20:33
Something else will catch it if I try to overwrite
brettw
2016/08/09 23:00:48
Presumably that will just be wrong. If changing th
| |
306 !old_value->list_value().empty() && | 333 !old_value->list_value().empty() && !right.list_value().empty()) { |
307 right.type() == Value::LIST && | 334 *err = MakeOverwriteError(op_node, *old_value); |
308 !right.list_value().empty()) { | 335 return Value(); |
309 *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.", | 336 } else if (old_value->type() == Value::SCOPE && |
310 std::string("This overwrites a previously-defined nonempty list ") + | 337 right.type() == Value::SCOPE && |
311 "(length " + | 338 old_value->scope_value()->HasValues(Scope::SEARCH_CURRENT) && |
312 base::IntToString(static_cast<int>(old_value->list_value().size())) | 339 right.scope_value()->HasValues(Scope::SEARCH_CURRENT)) { |
313 + ")."); | 340 *err = MakeOverwriteError(op_node, *old_value); |
314 err->AppendSubErr(Err(*old_value, "for previous definition", | |
315 "with another one (length " + | |
316 base::IntToString(static_cast<int>(right.list_value().size())) + | |
317 "). Did you mean " + | |
318 "\"+=\" to append instead? If you\nreally want to do this, do\n" | |
319 " foo = []\nbefore reassigning.")); | |
320 return Value(); | 341 return Value(); |
321 } | 342 } |
322 } | 343 } |
323 if (err->has_error()) | |
324 return Value(); | |
325 | 344 |
326 Value* written_value = dest->SetValue(std::move(right), op_node->right()); | 345 Value* written_value = dest->SetValue(std::move(right), op_node->right()); |
327 | 346 |
328 // Optionally apply the assignment filter in-place. | 347 // Optionally apply the assignment filter in-place. |
329 const PatternList* filter = dest->GetAssignmentFilter(exec_scope); | 348 const PatternList* filter = dest->GetAssignmentFilter(exec_scope); |
330 if (filter) { | 349 if (filter) { |
331 std::vector<Value>& list_value = written_value->list_value(); | 350 std::vector<Value>& list_value = written_value->list_value(); |
332 auto first_deleted = std::remove_if( | 351 auto first_deleted = std::remove_if( |
333 list_value.begin(), list_value.end(), | 352 list_value.begin(), list_value.end(), |
334 [filter](const Value& v) { | 353 [filter](const Value& v) { |
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
755 return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err); | 774 return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err); |
756 if (op.type() == Token::LESS_EQUAL) | 775 if (op.type() == Token::LESS_EQUAL) |
757 return ExecuteLessEquals(scope, op_node, left_value, right_value, err); | 776 return ExecuteLessEquals(scope, op_node, left_value, right_value, err); |
758 if (op.type() == Token::GREATER_THAN) | 777 if (op.type() == Token::GREATER_THAN) |
759 return ExecuteGreater(scope, op_node, left_value, right_value, err); | 778 return ExecuteGreater(scope, op_node, left_value, right_value, err); |
760 if (op.type() == Token::LESS_THAN) | 779 if (op.type() == Token::LESS_THAN) |
761 return ExecuteLess(scope, op_node, left_value, right_value, err); | 780 return ExecuteLess(scope, op_node, left_value, right_value, err); |
762 | 781 |
763 return Value(); | 782 return Value(); |
764 } | 783 } |
OLD | NEW |