Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: tools/gn/operators.cc

Issue 136723008: Remove some appending behavior from GN. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/gn/operators_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 } 89 }
90 break; 90 break;
91 91
92 default: 92 default:
93 break; 93 break;
94 } 94 }
95 } 95 }
96 96
97 // Assignment ----------------------------------------------------------------- 97 // Assignment -----------------------------------------------------------------
98 98
99 // We return a null value from this rather than the result of doing the append.
100 // See ValuePlusEquals for rationale.
99 Value ExecuteEquals(Scope* scope, 101 Value ExecuteEquals(Scope* scope,
100 const BinaryOpNode* op_node, 102 const BinaryOpNode* op_node,
101 const Token& left, 103 const Token& left,
102 const Value& right, 104 const Value& right,
103 Err* err) { 105 Err* err) {
104 const Value* old_value = scope->GetValue(left.value(), false); 106 const Value* old_value = scope->GetValue(left.value(), false);
105 if (old_value) { 107 if (old_value) {
106 if (scope->IsSetButUnused(left.value())) { 108 // Throw an error when overwriting a nonempty list with another nonempty
107 // Throw an error for re-assigning without using the value first. The 109 // list item. This is to detect the case where you write
108 // exception is that you can overwrite an empty list with another list 110 // defines = ["FOO"]
109 // since this is the way to get around the "can't overwrite a nonempty 111 // and you overwrote inherited ones, when instead you mean to append:
110 // list with another nonempty list" restriction. 112 // defines += ["FOO"]
111 if (old_value->type() != Value::LIST || 113 if (old_value->type() == Value::LIST &&
112 !old_value->list_value().empty()) { 114 !old_value->list_value().empty() &&
113 *err = Err(op_node->left()->GetRange(), "Overwriting unused variable.", 115 right.type() == Value::LIST &&
114 "This overwrites a previous assignment to \"" + 116 !right.list_value().empty()) {
115 left.value().as_string() + "\" that had no effect."); 117 *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.",
116 err->AppendSubErr(Err(*scope->GetValue(left.value()), 118 std::string("This overwrites a previously-defined nonempty list ") +
117 "Previously set here.", 119 "(length " +
118 "Maybe you wanted \"+=\" to append instead?")); 120 base::IntToString(static_cast<int>(old_value->list_value().size()))
119 return Value(); 121 + ").");
120 } 122 err->AppendSubErr(Err(*old_value, "for previous definition",
121 } else { 123 "with another one (length " +
122 // Throw an error when overwriting a nonempty list with another nonempty 124 base::IntToString(static_cast<int>(right.list_value().size())) +
123 // list item. This is to detect the case where you write 125 "). Did you mean " +
124 // defines = ["FOO"] 126 "\"+=\" to append instead? If you\nreally want to do this, do\n " +
125 // and you overwrote inherited ones, when instead you mean to append: 127 left.value().as_string() + " = []\nbefore reassigning."));
126 // defines += ["FOO"] 128 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 } 129 }
145 } 130 }
146 if (err->has_error()) 131 if (err->has_error())
147 return Value(); 132 return Value();
148 133
149 if (right.type() == Value::LIST && left.value() == kSourcesName) { 134 if (right.type() == Value::LIST && left.value() == kSourcesName) {
150 // Assigning to sources, filter the list. Here we do the filtering and 135 // 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 136 // copying in one step to save an extra list copy (the lists may be
152 // long). 137 // long).
153 Value* set_value = scope->SetValue(left.value(), 138 Value* set_value = scope->SetValue(left.value(),
154 Value(op_node, Value::LIST), op_node); 139 Value(op_node, Value::LIST), op_node);
155 set_value->list_value().reserve(right.list_value().size()); 140 set_value->list_value().reserve(right.list_value().size());
156 AppendFilteredSourcesToValue(scope, right, set_value); 141 AppendFilteredSourcesToValue(scope, right, set_value);
157 } else { 142 } else {
158 // Normal value set, just copy it. 143 // Normal value set, just copy it.
159 scope->SetValue(left.value(), right, op_node->right()); 144 scope->SetValue(left.value(), right, op_node->right());
160 } 145 }
161 return Value(); 146 return Value();
162 } 147 }
163 148
164 // allow_type_conversion indicates if we're allowed to change the type of the 149 // allow_type_conversion indicates if we're allowed to change the type of the
165 // left value. This is set to true when doing +, and false when doing +=. 150 // left value. This is set to true when doing +, and false when doing +=.
151 //
152 // Note that we return Value() from here, which is different than C++. This
153 // means you can't do clever things like foo = [ bar += baz ] to simultaneously
154 // append to and use a value. This is basically never needed in out build
155 // scripts and is just as likely an error as the intended behavior, and it also
156 // involves a copy of the value when it's returned. Many times we're appending
157 // to large lists, and copying the value to discard it for the next statement
158 // is very wasteful.
166 void ValuePlusEquals(const Scope* scope, 159 void ValuePlusEquals(const Scope* scope,
167 const BinaryOpNode* op_node, 160 const BinaryOpNode* op_node,
168 const Token& left_token, 161 const Token& left_token,
169 Value* left, 162 Value* left,
170 const Value& right, 163 const Value& right,
171 bool allow_type_conversion, 164 bool allow_type_conversion,
172 Err* err) { 165 Err* err) {
173 switch (left->type()) { 166 switch (left->type()) {
174 // Left-hand-side int. 167 // Left-hand-side int.
175 case Value::INTEGER: 168 case Value::INTEGER:
(...skipping 27 matching lines...) Expand all
203 return; 196 return;
204 197
205 default: 198 default:
206 break; 199 break;
207 } 200 }
208 break; 201 break;
209 202
210 // Left-hand-side list. 203 // Left-hand-side list.
211 case Value::LIST: 204 case Value::LIST:
212 switch (right.type()) { 205 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. 206 case Value::LIST: // list + list -> list concat.
222 if (left_token.value() == kSourcesName) { 207 if (left_token.value() == kSourcesName) {
223 // Filter additions through the assignment filter. 208 // Filter additions through the assignment filter.
224 AppendFilteredSourcesToValue(scope, right, left); 209 AppendFilteredSourcesToValue(scope, right, left);
225 } else { 210 } else {
226 // Normal list concat. 211 // Normal list concat.
227 for (size_t i = 0; i < right.list_value().size(); i++) 212 for (size_t i = 0; i < right.list_value().size(); i++)
228 left->list_value().push_back(right.list_value()[i]); 213 left->list_value().push_back(right.list_value()[i]);
229 } 214 }
230 return; 215 return;
231 216
232 default: 217 default:
233 break; 218 *err = Err(op_node->op(), "Incompatible types to add.",
219 "To append a single item to a list do \"foo += [ bar ]\".");
220 return;
234 } 221 }
235 222
236 default: 223 default:
237 break; 224 break;
238 } 225 }
239 226
240 *err = Err(op_node->op(), "Incompatible types to add.", 227 *err = Err(op_node->op(), "Incompatible types to add.",
241 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " + 228 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
242 Value::DescribeType(right.type()) + "."); 229 Value::DescribeType(right.type()) + ".");
243 } 230 }
(...skipping 11 matching lines...) Expand all
255 *err = Err(left, "Undefined variable for +=.", 242 *err = Err(left, "Undefined variable for +=.",
256 "I don't have something with this name in scope now."); 243 "I don't have something with this name in scope now.");
257 return Value(); 244 return Value();
258 } 245 }
259 ValuePlusEquals(scope, op_node, left, left_value, right, false, err); 246 ValuePlusEquals(scope, op_node, left, left_value, right, false, err);
260 left_value->set_origin(op_node); 247 left_value->set_origin(op_node);
261 scope->MarkUnused(left.value()); 248 scope->MarkUnused(left.value());
262 return Value(); 249 return Value();
263 } 250 }
264 251
252 // We return a null value from this rather than the result of doing the append.
253 // See ValuePlusEquals for rationale.
265 void ValueMinusEquals(const BinaryOpNode* op_node, 254 void ValueMinusEquals(const BinaryOpNode* op_node,
266 Value* left, 255 Value* left,
267 const Value& right, 256 const Value& right,
268 bool allow_type_conversion, 257 bool allow_type_conversion,
269 Err* err) { 258 Err* err) {
270 switch (left->type()) { 259 switch (left->type()) {
271 // Left-hand-side int. 260 // Left-hand-side int.
272 case Value::INTEGER: 261 case Value::INTEGER:
273 switch (right.type()) { 262 switch (right.type()) {
274 case Value::INTEGER: // int - int -> subtraction. 263 case Value::INTEGER: // int - int -> subtraction.
275 left->int_value() -= right.int_value(); 264 left->int_value() -= right.int_value();
276 return; 265 return;
277 266
278 default: 267 default:
279 break; 268 break;
280 } 269 }
281 break; 270 break;
282 271
283 // Left-hand-side string. 272 // Left-hand-side string.
284 case Value::STRING: 273 case Value::STRING:
285 break; // All are errors. 274 break; // All are errors.
286 275
287 // Left-hand-side list. 276 // Left-hand-side list.
288 case Value::LIST: 277 case Value::LIST:
289 RemoveMatchesFromList(op_node, left, right, err); 278 if (right.type() != Value::LIST) {
279 *err = Err(op_node->op(), "Incompatible types to subtract.",
280 "To remove a single item from a list do \"foo -= [ bar ]\".");
281 } else {
282 RemoveMatchesFromList(op_node, left, right, err);
283 }
290 return; 284 return;
291 285
292 default: 286 default:
293 break; 287 break;
294 } 288 }
295 289
296 *err = Err(op_node->op(), "Incompatible types to subtract.", 290 *err = Err(op_node->op(), "Incompatible types to subtract.",
297 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " + 291 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
298 Value::DescribeType(right.type()) + "."); 292 Value::DescribeType(right.type()) + ".");
299 } 293 }
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 return ExecuteLess(scope, op_node, left_value, right_value, err); 579 return ExecuteLess(scope, op_node, left_value, right_value, err);
586 580
587 // ||, &&. 581 // ||, &&.
588 if (op.type() == Token::BOOLEAN_OR) 582 if (op.type() == Token::BOOLEAN_OR)
589 return ExecuteOr(scope, op_node, left_value, right_value, err); 583 return ExecuteOr(scope, op_node, left_value, right_value, err);
590 if (op.type() == Token::BOOLEAN_AND) 584 if (op.type() == Token::BOOLEAN_AND)
591 return ExecuteAnd(scope, op_node, left_value, right_value, err); 585 return ExecuteAnd(scope, op_node, left_value, right_value, err);
592 586
593 return Value(); 587 return Value();
594 } 588 }
OLDNEW
« no previous file with comments | « no previous file | tools/gn/operators_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698