mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
128 lines
5.0 KiB
C++
128 lines
5.0 KiB
C++
|
// Copyright 2014 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/template.h"
|
||
|
|
||
|
#include <memory>
|
||
|
#include <utility>
|
||
|
|
||
|
#include "tools/gn/err.h"
|
||
|
#include "tools/gn/functions.h"
|
||
|
#include "tools/gn/parse_tree.h"
|
||
|
#include "tools/gn/scope.h"
|
||
|
#include "tools/gn/scope_per_file_provider.h"
|
||
|
#include "tools/gn/value.h"
|
||
|
#include "tools/gn/variables.h"
|
||
|
|
||
|
Template::Template(const Scope* scope, const FunctionCallNode* def)
|
||
|
: closure_(scope->MakeClosure()),
|
||
|
definition_(def) {
|
||
|
}
|
||
|
|
||
|
Template::Template(std::unique_ptr<Scope> scope, const FunctionCallNode* def)
|
||
|
: closure_(std::move(scope)), definition_(def) {}
|
||
|
|
||
|
Template::~Template() = default;
|
||
|
|
||
|
Value Template::Invoke(Scope* scope,
|
||
|
const FunctionCallNode* invocation,
|
||
|
const std::string& template_name,
|
||
|
const std::vector<Value>& args,
|
||
|
BlockNode* block,
|
||
|
Err* err) const {
|
||
|
// Don't allow templates to be executed from imported files. Imports are for
|
||
|
// simple values only.
|
||
|
if (!EnsureNotProcessingImport(invocation, scope, err))
|
||
|
return Value();
|
||
|
|
||
|
// First run the invocation's block. Need to allocate the scope on the heap
|
||
|
// so we can pass ownership to the template.
|
||
|
std::unique_ptr<Scope> invocation_scope = std::make_unique<Scope>(scope);
|
||
|
if (!FillTargetBlockScope(scope, invocation, template_name,
|
||
|
block, args, invocation_scope.get(), err))
|
||
|
return Value();
|
||
|
|
||
|
{
|
||
|
// Don't allow the block of the template invocation to include other
|
||
|
// targets configs, or template invocations. This must only be applied
|
||
|
// to the invoker's block rather than the whole function because the
|
||
|
// template execution itself must be able to define targets, etc.
|
||
|
NonNestableBlock non_nestable(scope, invocation, "template invocation");
|
||
|
if (!non_nestable.Enter(err))
|
||
|
return Value();
|
||
|
|
||
|
block->Execute(invocation_scope.get(), err);
|
||
|
if (err->has_error())
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
// Set up the scope to run the template and set the current directory for the
|
||
|
// template (which ScopePerFileProvider uses to base the target-related
|
||
|
// variables target_gen_dir and target_out_dir on) to be that of the invoker.
|
||
|
// This way, files don't have to be rebased and target_*_dir works the way
|
||
|
// people expect (otherwise its to easy to be putting generated files in the
|
||
|
// gen dir corresponding to an imported file).
|
||
|
Scope template_scope(closure_.get());
|
||
|
template_scope.set_source_dir(scope->GetSourceDir());
|
||
|
|
||
|
ScopePerFileProvider per_file_provider(&template_scope, true);
|
||
|
|
||
|
// Targets defined in the template go in the collector for the invoking file.
|
||
|
template_scope.set_item_collector(scope->GetItemCollector());
|
||
|
|
||
|
// We jump through some hoops to avoid copying the invocation scope when
|
||
|
// setting it in the template scope (since the invocation scope may have
|
||
|
// large lists of source files in it and could be expensive to copy).
|
||
|
//
|
||
|
// Scope.SetValue will copy the value which will in turn copy the scope, but
|
||
|
// if we instead create a value and then set the scope on it, the copy can
|
||
|
// be avoided.
|
||
|
template_scope.SetValue(variables::kInvoker,
|
||
|
Value(nullptr, std::unique_ptr<Scope>()), invocation);
|
||
|
Value* invoker_value = template_scope.GetMutableValue(
|
||
|
variables::kInvoker, Scope::SEARCH_NESTED, false);
|
||
|
invoker_value->SetScopeValue(std::move(invocation_scope));
|
||
|
template_scope.set_source_dir(scope->GetSourceDir());
|
||
|
|
||
|
const base::StringPiece target_name(variables::kTargetName);
|
||
|
template_scope.SetValue(target_name,
|
||
|
Value(invocation, args[0].string_value()),
|
||
|
invocation);
|
||
|
|
||
|
// Actually run the template code.
|
||
|
Value result =
|
||
|
definition_->block()->Execute(&template_scope, err);
|
||
|
if (err->has_error()) {
|
||
|
// If there was an error, append the caller location so the error message
|
||
|
// displays a stack trace of how it got here.
|
||
|
err->AppendSubErr(Err(invocation, "whence it was called."));
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
// Check for unused variables in the invocation scope. This will find typos
|
||
|
// of things the caller meant to pass to the template but the template didn't
|
||
|
// read out.
|
||
|
//
|
||
|
// This is a bit tricky because it's theoretically possible for the template
|
||
|
// to overwrite the value of "invoker" and free the Scope owned by the
|
||
|
// value. So we need to look it up again and don't do anything if it doesn't
|
||
|
// exist.
|
||
|
invoker_value = template_scope.GetMutableValue(
|
||
|
variables::kInvoker, Scope::SEARCH_NESTED, false);
|
||
|
if (invoker_value && invoker_value->type() == Value::SCOPE) {
|
||
|
if (!invoker_value->scope_value()->CheckForUnusedVars(err))
|
||
|
return Value();
|
||
|
}
|
||
|
|
||
|
// Check for unused variables in the template itself.
|
||
|
if (!template_scope.CheckForUnusedVars(err))
|
||
|
return Value();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
LocationRange Template::GetDefinitionRange() const {
|
||
|
return definition_->GetRange();
|
||
|
}
|