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 """Helper functions useful when writing scripts that integrate with GN. | 5 """Helper functions useful when writing scripts that integrate with GN. |
6 | 6 |
7 The main functions are ToGNString and FromGNString which convert between | 7 The main functions are ToGNString and FromGNString which convert between |
8 serialized GN veriables and Python variables. | 8 serialized GN veriables and Python variables. |
9 | 9 |
10 To use in a random python file in the build: | 10 To use in a random python file in the build: |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
93 the Python string literal directly. | 93 the Python string literal directly. |
94 | 94 |
95 The main use cases for this is for other types, in particular lists. When | 95 The main use cases for this is for other types, in particular lists. When |
96 using string interpolation on a list (as in the top example) the embedded | 96 using string interpolation on a list (as in the top example) the embedded |
97 strings will be quoted and escaped according to GN rules so the list can be | 97 strings will be quoted and escaped according to GN rules so the list can be |
98 re-parsed to get the same result.""" | 98 re-parsed to get the same result.""" |
99 parser = GNValueParser(input) | 99 parser = GNValueParser(input) |
100 return parser.Parse() | 100 return parser.Parse() |
101 | 101 |
102 | 102 |
103 def FromGNArgs(input): | |
104 """Converts a string with a bunch of gn arg assignments into a Python dict. | |
105 | |
106 Given a whitespace-separated list of | |
107 | |
108 <ident> = (integer | string | boolean) | |
109 | |
110 gn assignments, this returns a Python dict, i.e.: | |
111 | |
112 FromGNArgs("foo=true\nbar=1\n") -> { 'foo': True, 'bar': 1 }. | |
113 | |
114 Only simple types are supported; variables, complex types, calls | |
115 and other, more complicated things are not. | |
116 | |
117 This routine is meant to handle only the simple sorts of values that | |
118 arise in parsing --args. | |
119 """ | |
120 parser = GNValueParser(input) | |
121 return parser.ParseArgs() | |
122 | |
123 | |
103 def UnescapeGNString(value): | 124 def UnescapeGNString(value): |
104 """Given a string with GN escaping, returns the unescaped string. | 125 """Given a string with GN escaping, returns the unescaped string. |
105 | 126 |
106 Be careful not to feed with input from a Python parsing function like | 127 Be careful not to feed with input from a Python parsing function like |
107 'ast' because it will do Python unescaping, which will be incorrect when | 128 'ast' because it will do Python unescaping, which will be incorrect when |
108 fed into the GN unescaper.""" | 129 fed into the GN unescaper.""" |
109 result = '' | 130 result = '' |
110 i = 0 | 131 i = 0 |
111 while i < len(value): | 132 while i < len(value): |
112 if value[i] == '\\': | 133 if value[i] == '\\': |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
164 - GN lists ('[1, "asdf", 3]') will be converted to Python lists. | 185 - GN lists ('[1, "asdf", 3]') will be converted to Python lists. |
165 | 186 |
166 - GN scopes ('{ ... }') are not supported.""" | 187 - GN scopes ('{ ... }') are not supported.""" |
167 result = self._ParseAllowTrailing() | 188 result = self._ParseAllowTrailing() |
168 self.ConsumeWhitespace() | 189 self.ConsumeWhitespace() |
169 if not self.IsDone(): | 190 if not self.IsDone(): |
170 raise GNException("Trailing input after parsing:\n " + | 191 raise GNException("Trailing input after parsing:\n " + |
171 self.input[self.cur:]) | 192 self.input[self.cur:]) |
172 return result | 193 return result |
173 | 194 |
174 def _ParseAllowTrailing(self): | 195 def ParseArgs(self): |
196 """Converts a whitespace-separated list of ident=literals to a dict. | |
197 | |
198 See additional usage notes on FromGNArgs, above. | |
199 """ | |
200 d = {} | |
201 | |
202 self.ConsumeWhitespace() | |
203 while not self.IsDone(): | |
204 ident = self._ParseIdent() | |
205 self.ConsumeWhitespace() | |
206 if self.input[self.cur] != '=': | |
207 raise GNException("Unexpected token: " + self.input[self.cur:]) | |
208 self.cur += 1 | |
209 self.ConsumeWhitespace() | |
210 val = self._ParseAllowTrailing(lists_are_allowed=False) | |
brettw
2016/04/05 19:25:27
It seems like you go through some effort here to d
Dirk Pranke
2016/04/05 19:28:42
I don't remember exactly now, but I have a vague m
| |
211 self.ConsumeWhitespace() | |
212 d[ident] = val | |
213 | |
214 return d | |
215 | |
216 def _ParseAllowTrailing(self, lists_are_allowed=True): | |
175 """Internal version of Parse that doesn't check for trailing stuff.""" | 217 """Internal version of Parse that doesn't check for trailing stuff.""" |
176 self.ConsumeWhitespace() | 218 self.ConsumeWhitespace() |
177 if self.IsDone(): | 219 if self.IsDone(): |
178 raise GNException("Expected input to parse.") | 220 raise GNException("Expected input to parse.") |
179 | 221 |
180 next_char = self.input[self.cur] | 222 next_char = self.input[self.cur] |
181 if next_char == '[': | 223 if lists_are_allowed and next_char == '[': |
182 return self.ParseList() | 224 return self.ParseList() |
183 elif _IsDigitOrMinus(next_char): | 225 elif _IsDigitOrMinus(next_char): |
184 return self.ParseNumber() | 226 return self.ParseNumber() |
185 elif next_char == '"': | 227 elif next_char == '"': |
186 return self.ParseString() | 228 return self.ParseString() |
187 elif self._ConstantFollows('true'): | 229 elif self._ConstantFollows('true'): |
188 return True | 230 return True |
189 elif self._ConstantFollows('false'): | 231 elif self._ConstantFollows('false'): |
190 return False | 232 return False |
191 else: | 233 else: |
192 raise GNException("Unexpected token: " + self.input[self.cur:]) | 234 raise GNException("Unexpected token: " + self.input[self.cur:]) |
193 | 235 |
236 def _ParseIdent(self): | |
237 id = '' | |
238 | |
239 next_char = self.input[self.cur] | |
240 if not next_char.isalpha() and not next_char=='_': | |
241 raise GNException("Expected an identifier: " + self.input[self.cur:]) | |
242 | |
243 id += next_char | |
244 self.cur += 1 | |
245 | |
246 next_char = self.input[self.cur] | |
247 while next_char.isalpha() or next_char.isdigit() or next_char=='_': | |
248 id += next_char | |
249 self.cur += 1 | |
250 next_char = self.input[self.cur] | |
251 | |
252 return id | |
253 | |
194 def ParseNumber(self): | 254 def ParseNumber(self): |
195 self.ConsumeWhitespace() | 255 self.ConsumeWhitespace() |
196 if self.IsDone(): | 256 if self.IsDone(): |
197 raise GNException('Expected number but got nothing.') | 257 raise GNException('Expected number but got nothing.') |
198 | 258 |
199 begin = self.cur | 259 begin = self.cur |
200 | 260 |
201 # The first character can include a negative sign. | 261 # The first character can include a negative sign. |
202 if not self.IsDone() and _IsDigitOrMinus(self.input[self.cur]): | 262 if not self.IsDone() and _IsDigitOrMinus(self.input[self.cur]): |
203 self.cur += 1 | 263 self.cur += 1 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 location in the input. If it does, the text is consumed and the function | 339 location in the input. If it does, the text is consumed and the function |
280 returns true. Otherwise, returns false and the current position is | 340 returns true. Otherwise, returns false and the current position is |
281 unchanged.""" | 341 unchanged.""" |
282 end = self.cur + len(constant) | 342 end = self.cur + len(constant) |
283 if end > len(self.input): | 343 if end > len(self.input): |
284 return False # Not enough room. | 344 return False # Not enough room. |
285 if self.input[self.cur:end] == constant: | 345 if self.input[self.cur:end] == constant: |
286 self.cur = end | 346 self.cur = end |
287 return True | 347 return True |
288 return False | 348 return False |
OLD | NEW |