Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: tools/gn/function_forward_variables_from.cc

Issue 1263053003: Add forward_variables_from() and target() to GN (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698