| 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 """Blink IDL Intermediate Representation (IR) classes. | 
|  | 30 | 
|  | 31 Classes are primarily constructors, which build an IdlDefinitions object | 
|  | 32 (and various contained objects) from an AST (produced by blink_idl_parser). | 
|  | 33 | 
|  | 34 This is in two steps: | 
|  | 35 * Constructors walk the AST, creating objects. | 
|  | 36 * Typedef resolution. | 
|  | 37 | 
|  | 38 Typedefs are all resolved here, and not stored in IR. | 
|  | 39 | 
|  | 40 Typedef resolution uses some auxiliary classes and OOP techniques to make this | 
|  | 41 a generic call, via the resolve_typedefs() method. | 
|  | 42 | 
|  | 43 Class hierarchy (mostly containment, '<' for inheritance): | 
|  | 44 | 
|  | 45 IdlDefinitions | 
|  | 46     IdlCallbackFunction < TypedObject | 
|  | 47     IdlEnum :: FIXME: remove, just use a dict for enums | 
|  | 48     IdlInterface | 
|  | 49         IdlAttribute < TypedObject | 
|  | 50         IdlConstant < TypedObject | 
|  | 51         IdlOperation < TypedObject | 
|  | 52             IdlArgument < TypedObject | 
|  | 53     IdlException < IdlInterface | 
|  | 54         (same contents as IdlInterface) | 
|  | 55 | 
|  | 56 TypedObject :: mixin for typedef resolution | 
|  | 57 | 
|  | 58 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler | 
|  | 59 """ | 
|  | 60 | 
|  | 61 import abc | 
|  | 62 | 
|  | 63 from idl_types import IdlType, IdlUnionType | 
|  | 64 | 
|  | 65 SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'DELETER'] | 
|  | 66 STANDARD_TYPEDEFS = { | 
|  | 67     # http://www.w3.org/TR/WebIDL/#common-DOMTimeStamp | 
|  | 68     'DOMTimeStamp': 'unsigned long long', | 
|  | 69 } | 
|  | 70 | 
|  | 71 | 
|  | 72 ################################################################################ | 
|  | 73 # TypedObject (mixin for typedef resolution) | 
|  | 74 ################################################################################ | 
|  | 75 | 
|  | 76 class TypedObject(object): | 
|  | 77     """Object with a type, such as an Attribute or Operation (return value). | 
|  | 78 | 
|  | 79     The type can be an actual type, or can be a typedef, which must be resolved | 
|  | 80     before passing data to the code generator. | 
|  | 81     """ | 
|  | 82     __metaclass__ = abc.ABCMeta | 
|  | 83     idl_type = None | 
|  | 84 | 
|  | 85     def resolve_typedefs(self, typedefs): | 
|  | 86         """Resolve typedefs to actual types in the object.""" | 
|  | 87         # Constructors don't have their own return type, because it's the | 
|  | 88         # interface itself. | 
|  | 89         if not self.idl_type: | 
|  | 90             return | 
|  | 91         # Need to re-assign self.idl_type, not just mutate idl_type, | 
|  | 92         # since type(idl_type) may change. | 
|  | 93         self.idl_type = self.idl_type.resolve_typedefs(typedefs) | 
|  | 94 | 
|  | 95 | 
|  | 96 ################################################################################ | 
|  | 97 # Definitions (main container class) | 
|  | 98 ################################################################################ | 
|  | 99 | 
|  | 100 class IdlDefinitions(object): | 
|  | 101     def __init__(self, node): | 
|  | 102         """Args: node: AST root node, class == 'File'""" | 
|  | 103         self.callback_functions = {} | 
|  | 104         self.dictionaries = {} | 
|  | 105         self.enumerations = {} | 
|  | 106         self.interfaces = {} | 
|  | 107 | 
|  | 108         node_class = node.GetClass() | 
|  | 109         if node_class != 'File': | 
|  | 110             raise ValueError('Unrecognized node class: %s' % node_class) | 
|  | 111 | 
|  | 112         typedefs = dict((typedef_name, IdlType(type_name)) | 
|  | 113                         for typedef_name, type_name in | 
|  | 114                         STANDARD_TYPEDEFS.iteritems()) | 
|  | 115 | 
|  | 116         children = node.GetChildren() | 
|  | 117         for child in children: | 
|  | 118             child_class = child.GetClass() | 
|  | 119             if child_class == 'Interface': | 
|  | 120                 interface = IdlInterface(child) | 
|  | 121                 self.interfaces[interface.name] = interface | 
|  | 122             elif child_class == 'Exception': | 
|  | 123                 exception = IdlException(child) | 
|  | 124                 # For simplicity, treat exceptions as interfaces | 
|  | 125                 self.interfaces[exception.name] = exception | 
|  | 126             elif child_class == 'Typedef': | 
|  | 127                 type_name = child.GetName() | 
|  | 128                 typedefs[type_name] = typedef_node_to_type(child) | 
|  | 129             elif child_class == 'Enum': | 
|  | 130                 enumeration = IdlEnum(child) | 
|  | 131                 self.enumerations[enumeration.name] = enumeration | 
|  | 132             elif child_class == 'Callback': | 
|  | 133                 callback_function = IdlCallbackFunction(child) | 
|  | 134                 self.callback_functions[callback_function.name] = callback_funct
     ion | 
