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/err.h" 6 #include "tools/gn/functions.h" 7 #include "tools/gn/parse_tree.h" 8 #include "tools/gn/scope.h" 9 10 namespace functions { 11 12 namespace { 13 14 15 } // namespace 16 17 const char kForEach[] = "foreach"; 18 const char kForEach_HelpShort[] = 19 "foreach: Iterate over a list."; 20 const char kForEach_Help[] = 21 "foreach: Iterate over a list.\n" 22 "\n" 23 " foreach(<loop_var>, <list>) {\n" 24 " <loop contents>\n" 25 " }\n" 26 "\n" 27 " Executes the loop contents block over each item in the list,\n" 28 " assigning the loop_var to each item in sequence.\n" 29 "\n" 30 " The block does not introduce a new scope, so that variable assignments\n" 31 " inside the loop will be visible once the loop terminates.\n" 32 "\n" 33 " The loop variable will temporarily shadow any existing variables with\n" 34 " the same name for the duration of the loop. After the loop terminates\n" 35 " the loop variable will no longer be in scope, and the previous value\n" 36 " (if any) will be restored.\n" 37 "\n" 38 "Example\n" 39 "\n" 40 " mylist = [ \"a\", \"b\", \"c\" ]\n" 41 " foreach(i, mylist) {\n" 42 " print(i)\n" 43 " }\n" 44 "\n" 45 " Prints:\n" 46 " a\n" 47 " b\n" 48 " c\n"; 49 Value RunForEach(Scope* scope, 50 const FunctionCallNode* function, 51 const ListNode* args_list, 52 Err* err) { 53 const std::vector<const ParseNode*>& args_vector = args_list->contents(); 54 if (args_vector.size() != 2) { 55 *err = Err(function, "Wrong number of arguments to foreach().", 56 "Expecting exactly two."); 57 return Value(); 58 } 59 60 // Extract the loop variable. 61 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); 62 if (!identifier) { 63 *err = Err(args_vector[0], "Expected an identifier for the loop var."); 64 return Value(); 65 } 66 base::StringPiece loop_var(identifier->value().value()); 67 68 // Extract the list, avoid a copy if it's an identifier (common case). 69 Value value_storage_for_exec; // Backing for list_value when we need to exec. 70 const Value* list_value = NULL; 71 const IdentifierNode* list_identifier = args_vector[1]->AsIdentifier(); 72 if (list_identifier) { 73 list_value = scope->GetValue(list_identifier->value().value()); 74 if (!list_value) { 75 *err = Err(args_vector[1], "Undefined identifier."); 76 return Value(); 77 } 78 } else { 79 // Not an identifier, evaluate the node to get the result. 80 Scope list_exec_scope(scope); 81 value_storage_for_exec = args_vector[1]->Execute(scope, err); 82 if (err->has_error()) 83 return Value(); 84 list_value = &value_storage_for_exec; 85 } 86 if (!list_value->VerifyTypeIs(Value::LIST, err)) 87 return Value(); 88 const std::vector<Value>& list = list_value->list_value(); 89 90 // Block to execute. 91 const BlockNode* block = function->block(); 92 if (!block) { 93 *err = Err(function, "Expected { after foreach."); 94 return Value(); 95 } 96 97 // If the loop variable was previously defined in this scope, save it so we 98 // can put it back after the loop is done. 99 const Value* old_loop_value_ptr = scope->GetValue(loop_var); 100 Value old_loop_value; 101 if (old_loop_value_ptr) 102 old_loop_value = *old_loop_value_ptr; 103 104 for (size_t i = 0; i < list.size(); i++) { 105 scope->SetValue(loop_var, list[i], function); 106 block->ExecuteBlockInScope(scope, err); 107 if (err->has_error()) 108 return Value(); 109 } 110 111 // Put back loop var. 112 if (old_loop_value_ptr) { 113 // Put back old value. Use the copy we made, rather than use the pointer, 114 // which will probably point to the new value now in the scope. 115 scope->SetValue(loop_var, old_loop_value, old_loop_value.origin()); 116 } else { 117 // Loop variable was undefined before loop, delete it. 118 scope->RemoveIdentifier(loop_var); 119 } 120 121 return Value(); 122 } 123 124 } // namespace functions 125