Chromium Code Reviews| 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/err.h" | 5 #include "tools/gn/err.h" |
| 6 #include "tools/gn/functions.h" | 6 #include "tools/gn/functions.h" |
| 7 #include "tools/gn/parse_tree.h" | 7 #include "tools/gn/parse_tree.h" |
| 8 #include "tools/gn/scope.h" | 8 #include "tools/gn/scope.h" |
| 9 | 9 |
| 10 namespace functions { | 10 namespace functions { |
| 11 | 11 |
| 12 namespace { | 12 namespace { |
| 13 | 13 |
| 14 void ForwardAllValues(const FunctionCallNode* function, | 14 void ForwardAllValues(const FunctionCallNode* function, |
| 15 Scope* source, | 15 Scope* source, |
| 16 Scope* dest, | 16 Scope* dest, |
| 17 const std::set<std::string>& exclusion_set, | |
| 17 Err* err) { | 18 Err* err) { |
| 18 Scope::MergeOptions options; | 19 Scope::MergeOptions options; |
| 19 // This function needs to clobber existing for it to be useful. It will be | 20 // 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 // 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 // default stuff like configs set up in both scopes, so it would always |
| 22 // fail if it didn't clobber. | 23 // fail if it didn't clobber. |
| 23 options.clobber_existing = true; | 24 options.clobber_existing = true; |
| 24 options.skip_private_vars = true; | 25 options.skip_private_vars = true; |
| 25 options.mark_dest_used = false; | 26 options.mark_dest_used = false; |
| 27 options.excluded_values = exclusion_set; | |
| 26 source->NonRecursiveMergeTo(dest, options, function, | 28 source->NonRecursiveMergeTo(dest, options, function, |
| 27 "source scope", err); | 29 "source scope", err); |
| 28 source->MarkAllUsed(); | 30 source->MarkAllUsed(); |
| 29 } | 31 } |
| 30 | 32 |
| 31 void ForwardValuesFromList(Scope* source, | 33 void ForwardValuesFromList(Scope* source, |
| 32 Scope* dest, | 34 Scope* dest, |
| 33 const std::vector<Value>& list, | 35 const std::vector<Value>& list, |
| 36 const std::set<std::string>& exclusion_set, | |
| 34 Err* err) { | 37 Err* err) { |
| 35 for (const Value& cur : list) { | 38 for (const Value& cur : list) { |
| 36 if (!cur.VerifyTypeIs(Value::STRING, err)) | 39 if (!cur.VerifyTypeIs(Value::STRING, err)) |
| 37 return; | 40 return; |
| 41 if (exclusion_set.find(cur.string_value()) != exclusion_set.end()) | |
| 42 continue; | |
| 38 const Value* value = source->GetValue(cur.string_value(), true); | 43 const Value* value = source->GetValue(cur.string_value(), true); |
| 39 if (value) { | 44 if (value) { |
| 40 // Use the storage key for the original value rather than the string in | 45 // 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 | 46 // "cur" because "cur" is a temporary that will be deleted, and Scopes |
| 42 // expect a persistent StringPiece (it won't copy). Not doing this will | 47 // expect a persistent StringPiece (it won't copy). Not doing this will |
| 43 // lead the scope's key to point to invalid memory after this returns. | 48 // lead the scope's key to point to invalid memory after this returns. |
| 44 base::StringPiece storage_key = source->GetStorageKey(cur.string_value()); | 49 base::StringPiece storage_key = source->GetStorageKey(cur.string_value()); |
| 45 if (storage_key.empty()) { | 50 if (storage_key.empty()) { |
| 46 // Programmatic value, don't allow copying. | 51 // Programmatic value, don't allow copying. |
| 47 *err = Err(cur, "This value can't be forwarded.", | 52 *err = Err(cur, "This value can't be forwarded.", |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 61 } // namespace | 66 } // namespace |
| 62 | 67 |
| 63 const char kForwardVariablesFrom[] = "forward_variables_from"; | 68 const char kForwardVariablesFrom[] = "forward_variables_from"; |
| 64 const char kForwardVariablesFrom_HelpShort[] = | 69 const char kForwardVariablesFrom_HelpShort[] = |
| 65 "forward_variables_from: Copies variables from a different scope."; | 70 "forward_variables_from: Copies variables from a different scope."; |
| 66 const char kForwardVariablesFrom_Help[] = | 71 const char kForwardVariablesFrom_Help[] = |
| 67 "forward_variables_from: Copies variables from a different scope.\n" | 72 "forward_variables_from: Copies variables from a different scope.\n" |
| 68 "\n" | 73 "\n" |
| 69 " forward_variables_from(from_scope, variable_list_or_star)\n" | 74 " forward_variables_from(from_scope, variable_list_or_star)\n" |
| 70 "\n" | 75 "\n" |
| 76 " forward_variables_from(from_scope, variable_list_or_star,\n" | |
| 77 " variable_to_not_forward_list)\n" | |
| 78 "\n" | |
| 71 " Copies the given variables from the given scope to the local scope\n" | 79 " Copies the given variables from the given scope to the local scope\n" |
| 72 " if they exist. This is normally used in the context of templates to\n" | 80 " if they exist. This is normally used in the context of templates to\n" |
| 73 " use the values of variables defined in the template invocation to\n" | 81 " use the values of variables defined in the template invocation to\n" |
| 74 " a template-defined target.\n" | 82 " a template-defined target.\n" |
| 75 "\n" | 83 "\n" |
| 76 " The variables in the given variable_list will be copied if they exist\n" | 84 " The variables in the given variable_list will be copied if they exist\n" |
| 77 " in the given scope or any enclosing scope. If they do not exist,\n" | 85 " in the given scope or any enclosing scope. If they do not exist,\n" |
| 78 " nothing will happen and they be left undefined in the current scope.\n" | 86 " nothing will happen and they be left undefined in the current scope.\n" |
| 79 "\n" | 87 "\n" |
| 80 " As a special case, if the variable_list is a string with the value of\n" | 88 " As a special case, if the variable_list is a string with the value of\n" |
| 81 " \"*\", all variables from the given scope will be copied. \"*\" only\n" | 89 " \"*\", all variables from the given scope will be copied. \"*\" only\n" |
| 82 " copies variables set directly on the from_scope, not enclosing ones.\n" | 90 " copies variables set directly on the from_scope, not enclosing ones.\n" |
| 83 " Otherwise it would duplicate all global variables.\n" | 91 " Otherwise it would duplicate all global variables.\n" |
| 84 "\n" | 92 "\n" |
| 85 " When an explicit list of variables is supplied, if the variable exists\n" | 93 " When an explicit list of variables is supplied, if the variable exists\n" |
| 86 " in the current (destination) scope already, an error will be thrown.\n" | 94 " in the current (destination) scope already, an error will be thrown.\n" |
| 87 " If \"*\" is specified, variables in the current scope will be\n" | 95 " If \"*\" is specified, variables in the current scope will be\n" |
| 88 " clobbered (the latter is important because most targets have an\n" | 96 " clobbered (the latter is important because most targets have an\n" |
| 89 " implicit configs list, which means it wouldn't work at all if it\n" | 97 " implicit configs list, which means it wouldn't work at all if it\n" |
| 90 " didn't clobber).\n" | 98 " didn't clobber).\n" |
| 91 "\n" | 99 "\n" |
| 92 " The sources assignment filter (see \"gn help " | 100 " The sources assignment filter (see \"gn help " |
| 93 "set_sources_assignment_filter\")\n" | 101 "set_sources_assignment_filter\")\n" |
| 94 " is never applied by this function. It's assumed than any desired\n" | 102 " is never applied by this function. It's assumed than any desired\n" |
| 95 " filtering was already done when sources was set on the from_scope.\n" | 103 " filtering was already done when sources was set on the from_scope.\n" |
| 96 "\n" | 104 "\n" |
| 105 " The second form of the function allows to give a list of variables not\n" | |
| 106 " to forward. This is mostly useful when used in combination with \"*\".\n" | |
| 107 "\n" | |
| 97 "Examples\n" | 108 "Examples\n" |
| 98 "\n" | 109 "\n" |
| 99 " # This is a common action template. It would invoke a script with\n" | 110 " # This is a common action template. It would invoke a script with\n" |
| 100 " # some given parameters, and wants to use the various types of deps\n" | 111 " # some given parameters, and wants to use the various types of deps\n" |
| 101 " # and the visibility from the invoker if it's defined. It also injects\n" | 112 " # and the visibility from the invoker if it's defined. It also injects\n" |
| 102 " # an additional dependency to all targets.\n" | 113 " # an additional dependency to all targets.\n" |
| 103 " template(\"my_test\") {\n" | 114 " template(\"my_test\") {\n" |
| 104 " action(target_name) {\n" | 115 " action(target_name) {\n" |
| 105 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n" | 116 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n" |
| 106 " \"public_deps\", \"visibility\" " | 117 " \"public_deps\", \"visibility\" " |
| 107 "])\n" | 118 "])\n" |
| 108 " # Add our test code to the dependencies.\n" | 119 " # Add our test code to the dependencies.\n" |
| 109 " # \"deps\" may or may not be defined at this point.\n" | 120 " # \"deps\" may or may not be defined at this point.\n" |
| 110 " if (defined(deps)) {\n" | 121 " if (defined(deps)) {\n" |
| 111 " deps += [ \"//tools/doom_melon\" ]\n" | 122 " deps += [ \"//tools/doom_melon\" ]\n" |
| 112 " } else {\n" | 123 " } else {\n" |
| 113 " deps = [ \"//tools/doom_melon\" ]\n" | 124 " deps = [ \"//tools/doom_melon\" ]\n" |
| 114 " }\n" | 125 " }\n" |
| 115 " }\n" | 126 " }\n" |
| 116 " }\n" | 127 " }\n" |
| 117 "\n" | 128 "\n" |
| 118 " # This is a template around either a target whose type depends on a\n" | 129 " # This is a template around either a target whose type depends on a\n" |
| 119 " # global variable. It forwards all values from the invoker.\n" | 130 " # global variable. It forwards all values from the invoker.\n" |
| 120 " template(\"my_wrapper\") {\n" | 131 " template(\"my_wrapper\") {\n" |
| 121 " target(my_wrapper_target_type, target_name) {\n" | 132 " target(my_wrapper_target_type, target_name) {\n" |
| 122 " forward_variables_from(invoker, \"*\")\n" | 133 " forward_variables_from(invoker, \"*\")\n" |
| 123 " }\n" | 134 " }\n" |
| 124 " }\n"; | 135 " }\n" |
| 136 "\n" | |
| 137 " # This is a template around another template that uses a variable to\n" | |
| 138 " # initialize another variable and is only interested in that one.\n" | |
| 139 " template(\"my_ios_test_app\") {\n" | |
| 140 " ios_test_app(target_name) {\n" | |
| 141 " forward_variables_from(invoker, \"*\", [\"test_bundle_name\"])\n" | |
| 142 " if (!defined(extra_substitutions)) {\n" | |
| 143 " extra_substitutions = []\n" | |
| 144 " }\n" | |
| 145 " extra_substitutions += [ \"BUNDLE_ID_TEST_NAME=$test_bundle_name\" " | |
| 146 "]\n" | |
| 147 " }\n" | |
| 148 " }\n"; | |
| 125 | 149 |
| 126 // This function takes a ListNode rather than a resolved vector of values | 150 // This function takes a ListNode rather than a resolved vector of values |
| 127 // both avoid copying the potentially-large source scope, and so the variables | 151 // both avoid copying the potentially-large source scope, and so the variables |
| 128 // in the source scope can be marked as used. | 152 // in the source scope can be marked as used. |
| 129 Value RunForwardVariablesFrom(Scope* scope, | 153 Value RunForwardVariablesFrom(Scope* scope, |
| 130 const FunctionCallNode* function, | 154 const FunctionCallNode* function, |
| 131 const ListNode* args_list, | 155 const ListNode* args_list, |
| 132 Err* err) { | 156 Err* err) { |
| 133 const std::vector<const ParseNode*>& args_vector = args_list->contents(); | 157 const std::vector<const ParseNode*>& args_vector = args_list->contents(); |
| 134 if (args_vector.size() != 2) { | 158 if (args_vector.size() != 2 && args_vector.size() != 3) { |
|
tfarina
2016/01/25 12:15:25
just args_vector.size() != 3 right?
sdefresne
2016/01/25 15:28:30
No, the last argument is optional, so "forward_var
| |
| 135 *err = Err(function, "Wrong number of arguments.", | 159 *err = Err(function, "Wrong number of arguments.", |
| 136 "Expecting exactly two."); | 160 "Expecting exactly two."); |
|
tfarina
2016/01/25 12:15:25
update this error message?
sdefresne
2016/01/25 15:28:30
Done, thank you.
| |
| 137 return Value(); | 161 return Value(); |
| 138 } | 162 } |
| 139 | 163 |
| 140 // Extract the scope identifier. This assumes the first parameter is an | 164 // Extract the scope identifier. This assumes the first parameter is an |
| 141 // identifier. It is difficult to write code where this is not the case, and | 165 // identifier. It is difficult to write code where this is not the case, and |
| 142 // this saves an expensive scope copy. If necessary, this could be expanded | 166 // this saves an expensive scope copy. If necessary, this could be expanded |
| 143 // to execute the ParseNode and get the value out if it's not an identifer. | 167 // to execute the ParseNode and get the value out if it's not an identifer. |
| 144 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); | 168 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); |
| 145 if (!identifier) { | 169 if (!identifier) { |
| 146 *err = Err(args_vector[0], "Expected an identifier for the scope."); | 170 *err = Err(args_vector[0], "Expected an identifier for the scope."); |
| 147 return Value(); | 171 return Value(); |
| 148 } | 172 } |
| 149 | 173 |
| 150 // Extract the source scope. | 174 // Extract the source scope. |
| 151 Value* value = scope->GetMutableValue(identifier->value().value(), true); | 175 Value* value = scope->GetMutableValue(identifier->value().value(), true); |
| 152 if (!value) { | 176 if (!value) { |
| 153 *err = Err(identifier, "Undefined identifier."); | 177 *err = Err(identifier, "Undefined identifier."); |
| 154 return Value(); | 178 return Value(); |
| 155 } | 179 } |
| 156 if (!value->VerifyTypeIs(Value::SCOPE, err)) | 180 if (!value->VerifyTypeIs(Value::SCOPE, err)) |
| 157 return Value(); | 181 return Value(); |
| 158 Scope* source = value->scope_value(); | 182 Scope* source = value->scope_value(); |
| 159 | 183 |
| 184 // Extract the exclusion list if defined. | |
| 185 std::set<std::string> exclusion_set; | |
| 186 if (args_vector.size() == 3) { | |
| 187 Value exclusion_value = args_vector[2]->Execute(scope, err); | |
| 188 if (err->has_error()) | |
| 189 return Value(); | |
| 190 | |
| 191 if (exclusion_value.type() != Value::LIST) { | |
| 192 *err = Err(exclusion_value, "Not a valid list of variables to exclude.", | |
| 193 "Expecting a list of strings."); | |
| 194 return Value(); | |
| 195 } | |
| 196 | |
| 197 for (const Value& cur : exclusion_value.list_value()) { | |
| 198 if (!cur.VerifyTypeIs(Value::STRING, err)) | |
| 199 return Value(); | |
| 200 | |
| 201 exclusion_set.insert(exclusion_set.end(), cur.string_value()); | |
| 202 } | |
| 203 } | |
| 204 | |
| 160 // Extract the list. If all_values is not set, the what_value will be a list. | 205 // Extract the list. If all_values is not set, the what_value will be a list. |
| 161 Value what_value = args_vector[1]->Execute(scope, err); | 206 Value what_value = args_vector[1]->Execute(scope, err); |
| 162 if (err->has_error()) | 207 if (err->has_error()) |
| 163 return Value(); | 208 return Value(); |
| 164 if (what_value.type() == Value::STRING) { | 209 if (what_value.type() == Value::STRING) { |
| 165 if (what_value.string_value() == "*") { | 210 if (what_value.string_value() == "*") { |
| 166 ForwardAllValues(function, source, scope, err); | 211 ForwardAllValues(function, source, scope, exclusion_set, err); |
| 167 return Value(); | 212 return Value(); |
| 168 } | 213 } |
| 169 } else { | 214 } else { |
| 170 if (what_value.type() == Value::LIST) { | 215 if (what_value.type() == Value::LIST) { |
| 171 ForwardValuesFromList(source, scope, what_value.list_value(), err); | 216 ForwardValuesFromList(source, scope, what_value.list_value(), |
| 217 exclusion_set, err); | |
| 172 return Value(); | 218 return Value(); |
| 173 } | 219 } |
| 174 } | 220 } |
| 175 | 221 |
| 176 // Not the right type of argument. | 222 // Not the right type of argument. |
| 177 *err = Err(what_value, "Not a valid list of variables to copy.", | 223 *err = Err(what_value, "Not a valid list of variables to copy.", |
| 178 "Expecting either the string \"*\" or a list of strings."); | 224 "Expecting either the string \"*\" or a list of strings."); |
| 179 return Value(); | 225 return Value(); |
| 180 } | 226 } |
| 181 | 227 |
| 182 } // namespace functions | 228 } // namespace functions |
| OLD | NEW |