|  | 135             elif child_class == 'Implements': | 
|  | 136                 # Implements is handled at the interface merging step | 
|  | 137                 pass | 
|  | 138             elif child_class == 'Dictionary': | 
|  | 139                 dictionary = IdlDictionary(child) | 
|  | 140                 self.dictionaries[dictionary.name] = dictionary | 
|  | 141             else: | 
|  | 142                 raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 143 | 
|  | 144         # Typedefs are not stored in IR: | 
|  | 145         # Resolve typedefs with the actual types and then discard the Typedefs. | 
|  | 146         # http://www.w3.org/TR/WebIDL/#idl-typedefs | 
|  | 147         self.resolve_typedefs(typedefs) | 
|  | 148 | 
|  | 149     def resolve_typedefs(self, typedefs): | 
|  | 150         for callback_function in self.callback_functions.itervalues(): | 
|  | 151             callback_function.resolve_typedefs(typedefs) | 
|  | 152         for interface in self.interfaces.itervalues(): | 
|  | 153             interface.resolve_typedefs(typedefs) | 
|  | 154 | 
|  | 155     def update(self, other): | 
|  | 156         """Update with additional IdlDefinitions.""" | 
|  | 157         for interface_name, new_interface in other.interfaces.iteritems(): | 
|  | 158             if not new_interface.is_partial: | 
|  | 159                 # Add as new interface | 
|  | 160                 self.interfaces[interface_name] = new_interface | 
|  | 161                 continue | 
|  | 162 | 
|  | 163             # Merge partial to existing interface | 
|  | 164             try: | 
|  | 165                 self.interfaces[interface_name].merge(new_interface) | 
|  | 166             except KeyError: | 
|  | 167                 raise Exception('Tried to merge partial interface for {0}, ' | 
|  | 168                                 'but no existing interface by that name' | 
|  | 169                                 .format(interface_name)) | 
|  | 170 | 
|  | 171             # Merge callbacks and enumerations | 
|  | 172             self.enumerations.update(other.enumerations) | 
|  | 173             self.callback_functions.update(other.callback_functions) | 
|  | 174 | 
|  | 175 | 
|  | 176 ################################################################################ | 
|  | 177 # Callback Functions | 
|  | 178 ################################################################################ | 
|  | 179 | 
|  | 180 class IdlCallbackFunction(TypedObject): | 
|  | 181     def __init__(self, node): | 
|  | 182         children = node.GetChildren() | 
|  | 183         num_children = len(children) | 
|  | 184         if num_children != 2: | 
|  | 185             raise ValueError('Expected 2 children, got %s' % num_children) | 
|  | 186         type_node, arguments_node = children | 
|  | 187         arguments_node_class = arguments_node.GetClass() | 
|  | 188         if arguments_node_class != 'Arguments': | 
|  | 189             raise ValueError('Expected Arguments node, got %s' % arguments_node_
     class) | 
|  | 190 | 
|  | 191         self.name = node.GetName() | 
|  | 192         self.idl_type = type_node_to_type(type_node) | 
|  | 193         self.arguments = arguments_node_to_arguments(arguments_node) | 
|  | 194 | 
|  | 195     def resolve_typedefs(self, typedefs): | 
|  | 196         TypedObject.resolve_typedefs(self, typedefs) | 
|  | 197         for argument in self.arguments: | 
|  | 198             argument.resolve_typedefs(typedefs) | 
|  | 199 | 
|  | 200 | 
|  | 201 ################################################################################ | 
|  | 202 # Dictionary | 
|  | 203 ################################################################################ | 
|  | 204 | 
|  | 205 class IdlDictionary(object): | 
|  | 206     def __init__(self, node): | 
|  | 207         self.parent = None | 
|  | 208         self.name = node.GetName() | 
|  | 209         self.members = [] | 
|  | 210         for child in node.GetChildren(): | 
|  | 211             child_class = child.GetClass() | 
|  | 212             if child_class == 'Inherit': | 
|  | 213                 self.parent = child.GetName() | 
|  | 214             elif child_class == 'Key': | 
|  | 215                 self.members.append(IdlDictionaryMember(child)) | 
|  | 216             else: | 
|  | 217                 raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 218 | 
|  | 219 | 
|  | 220 class IdlDictionaryMember(object): | 
|  | 221     def __init__(self, node): | 
|  | 222         self.default_value = None | 
|  | 223         self.extended_attributes = {} | 
|  | 224         self.idl_type = None | 
|  | 225         self.name = node.GetName() | 
|  | 226         for child in node.GetChildren(): | 
|  | 227             child_class = child.GetClass() | 
|  | 228             if child_class == 'Type': | 
|  | 229                 self.idl_type = type_node_to_type(child) | 
|  | 230             elif child_class == 'Default': | 
|  | 231                 self.default_value = child.GetProperty('VALUE') | 
|  | 232             elif child_class == 'ExtAttributes': | 
|  | 233                 self.extended_attributes = ext_attributes_node_to_extended_attri
     butes(child) | 
