Home | History | Annotate | Download | only in gn
      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