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

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

Issue 21114002: Add initial prototype for the GN meta-buildsystem. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add owners and readme Created 7 years, 4 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 | « tools/gn/operators.h ('k') | tools/gn/output_file.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "tools/gn/operators.h"
6
7 #include "base/strings/string_number_conversions.h"
8 #include "tools/gn/err.h"
9 #include "tools/gn/parse_tree.h"
10 #include "tools/gn/scope.h"
11 #include "tools/gn/token.h"
12 #include "tools/gn/value.h"
13
14 namespace {
15
16 const char kSourcesName[] = "sources";
17
18 // Applies the sources assignment filter from the given scope to each element
19 // of source (can be a list or a string), appending it to dest if it doesn't
20 // match.
21 void AppendFilteredSourcesToValue(const Scope* scope,
22 const Value& source,
23 Value* dest) {
24 const PatternList* filter = scope->GetSourcesAssignmentFilter();
25
26 const std::vector<Value>& source_list = source.list_value();
27
28 if (source.type() == Value::STRING) {
29 if (!filter || filter->is_empty() ||
30 !filter->MatchesValue(source))
31 dest->list_value().push_back(source);
32 return;
33 }
34
35 // Otherwise source is a list.
36 DCHECK(source.type() == Value::LIST);
37 if (!filter || filter->is_empty()) {
38 // No filter, append everything.
39 for (size_t i = 0; i < source_list.size(); i++)
40 dest->list_value().push_back(source_list[i]);
41 return;
42 }
43
44 // Note: don't reserve() the dest vector here since that actually hurts
45 // the allocation pattern when the build script is doing multiple small
46 // additions.
47 for (size_t i = 0; i < source_list.size(); i++) {
48 if (!filter->MatchesValue(source_list[i]))
49 dest->list_value().push_back(source_list[i]);
50 }
51 }
52
53 void RemoveMatchesFromList(const BinaryOpNode* op_node,
54 Value* list,
55 const Value& to_remove,
56 Err* err) {
57 std::vector<Value>& v = list->list_value();
58 switch (to_remove.type()) {
59 case Value::INTEGER: // Filter out the individual int/string.
60 case Value::STRING: {
61 bool found_match = false;
62 for (size_t i = 0; i < v.size(); /* nothing */) {
63 if (v[i] == to_remove) {
64 found_match = true;
65 v.erase(v.begin() + i);
66 } else {
67 i++;
68 }
69 }
70 if (!found_match) {
71 *err = Err(to_remove.origin()->GetRange(), "Item not found",
72 "You were trying to remove \"" + to_remove.ToString() +
73 "\"\nfrom the list but it wasn't there.");
74 }
75 break;
76 }
77
78 case Value::LIST: // Filter out each individual thing.
79 for (size_t i = 0; i < to_remove.list_value().size(); i++) {
80 // TODO(brettw) if the nested item is a list, we may want to search
81 // for the literal list rather than remote the items in it.
82 RemoveMatchesFromList(op_node, list, to_remove.list_value()[i], err);
83 if (err->has_error())
84 return;
85 }
86 break;
87
88 default:
89 break;
90 }
91 }
92
93 // Assignment -----------------------------------------------------------------
94
95 Value ExecuteEquals(Scope* scope,
96 const BinaryOpNode* op_node,
97 const Token& left,
98 const Value& right,
99 Err* err) {
100 const Value* old_value = scope->GetValue(left.value(), false);
101 if (old_value) {
102 if (scope->IsSetButUnused(left.value())) {
103 // Throw an error for re-assigning without using the value first. The
104 // exception is that you can overwrite an empty list with another list
105 // since this is the way to get around the "can't overwrite a nonempty
106 // list with another nonempty list" restriction.
107 if (old_value->type() != Value::LIST ||
108 !old_value->list_value().empty()) {
109 *err = Err(op_node->left()->GetRange(), "Overwriting unused variable.",
110 "This overwrites a previous assignment to \"" +
111 left.value().as_string() + "\" that had no effect.");
112 err->AppendSubErr(Err(*scope->GetValue(left.value()),
113 "Previously set here.",
114 "Maybe you wanted \"+=\" to append instead?"));
115 return Value();
116 }
117 } else {
118 // Throw an error when overwriting a nonempty list with another nonempty
119 // list item. This is to detect the case where you write
120 // defines = ["FOO"]
121 // and you overwrote inherited ones, when instead you mean to append:
122 // defines += ["FOO"]
123 if (old_value->type() == Value::LIST &&
124 !old_value->list_value().empty() &&
125 right.type() == Value::LIST &&
126 !right.list_value().empty()) {
127 *err = Err(op_node->left()->GetRange(), "Replacing nonempty list.",
128 std::string("This overwrites a previously-defined nonempty list ") +
129 "(length " + base::IntToString(old_value->list_value().size()) +
130 ").");
131 err->AppendSubErr(Err(*old_value, "for previous definition",
132 "with another one (length " +
133 base::IntToString(right.list_value().size()) + "). Did you mean " +
134 "\"+=\" to append instead? If you\nreally want to do this, do\n " +
135 left.value().as_string() + " = []\nbefore reassigning."));
136 return Value();
137 }
138 }
139 }
140 if (err->has_error())
141 return Value();
142
143 if (right.type() == Value::LIST && left.value() == kSourcesName) {
144 // Assigning to sources, filter the list. Here we do the filtering and
145 // copying in one step to save an extra list copy (the lists may be
146 // long).
147 Value* set_value = scope->SetValue(left.value(),
148 Value(op_node, Value::LIST), op_node);
149 set_value->list_value().reserve(right.list_value().size());
150 AppendFilteredSourcesToValue(scope, right, set_value);
151 } else {
152 // Normal value set, just copy it.
153 scope->SetValue(left.value(), right, op_node->right());
154 }
155 return Value();
156 }
157
158 // allow_type_conversion indicates if we're allowed to change the type of the
159 // left value. This is set to true when doing +, and false when doing +=.
160 void ValuePlusEquals(const Scope* scope,
161 const BinaryOpNode* op_node,
162 const Token& left_token,
163 Value* left,
164 const Value& right,
165 bool allow_type_conversion,
166 Err* err) {
167 switch (left->type()) {
168 // Left-hand-side int.
169 case Value::INTEGER:
170 switch (right.type()) {
171 case Value::INTEGER: // int + int -> addition.
172 left->int_value() += right.int_value();
173 return;
174
175 case Value::STRING: // int + string -> string concat.
176 if (allow_type_conversion) {
177 *left = Value(op_node,
178 base::Int64ToString(left->int_value()) + right.string_value());
179 return;
180 }
181 break;
182
183 default:
184 break;
185 }
186 break;
187
188 // Left-hand-side string.
189 case Value::STRING:
190 switch (right.type()) {
191 case Value::INTEGER: // string + int -> string concat.
192 left->string_value().append(base::Int64ToString(right.int_value()));
193 return;
194
195 case Value::STRING: // string + string -> string contat.
196 left->string_value().append(right.string_value());
197 return;
198
199 default:
200 break;
201 }
202 break;
203
204 // Left-hand-side list.
205 case Value::LIST:
206 switch (right.type()) {
207 case Value::INTEGER: // list + integer -> list append.
208 case Value::STRING: // list + string -> list append.
209 if (left_token.value() == kSourcesName)
210 AppendFilteredSourcesToValue(scope, right, left);
211 else
212 left->list_value().push_back(right);
213 return;
214
215 case Value::LIST: // list + list -> list concat.
216 if (left_token.value() == kSourcesName) {
217 // Filter additions through the assignment filter.
218 AppendFilteredSourcesToValue(scope, right, left);
219 } else {
220 // Normal list concat.
221 for (size_t i = 0; i < right.list_value().size(); i++)
222 left->list_value().push_back(right.list_value()[i]);
223 }
224 return;
225
226 default:
227 break;
228 }
229
230 default:
231 break;
232 }
233
234 *err = Err(op_node->op(), "Incompatible types to add.",
235 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
236 Value::DescribeType(right.type()) + ".");
237 }
238
239 Value ExecutePlusEquals(Scope* scope,
240 const BinaryOpNode* op_node,
241 const Token& left,
242 const Value& right,
243 Err* err) {
244 // We modify in-place rather than doing read-modify-write to avoid
245 // copying large lists.
246 Value* left_value =
247 scope->GetValueForcedToCurrentScope(left.value(), op_node);
248 if (!left_value) {
249 *err = Err(left, "Undefined variable for +=.",
250 "I don't have something with this name in scope now.");
251 return Value();
252 }
253 ValuePlusEquals(scope, op_node, left, left_value, right, false, err);
254 left_value->set_origin(op_node);
255 scope->MarkUnused(left.value());
256 return Value();
257 }
258
259 void ValueMinusEquals(const BinaryOpNode* op_node,
260 Value* left,
261 const Value& right,
262 bool allow_type_conversion,
263 Err* err) {
264 switch (left->type()) {
265 // Left-hand-side int.
266 case Value::INTEGER:
267 switch (right.type()) {
268 case Value::INTEGER: // int - int -> subtraction.
269 left->int_value() -= right.int_value();
270 return;
271
272 default:
273 break;
274 }
275 break;
276
277 // Left-hand-side string.
278 case Value::STRING:
279 break; // All are errors.
280
281 // Left-hand-side list.
282 case Value::LIST:
283 RemoveMatchesFromList(op_node, left, right, err);
284 return;
285
286 default:
287 break;
288 }
289
290 *err = Err(op_node->op(), "Incompatible types to add.",
291 std::string("I see a ") + Value::DescribeType(left->type()) + " and a " +
292 Value::DescribeType(right.type()) + ".");
293 }
294
295 Value ExecuteMinusEquals(Scope* scope,
296 const BinaryOpNode* op_node,
297 const Token& left,
298 const Value& right,
299 Err* err) {
300 Value* left_value =
301 scope->GetValueForcedToCurrentScope(left.value(), op_node);
302 if (!left_value) {
303 *err = Err(left, "Undefined variable for -=.",
304 "I don't have something with this name in scope now.");
305 return Value();
306 }
307 ValueMinusEquals(op_node, left_value, right, false, err);
308 left_value->set_origin(op_node);
309 scope->MarkUnused(left.value());
310 return Value();
311 }
312
313 // Plus/Minus -----------------------------------------------------------------
314
315 Value ExecutePlus(Scope* scope,
316 const BinaryOpNode* op_node,
317 const Value& left,
318 const Value& right,
319 Err* err) {
320 Value ret = left;
321 ValuePlusEquals(scope, op_node, Token(), &ret, right, true, err);
322 ret.set_origin(op_node);
323 return ret;
324 }
325
326 Value ExecuteMinus(Scope* scope,
327 const BinaryOpNode* op_node,
328 const Value& left,
329 const Value& right,
330 Err* err) {
331 Value ret = left;
332 ValueMinusEquals(op_node, &ret, right, true, err);
333 ret.set_origin(op_node);
334 return ret;
335 }
336
337 // Comparison -----------------------------------------------------------------
338
339 Value ExecuteEqualsEquals(Scope* scope,
340 const BinaryOpNode* op_node,
341 const Value& left,
342 const Value& right,
343 Err* err) {
344 if (left == right)
345 return Value(op_node, 1);
346 return Value(op_node, 0);
347 }
348
349 Value ExecuteNotEquals(Scope* scope,
350 const BinaryOpNode* op_node,
351 const Value& left,
352 const Value& right,
353 Err* err) {
354 // Evaluate in terms of ==.
355 Value result = ExecuteEqualsEquals(scope, op_node, left, right, err);
356 result.int_value() = static_cast<int64>(!result.int_value());
357 return result;
358 }
359
360 Value FillNeedsToIntegersError(const BinaryOpNode* op_node,
361 const Value& left,
362 const Value& right,
363 Err* err) {
364 *err = Err(op_node, "Comparison requires two integers.",
365 "This operator can only compare two integers.");
366 err->AppendRange(left.origin()->GetRange());
367 err->AppendRange(right.origin()->GetRange());
368 return Value();
369 }
370
371 Value ExecuteLessEquals(Scope* scope,
372 const BinaryOpNode* op_node,
373 const Value& left,
374 const Value& right,
375 Err* err) {
376 if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
377 return FillNeedsToIntegersError(op_node, left, right, err);
378 return Value(op_node, left.int_value() <= right.int_value());
379 }
380
381 Value ExecuteGreaterEquals(Scope* scope,
382 const BinaryOpNode* op_node,
383 const Value& left,
384 const Value& right,
385 Err* err) {
386 if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
387 return FillNeedsToIntegersError(op_node, left, right, err);
388 return Value(op_node, left.int_value() >= right.int_value());
389 }
390
391 Value ExecuteGreater(Scope* scope,
392 const BinaryOpNode* op_node,
393 const Value& left,
394 const Value& right,
395 Err* err) {
396 if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
397 return FillNeedsToIntegersError(op_node, left, right, err);
398 return Value(op_node, left.int_value() > right.int_value());
399 }
400
401 Value ExecuteLess(Scope* scope,
402 const BinaryOpNode* op_node,
403 const Value& left,
404 const Value& right,
405 Err* err) {
406 if (left.type() != Value::INTEGER || right.type() != Value::INTEGER)
407 return FillNeedsToIntegersError(op_node, left, right, err);
408 return Value(op_node, left.int_value() < right.int_value());
409 }
410
411 // Binary ----------------------------------------------------------------------
412
413 Value ExecuteOr(Scope* scope,
414 const BinaryOpNode* op_node,
415 const Value& left,
416 const Value& right,
417 Err* err) {
418 return Value(op_node,
419 static_cast<int64>(left.InterpretAsInt() || right.InterpretAsInt()));
420 }
421
422 Value ExecuteAnd(Scope* scope,
423 const BinaryOpNode* op_node,
424 const Value& left,
425 const Value& right,
426 Err* err) {
427 return Value(op_node,
428 static_cast<int64>(left.InterpretAsInt() && right.InterpretAsInt()));
429 }
430
431 } // namespace
432
433 // ----------------------------------------------------------------------------
434
435 bool IsUnaryOperator(const Token& token) {
436 if (token.type() != Token::OPERATOR)
437 return false;
438 return token.value() == "!";
439 }
440
441 bool IsBinaryOperator(const Token& token) {
442 if (token.type() != Token::OPERATOR)
443 return false;
444 return token.value() == "=" ||
445 token.value() == "+=" ||
446 token.value() == "-=" ||
447 token.value() == "+" ||
448 token.value() == "-" ||
449 token.value() == "==" ||
450 token.value() == "!=" ||
451 token.value() == "<=" ||
452 token.value() == ">=" ||
453 token.value() == "<" ||
454 token.value() == ">" ||
455 token.value() == "&&" ||
456 token.value() == "||";
457 }
458
459 bool IsFunctionCallArgBeginScoper(const Token& token) {
460 return token.IsScoperEqualTo("(");
461 }
462
463 bool IsFunctionCallArgEndScoper(const Token& token) {
464 return token.IsScoperEqualTo(")");
465 }
466
467 bool IsScopeBeginScoper(const Token& token) {
468 return token.IsScoperEqualTo("{");
469 }
470
471 bool IsScopeEndScoper(const Token& token) {
472 return token.IsScoperEqualTo("}");
473 }
474
475 Value ExecuteUnaryOperator(Scope* scope,
476 const UnaryOpNode* op_node,
477 const Value& expr,
478 Err* err) {
479 DCHECK(op_node->op().IsOperatorEqualTo("!"));
480 return Value(op_node, !expr.InterpretAsInt());
481 }
482
483 Value ExecuteBinaryOperator(Scope* scope,
484 const BinaryOpNode* op_node,
485 const ParseNode* left,
486 const ParseNode* right,
487 Err* err) {
488 const Token& op = op_node->op();
489
490 // First handle the ones that take an lvalue.
491 if (op.IsOperatorEqualTo("=") ||
492 op.IsOperatorEqualTo("+=") ||
493 op.IsOperatorEqualTo("-=")) {
494 const IdentifierNode* left_id = left->AsIdentifier();
495 if (!left_id) {
496 *err = Err(op, "Operator requires an lvalue.",
497 "This thing on the left is not an idenfitier.");
498 err->AppendRange(left->GetRange());
499 return Value();
500 }
501 const Token& dest = left_id->value();
502
503 Value right_value = right->Execute(scope, err);
504 if (err->has_error())
505 return Value();
506 if (right_value.type() == Value::NONE) {
507 *err = Err(op, "Operator requires an rvalue.",
508 "This thing on the right does not evaluate to a value.");
509 err->AppendRange(right->GetRange());
510 return Value();
511 }
512
513 if (op.IsOperatorEqualTo("="))
514 return ExecuteEquals(scope, op_node, dest, right_value, err);
515 if (op.IsOperatorEqualTo("+="))
516 return ExecutePlusEquals(scope, op_node, dest, right_value, err);
517 if (op.IsOperatorEqualTo("-="))
518 return ExecuteMinusEquals(scope, op_node, dest, right_value, err);
519 NOTREACHED();
520 return Value();
521 }
522
523 // Left value.
524 Value left_value = left->Execute(scope, err);
525 if (err->has_error())
526 return Value();
527 if (left_value.type() == Value::NONE) {
528 *err = Err(op, "Operator requires an value.",
529 "This thing on the left does not evaluate to a value.");
530 err->AppendRange(left->GetRange());
531 return Value();
532 }
533
534 // Right value. Note: don't move this above to share code with the lvalue
535 // version since in this case we want to execute the left side first.
536 Value right_value = right->Execute(scope, err);
537 if (err->has_error())
538 return Value();
539 if (right_value.type() == Value::NONE) {
540 *err = Err(op, "Operator requires an value.",
541 "This thing on the right does not evaluate to a value.");
542 err->AppendRange(right->GetRange());
543 return Value();
544 }
545
546 // +, -.
547 if (op.IsOperatorEqualTo("-"))
548 return ExecuteMinus(scope, op_node, left_value, right_value, err);
549 if (op.IsOperatorEqualTo("+"))
550 return ExecutePlus(scope, op_node, left_value, right_value, err);
551
552 // Comparisons.
553 if (op.IsOperatorEqualTo("=="))
554 return ExecuteEqualsEquals(scope, op_node, left_value, right_value, err);
555 if (op.IsOperatorEqualTo("!="))
556 return ExecuteNotEquals(scope, op_node, left_value, right_value, err);
557 if (op.IsOperatorEqualTo(">="))
558 return ExecuteGreaterEquals(scope, op_node, left_value, right_value, err);
559 if (op.IsOperatorEqualTo("<="))
560 return ExecuteLessEquals(scope, op_node, left_value, right_value, err);
561 if (op.IsOperatorEqualTo(">"))
562 return ExecuteGreater(scope, op_node, left_value, right_value, err);
563 if (op.IsOperatorEqualTo("<"))
564 return ExecuteLess(scope, op_node, left_value, right_value, err);
565
566 // ||, &&.
567 if (op.IsOperatorEqualTo("||"))
568 return ExecuteOr(scope, op_node, left_value, right_value, err);
569 if (op.IsOperatorEqualTo("&&"))
570 return ExecuteAnd(scope, op_node, left_value, right_value, err);
571
572 return Value();
573 }
OLDNEW
« no previous file with comments | « tools/gn/operators.h ('k') | tools/gn/output_file.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698