|  | 234             else: | 
|  | 235                 raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 236 | 
|  | 237 | 
|  | 238 ################################################################################ | 
|  | 239 # Enumerations | 
|  | 240 ################################################################################ | 
|  | 241 | 
|  | 242 class IdlEnum(object): | 
|  | 243     # FIXME: remove, just treat enums as a dictionary | 
|  | 244     def __init__(self, node): | 
|  | 245         self.name = node.GetName() | 
|  | 246         self.values = [] | 
|  | 247         for child in node.GetChildren(): | 
|  | 248             self.values.append(child.GetName()) | 
|  | 249 | 
|  | 250 | 
|  | 251 ################################################################################ | 
|  | 252 # Interfaces and Exceptions | 
|  | 253 ################################################################################ | 
|  | 254 | 
|  | 255 class IdlInterface(object): | 
|  | 256     def __init__(self, node=None): | 
|  | 257         self.attributes = [] | 
|  | 258         self.constants = [] | 
|  | 259         self.constructors = [] | 
|  | 260         self.custom_constructors = [] | 
|  | 261         self.extended_attributes = {} | 
|  | 262         self.operations = [] | 
|  | 263         self.parent = None | 
|  | 264         if not node:  # Early exit for IdlException.__init__ | 
|  | 265             return | 
|  | 266 | 
|  | 267         self.is_callback = node.GetProperty('CALLBACK') or False | 
|  | 268         self.is_exception = False | 
|  | 269         # FIXME: uppercase 'Partial' => 'PARTIAL' in base IDL parser | 
|  | 270         self.is_partial = node.GetProperty('Partial') or False | 
|  | 271         self.name = node.GetName() | 
|  | 272 | 
|  | 273         children = node.GetChildren() | 
|  | 274         for child in children: | 
|  | 275             child_class = child.GetClass() | 
|  | 276             if child_class == 'Attribute': | 
|  | 277                 self.attributes.append(IdlAttribute(child)) | 
|  | 278             elif child_class == 'Const': | 
|  | 279                 self.constants.append(IdlConstant(child)) | 
|  | 280             elif child_class == 'ExtAttributes': | 
|  | 281                 extended_attributes = ext_attributes_node_to_extended_attributes
     (child) | 
|  | 282                 self.constructors, self.custom_constructors = ( | 
|  | 283                     extended_attributes_to_constructors(extended_attributes)) | 
|  | 284                 clear_constructor_attributes(extended_attributes) | 
|  | 285                 self.extended_attributes = extended_attributes | 
|  | 286             elif child_class == 'Operation': | 
|  | 287                 self.operations.append(IdlOperation(child)) | 
|  | 288             elif child_class == 'Inherit': | 
|  | 289                 self.parent = child.GetName() | 
|  | 290             else: | 
|  | 291                 raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 292 | 
|  | 293     def resolve_typedefs(self, typedefs): | 
|  | 294         for attribute in self.attributes: | 
|  | 295             attribute.resolve_typedefs(typedefs) | 
|  | 296         for constant in self.constants: | 
|  | 297             constant.resolve_typedefs(typedefs) | 
|  | 298         for constructor in self.constructors: | 
|  | 299             constructor.resolve_typedefs(typedefs) | 
|  | 300         for custom_constructor in self.custom_constructors: | 
|  | 301             custom_constructor.resolve_typedefs(typedefs) | 
|  | 302         for operation in self.operations: | 
|  | 303             operation.resolve_typedefs(typedefs) | 
|  | 304 | 
|  | 305     def merge(self, other): | 
|  | 306         """Merge in another interface's members (e.g., partial interface)""" | 
|  | 307         self.attributes.extend(other.attributes) | 
|  | 308         self.constants.extend(other.constants) | 
|  | 309         self.operations.extend(other.operations) | 
|  | 310 | 
|  | 311 | 
|  | 312 class IdlException(IdlInterface): | 
|  | 313     # Properly exceptions and interfaces are distinct, and thus should inherit a | 
|  | 314     # common base class (say, "IdlExceptionOrInterface"). | 
|  | 315     # However, there is only one exception (DOMException), and new exceptions | 
|  | 316     # are not expected. Thus it is easier to implement exceptions as a | 
|  | 317     # restricted subclass of interfaces. | 
|  | 318     # http://www.w3.org/TR/WebIDL/#idl-exceptions | 
|  | 319     def __init__(self, node): | 
|  | 320         # Exceptions are similar to Interfaces, but simpler | 
|  | 321         IdlInterface.__init__(self) | 
|  | 322         self.is_callback = False | 
|  | 323         self.is_exception = True | 
|  | 324         self.is_partial = False | 
|  | 325         self.name = node.GetName() | 
|  | 326 | 
|  | 327         children = node.GetChildren() | 
|  | 328         for child in children: | 
|  | 329             child_class = child.GetClass() | 
|  | 330             if child_class == 'Attribute': | 
|  | 331                 attribute = IdlAttribute(child) | 
|  | 332                 self.attributes.append(attribute) | 
|  | 333             elif child_class == 'Const': | 
|  | 334                 self.constants.append(IdlConstant(child)) | 
|  | 335             elif child_class == 'ExtAttributes': | 
|  | 336                 self.extended_attributes = ext_attributes_node_to_extended_attri
     butes(child) | 
