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