|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "tools/gn/err.h" | 
|  | #include "tools/gn/functions.h" | 
|  | #include "tools/gn/parse_tree.h" | 
|  | #include "tools/gn/scope.h" | 
|  |  | 
|  | namespace functions { | 
|  |  | 
|  | const char kForEach[] = "foreach"; | 
|  | const char kForEach_HelpShort[] = | 
|  | "foreach: Iterate over a list."; | 
|  | const char kForEach_Help[] = | 
|  | R"(foreach: Iterate over a list. | 
|  |  | 
|  | foreach(<loop_var>, <list>) { | 
|  | <loop contents> | 
|  | } | 
|  |  | 
|  | Executes the loop contents block over each item in the list, assigning the | 
|  | loop_var to each item in sequence. The <loop_var> will be a copy so assigning | 
|  | to it will not mutate the list. The loop will iterate over a copy of <list> | 
|  | so mutating it inside the loop will not affect iteration. | 
|  |  | 
|  | The block does not introduce a new scope, so that variable assignments inside | 
|  | the loop will be visible once the loop terminates. | 
|  |  | 
|  | The loop variable will temporarily shadow any existing variables with the | 
|  | same name for the duration of the loop. After the loop terminates the loop | 
|  | variable will no longer be in scope, and the previous value (if any) will be | 
|  | restored. | 
|  |  | 
|  | Example | 
|  |  | 
|  | mylist = [ "a", "b", "c" ] | 
|  | foreach(i, mylist) { | 
|  | print(i) | 
|  | } | 
|  |  | 
|  | Prints: | 
|  | a | 
|  | b | 
|  | c | 
|  | )"; | 
|  |  | 
|  | Value RunForEach(Scope* scope, | 
|  | const FunctionCallNode* function, | 
|  | const ListNode* args_list, | 
|  | Err* err) { | 
|  | const auto& args_vector = args_list->contents(); | 
|  | if (args_vector.size() != 2) { | 
|  | *err = Err(function, "Wrong number of arguments to foreach().", | 
|  | "Expecting exactly two."); | 
|  | return Value(); | 
|  | } | 
|  |  | 
|  | // Extract the loop variable. | 
|  | const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); | 
|  | if (!identifier) { | 
|  | *err = | 
|  | Err(args_vector[0].get(), "Expected an identifier for the loop var."); | 
|  | return Value(); | 
|  | } | 
|  | base::StringPiece loop_var(identifier->value().value()); | 
|  |  | 
|  | // Extract the list to iterate over. Always copy in case the code changes | 
|  | // the list variable inside the loop. | 
|  | Value list_value = args_vector[1]->Execute(scope, err); | 
|  | if (err->has_error()) | 
|  | return Value(); | 
|  | list_value.VerifyTypeIs(Value::Type::LIST, err); | 
|  | if (err->has_error()) | 
|  | return Value(); | 
|  | const std::vector<Value>& list = list_value.list_value(); | 
|  |  | 
|  | // Block to execute. | 
|  | const BlockNode* block = function->block(); | 
|  | if (!block) { | 
|  | *err = Err(function, "Expected { after foreach."); | 
|  | return Value(); | 
|  | } | 
|  |  | 
|  | // If the loop variable was previously defined in this scope, save it so we | 
|  | // can put it back after the loop is done. | 
|  | const Value* old_loop_value_ptr = scope->GetValue(loop_var); | 
|  | Value old_loop_value; | 
|  | if (old_loop_value_ptr) | 
|  | old_loop_value = *old_loop_value_ptr; | 
|  |  | 
|  | for (const auto& cur : list) { | 
|  | scope->SetValue(loop_var, cur, function); | 
|  | block->Execute(scope, err); | 
|  | if (err->has_error()) | 
|  | return Value(); | 
|  | } | 
|  |  | 
|  | // Put back loop var. | 
|  | if (old_loop_value_ptr) { | 
|  | // Put back old value. Use the copy we made, rather than use the pointer, | 
|  | // which will probably point to the new value now in the scope. | 
|  | scope->SetValue(loop_var, std::move(old_loop_value), | 
|  | old_loop_value.origin()); | 
|  | } else { | 
|  | // Loop variable was undefined before loop, delete it. | 
|  | scope->RemoveIdentifier(loop_var); | 
|  | } | 
|  |  | 
|  | return Value(); | 
|  | } | 
|  |  | 
|  | }  // namespace functions |