|  | 337             elif child_class == 'ExceptionOperation': | 
|  | 338                 self.operations.append(IdlOperation.from_exception_operation_nod
     e(child)) | 
|  | 339             else: | 
|  | 340                 raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 341 | 
|  | 342 | 
|  | 343 ################################################################################ | 
|  | 344 # Attributes | 
|  | 345 ################################################################################ | 
|  | 346 | 
|  | 347 class IdlAttribute(TypedObject): | 
|  | 348     def __init__(self, node): | 
|  | 349         self.is_read_only = node.GetProperty('READONLY') or False | 
|  | 350         self.is_static = node.GetProperty('STATIC') or False | 
|  | 351         self.name = node.GetName() | 
|  | 352         # Defaults, overridden below | 
|  | 353         self.idl_type = None | 
|  | 354         self.extended_attributes = {} | 
|  | 355 | 
|  | 356         children = node.GetChildren() | 
|  | 357         for child in children: | 
|  | 358             child_class = child.GetClass() | 
|  | 359             if child_class == 'Type': | 
|  | 360                 self.idl_type = type_node_to_type(child) | 
|  | 361             elif child_class == 'ExtAttributes': | 
|  | 362                 self.extended_attributes = ext_attributes_node_to_extended_attri
     butes(child) | 
|  | 363             else: | 
|  | 364                 raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 365 | 
|  | 366 | 
|  | 367 ################################################################################ | 
|  | 368 # Constants | 
|  | 369 ################################################################################ | 
|  | 370 | 
|  | 371 class IdlConstant(TypedObject): | 
|  | 372     def __init__(self, node): | 
|  | 373         children = node.GetChildren() | 
|  | 374         num_children = len(children) | 
|  | 375         if num_children < 2 or num_children > 3: | 
|  | 376             raise ValueError('Expected 2 or 3 children, got %s' % num_children) | 
|  | 377         type_node = children[0] | 
|  | 378         value_node = children[1] | 
|  | 379         value_node_class = value_node.GetClass() | 
|  | 380         if value_node_class != 'Value': | 
|  | 381             raise ValueError('Expected Value node, got %s' % value_node_class) | 
|  | 382 | 
|  | 383         self.name = node.GetName() | 
|  | 384         # ConstType is more limited than Type, so subtree is smaller and | 
|  | 385         # we don't use the full type_node_to_type function. | 
|  | 386         self.idl_type = type_node_inner_to_type(type_node) | 
|  | 387         self.value = value_node.GetName() | 
|  | 388 | 
|  | 389         if num_children == 3: | 
|  | 390             ext_attributes_node = children[2] | 
|  | 391             self.extended_attributes = ext_attributes_node_to_extended_attribute
     s(ext_attributes_node) | 
