OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "tools/gn/template.h" | 5 #include "tools/gn/template.h" |
6 | 6 |
7 #include "tools/gn/err.h" | 7 #include "tools/gn/err.h" |
8 #include "tools/gn/functions.h" | 8 #include "tools/gn/functions.h" |
9 #include "tools/gn/parse_tree.h" | 9 #include "tools/gn/parse_tree.h" |
10 #include "tools/gn/scope.h" | 10 #include "tools/gn/scope.h" |
(...skipping 21 matching lines...) Expand all Loading... | |
32 Value Template::Invoke(Scope* scope, | 32 Value Template::Invoke(Scope* scope, |
33 const FunctionCallNode* invocation, | 33 const FunctionCallNode* invocation, |
34 const std::vector<Value>& args, | 34 const std::vector<Value>& args, |
35 BlockNode* block, | 35 BlockNode* block, |
36 Err* err) const { | 36 Err* err) const { |
37 // Don't allow templates to be executed from imported files. Imports are for | 37 // Don't allow templates to be executed from imported files. Imports are for |
38 // simple values only. | 38 // simple values only. |
39 if (!EnsureNotProcessingImport(invocation, scope, err)) | 39 if (!EnsureNotProcessingImport(invocation, scope, err)) |
40 return Value(); | 40 return Value(); |
41 | 41 |
42 // First run the invocation's block. | 42 // First run the invocation's block. Need to allocate the scope on the heap |
43 Scope invocation_scope(scope); | 43 // so we can pass ownership to the template. |
44 scoped_ptr<Scope> invocation_scope(new Scope(scope)); | |
44 if (!FillTargetBlockScope(scope, invocation, | 45 if (!FillTargetBlockScope(scope, invocation, |
45 invocation->function().value().as_string(), | 46 invocation->function().value().as_string(), |
46 block, args, &invocation_scope, err)) | 47 block, args, invocation_scope.get(), err)) |
47 return Value(); | 48 return Value(); |
48 block->ExecuteBlockInScope(&invocation_scope, err); | 49 block->ExecuteBlockInScope(invocation_scope.get(), err); |
49 if (err->has_error()) | 50 if (err->has_error()) |
50 return Value(); | 51 return Value(); |
51 | 52 |
52 // Set up the scope to run the template. This should be dependent on the | 53 // Set up the scope to run the template. This should be dependent on the |
53 // closure, but have the "invoker" and "target_name" values injected, and the | 54 // closure, but have the "invoker" and "target_name" values injected, and the |
54 // current dir matching the invoker. | 55 // current dir matching the invoker. We jump through some hoops to avoid |
56 // copying the invocation scope when setting it in the template scope (since | |
57 // the invocation scope may have large lists of source files in it and could | |
58 // be expensive to copy). | |
59 // | |
60 // Scope.SetValue will copy the value which will in turn copy the scope, but | |
61 // if we instead create a value and then set the scope on it, the copy can | |
62 // be avoided. | |
55 Scope template_scope(closure_.get()); | 63 Scope template_scope(closure_.get()); |
56 template_scope.SetValue("invoker", Value(NULL, &invocation_scope), | 64 const char kInvoker[] = "invoker"; |
65 template_scope.SetValue(kInvoker, Value(NULL, scoped_ptr<Scope>()), | |
57 invocation); | 66 invocation); |
67 Value* invoker_value = template_scope.GetMutableValue(kInvoker, false); | |
68 invoker_value->SetScopeValue(invocation_scope.Pass()); | |
58 template_scope.set_source_dir(scope->GetSourceDir()); | 69 template_scope.set_source_dir(scope->GetSourceDir()); |
59 | 70 |
60 const base::StringPiece target_name("target_name"); | 71 const base::StringPiece target_name("target_name"); |
61 template_scope.SetValue(target_name, | 72 template_scope.SetValue(target_name, |
62 Value(invocation, args[0].string_value()), | 73 Value(invocation, args[0].string_value()), |
63 invocation); | 74 invocation); |
64 | 75 |
65 // Run the template code. Don't check for unused variables since the | 76 // Run the template code. Don't check for unused variables since the |
66 // template could be executed in many different ways and it could be that | 77 // template could be executed in many different ways and it could be that |
67 // not all executions use all values in the closure. | 78 // not all executions use all values in the closure. |
68 return definition_->block()->ExecuteBlockInScope(&template_scope, err); | 79 Value result = |
80 definition_->block()->ExecuteBlockInScope(&template_scope, err); | |
81 | |
82 // Check for unused variables in the invocation scope. This will find typos | |
83 // of things the caller meant to pass to the template but the template didn't | |
84 // read out. | |
85 // | |
86 // This is a bit tricky because it's theoretically possible for the template | |
scottmg
2014/04/04 20:15:47
Is there some way to make invoker readonly to avoi
brettw
2014/04/04 20:35:13
Nope, I don't have support for readonly variables.
| |
87 // to overwrite the value of "invoker" and free the Scope owned by the | |
88 // value. So we need to look it up again and don't do anything if it doesn't | |
89 // exist. | |
90 invoker_value = template_scope.GetMutableValue(kInvoker, false); | |
91 if (invoker_value && invoker_value->type() == Value::SCOPE) { | |
92 if (!invoker_value->scope_value()->CheckForUnusedVars(err)) | |
93 return Value(); | |
94 } | |
95 | |
96 // Check for unused variables in the template itself. | |
97 if (!template_scope.CheckForUnusedVars(err)) | |
98 return Value(); | |
99 | |
100 return result; | |
69 } | 101 } |
70 | 102 |
71 LocationRange Template::GetDefinitionRange() const { | 103 LocationRange Template::GetDefinitionRange() const { |
72 return definition_->GetRange(); | 104 return definition_->GetRange(); |
73 } | 105 } |
OLD | NEW |