OLD | NEW |
(Empty) | |
| 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 |
| 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). Not doing this will |
| 43 // lead the scope's key to point to invalid memory after this returns. |
| 44 base::StringPiece storage_key = source->GetStorageKey(cur.string_value()); |
| 45 if (storage_key.empty()) { |
| 46 // Programmatic value, don't allow copying. |
| 47 *err = Err(cur, "This value can't be forwarded.", |
| 48 "The variable \"" + cur.string_value() + "\" is a built-in."); |
| 49 return; |
| 50 } |
| 51 |
| 52 // Keep the origin information from the original value. The normal |
| 53 // usage is for this to be used in a template, and if there's an error, |
| 54 // the user expects to see the line where they set the variable |
| 55 // blamed, rather than a template call to forward_variables_from(). |
| 56 dest->SetValue(storage_key, *value, value->origin()); |
| 57 } |
| 58 } |
| 59 } |
| 60 |
| 61 } // namespace |
| 62 |
| 63 const char kForwardVariablesFrom[] = "forward_variables_from"; |
| 64 const char kForwardVariablesFrom_HelpShort[] = |
| 65 "forward_variables_from: Copies variables from a different scope."; |
| 66 const char kForwardVariablesFrom_Help[] = |
| 67 "forward_variables_from: Copies variables from a different scope.\n" |
| 68 "\n" |
| 69 " forward_variables_from(from_scope, variable_list_or_star)\n" |
| 70 "\n" |
| 71 " 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" |
| 73 " use the values of variables defined in the template invocation to\n" |
| 74 " a template-defined target.\n" |
| 75 "\n" |
| 76 " 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" |
| 78 " nothing will happen and they be left undefined in the current scope.\n" |
| 79 "\n" |
| 80 " 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" |
| 82 " copies variables set directly on the from_scope, not enclosing ones.\n" |
| 83 " Otherwise it would duplicate all global variables.\n" |
| 84 "\n" |
| 85 " 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" |
| 87 " If \"*\" is specified, variables in the current scope will be\n" |
| 88 " 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" |
| 90 " didn't clobber).\n" |
| 91 "\n" |
| 92 " The sources assignment filter (see \"gn help " |
| 93 "set_sources_assignment_filter\")\n" |
| 94 " 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" |
| 96 "\n" |
| 97 "Examples\n" |
| 98 "\n" |
| 99 " # 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" |
| 101 " # and the visibility from the invoker if it's defined. It also injects\n" |
| 102 " # an additional dependency to all targets.\n" |
| 103 " template(\"my_test\") {\n" |
| 104 " action(target_name) {\n" |
| 105 " forward_variables_from(invoker, [ \"data_deps\", \"deps\",\n" |
| 106 " \"public_deps\", \"visibility\" " |
| 107 "])\n" |
| 108 " # Add our test code to the dependencies.\n" |
| 109 " # \"deps\" may or may not be defined at this point.\n" |
| 110 " if (defined(deps)) {\n" |
| 111 " deps += [ \"//tools/doom_melon\" ]\n" |
| 112 " } else {\n" |
| 113 " deps = [ \"//tools/doom_melon\" ]\n" |
| 114 " }\n" |
| 115 " }\n" |
| 116 " }\n" |
| 117 "\n" |
| 118 " # 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" |
| 120 " template(\"my_wrapper\") {\n" |
| 121 " target(my_wrapper_target_type, target_name) {\n" |
| 122 " forward_variables_from(invoker, \"*\")\n" |
| 123 " }\n" |
| 124 " }\n"; |
| 125 |
| 126 // 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 |
| 128 // in the source scope can be marked as used. |
| 129 Value RunForwardVariablesFrom(Scope* scope, |
| 130 const FunctionCallNode* function, |
| 131 const ListNode* args_list, |
| 132 Err* err) { |
| 133 const std::vector<const ParseNode*>& args_vector = args_list->contents(); |
| 134 if (args_vector.size() != 2) { |
| 135 *err = Err(function, "Wrong number of arguments.", |
| 136 "Expecting exactly two."); |
| 137 return Value(); |
| 138 } |
| 139 |
| 140 // 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 |
| 142 // 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. |
| 144 const IdentifierNode* identifier = args_vector[0]->AsIdentifier(); |
| 145 if (!identifier) { |
| 146 *err = Err(args_vector[0], "Expected an identifier for the scope."); |
| 147 return Value(); |
| 148 } |
| 149 |
| 150 // Extract the source scope. |
| 151 Value* value = scope->GetMutableValue(identifier->value().value(), true); |
| 152 if (!value) { |
| 153 *err = Err(identifier, "Undefined identifier."); |
| 154 return Value(); |
| 155 } |
| 156 if (!value->VerifyTypeIs(Value::SCOPE, err)) |
| 157 return Value(); |
| 158 Scope* source = value->scope_value(); |
| 159 |
| 160 // 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); |
| 162 if (err->has_error()) |
| 163 return Value(); |
| 164 if (what_value.type() == Value::STRING) { |
| 165 if (what_value.string_value() == "*") { |
| 166 ForwardAllValues(function, source, scope, err); |
| 167 return Value(); |
| 168 } |
| 169 } else { |
| 170 if (what_value.type() == Value::LIST) { |
| 171 ForwardValuesFromList(source, scope, what_value.list_value(), err); |
| 172 return Value(); |
| 173 } |
| 174 } |
| 175 |
| 176 // Not the right type of argument. |
| 177 *err = Err(what_value, "Not a valid list of variables to copy.", |
| 178 "Expecting either the string \"*\" or a list of strings."); |
| 179 return Value(); |
| 180 } |
| 181 |
| 182 } // namespace functions |
OLD | NEW |