OLD | NEW |
(Empty) | |
| 1 # Copyright (C) 2013 Google Inc. All rights reserved. |
| 2 # |
| 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are |
| 5 # met: |
| 6 # |
| 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer |
| 11 # in the documentation and/or other materials provided with the |
| 12 # distribution. |
| 13 # * Neither the name of Google Inc. nor the names of its |
| 14 # contributors may be used to endorse or promote products derived from |
| 15 # this software without specific prior written permission. |
| 16 # |
| 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 |
| 29 """Parser for Blink IDL |
| 30 |
| 31 The parser uses the PLY (Python Lex-Yacc) library to build a set of parsing |
| 32 rules which understand the Blink dialect of Web IDL. |
| 33 It derives from a standard Web IDL parser, overriding the rules where Blink |
| 34 IDL differs. |
| 35 |
| 36 Web IDL: |
| 37 http://www.w3.org/TR/WebIDL/ |
| 38 Web IDL Grammar: |
| 39 http://www.w3.org/TR/WebIDL/#idl-grammar |
| 40 PLY: |
| 41 http://www.dabeaz.com/ply/ |
| 42 """ |
| 43 |
| 44 # Disable check for line length and Member as Function due to how grammar rules |
| 45 # are defined with PLY |
| 46 # |
| 47 # pylint: disable=R0201 |
| 48 # pylint: disable=C0301 |
| 49 # |
| 50 # Disable attribute validation, as lint can't import parent class to check |
| 51 # pylint: disable=E1101 |
| 52 |
| 53 import os.path |
| 54 import sys |
| 55 |
| 56 # PLY is in Chromium src/third_party/ply |
| 57 module_path, module_name = os.path.split(__file__) |
| 58 third_party = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pard
ir) |
| 59 sys.path.append(third_party) |
| 60 from ply import yacc |
| 61 |
| 62 # Base parser is in Chromium src/tools/idl_parser |
| 63 tools_dir = os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir
, os.pardir, 'tools') |
| 64 sys.path.append(tools_dir) |
| 65 from idl_parser.idl_parser import IDLParser, ListFromConcat |
| 66 |
| 67 from blink_idl_lexer import BlinkIDLLexer |
| 68 |
| 69 |
| 70 REMOVED_RULES = ['Comments', # [0.1] |
| 71 'CommentsRest', # [0.2] |
| 72 'AttributeOrOperation', # [30] |
| 73 'StringifierAttributeOrOperation', # [31] |
| 74 'Operation', # [35] |
| 75 'Qualifiers', # [36] |
| 76 ] |
| 77 |
| 78 |
| 79 class BlinkIDLParser(IDLParser): |
| 80 # Numbering scheme is: |
| 81 # [1] for Web IDL spec (or base Pepper IDL) |
| 82 # [b1] for Blink IDL (overrides Web IDL or inserts rule) |
| 83 # [s1] is for numbering Sakamoto |
| 84 |
| 85 # [0] Override Pepper definition, since we strip comments |
| 86 def p_Top(self, p): |
| 87 """Top : Definitions""" |
| 88 p[0] = p[1] |
| 89 |
| 90 # [3] Override Pepper action, since we distinguish callbacks |
| 91 def p_CallbackOrInterface(self, p): |
| 92 """CallbackOrInterface : CALLBACK CallbackRestOrInterface |
| 93 | Interface""" |
| 94 if len(p) > 2: |
| 95 p[2].AddChildren(self.BuildTrue('Callback')) |
| 96 p[0] = p[2] |
| 97 else: |
| 98 p[0] = p[1] |
| 99 |
| 100 # [b10] |
| 101 def p_InterfaceMember(self, p): |
| 102 """InterfaceMember : Const |
| 103 | AttributeOrOperationOrIterator""" |
| 104 # Standard is (no 'OrIterator'): |
| 105 # InterfaceMember : Const |
| 106 # | AttributeOrOperation |
| 107 p[0] = p[1] |
| 108 |
| 109 # [b19] |
| 110 # List needed for multiple inheritance in SVG |
| 111 # FIXME: remove when multiple inheritance (which is deprecated) is removed |
| 112 def p_Inheritance(self, p): |
| 113 """Inheritance : ':' ScopedNameList |
| 114 |""" |
| 115 # Standard is (single identifier, not list): |
| 116 # """Inheritance : ':' identifier |
| 117 # |""" |
| 118 if len(p) > 1: |
| 119 p[0] = self.BuildProduction('MultipleInherit', p, 2, p[2]) |
| 120 |
| 121 # [b27] |
| 122 def p_ConstValue(self, p): |
| 123 """ConstValue : BooleanLiteral |
| 124 | FloatLiteral |
| 125 | IntegerLiteral |
| 126 | StringLiteral |
| 127 | null""" |
| 128 # Standard is (no 'string', fewer 'Literals'): |
| 129 # ConstValue : BooleanLiteral |
| 130 # | FloatLiteral |
| 131 # | integer |
| 132 # | NULL |
| 133 p[0] = p[1] |
| 134 |
| 135 # [b27.1] |
| 136 def p_IntegerLiteral(self, p): |
| 137 """IntegerLiteral : integer""" |
| 138 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'integer'), |
| 139 self.BuildAttribute('NAME', p[1])) |
| 140 |
| 141 # [b27.2] |
| 142 def p_StringLiteral(self, p): |
| 143 """StringLiteral : string""" |
| 144 p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'DOMString'), |
| 145 self.BuildAttribute('NAME', p[1])) |
| 146 |
| 147 # [b30] |
| 148 # Replaces [30] AttributeOrOperation |
| 149 def p_AttributeOrOperationOrIterator(self, p): |
| 150 """AttributeOrOperationOrIterator : Serializer |
| 151 | Qualifier AttributeOrOperationRest |
| 152 | Attribute |
| 153 | OperationOrIterator""" |
| 154 # Standard is: |
| 155 # AttributeOrOperation : "stringifier" StringifierAttributeOrOperation |
| 156 # | Attribute |
| 157 # | Operation |
| 158 if len(p) > 2: |
| 159 p[2].AddChildren(p[1]) |
| 160 p[0] = p[2] |
| 161 else: |
| 162 p[0] = p[1] |
| 163 |
| 164 # Serialization |
| 165 # FIXME: can we remove?? |
| 166 # [s31] |
| 167 def p_Serializer(self, p): |
| 168 """Serializer : SERIALIZER SerializerRest""" |
| 169 p[0] = p[1] |
| 170 |
| 171 # [s32] |
| 172 def p_SerializerRest(self, p): |
| 173 """SerializerRest : OperationRest |
| 174 | '=' SerializationPattern |
| 175 |""" |
| 176 if len(p) > 2: |
| 177 p[0] = p[2] |
| 178 elif len(p) == 2: |
| 179 p[0] = p[1] |
| 180 |
| 181 # [s33] |
| 182 def p_SerializationPattern(self, p): |
| 183 """SerializationPattern : '{' SerializationPatternMap '}' |
| 184 | '[' SerializationPatternList ']' |
| 185 | identifier""" |
| 186 if len(p) == 4: |
| 187 p[0] = p[2] |
| 188 else: |
| 189 p[0] = p[1] |
| 190 |
| 191 # [s34] |
| 192 def p_SerializationPatternMap(self, p): |
| 193 """SerializationPatternMap : GETTER |
| 194 | INHERIT Identifiers |
| 195 | identifier Identifiers |
| 196 |""" |
| 197 if len(p) > 1: |
| 198 p[0] = p[1] |
| 199 |
| 200 # [s35] |
| 201 def p_SerializationPatternList(self, p): |
| 202 """SerializationPatternList : GETTER |
| 203 | identifier Identifiers |
| 204 |""" |
| 205 if len(p) > 1: |
| 206 p[0] = p[1] |
| 207 |
| 208 # [s36] |
| 209 def p_Identifiers(self, p): |
| 210 """Identifiers : ',' identifier Identifiers |
| 211 |""" |
| 212 if len(p) > 1: |
| 213 p[0] = p[2] |
| 214 |
| 215 # Iterator and SpecialOperation |
| 216 # Follows [35] Operation |
| 217 # [b35.1] |
| 218 def p_OperationOrIterator(self, p): |
| 219 """OperationOrIterator : ReturnType OperationOrIteratorRest |
| 220 | SpecialOperation""" |
| 221 if len(p) > 2: |
| 222 p[0] = self.BuildProduction('OperationOrIterator', p, 2, ListFromCon
cat(p[1], p[2])) |
| 223 else: |
| 224 p[0] = p[1] |
| 225 |
| 226 # [b35.2] |
| 227 def p_OperationOrIteratorRest(self, p): |
| 228 """OperationOrIteratorRest : IteratorRest |
| 229 | OperationRest""" |
| 230 p[0] = p[1] |
| 231 |
| 232 # [b35.3] |
| 233 def p_IteratorRest(self, p): |
| 234 """IteratorRest : ITERATOR OptionalIteratorInterfaceOrObject ';'""" |
| 235 p[0] = p[2] |
| 236 |
| 237 # [b35.4] |
| 238 def p_OptionalIteratorInterfaceOrObject(self, p): |
| 239 """OptionalIteratorInterfaceOrObject : OptionalIteratorInterface |
| 240 | OBJECT""" |
| 241 p[0] = p[1] |
| 242 |
| 243 # [b35.5] |
| 244 def p_OptionalIteratorInterface(self, p): |
| 245 """OptionalIteratorInterface : '=' identifier |
| 246 |""" |
| 247 if len(p) > 2: |
| 248 p[0] = p[2] |
| 249 |
| 250 # [b35.6] |
| 251 def p_SpecialOperation(self, p): |
| 252 """SpecialOperation : Special Specials ReturnType OperationRest""" |
| 253 specials = ListFromConcat(p[1], p[2]) |
| 254 p[4].AddChildren(p[3]) |
| 255 p[0] = p[4] |
| 256 p[0].AddChildren(specials) |
| 257 |
| 258 # Follows [36] Qualifiers |
| 259 # [b36.1] [s37] |
| 260 def p_Qualifier(self, p): |
| 261 """Qualifier : STATIC |
| 262 | STRINGIFIER""" |
| 263 if p[1] == 'static': |
| 264 p[0] = self.BuildTrue('STATIC') |
| 265 elif p[1] == 'stringifier': |
| 266 p[0] = self.BuildTrue('STRINGIFIER') |
| 267 |
| 268 # [b39] |
| 269 def p_OperationRest(self, p): |
| 270 """OperationRest : OptionalIdentifier '(' ArgumentList ')' Raises ';'""" |
| 271 # Standard is: |
| 272 # OperationRest : ReturnType OptionalIdentifier '(' ArgumentList ')' ';' |
| 273 arguments = self.BuildProduction('Arguments', p, 2, p[3]) |
| 274 p[0] = self.BuildNamed('Operation', p, 1, arguments) |
| 275 |
| 276 # [b39.1] |
| 277 def p_Raises(self, p): |
| 278 """Raises : RAISES ExceptionList |
| 279 |""" |
| 280 if len(p) > 2: |
| 281 p[0] = p[2] |
| 282 |
| 283 # [s39.2] |
| 284 def p_ExceptionList(self, p): |
| 285 """ExceptionList : '(' ScopedNameList ')'""" |
| 286 p[0] = p[2] |
| 287 |
| 288 # [b39.3] |
| 289 def p_AttributeOrOperationRest(self, p): |
| 290 """AttributeOrOperationRest : AttributeRest |
| 291 | ReturnType OperationRest |
| 292 | ';'""" |
| 293 if len(p) > 2: |
| 294 p[2].AddChildren(p[1]) |
| 295 p[0] = p[2] |
| 296 elif len(p) == 2 and p[1] != ';': |
| 297 p[0] = p[1] |
| 298 |
| 299 # [b39.2] |
| 300 def p_AttributeRest(self, p): |
| 301 """AttributeRest : ReadOnly ATTRIBUTE Type identifier Get ';'""" |
| 302 p[0] = self.BuildNamed('Attribute', p, 4,
ListFromConcat(p[1], p[3], p[5])) |
| 303 |
| 304 # [b39.3] |
| 305 def p_Get(self, p): |
| 306 """Get : InheritsGetter SetRaises |
| 307 | SetGetRaises |
| 308 |""" |
| 309 if len(p) > 2: |
| 310 p[0] = p[2] |
| 311 elif len(p) == 2: |
| 312 p[0] = p[1] |
| 313 |
| 314 # [s39.4] |
| 315 def p_InheritsGetter(self, p): |
| 316 """InheritsGetter : INHERITS GETTER""" |
| 317 pass |
| 318 |
| 319 # [b47] |
| 320 def p_ExceptionMember(self, p): |
| 321 """ExceptionMember : Const |
| 322 | ExceptionField |
| 323 | Attribute |
| 324 | ExceptionFieldToString""" |
| 325 # Standard is: |
| 326 # ExceptionMember : Const |
| 327 # | ExceptionField |
| 328 p[0] = p[1] |
| 329 |
| 330 # [b47.1] |
| 331 def p_ExceptionFieldToString(self, p): |
| 332 """ExceptionFieldToString : Type identifier '(' ')' ';'""" |
| 333 # Needed to handle: |
| 334 # // Override in a Mozilla compatible format |
| 335 # [NotEnumerable] DOMString toString(); |
| 336 p[0] = self.BuildNamed('ExceptionFieldToString', p, 2, p[1]) |
| 337 |
| 338 # Extended attributes |
| 339 # [b49] Override Pepper: remove comment field, since comments stripped |
| 340 # FIXME: Upstream |
| 341 def p_ExtendedAttributeList(self, p): |
| 342 """ExtendedAttributeList : '[' ExtendedAttribute ExtendedAttributes ']' |
| 343 | '[' ']' |
| 344 | """ |
| 345 if len(p) > 3: |
| 346 items = ListFromConcat(p[2], p[3]) |
| 347 attribs = self.BuildProduction('ExtAttributes', p, 1, items) |
| 348 p[0] = ListFromConcat(p[0], attribs) |
| 349 |
| 350 # [b50] Allow optional trailing comma |
| 351 def p_ExtendedAttributes(self, p): |
| 352 """ExtendedAttributes : ',' ExtendedAttribute ExtendedAttributes |
| 353 | ',' |
| 354 |""" |
| 355 if len(p) > 2: |
| 356 p[0] = ListFromConcat(p[2], p[3]) |
| 357 |
| 358 # [b51] Add ExtendedAttributeIdentOrIdent and ExtendedAttributeIdentAndIdent |
| 359 def p_ExtendedAttribute(self, p): |
| 360 """ExtendedAttribute : ExtendedAttributeNoArgs |
| 361 | ExtendedAttributeArgList |
| 362 | ExtendedAttributeIdent |
| 363 | ExtendedAttributeIdentOrIdent |
| 364 | ExtendedAttributeIdentAndIdent |
| 365 | ExtendedAttributeNamedArgList""" |
| 366 p[0] = p[1] |
| 367 |
| 368 # FIXME: Upstream UnionType |
| 369 # [59] |
| 370 def p_UnionType(self, p): |
| 371 """UnionType : '(' UnionMemberType OR UnionMemberType UnionMemberTypes '
)'""" |
| 372 members = ListFromConcat(p[2], p[4], p[5]) |
| 373 p[0] = self.BuildProduction('UnionType', p, 1, members) |
| 374 |
| 375 # [60] |
| 376 def p_UnionMemberType(self, p): |
| 377 """UnionMemberType : NonAnyType |
| 378 | UnionType TypeSuffix |
| 379 | ANY '[' ']' TypeSuffix""" |
| 380 if len(p) == 2: |
| 381 p[0] = p[1] |
| 382 elif len(p) == 3: |
| 383 p[0] = ListFromConcat(p[1], p[2]) |
| 384 else: |
| 385 p[0] = ListFromConcat(self.BuildProduction('Any', p, 1), p[4]) |
| 386 |
| 387 # [61] |
| 388 def p_UnionMemberTypes(self, p): |
| 389 """UnionMemberTypes : OR UnionMemberType UnionMemberTypes |
| 390 |""" |
| 391 if len(p) > 1: |
| 392 p[0] = ListFromConcat(p[2], p[3]) |
| 393 |
| 394 # [70] Override Pepper to remove non-standard sized array |
| 395 # FIXME: upstream should remove sized array from base |
| 396 def p_TypeSuffix(self, p): |
| 397 """TypeSuffix : '[' ']' TypeSuffix |
| 398 | '?' TypeSuffixStartingWithArray |
| 399 |""" |
| 400 if len(p) == 4: |
| 401 p[0] = self.BuildProduction('Array', p, 1, p[3]) |
| 402 |
| 403 if len(p) == 3: |
| 404 p[0] = ListFromConcat(self.BuildTrue('NULLABLE'), p[2]) |
| 405 |
| 406 # [b76.1] |
| 407 def p_ExtendedAttributeIdentOrIdent(self, p): |
| 408 """ExtendedAttributeIdentOrIdent : identifier '=' identifier '|' identif
ier""" |
| 409 # Used in a handful of files |
| 410 value = self.BuildAttribute('VALUE', p[3] + '|' + p[5]) |
| 411 p[0] = self.BuildNamed('ExtAttribute', p, 1, value) |
| 412 |
| 413 # [b76.2] |
| 414 def p_ExtendedAttributeIdentAndIdent(self, p): |
| 415 """ExtendedAttributeIdentAndIdent : identifier '=' identifier '&' identi
fier""" |
| 416 # FIXME: Used only in NavigatorContentUtils.idl, |
| 417 # which doesn't appear to be parsed - remove? |
| 418 value = self.BuildAttribute('VALUE', p[3] + '&' + p[5]) |
| 419 p[0] = self.BuildNamed('ExtAttribute', p, 1, value) |
| 420 |
| 421 # Exceptions |
| 422 # [s25] |
| 423 def p_SetGetRaises(self, p): |
| 424 """SetGetRaises : SetRaises GetRaises2 |
| 425 | GetRaises |
| 426 | SetGetRaises2""" |
| 427 p[0] = p[1] |
| 428 |
| 429 # [s27] |
| 430 def p_GetRaises(self, p): |
| 431 """GetRaises : GETTER RAISES ExceptionList""" |
| 432 p[0] = p[3] |
| 433 |
| 434 # [s27.5] |
| 435 def p_GetRaises2(self, p): |
| 436 """GetRaises2 : ',' GETTER RAISES ExceptionList |
| 437 |""" |
| 438 p[0] = p[4] |
| 439 |
| 440 # [s28] |
| 441 def p_SetRaises(self, p): |
| 442 """SetRaises : SETTER RAISES ExceptionList""" |
| 443 p[0] = p[3] |
| 444 |
| 445 # [s29] |
| 446 def p_SetGetRaises2(self, p): |
| 447 """SetGetRaises2 : GetRaises3 SetRaises3""" |
| 448 # FIXME |
| 449 p[0] = p[1] |
| 450 |
| 451 # [s29a] |
| 452 def p_GetRaises3(self, p): |
| 453 """GetRaises3 : GETRAISES ExceptionList |
| 454 |""" |
| 455 p[0] = p[2] |
| 456 |
| 457 # [s29b] |
| 458 def p_SetRaises3(self, p): |
| 459 """SetRaises3 : SETRAISES ExceptionList |
| 460 |""" |
| 461 p[0] = p[2] |
| 462 |
| 463 # Scoped names |
| 464 # FIXME: remove?? |
| 465 # [s63] |
| 466 def p_ScopedNameList(self, p): |
| 467 """ScopedNameList : ScopedName ScopedNames""" |
| 468 scoped_name = self.BuildNamed('ScopedName', p, 1) |
| 469 p[0] = ListFromConcat(scoped_name, p[2]) |
| 470 |
| 471 # [s64] |
| 472 def p_ScopedNames(self, p): |
| 473 """ScopedNames : ',' ScopedName ScopedNames |
| 474 |""" |
| 475 if len(p) > 1: |
| 476 scoped_name = self.BuildNamed('ScopedName', p, 2) |
| 477 p[0] = ListFromConcat(scoped_name, p[3]) |
| 478 |
| 479 # [s65] |
| 480 def p_ScopedName(self, p): |
| 481 """ScopedName : AbsoluteScopedName |
| 482 | RelativeScopedName""" |
| 483 p[0] = p[1] |
| 484 |
| 485 # [s66] |
| 486 def p_AbsoluteScopedName(self, p): |
| 487 """AbsoluteScopedName : SCOPE_RESOLUTION identifier ScopedNameParts""" |
| 488 p[0] = p[2] |
| 489 |
| 490 # [s67] |
| 491 def p_RelativeScopedName(self, p): |
| 492 """RelativeScopedName : identifier ScopedNameParts""" |
| 493 p[0] = p[1] |
| 494 |
| 495 # [s68] |
| 496 def p_ScopedNameParts(self, p): |
| 497 """ScopedNameParts : SCOPE_RESOLUTION identifier ScopedNameParts |
| 498 |""" |
| 499 # if len(p) > 1: |
| 500 # p[0] = p[2] |
| 501 pass |
| 502 |
| 503 def __dir__(self): |
| 504 # Remove rules from listing so yacc doesn't parse them |
| 505 keys = set(self.__dict__.keys() + dir(self.__class__)) |
| 506 for rule in REMOVED_RULES: |
| 507 keys.remove('p_' + rule) |
| 508 return list(keys) |
| 509 |
| 510 def __init__(self, lexer, verbose=False, debug=False, mute_error=False): |
| 511 self.lexer = lexer |
| 512 self.tokens = lexer.KnownTokens() |
| 513 # SLR yields faster table generation (same output), ok b/c LL(1) grammar |
| 514 self.yaccobj = yacc.yacc(module=self, debug=debug, method='SLR') |
| 515 # Optimized mode, improves startup time of yacc compiler |
| 516 # optimize=1 |
| 517 # Turn on table generation with: |
| 518 # write_tables=1 |
| 519 # Turn off table generation with: |
| 520 # tabmodule=None, write_tables=0 |
| 521 self.parse_debug = debug |
| 522 self.verbose = verbose |
| 523 self.mute_error = mute_error |
| 524 self._parse_errors = 0 |
| 525 self._parse_warnings = 0 |
| 526 self._last_error_msg = None |
| 527 self._last_error_lineno = 0 |
| 528 self._last_error_pos = 0 |
| 529 |
| 530 |
| 531 # If run by itself, attempt to build the parser |
| 532 if __name__ == '__main__': |
| 533 parser = BlinkIDLParser(BlinkIDLLexer()) |
OLD | NEW |