| Index: tools/gn/template.cc
|
| diff --git a/tools/gn/template.cc b/tools/gn/template.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cae5e0c2d092c4439fa1028624d79fc286e2dd5c
|
| --- /dev/null
|
| +++ b/tools/gn/template.cc
|
| @@ -0,0 +1,73 @@
|
| +// 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 "tools/gn/err.h"
|
| +#include "tools/gn/functions.h"
|
| +#include "tools/gn/parse_tree.h"
|
| +#include "tools/gn/scope.h"
|
| +#include "tools/gn/value.h"
|
| +
|
| +Template::Template(const Scope* scope, const FunctionCallNode* def)
|
| + : closure_(scope->MakeClosure()),
|
| + definition_(def) {
|
| +}
|
| +
|
| +Template::Template(scoped_ptr<Scope> scope, const FunctionCallNode* def)
|
| + : closure_(scope.Pass()),
|
| + definition_(def) {
|
| +}
|
| +
|
| +Template::~Template() {
|
| +}
|
| +
|
| +scoped_ptr<Template> Template::Clone() const {
|
| + // We can make a new closure from our closure to copy it.
|
| + return scoped_ptr<Template>(
|
| + new Template(closure_->MakeClosure(), definition_));
|
| +}
|
| +
|
| +Value Template::Invoke(Scope* scope,
|
| + const FunctionCallNode* invocation,
|
| + 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.
|
| + Scope invocation_scope(scope);
|
| + if (!FillTargetBlockScope(scope, invocation,
|
| + invocation->function().value().as_string(),
|
| + block, args, &invocation_scope, err))
|
| + return Value();
|
| + block->ExecuteBlockInScope(&invocation_scope, err);
|
| + if (err->has_error())
|
| + return Value();
|
| +
|
| + // Set up the scope to run the template. This should be dependent on the
|
| + // closure, but have the "invoker" and "target_name" values injected, and the
|
| + // current dir matching the invoker.
|
| + Scope template_scope(closure_.get());
|
| + template_scope.SetValue("invoker", Value(NULL, &invocation_scope),
|
| + invocation);
|
| + template_scope.set_source_dir(scope->GetSourceDir());
|
| +
|
| + const base::StringPiece target_name("target_name");
|
| + template_scope.SetValue(target_name,
|
| + Value(invocation, args[0].string_value()),
|
| + invocation);
|
| +
|
| + // Run the template code. Don't check for unused variables since the
|
| + // template could be executed in many different ways and it could be that
|
| + // not all executions use all values in the closure.
|
| + return definition_->block()->ExecuteBlockInScope(&template_scope, err);
|
| +}
|
| +
|
| +LocationRange Template::GetDefinitionRange() const {
|
| + return definition_->GetRange();
|
| +}
|
|
|