mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
114 lines
3.4 KiB
C++
114 lines
3.4 KiB
C++
|
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#include "tools/gn/err.h"
|
||
|
#include "tools/gn/functions.h"
|
||
|
#include "tools/gn/parse_tree.h"
|
||
|
#include "tools/gn/scope.h"
|
||
|
|
||
|
namespace functions {
|
||
|
|
||
|
const char kForEach[] = "foreach";
|
||
|
const char kForEach_HelpShort[] =
|
||
|
"foreach: Iterate over a list.";
|
||
|
const char kForEach_Help[] =
|
||
|
R"(foreach: Iterate over a list.
|
||
|
|
||
|
foreach(<loop_var>, <list>) {
|
||
|
<loop contents>
|
||
|
}
|
||
|
|
||
|
Executes the loop contents block over each item in the list, assigning the
|
||
|
loop_var to each item in sequence. The <loop_var> will be a copy so assigning
|
||
|
to it will not mutate the list. The loop will iterate over a copy of <list>
|
||
|
so mutating it inside the loop will not affect iteration.
|
||
|
|
||
|
The block does not introduce a new scope, so that variable assignments inside
|
||
|
the loop will be visible once the loop terminates.
|
||
|
|
||
|
The loop variable will temporarily shadow any existing variables with the
|
||
|
same name for the duration of the loop. After the loop terminates the loop
|
||
|
variable will no longer be in scope, and the previous value (if any) will be
|
||
|
restored.
|
||
|
|
||
|
Example
|
||
|
|
||
|
mylist = [ "a", "b", "c" ]
|
||
|
foreach(i, mylist) {
|
||
|
print(i)
|
||
|
}
|
||
|
|
||
|
Prints:
|
||
|
a
|
||
|
b
|
||
|
c
|
||
|
)";
|
||
|
|
||
|
Value RunForEach(Scope* scope,
|
||
|
const FunctionCallNode* function,
|
||
|
const ListNode* args_list,
|
||
|
Err* err) {
|
||
|
const auto& args_vector = args_list->contents();
|
||
|
if (args_vector.size() != 2) {
|
||
|
*err = Err(function, "Wrong number of arguments to foreach().",
|
||
|
"Expecting exactly two.");
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
// Extract the loop variable.
|
||
|
const IdentifierNode* identifier = args_vector[0]->AsIdentifier();
|
||
|
if (!identifier) {
|
||
|
*err =
|
||
|
Err(args_vector[0].get(), "Expected an identifier for the loop var.");
|
||
|
return Value();
|
||
|
}
|
||
|
base::StringPiece loop_var(identifier->value().value());
|
||
|
|
||
|
// Extract the list to iterate over. Always copy in case the code changes
|
||
|
// the list variable inside the loop.
|
||
|
Value list_value = args_vector[1]->Execute(scope, err);
|
||
|
if (err->has_error())
|
||
|
return Value();
|
||
|
list_value.VerifyTypeIs(Value::Type::LIST, err);
|
||
|
if (err->has_error())
|
||
|
return Value();
|
||
|
const std::vector<Value>& list = list_value.list_value();
|
||
|
|
||
|
// Block to execute.
|
||
|
const BlockNode* block = function->block();
|
||
|
if (!block) {
|
||
|
*err = Err(function, "Expected { after foreach.");
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
// If the loop variable was previously defined in this scope, save it so we
|
||
|
// can put it back after the loop is done.
|
||
|
const Value* old_loop_value_ptr = scope->GetValue(loop_var);
|
||
|
Value old_loop_value;
|
||
|
if (old_loop_value_ptr)
|
||
|
old_loop_value = *old_loop_value_ptr;
|
||
|
|
||
|
for (const auto& cur : list) {
|
||
|
scope->SetValue(loop_var, cur, function);
|
||
|
block->Execute(scope, err);
|
||
|
if (err->has_error())
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
// Put back loop var.
|
||
|
if (old_loop_value_ptr) {
|
||
|
// Put back old value. Use the copy we made, rather than use the pointer,
|
||
|
// which will probably point to the new value now in the scope.
|
||
|
scope->SetValue(loop_var, std::move(old_loop_value),
|
||
|
old_loop_value.origin());
|
||
|
} else {
|
||
|
// Loop variable was undefined before loop, delete it.
|
||
|
scope->RemoveIdentifier(loop_var);
|
||
|
}
|
||
|
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
} // namespace functions
|