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