Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / gn / function_foreach.cc
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(), true);
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