1// Copyright 2014 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/template.h" 6 7#include "tools/gn/err.h" 8#include "tools/gn/functions.h" 9#include "tools/gn/parse_tree.h" 10#include "tools/gn/scope.h" 11#include "tools/gn/scope_per_file_provider.h" 12#include "tools/gn/value.h" 13 14Template::Template(const Scope* scope, const FunctionCallNode* def) 15 : closure_(scope->MakeClosure()), 16 definition_(def) { 17} 18 19Template::Template(scoped_ptr<Scope> scope, const FunctionCallNode* def) 20 : closure_(scope.Pass()), 21 definition_(def) { 22} 23 24Template::~Template() { 25} 26 27Value Template::Invoke(Scope* scope, 28 const FunctionCallNode* invocation, 29 const std::vector<Value>& args, 30 BlockNode* block, 31 Err* err) const { 32 // Don't allow templates to be executed from imported files. Imports are for 33 // simple values only. 34 if (!EnsureNotProcessingImport(invocation, scope, err)) 35 return Value(); 36 37 // First run the invocation's block. Need to allocate the scope on the heap 38 // so we can pass ownership to the template. 39 scoped_ptr<Scope> invocation_scope(new Scope(scope)); 40 if (!FillTargetBlockScope(scope, invocation, 41 invocation->function().value().as_string(), 42 block, args, invocation_scope.get(), err)) 43 return Value(); 44 block->ExecuteBlockInScope(invocation_scope.get(), err); 45 if (err->has_error()) 46 return Value(); 47 48 // Set up the scope to run the template and set the current directory for the 49 // template (which ScopePerFileProvider uses to base the target-related 50 // variables target_gen_dir and target_out_dir on) to be that of the invoker. 51 // This way, files don't have to be rebased and target_*_dir works the way 52 // people expect (otherwise its to easy to be putting generated files in the 53 // gen dir corresponding to an imported file). 54 Scope template_scope(closure_.get()); 55 template_scope.set_source_dir(scope->GetSourceDir()); 56 57 ScopePerFileProvider per_file_provider(&template_scope, true); 58 59 // Targets defined in the template go in the collector for the invoking file. 60 template_scope.set_item_collector(scope->GetItemCollector()); 61 62 // We jump through some hoops to avoid copying the invocation scope when 63 // setting it in the template scope (since the invocation scope may have 64 // large lists of source files in it and could be expensive to copy). 65 // 66 // Scope.SetValue will copy the value which will in turn copy the scope, but 67 // if we instead create a value and then set the scope on it, the copy can 68 // be avoided. 69 const char kInvoker[] = "invoker"; 70 template_scope.SetValue(kInvoker, Value(NULL, scoped_ptr<Scope>()), 71 invocation); 72 Value* invoker_value = template_scope.GetMutableValue(kInvoker, false); 73 invoker_value->SetScopeValue(invocation_scope.Pass()); 74 template_scope.set_source_dir(scope->GetSourceDir()); 75 76 const base::StringPiece target_name("target_name"); 77 template_scope.SetValue(target_name, 78 Value(invocation, args[0].string_value()), 79 invocation); 80 81 // Actually run the template code. 82 Value result = 83 definition_->block()->ExecuteBlockInScope(&template_scope, err); 84 if (err->has_error()) { 85 // If there was an error, append the caller location so the error message 86 // displays a stack trace of how it got here. 87 err->AppendSubErr(Err(invocation, "whence it was called.")); 88 return Value(); 89 } 90 91 // Check for unused variables in the invocation scope. This will find typos 92 // of things the caller meant to pass to the template but the template didn't 93 // read out. 94 // 95 // This is a bit tricky because it's theoretically possible for the template 96 // to overwrite the value of "invoker" and free the Scope owned by the 97 // value. So we need to look it up again and don't do anything if it doesn't 98 // exist. 99 invoker_value = template_scope.GetMutableValue(kInvoker, false); 100 if (invoker_value && invoker_value->type() == Value::SCOPE) { 101 if (!invoker_value->scope_value()->CheckForUnusedVars(err)) 102 return Value(); 103 } 104 105 // Check for unused variables in the template itself. 106 if (!template_scope.CheckForUnusedVars(err)) 107 return Value(); 108 109 return result; 110} 111 112LocationRange Template::GetDefinitionRange() const { 113 return definition_->GetRange(); 114} 115