Change next_proto member type.
[chromium-blink-merge.git] / tools / gn / function_foreach.cc
blob321bd0a0204904d5ffd53e013c693ebd07e1e590
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.
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"
10 namespace functions {
12 namespace {
15 } // namespace
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();
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();
66 base::StringPiece loop_var(identifier->value().value());
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(), true);
74 if (!list_value) {
75 *err = Err(args_vector[1], "Undefined identifier.");
76 return Value();
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;
86 if (!list_value->VerifyTypeIs(Value::LIST, err))
87 return Value();
88 const std::vector<Value>& list = list_value->list_value();
90 // Block to execute.
91 const BlockNode* block = function->block();
92 if (!block) {
93 *err = Err(function, "Expected { after foreach.");
94 return Value();
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;
104 for (const auto& cur : list) {
105 scope->SetValue(loop_var, cur, function);
106 block->ExecuteBlockInScope(scope, err);
107 if (err->has_error())
108 return Value();
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);
121 return Value();
124 } // namespace functions