|  | 392         else: | 
|  | 393             self.extended_attributes = {} | 
|  | 394 | 
|  | 395 | 
|  | 396 ################################################################################ | 
|  | 397 # Literals | 
|  | 398 ################################################################################ | 
|  | 399 | 
|  | 400 class IdlLiteral(object): | 
|  | 401     def __init__(self, idl_type, value): | 
|  | 402         self.idl_type = idl_type | 
|  | 403         self.value = value | 
|  | 404         self.is_null = False | 
|  | 405 | 
|  | 406     def __str__(self): | 
|  | 407         if self.idl_type == 'DOMString': | 
|  | 408             return 'String("%s")' % self.value | 
|  | 409         if self.idl_type == 'integer': | 
|  | 410             return '%d' % self.value | 
|  | 411         if self.idl_type == 'float': | 
|  | 412             return '%g' % self.value | 
|  | 413         if self.idl_type == 'boolean': | 
|  | 414             return 'true' if self.value else 'false' | 
|  | 415         raise ValueError('Unsupported literal type: %s' % self.idl_type) | 
|  | 416 | 
|  | 417 | 
|  | 418 class IdlLiteralNull(IdlLiteral): | 
|  | 419     def __init__(self): | 
|  | 420         self.idl_type = 'NULL' | 
|  | 421         self.value = None | 
|  | 422         self.is_null = True | 
|  | 423 | 
|  | 424     def __str__(self): | 
|  | 425         return 'nullptr' | 
|  | 426 | 
|  | 427 | 
|  | 428 def default_node_to_idl_literal(node): | 
|  | 429     # FIXME: This code is unnecessarily complicated due to the rather | 
|  | 430     # inconsistent way the upstream IDL parser outputs default values. | 
|  | 431     # http://crbug.com/374178 | 
|  | 432     idl_type = node.GetProperty('TYPE') | 
|  | 433     if idl_type == 'DOMString': | 
|  | 434         value = node.GetProperty('NAME') | 
|  | 435         if '"' in value or '\\' in value: | 
|  | 436             raise ValueError('Unsupported string value: %r' % value) | 
|  | 437         return IdlLiteral(idl_type, value) | 
|  | 438     if idl_type == 'integer': | 
|  | 439         return IdlLiteral(idl_type, int(node.GetProperty('NAME'))) | 
|  | 440     if idl_type == 'float': | 
|  | 441         return IdlLiteral(idl_type, float(node.GetProperty('VALUE'))) | 
|  | 442     if idl_type == 'boolean': | 
|  | 443         return IdlLiteral(idl_type, node.GetProperty('VALUE')) | 
|  | 444     if idl_type == 'NULL': | 
|  | 445         return IdlLiteralNull() | 
|  | 446     raise ValueError('Unrecognized default value type: %s' % idl_type) | 
|  | 447 | 
|  | 448 | 
|  | 449 ################################################################################ | 
|  | 450 # Operations | 
|  | 451 ################################################################################ | 
|  | 452 | 
|  | 453 class IdlOperation(TypedObject): | 
|  | 454     def __init__(self, node=None): | 
|  | 455         self.arguments = [] | 
|  | 456         self.extended_attributes = {} | 
|  | 457         self.specials = [] | 
|  | 458         self.is_constructor = False | 
|  | 459 | 
|  | 460         if not node: | 
|  | 461             self.is_static = False | 
|  | 462             return | 
|  | 463         self.name = node.GetName()  # FIXME: should just be: or '' | 
|  | 464         # FIXME: AST should use None internally | 
|  | 465         if self.name == '_unnamed_': | 
|  | 466             self.name = '' | 
|  | 467 | 
|  | 468         self.is_static = node.GetProperty('STATIC') or False | 
|  | 469         property_dictionary = node.GetProperties() | 
|  | 470         for special_keyword in SPECIAL_KEYWORD_LIST: | 
|  | 471             if special_keyword in property_dictionary: | 
|  | 472                 self.specials.append(special_keyword.lower()) | 
|  | 473 | 
|  | 474         self.idl_type = None | 
|  | 475         children = node.GetChildren() | 
|  | 476         for child in children: | 
|  | 477             child_class = child.GetClass() | 
|  | 478             if child_class == 'Arguments': | 
|  | 479                 self.arguments = arguments_node_to_arguments(child) | 
|  | 480             elif child_class == 'Type': | 
|  | 481                 self.idl_type = type_node_to_type(child) | 
|  | 482             elif child_class == 'ExtAttributes': | 
|  | 483                 self.extended_attributes = ext_attributes_node_to_extended_attri
     butes(child) | 
