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" |
| 11 #include "tools/gn/scope_per_file_provider.h" |
11 #include "tools/gn/value.h" | 12 #include "tools/gn/value.h" |
12 | 13 |
13 Template::Template(const Scope* scope, const FunctionCallNode* def) | 14 Template::Template(const Scope* scope, const FunctionCallNode* def) |
14 : closure_(scope->MakeClosure()), | 15 : closure_(scope->MakeClosure()), |
15 definition_(def) { | 16 definition_(def) { |
16 } | 17 } |
17 | 18 |
18 Template::Template(scoped_ptr<Scope> scope, const FunctionCallNode* def) | 19 Template::Template(scoped_ptr<Scope> scope, const FunctionCallNode* def) |
19 : closure_(scope.Pass()), | 20 : closure_(scope.Pass()), |
20 definition_(def) { | 21 definition_(def) { |
(...skipping 22 matching lines...) Expand all Loading... |
43 // so we can pass ownership to the template. | 44 // so we can pass ownership to the template. |
44 scoped_ptr<Scope> invocation_scope(new Scope(scope)); | 45 scoped_ptr<Scope> invocation_scope(new Scope(scope)); |
45 if (!FillTargetBlockScope(scope, invocation, | 46 if (!FillTargetBlockScope(scope, invocation, |
46 invocation->function().value().as_string(), | 47 invocation->function().value().as_string(), |
47 block, args, invocation_scope.get(), err)) | 48 block, args, invocation_scope.get(), err)) |
48 return Value(); | 49 return Value(); |
49 block->ExecuteBlockInScope(invocation_scope.get(), err); | 50 block->ExecuteBlockInScope(invocation_scope.get(), err); |
50 if (err->has_error()) | 51 if (err->has_error()) |
51 return Value(); | 52 return Value(); |
52 | 53 |
53 // Set up the scope to run the template. This should be dependent on the | 54 // Set up the scope to run the template and set the current directory for the |
54 // closure, but have the "invoker" and "target_name" values injected, and the | 55 // template (which ScopePerFileProvider uses to base the target-related |
55 // current dir matching the invoker. We jump through some hoops to avoid | 56 // variables target_gen_dir and target_out_dir on) to be that of the invoker. |
56 // copying the invocation scope when setting it in the template scope (since | 57 // This way, files don't have to be rebased and target_*_dir works the way |
57 // the invocation scope may have large lists of source files in it and could | 58 // people expect (otherwise its to easy to be putting generated files in the |
58 // be expensive to copy). | 59 // gen dir corresponding to an imported file). |
| 60 Scope template_scope(closure_.get()); |
| 61 template_scope.set_source_dir(scope->GetSourceDir()); |
| 62 |
| 63 ScopePerFileProvider per_file_provider(&template_scope, true); |
| 64 |
| 65 // We jump through some hoops to avoid copying the invocation scope when |
| 66 // setting it in the template scope (since the invocation scope may have |
| 67 // large lists of source files in it and could be expensive to copy). |
59 // | 68 // |
60 // Scope.SetValue will copy the value which will in turn copy the scope, but | 69 // 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 | 70 // if we instead create a value and then set the scope on it, the copy can |
62 // be avoided. | 71 // be avoided. |
63 Scope template_scope(closure_.get()); | |
64 const char kInvoker[] = "invoker"; | 72 const char kInvoker[] = "invoker"; |
65 template_scope.SetValue(kInvoker, Value(NULL, scoped_ptr<Scope>()), | 73 template_scope.SetValue(kInvoker, Value(NULL, scoped_ptr<Scope>()), |
66 invocation); | 74 invocation); |
67 Value* invoker_value = template_scope.GetMutableValue(kInvoker, false); | 75 Value* invoker_value = template_scope.GetMutableValue(kInvoker, false); |
68 invoker_value->SetScopeValue(invocation_scope.Pass()); | 76 invoker_value->SetScopeValue(invocation_scope.Pass()); |
69 template_scope.set_source_dir(scope->GetSourceDir()); | 77 template_scope.set_source_dir(scope->GetSourceDir()); |
70 | 78 |
71 const base::StringPiece target_name("target_name"); | 79 const base::StringPiece target_name("target_name"); |
72 template_scope.SetValue(target_name, | 80 template_scope.SetValue(target_name, |
73 Value(invocation, args[0].string_value()), | 81 Value(invocation, args[0].string_value()), |
74 invocation); | 82 invocation); |
75 | 83 |
76 // Run the template code. Don't check for unused variables since the | 84 // Actually run the template code. |
77 // template could be executed in many different ways and it could be that | |
78 // not all executions use all values in the closure. | |
79 Value result = | 85 Value result = |
80 definition_->block()->ExecuteBlockInScope(&template_scope, err); | 86 definition_->block()->ExecuteBlockInScope(&template_scope, err); |
| 87 if (err->has_error()) |
| 88 return Value(); |
81 | 89 |
82 // Check for unused variables in the invocation scope. This will find typos | 90 // 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 | 91 // of things the caller meant to pass to the template but the template didn't |
84 // read out. | 92 // read out. |
85 // | 93 // |
86 // This is a bit tricky because it's theoretically possible for the template | 94 // This is a bit tricky because it's theoretically possible for the template |
87 // to overwrite the value of "invoker" and free the Scope owned by the | 95 // 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 | 96 // value. So we need to look it up again and don't do anything if it doesn't |
89 // exist. | 97 // exist. |
90 invoker_value = template_scope.GetMutableValue(kInvoker, false); | 98 invoker_value = template_scope.GetMutableValue(kInvoker, false); |
91 if (invoker_value && invoker_value->type() == Value::SCOPE) { | 99 if (invoker_value && invoker_value->type() == Value::SCOPE) { |
92 if (!invoker_value->scope_value()->CheckForUnusedVars(err)) | 100 if (!invoker_value->scope_value()->CheckForUnusedVars(err)) |
93 return Value(); | 101 return Value(); |
94 } | 102 } |
95 | 103 |
96 // Check for unused variables in the template itself. | 104 // Check for unused variables in the template itself. |
97 if (!template_scope.CheckForUnusedVars(err)) | 105 if (!template_scope.CheckForUnusedVars(err)) |
98 return Value(); | 106 return Value(); |
99 | 107 |
100 return result; | 108 return result; |
101 } | 109 } |
102 | 110 |
103 LocationRange Template::GetDefinitionRange() const { | 111 LocationRange Template::GetDefinitionRange() const { |
104 return definition_->GetRange(); | 112 return definition_->GetRange(); |
105 } | 113 } |
OLD | NEW |