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"
12 const char kForEach
[] = "foreach";
13 const char kForEach_HelpShort
[] =
14 "foreach: Iterate over a list.";
15 const char kForEach_Help
[] =
16 "foreach: Iterate over a list.\n"
18 " foreach(<loop_var>, <list>) {\n"
22 " Executes the loop contents block over each item in the list,\n"
23 " assigning the loop_var to each item in sequence.\n"
25 " The block does not introduce a new scope, so that variable assignments\n"
26 " inside the loop will be visible once the loop terminates.\n"
28 " The loop variable will temporarily shadow any existing variables with\n"
29 " the same name for the duration of the loop. After the loop terminates\n"
30 " the loop variable will no longer be in scope, and the previous value\n"
31 " (if any) will be restored.\n"
35 " mylist = [ \"a\", \"b\", \"c\" ]\n"
36 " foreach(i, mylist) {\n"
45 Value
RunForEach(Scope
* scope
,
46 const FunctionCallNode
* function
,
47 const ListNode
* args_list
,
49 const std::vector
<const ParseNode
*>& args_vector
= args_list
->contents();
50 if (args_vector
.size() != 2) {
51 *err
= Err(function
, "Wrong number of arguments to foreach().",
52 "Expecting exactly two.");
56 // Extract the loop variable.
57 const IdentifierNode
* identifier
= args_vector
[0]->AsIdentifier();
59 *err
= Err(args_vector
[0], "Expected an identifier for the loop var.");
62 base::StringPiece
loop_var(identifier
->value().value());
64 // Extract the list, avoid a copy if it's an identifier (common case).
65 Value value_storage_for_exec
; // Backing for list_value when we need to exec.
66 const Value
* list_value
= nullptr;
67 const IdentifierNode
* list_identifier
= args_vector
[1]->AsIdentifier();
68 if (list_identifier
) {
69 list_value
= scope
->GetValue(list_identifier
->value().value(), true);
71 *err
= Err(args_vector
[1], "Undefined identifier.");
75 // Not an identifier, evaluate the node to get the result.
76 Scope
list_exec_scope(scope
);
77 value_storage_for_exec
= args_vector
[1]->Execute(scope
, err
);
80 list_value
= &value_storage_for_exec
;
82 if (!list_value
->VerifyTypeIs(Value::LIST
, err
))
84 const std::vector
<Value
>& list
= list_value
->list_value();
87 const BlockNode
* block
= function
->block();
89 *err
= Err(function
, "Expected { after foreach.");
93 // If the loop variable was previously defined in this scope, save it so we
94 // can put it back after the loop is done.
95 const Value
* old_loop_value_ptr
= scope
->GetValue(loop_var
);
97 if (old_loop_value_ptr
)
98 old_loop_value
= *old_loop_value_ptr
;
100 for (const auto& cur
: list
) {
101 scope
->SetValue(loop_var
, cur
, function
);
102 block
->Execute(scope
, err
);
103 if (err
->has_error())
107 // Put back loop var.
108 if (old_loop_value_ptr
) {
109 // Put back old value. Use the copy we made, rather than use the pointer,
110 // which will probably point to the new value now in the scope.
111 scope
->SetValue(loop_var
, old_loop_value
, old_loop_value
.origin());
113 // Loop variable was undefined before loop, delete it.
114 scope
->RemoveIdentifier(loop_var
);
120 } // namespace functions