|  | 484             else: | 
|  | 485                 raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 486 | 
|  | 487     @classmethod | 
|  | 488     def from_exception_operation_node(cls, node): | 
|  | 489         # Needed to handle one case in DOMException.idl: | 
|  | 490         # // Override in a Mozilla compatible format | 
|  | 491         # [NotEnumerable] DOMString toString(); | 
|  | 492         # FIXME: can we remove this? replace with a stringifier? | 
|  | 493         operation = cls() | 
|  | 494         operation.name = node.GetName() | 
|  | 495         children = node.GetChildren() | 
|  | 496         if len(children) < 1 or len(children) > 2: | 
|  | 497             raise ValueError('ExceptionOperation node with %s children, expected
      1 or 2' % len(children)) | 
|  | 498 | 
|  | 499         type_node = children[0] | 
|  | 500         operation.idl_type = type_node_to_type(type_node) | 
|  | 501 | 
|  | 502         if len(children) > 1: | 
|  | 503             ext_attributes_node = children[1] | 
|  | 504             operation.extended_attributes = ext_attributes_node_to_extended_attr
     ibutes(ext_attributes_node) | 
|  | 505 | 
|  | 506         return operation | 
|  | 507 | 
|  | 508     @classmethod | 
|  | 509     def constructor_from_arguments_node(cls, name, arguments_node): | 
|  | 510         constructor = cls() | 
|  | 511         constructor.name = name | 
|  | 512         constructor.arguments = arguments_node_to_arguments(arguments_node) | 
|  | 513         constructor.is_constructor = True | 
|  | 514         return constructor | 
|  | 515 | 
|  | 516     def resolve_typedefs(self, typedefs): | 
|  | 517         TypedObject.resolve_typedefs(self, typedefs) | 
|  | 518         for argument in self.arguments: | 
|  | 519             argument.resolve_typedefs(typedefs) | 
|  | 520 | 
|  | 521 | 
|  | 522 ################################################################################ | 
|  | 523 # Arguments | 
|  | 524 ################################################################################ | 
|  | 525 | 
|  | 526 class IdlArgument(TypedObject): | 
|  | 527     def __init__(self, node): | 
|  | 528         self.extended_attributes = {} | 
|  | 529         self.idl_type = None | 
|  | 530         self.is_optional = node.GetProperty('OPTIONAL')  # syntax: (optional T) | 
|  | 531         self.is_variadic = False  # syntax: (T...) | 
|  | 532         self.name = node.GetName() | 
|  | 533         self.default_value = None | 
|  | 534 | 
|  | 535         children = node.GetChildren() | 
|  | 536         for child in children: | 
|  | 537             child_class = child.GetClass() | 
|  | 538             if child_class == 'Type': | 
|  | 539                 self.idl_type = type_node_to_type(child) | 
|  | 540             elif child_class == 'ExtAttributes': | 
|  | 541                 self.extended_attributes = ext_attributes_node_to_extended_attri
     butes(child) | 
|  | 542             elif child_class == 'Argument': | 
|  | 543                 child_name = child.GetName() | 
|  | 544                 if child_name != '...': | 
|  | 545                     raise ValueError('Unrecognized Argument node; expected "..."
     , got "%s"' % child_name) | 
|  | 546                 self.is_variadic = child.GetProperty('ELLIPSIS') or False | 
|  | 547             elif child_class == 'Default': | 
|  | 548                 self.default_value = default_node_to_idl_literal(child) | 
|  | 549             else: | 
|  | 550                 raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 551 | 
|  | 552 | 
|  | 553 def arguments_node_to_arguments(node): | 
|  | 554     # [Constructor] and [CustomConstructor] without arguments (the bare form) | 
|  | 555     # have None instead of an arguments node, but have the same meaning as using | 
|  | 556     # an empty argument list, [Constructor()], so special-case this. | 
|  | 557     # http://www.w3.org/TR/WebIDL/#Constructor | 
|  | 558     if node is None: | 
|  | 559         return [] | 
|  | 560     return [IdlArgument(argument_node) | 
|  | 561             for argument_node in node.GetChildren()] | 
|  | 562 | 
|  | 563 | 
|  | 564 ################################################################################ | 
|  | 565 # Extended attributes | 
|  | 566 ################################################################################ | 
|  | 567 | 
|  | 568 def ext_attributes_node_to_extended_attributes(node): | 
|  | 569     """ | 
|  | 570     Returns: | 
|  | 571       Dictionary of {ExtAttributeName: ExtAttributeValue}. | 
|  | 572       Value is usually a string, with three exceptions: | 
|  | 573       Constructors: value is a list of Arguments nodes, corresponding to | 
|  | 574         possible signatures of the constructor. | 
|  | 575       CustomConstructors: value is a list of Arguments nodes, corresponding to | 
|  | 576         possible signatures of the custom constructor. | 
|  | 577       NamedConstructor: value is a Call node, corresponding to the single | 
|  | 578         signature of the named constructor. | 
|  | 579     """ | 
|  | 580     # Primarily just make a dictionary from the children. | 
|  | 581     # The only complexity is handling various types of constructors: | 
|  | 582     # Constructors and Custom Constructors can have duplicate entries due to | 
|  | 583     # overloading, and thus are stored in temporary lists. | 
|  | 584     # However, Named Constructors cannot be overloaded, and thus do not have | 
|  | 585     # a list. | 
|  | 586     # FIXME: move Constructor logic into separate function, instead of modifying | 
|  | 587     #        extended attributes in-place. | 
|  | 588     constructors = [] | 
|  | 589     custom_constructors = [] | 
|  | 590     extended_attributes = {} | 
|  | 591 | 
|  | 592     def child_node(extended_attribute_node): | 
|  | 593         children = extended_attribute_node.GetChildren() | 
|  | 594         if not children: | 
|  | 595             return None | 
|  | 596         if len(children) > 1: | 
|  | 597             raise ValueError('ExtAttributes node with %s children, expected at m
     ost 1' % len(children)) | 
|  | 598         return children[0] | 
|  | 599 | 
|  | 600     extended_attribute_node_list = node.GetChildren() | 
|  | 601     for extended_attribute_node in extended_attribute_node_list: | 
|  | 602         name = extended_attribute_node.GetName() | 
|  | 603         child = child_node(extended_attribute_node) | 
|  | 604         child_class = child and child.GetClass() | 
|  | 605         if name == 'Constructor': | 
|  | 606             if child_class and child_class != 'Arguments': | 
|  | 607                 raise ValueError('Constructor only supports Arguments as child, 
     but has child of class: %s' % child_class) | 
|  | 608             constructors.append(child) | 
|  | 609         elif name == 'CustomConstructor': | 
|  | 610             if child_class and child_class != 'Arguments': | 
|  | 611                 raise ValueError('[CustomConstructor] only supports Arguments as
      child, but has child of class: %s' % child_class) | 
|  | 612             custom_constructors.append(child) | 
|  | 613         elif name == 'NamedConstructor': | 
|  | 614             if child_class and child_class != 'Call': | 
|  | 615                 raise ValueError('[NamedConstructor] only supports Call as child
     , but has child of class: %s' % child_class) | 
|  | 616             extended_attributes[name] = child | 
|  | 617         elif name == 'SetWrapperReferenceTo': | 
|  | 618             if not child: | 
|  | 619                 raise ValueError('[SetWrapperReferenceTo] requires a child, but 
     has none.') | 
|  | 620             if child_class != 'Arguments': | 
|  | 621                 raise ValueError('[SetWrapperReferenceTo] only supports Argument
     s as child, but has child of class: %s' % child_class) | 
|  | 622             extended_attributes[name] = arguments_node_to_arguments(child) | 
|  | 623         elif child: | 
|  | 624             raise ValueError('ExtAttributes node with unexpected children: %s' %
      name) | 
|  | 625         else: | 
|  | 626             value = extended_attribute_node.GetProperty('VALUE') | 
|  | 627             extended_attributes[name] = value | 
|  | 628 | 
|  | 629     # Store constructors and custom constructors in special list attributes, | 
|  | 630     # which are deleted later. Note plural in key. | 
|  | 631     if constructors: | 
|  | 632         extended_attributes['Constructors'] = constructors | 
|  | 633     if custom_constructors: | 
|  | 634         extended_attributes['CustomConstructors'] = custom_constructors | 
|  | 635 | 
|  | 636     return extended_attributes | 
|  | 637 | 
|  | 638 | 
|  | 639 def extended_attributes_to_constructors(extended_attributes): | 
|  | 640     """Returns constructors and custom_constructors (lists of IdlOperations). | 
|  | 641 | 
|  | 642     Auxiliary function for IdlInterface.__init__. | 
|  | 643     """ | 
|  | 644 | 
|  | 645     constructor_list = extended_attributes.get('Constructors', []) | 
|  | 646     constructors = [ | 
|  | 647         IdlOperation.constructor_from_arguments_node('Constructor', arguments_no
     de) | 
|  | 648         for arguments_node in constructor_list] | 
|  | 649 | 
|  | 650     custom_constructor_list = extended_attributes.get('CustomConstructors', []) | 
|  | 651     custom_constructors = [ | 
|  | 652         IdlOperation.constructor_from_arguments_node('CustomConstructor', argume
     nts_node) | 
|  | 653         for arguments_node in custom_constructor_list] | 
|  | 654 | 
|  | 655     if 'NamedConstructor' in extended_attributes: | 
|  | 656         # FIXME: support overloaded named constructors, and make homogeneous | 
|  | 657         name = 'NamedConstructor' | 
|  | 658         call_node = extended_attributes['NamedConstructor'] | 
|  | 659         extended_attributes['NamedConstructor'] = call_node.GetName() | 
|  | 660         children = call_node.GetChildren() | 
|  | 661         if len(children) != 1: | 
|  | 662             raise ValueError('NamedConstructor node expects 1 child, got %s.' % 
     len(children)) | 
|  | 663         arguments_node = children[0] | 
|  | 664         named_constructor = IdlOperation.constructor_from_arguments_node('NamedC
     onstructor', arguments_node) | 
|  | 665         # FIXME: should return named_constructor separately; appended for Perl | 
|  | 666         constructors.append(named_constructor) | 
|  | 667 | 
|  | 668     return constructors, custom_constructors | 
|  | 669 | 
|  | 670 | 
|  | 671 def clear_constructor_attributes(extended_attributes): | 
|  | 672     # Deletes Constructor*s* (plural), sets Constructor (singular) | 
|  | 673     if 'Constructors' in extended_attributes: | 
|  | 674         del extended_attributes['Constructors'] | 
|  | 675         extended_attributes['Constructor'] = None | 
|  | 676     if 'CustomConstructors' in extended_attributes: | 
|  | 677         del extended_attributes['CustomConstructors'] | 
|  | 678         extended_attributes['CustomConstructor'] = None | 
|  | 679 | 
|  | 680 | 
|  | 681 ################################################################################ | 
|  | 682 # Types | 
|  | 683 ################################################################################ | 
|  | 684 | 
|  | 685 def type_node_to_type(node): | 
|  | 686     children = node.GetChildren() | 
|  | 687     if len(children) < 1 or len(children) > 2: | 
|  | 688         raise ValueError('Type node expects 1 or 2 children (type + optional arr
     ay []), got %s (multi-dimensional arrays are not supported).' % len(children)) | 
|  | 689 | 
|  | 690     type_node_child = children[0] | 
|  | 691 | 
|  | 692     if len(children) == 2: | 
|  | 693         array_node = children[1] | 
|  | 694         array_node_class = array_node.GetClass() | 
|  | 695         if array_node_class != 'Array': | 
|  | 696             raise ValueError('Expected Array node as TypeSuffix, got %s node.' %
      array_node_class) | 
|  | 697         # FIXME: use IdlArrayType instead of is_array, once have that | 
|  | 698         is_array = True | 
|  | 699     else: | 
|  | 700         is_array = False | 
|  | 701 | 
|  | 702     is_nullable = node.GetProperty('NULLABLE') or False  # syntax: T? | 
|  | 703 | 
|  | 704     return type_node_inner_to_type(type_node_child, is_array=is_array, is_nullab
     le=is_nullable) | 
|  | 705 | 
|  | 706 | 
|  | 707 def type_node_inner_to_type(node, is_array=False, is_nullable=False): | 
|  | 708     # FIXME: remove is_array and is_nullable once have IdlArrayType and IdlNulla
     bleType | 
|  | 709     node_class = node.GetClass() | 
|  | 710     # Note Type*r*ef, not Typedef, meaning the type is an identifier, thus | 
|  | 711     # either a typedef shorthand (but not a Typedef declaration itself) or an | 
|  | 712     # interface type. We do not distinguish these, and just use the type name. | 
|  | 713     if node_class in ['PrimitiveType', 'Typeref']: | 
|  | 714         # unrestricted syntax: unrestricted double | unrestricted float | 
|  | 715         is_unrestricted = node.GetProperty('UNRESTRICTED') or False | 
|  | 716         return IdlType(node.GetName(), is_array=is_array, is_nullable=is_nullabl
     e, is_unrestricted=is_unrestricted) | 
|  | 717     elif node_class == 'Any': | 
|  | 718         return IdlType('any', is_array=is_array, is_nullable=is_nullable) | 
|  | 719     elif node_class == 'Sequence': | 
|  | 720         if is_array: | 
|  | 721             raise ValueError('Arrays of sequences are not supported') | 
|  | 722         return sequence_node_to_type(node, is_nullable=is_nullable) | 
|  | 723     elif node_class == 'UnionType': | 
|  | 724         if is_array: | 
|  | 725             raise ValueError('Arrays of unions are not supported') | 
|  | 726         return union_type_node_to_idl_union_type(node, is_nullable=is_nullable) | 
|  | 727     raise ValueError('Unrecognized node class: %s' % node_class) | 
|  | 728 | 
|  | 729 | 
|  | 730 def sequence_node_to_type(node, is_nullable=False): | 
|  | 731     children = node.GetChildren() | 
|  | 732     if len(children) != 1: | 
|  | 733         raise ValueError('Sequence node expects exactly 1 child, got %s' % len(c
     hildren)) | 
|  | 734     sequence_child = children[0] | 
|  | 735     sequence_child_class = sequence_child.GetClass() | 
|  | 736     if sequence_child_class != 'Type': | 
|  | 737         raise ValueError('Unrecognized node class: %s' % sequence_child_class) | 
|  | 738     element_type = type_node_to_type(sequence_child).base_type | 
|  | 739     return IdlType(element_type, is_sequence=True, is_nullable=is_nullable) | 
|  | 740 | 
|  | 741 | 
|  | 742 def typedef_node_to_type(node): | 
|  | 743     children = node.GetChildren() | 
|  | 744     if len(children) != 1: | 
|  | 745         raise ValueError('Typedef node with %s children, expected 1' % len(child
     ren)) | 
|  | 746     child = children[0] | 
|  | 747     child_class = child.GetClass() | 
|  | 748     if child_class != 'Type': | 
|  | 749         raise ValueError('Unrecognized node class: %s' % child_class) | 
|  | 750     return type_node_to_type(child) | 
|  | 751 | 
|  | 752 | 
|  | 753 def union_type_node_to_idl_union_type(node, is_nullable=False): | 
|  | 754     member_types = [type_node_to_type(member_type_node) | 
|  | 755                     for member_type_node in node.GetChildren()] | 
|  | 756     return IdlUnionType(member_types, is_nullable=is_nullable) | 
| OLD | NEW | 
|---|