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

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

Issue 223783005: Add support for reading .gypi files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 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/input_conversion.h" 5 #include "tools/gn/input_conversion.h"
6 6
7 #include "base/strings/string_split.h" 7 #include "base/strings/string_split.h"
8 #include "base/strings/string_util.h" 8 #include "base/strings/string_util.h"
9 #include "tools/gn/build_settings.h" 9 #include "tools/gn/build_settings.h"
10 #include "tools/gn/err.h" 10 #include "tools/gn/err.h"
11 #include "tools/gn/input_file.h" 11 #include "tools/gn/input_file.h"
12 #include "tools/gn/label.h" 12 #include "tools/gn/label.h"
13 #include "tools/gn/parse_tree.h" 13 #include "tools/gn/parse_tree.h"
14 #include "tools/gn/parser.h" 14 #include "tools/gn/parser.h"
15 #include "tools/gn/scheduler.h"
15 #include "tools/gn/scope.h" 16 #include "tools/gn/scope.h"
16 #include "tools/gn/settings.h" 17 #include "tools/gn/settings.h"
17 #include "tools/gn/tokenizer.h" 18 #include "tools/gn/tokenizer.h"
18 #include "tools/gn/value.h" 19 #include "tools/gn/value.h"
19 20
20 namespace { 21 namespace {
21 22
22 // When parsing the result as a value, we may get various types of errors. 23 // When parsing the result as a value, we may get various types of errors.
23 // This creates an error message for this case with an optional nested error 24 // This creates an error message for this case with an optional nested error
24 // message to reference. If there is no nested err, pass Err(). 25 // message to reference. If there is no nested err, pass Err().
(...skipping 15 matching lines...) Expand all
40 help_text.append("\nThe exact error was:"); 41 help_text.append("\nThe exact error was:");
41 42
42 Err result(origin, "Script result wasn't a valid value.", help_text); 43 Err result(origin, "Script result wasn't a valid value.", help_text);
43 if (nested.has_error()) { 44 if (nested.has_error()) {
44 result.AppendSubErr(Err(LocationRange(), nested.message(), 45 result.AppendSubErr(Err(LocationRange(), nested.message(),
45 nested.help_text())); 46 nested.help_text()));
46 } 47 }
47 return result; 48 return result;
48 } 49 }
49 50
51 enum ValueOrScope {
52 PARSE_VALUE, // Treat the input as an expression.
53 PARSE_SCOPE, // Treat the input as code and return the resulting scope.
54 };
55
50 // Sets the origin of the value and any nested values with the given node. 56 // Sets the origin of the value and any nested values with the given node.
51 Value ParseString(const std::string& input, 57 Value ParseValueOrScope(const std::string& input,
52 const ParseNode* origin, 58 ValueOrScope what,
53 Err* err) { 59 const ParseNode* origin,
54 SourceFile empty_source_for_most_vexing_parse; 60 Err* err) {
55 InputFile input_file(empty_source_for_most_vexing_parse); 61 // The memory for these will be kept around by the input file manager
56 input_file.SetContents(input); 62 // so the origin parse nodes for the values will be preserved.
63 InputFile* input_file;
64 std::vector<Token>* tokens;
65 scoped_ptr<ParseNode>* parse_root_ptr;
66 g_scheduler->input_file_manager()->AddDynamicInput(
67 &input_file, &tokens, &parse_root_ptr);
57 68
58 std::vector<Token> tokens = Tokenizer::Tokenize(&input_file, err); 69 input_file->SetContents(input);
70 input_file->set_friendly_name("Script input"); // TODO(brettw) make nicer.
71
72 *tokens = Tokenizer::Tokenize(input_file, err);
59 if (err->has_error()) { 73 if (err->has_error()) {
60 *err = MakeParseErr(input, origin, *err); 74 *err = MakeParseErr(input, origin, *err);
61 return Value(); 75 return Value();
62 } 76 }
63 77
64 scoped_ptr<ParseNode> expression = Parser::ParseExpression(tokens, err); 78 // Parse the file according to what we're looking for.
79 if (what == PARSE_VALUE)
80 *parse_root_ptr = Parser::ParseExpression(*tokens, err);
81 else
82 *parse_root_ptr = Parser::Parse(*tokens, err); // Will return a Block.
65 if (err->has_error()) { 83 if (err->has_error()) {
66 *err = MakeParseErr(input, origin, *err); 84 *err = MakeParseErr(input, origin, *err);
67 return Value(); 85 return Value();
68 } 86 }
87 ParseNode* parse_root = parse_root_ptr->get(); // For nicer syntax below.
69 88
70 // It's valid for the result to be a null pointer, this just means that the 89 // It's valid for the result to be a null pointer, this just means that the
71 // script returned nothing. 90 // script returned nothing.
72 if (!expression) 91 if (!parse_root)
73 return Value(); 92 return Value();
74 93
75 // The result should either be a list or a literal, anything else is 94 // When parsing as a value, the result should either be a list or a literal,
76 // invalid. 95 // anything else is invalid.
77 if (!expression->AsList() && !expression->AsLiteral()) { 96 if (what == PARSE_VALUE) {
78 *err = MakeParseErr(input, origin, Err()); 97 if (!parse_root->AsList() && !parse_root->AsLiteral()) {
79 return Value(); 98 *err = MakeParseErr(input, origin, Err());
99 return Value();
100 }
80 } 101 }
81 102
82 BuildSettings build_settings; 103 BuildSettings build_settings;
83 Settings settings(&build_settings, std::string()); 104 Settings settings(&build_settings, std::string());
84 Scope scope(&settings); 105 Scope scope(&settings);
85 106
86 Err nested_err; 107 Err nested_err;
87 Value result = expression->Execute(&scope, &nested_err); 108 Value result = parse_root->Execute(&scope, &nested_err);
88 if (nested_err.has_error()) { 109 if (nested_err.has_error()) {
89 *err = MakeParseErr(input, origin, nested_err); 110 *err = MakeParseErr(input, origin, nested_err);
90 return Value(); 111 return Value();
91 } 112 }
92 113
93 // The returned value will have references to the temporary parse nodes we 114 // When we want the result as a scope, the result is actually the scope
94 // made on the stack. If the values are used in an error message in the 115 // we made, rather than the result of running the code (which will be
95 // future, this will crash. Reset the origin of all values to be our 116 // empty).
96 // containing origin. 117 if (what == PARSE_SCOPE) {
97 result.RecursivelySetOrigin(origin); 118 DCHECK(result.type() == Value::NONE);
119 // Convert the scope to a dictionary. We have to return the result, and
120 // a scope value does not own its scope.
121 result = Value(origin, Value::DICT);
122 std::vector<base::StringPiece> keys;
123 scope.GetCurrentScopeKeys(&keys);
124 for (size_t i = 0; i < keys.size(); i++) {
125 result.dict_value()[keys[i].as_string()] =
126 *scope.GetValue(keys[i], false);
127 }
128 }
98 return result; 129 return result;
99 } 130 }
100 131
101 Value ParseList(const std::string& input, 132 Value ParseList(const std::string& input, const ParseNode* origin, Err* err) {
102 const ParseNode* origin,
103 Err* err) {
104 Value ret(origin, Value::LIST); 133 Value ret(origin, Value::LIST);
105 std::vector<std::string> as_lines; 134 std::vector<std::string> as_lines;
106 base::SplitString(input, '\n', &as_lines); 135 base::SplitString(input, '\n', &as_lines);
107 136
108 // Trim one empty line from the end since the last line might end in a 137 // Trim one empty line from the end since the last line might end in a
109 // newline. If the user wants more trimming, they'll specify "trim" in the 138 // newline. If the user wants more trimming, they'll specify "trim" in the
110 // input conversion options. 139 // input conversion options.
111 if (!as_lines.empty() && as_lines[as_lines.size() - 1].empty()) 140 if (!as_lines.empty() && as_lines[as_lines.size() - 1].empty())
112 as_lines.resize(as_lines.size() - 1); 141 as_lines.resize(as_lines.size() - 1);
113 142
(...skipping 20 matching lines...) Expand all
134 std::string trimmed; 163 std::string trimmed;
135 base::TrimWhitespaceASCII(input, base::TRIM_ALL, &trimmed); 164 base::TrimWhitespaceASCII(input, base::TRIM_ALL, &trimmed);
136 165
137 // Remove "trim" prefix from the input conversion and re-run. 166 // Remove "trim" prefix from the input conversion and re-run.
138 return DoConvertInputToValue( 167 return DoConvertInputToValue(
139 trimmed, origin, original_input_conversion, 168 trimmed, origin, original_input_conversion,
140 input_conversion.substr(arraysize(kTrimPrefix) - 1), err); 169 input_conversion.substr(arraysize(kTrimPrefix) - 1), err);
141 } 170 }
142 171
143 if (input_conversion == "value") 172 if (input_conversion == "value")
144 return ParseString(input, origin, err); 173 return ParseValueOrScope(input, PARSE_VALUE, origin, err);
145 if (input_conversion == "string") 174 if (input_conversion == "string")
146 return Value(origin, input); 175 return Value(origin, input);
147 if (input_conversion == "list lines") 176 if (input_conversion == "list lines")
148 return ParseList(input, origin, err); 177 return ParseList(input, origin, err);
178 if (input_conversion == "scope")
179 return ParseValueOrScope(input, PARSE_SCOPE, origin, err);
149 180
150 *err = Err(original_input_conversion, "Not a valid input_conversion.", 181 *err = Err(original_input_conversion, "Not a valid input_conversion.",
151 "Have you considered a career in retail?"); 182 "Have you considered a career in retail?");
152 return Value(); 183 return Value();
153 } 184 }
154 185
155 } // namespace 186 } // namespace
156 187
157 extern const char kInputConversion_Help[] = 188 extern const char kInputConversion_Help[] =
158 "input_conversion: Specifies how to transform input to a variable.\n" 189 "input_conversion: Specifies how to transform input to a variable.\n"
159 "\n" 190 "\n"
160 " input_conversion is an argument to read_file and exec_script that\n" 191 " input_conversion is an argument to read_file and exec_script that\n"
161 " specifies how the result of the read operation should be converted\n" 192 " specifies how the result of the read operation should be converted\n"
162 " into a variable.\n" 193 " into a variable.\n"
163 "\n" 194 "\n"
164 " \"\" (the default)\n" 195 " \"\" (the default)\n"
165 " Discard the result and return None.\n" 196 " Discard the result and return None.\n"
166 "\n" 197 "\n"
167 " \"list lines\"\n" 198 " \"list lines\"\n"
168 " Return the file contents as a list, with a string for each line.\n" 199 " Return the file contents as a list, with a string for each line.\n"
169 " The newlines will not be present in the result. The last line may\n" 200 " The newlines will not be present in the result. The last line may\n"
170 " or may not end in a newline.\n" 201 " or may not end in a newline.\n"
171 "\n" 202 "\n"
172 " After splitting, each individual line will be trimmed of\n" 203 " After splitting, each individual line will be trimmed of\n"
173 " whitespace on both ends.\n" 204 " whitespace on both ends.\n"
174 "\n" 205 "\n"
206 " \"scope\"\n"
207 " Execute the block as GN code and return a scope with the\n"
208 " resulting values in it. If the input was:\n"
209 " a = [ \"hello.cc\", \"world.cc\" ]\n"
210 " b = 26\n"
211 " and you read the result into a variable named \"val\", then you\n"
212 " could access contents the \".\" operator on \"val\":\n"
213 " sources = val.a\n"
214 " some_count = val.b\n"
215 "\n"
216 " \"string\"\n"
217 " Return the file contents into a single string.\n"
218 "\n"
175 " \"value\"\n" 219 " \"value\"\n"
176 " Parse the input as if it was a literal rvalue in a buildfile.\n" 220 " Parse the input as if it was a literal rvalue in a buildfile.\n"
177 " Examples of typical program output using this mode:\n" 221 " Examples of typical program output using this mode:\n"
178 " [ \"foo\", \"bar\" ] (result will be a list)\n" 222 " [ \"foo\", \"bar\" ] (result will be a list)\n"
179 " or\n" 223 " or\n"
180 " \"foo bar\" (result will be a string)\n" 224 " \"foo bar\" (result will be a string)\n"
181 " or\n" 225 " or\n"
182 " 5 (result will be an integer)\n" 226 " 5 (result will be an integer)\n"
183 "\n" 227 "\n"
184 " Note that if the input is empty, the result will be a null value\n" 228 " Note that if the input is empty, the result will be a null value\n"
185 " which will produce an error if assigned to a variable.\n" 229 " which will produce an error if assigned to a variable.\n"
186 "\n" 230 "\n"
187 " \"string\"\n"
188 " Return the file contents into a single string.\n"
189 "\n"
190 " \"trim ...\"\n" 231 " \"trim ...\"\n"
191 " Prefixing any of the other transformations with the word \"trim\"\n" 232 " Prefixing any of the other transformations with the word \"trim\"\n"
192 " will result in whitespace being trimmed from the beginning and end\n" 233 " will result in whitespace being trimmed from the beginning and end\n"
193 " of the result before processing.\n" 234 " of the result before processing.\n"
194 "\n" 235 "\n"
195 " Examples: \"trim string\" or \"trim list lines\"\n" 236 " Examples: \"trim string\" or \"trim list lines\"\n"
196 "\n" 237 "\n"
197 " Note that \"trim value\" is useless because the value parser skips\n" 238 " Note that \"trim value\" is useless because the value parser skips\n"
198 " whitespace anyway.\n"; 239 " whitespace anyway.\n";
199 240
200 Value ConvertInputToValue(const std::string& input, 241 Value ConvertInputToValue(const std::string& input,
201 const ParseNode* origin, 242 const ParseNode* origin,
202 const Value& input_conversion_value, 243 const Value& input_conversion_value,
203 Err* err) { 244 Err* err) {
204 if (input_conversion_value.type() == Value::NONE) 245 if (input_conversion_value.type() == Value::NONE)
205 return Value(); // Allow null inputs to mean discard the result. 246 return Value(); // Allow null inputs to mean discard the result.
206 if (!input_conversion_value.VerifyTypeIs(Value::STRING, err)) 247 if (!input_conversion_value.VerifyTypeIs(Value::STRING, err))
207 return Value(); 248 return Value();
208 return DoConvertInputToValue(input, origin, input_conversion_value, 249 return DoConvertInputToValue(input, origin, input_conversion_value,
209 input_conversion_value.string_value(), err); 250 input_conversion_value.string_value(), err);
210 } 251 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698