OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 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/err.h" | |
6 #include "tools/gn/functions.h" | |
7 #include "tools/gn/parse_tree.h" | |
8 #include "tools/gn/scope.h" | |
9 | |
10 namespace functions { | |
11 | |
12 namespace { | |
13 | |
14 void ForwardAllValues(const FunctionCallNode* function, | |
15 Scope* source, | |
16 Scope* dest, | |
17 Err* err) { | |
18 Scope::MergeOptions options; | |
19 // This function needs to clobber existing for it to be useful. It will be | |
20 // called in a template to forward all values, but there will be some | |
21 // default stuff like configs set up in both scopes, so it would always | |
22 // fail if it didn't clobber. | |
23 options.clobber_existing = true; | |
24 options.skip_private_vars = true; | |
25 options.mark_dest_used = false; | |
26 source->NonRecursiveMergeTo(dest, options, function, | |
27 "source scope", err); | |
28 source->MarkAllUsed(); | |
29 } | |
30 | |
31 void ForwardValuesFromList(Scope* source, | |
32 Scope* dest, | |
33 const std::vector<Value>& list, | |
34 Err* err) { | |
35 for (const Value& cur : list) { | |
36 if (!cur.VerifyTypeIs(Value::STRING, err)) | |
37 return; | |
38 const Value* value = source->GetValue(cur.string_value(), true); | |
39 if (value) { | |
40 // Use the storage key for the original value rather than the string in | |
41 // "cur" because "cur" is a temporary that will be deleted, and Scopes | |
42 // expect a persistent StringPiece (it won't copy). | |
43 base::StringPiece storage_key = source->GetStorageKey(cur.string_value()); | |
Dirk Pranke
2015/08/03 19:07:19
Am I understanding this correctly that the main va
| |
44 if (storage_key.empty()) | |
45 continue; // Programatic value, don't copy. | |
Dirk Pranke
2015/08/03 19:07:19
typo: programmatic
Dirk Pranke
2015/08/03 19:50:29
This should probably be an error rather than just
| |
46 | |
47 // Keep the origin information from the original value. The normal | |
48 // usage is for this to be used in a template, and if there's an error, | |
49 // the user expects to see the line where they set the variable | |
50 // blamed, rather than a template call to forward_variables_from(). | |
51 dest->SetValue(storage_key, *value, value->origin()); | |
52 } | |
53 } | |
54 } | |
55 | |
56 } // namespace | |
57 | |
58 const char kForwardVariablesFrom[] = "forward_variables_from"; | |
59 const char kForwardVariablesFrom_HelpShort[] = | |
60 "forward_variables_from: Copies variables from a different scope."; | |
61 const char kForwardVariablesFrom_Help[] = | |
62 "forward_variables_from: Copies variables from a different scope.\n" | |
63 "\n" | |
64 " forward_variables_from(from_scope, variable_list_or_star)\n" | |
65 "\n" | |
66 " Copies the given variables from the given scope to the local scope\n" | |
67 " if they exist. This is normally used in the context of templates to\n" | |
68 " use the values of variables defined in the template invocation to\n" | |
69 " a template-defined target.\n" | |
70 "\n" | |
71 " The variables in the given variable_list will be copied if they exist\n" | |
72 " in the given scope or any enclosing scope. If they do not exist,\n" | |
73 " nothing will happen and they be left undefined in the current scope.\n" | |
74 "\n" | |
75 " As a special case, if the variable_list is a string with the value of\n" | |
76 " \"*\", all variables from the given scope will be copied. Note that\n" | |
77 " this will not copy variables from enclosing scopes, only those set\n" | |
78 " directly on the referenced scope. Otherwise it will copy all kinds of\n" | |
Dirk Pranke
2015/08/03 19:07:20
suggest putting the last sentence in parentheses a
| |
79 " global variables.\n" | |
80 "\n" | |
81 " If any of the given variables exist in the current scope already, an\n" | |
82 " error will be thrown.\n" | |
83 "\n" | |
84 "Examples\n" | |
85 "\n" | |
86 " # This is a common action template. It would invoke a script with\n" | |
87 " # some given parameters, and wants to use the various types of deps\n" | |
88 " # and the visibility from the invoker if it's defined. It also injects\n" | |
89 " # an additional dependency to all targets.\n" | |
90 " template(\"my_test\") {\n" | |
91 " action(target_name) {\n" | |
92 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n" | |
93 " \"public_deps\", \"visibility\" " | |
94 "])\n" | |
95 " # Add our test code to the dependencies.\n" | |
96 " # \"deps\" may or may not be defined at this point.\n" | |
97 " if (defined(deps)) {\n" | |
98 " deps += [ \"//tools/doom_melon\" ]\n" | |
99 " } else {\n" | |
100 " deps = [ \"//tools/doom_melon\" ]\n" | |
101 " }\n" | |
102 " }\n" | |
103 " }\n" | |
104 "\n" | |
105 " # This is a template around either a target whose type depends on a\n" | |
106 " # global variable. It forwards all values from the invoker.\n" | |
107 " template(\"my_wrapper\") {\n" | |
108 " target(my_wrapper_target_type, target_name) {\n" | |
109 " forward_variables_from(invoker, \"*\")\n" | |
110 " }\n" | |
111 " }\n"; | |
112 | |
113 // This function takes a ListNode rather than a resolved vector of values | |
114 // both avoid copying the potentially-large source scope, and so the variables | |
115 // in the source scope can be marked as used. | |
116 Value RunForwardVariablesFrom(Scope* scope, | |
117 const FunctionCallNode* function, | |
118 const ListNode* args_list, | |
119 Err* err) { | |
120 const std::vector<const ParseNode*>& args_vector = args_list->contents(); | |
121 if (args_vector.size() != 2) { | |
122 *err = Err(function, "Wrong number of arguments.", | |
123 "Expecting exactly two."); | |
124 return Value(); | |
125 } | |
126 | |
127 // Extract the scope identifier. This assumes the first parameter is an | |
128 // identifier. It is difficult to write code where this is not the case, and | |
129 // this saves an expensive scope copy. If necessary, this could be expanded | |
130 // to execute the ParseNode and get the value out if it's not an identifer. | |
131 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); | |
132 if (!identifier) { | |
133 *err = Err(args_vector[0], "Expected an identifier for the scope."); | |
134 return Value(); | |
135 } | |
136 | |
137 // Extract the source scope. | |
138 Value* value = scope->GetMutableValue(identifier->value().value(), true); | |
139 if (!value) { | |
140 *err = Err(identifier, "Undefined identifier."); | |
141 return Value(); | |
142 } | |
143 if (!value->VerifyTypeIs(Value::SCOPE, err)) | |
144 return Value(); | |
145 Scope* source = value->scope_value(); | |
146 | |
147 // Extract the list. If all_values is not set, the what_value will be a list. | |
148 Value what_value = args_vector[1]->Execute(scope, err); | |
149 if (err->has_error()) | |
150 return Value(); | |
151 if (what_value.type() == Value::STRING) { | |
152 if (what_value.string_value() == "*") { | |
153 ForwardAllValues(function, source, scope, err); | |
154 return Value(); | |
155 } | |
156 } else { | |
157 if (what_value.type() == Value::LIST) { | |
158 ForwardValuesFromList(source, scope, what_value.list_value(), err); | |
159 return Value(); | |
160 } | |
161 } | |
162 | |
163 // Not the right type of argument. | |
164 *err = Err(what_value, "Not a valid list of variables to copy.", | |
165 "Expecting either the string \"*\" or a list of strings."); | |
166 return Value(); | |
167 } | |
168 | |
169 } // namespace functions | |
OLD | NEW |