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 31Classes are primarily constructors, which build an IdlDefinitions object 32(and various contained objects) from an AST (produced by blink_idl_parser). 33 34This is in two steps: 35* Constructors walk the AST, creating objects. 36* Typedef resolution. 37 38Typedefs are all resolved here, and not stored in IR. 39 40Typedef resolution uses some auxiliary classes and OOP techniques to make this 41a generic call, via the resolve_typedefs() method. 42 43Class hierarchy (mostly containment, '<' for inheritance): 44 45IdlDefinitions 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 56TypedObject :: mixin for typedef resolution 57 58Design doc: http://www.chromium.org/developers/design-documents/idl-compiler 59""" 60 61import abc 62 63from idl_types import IdlType, IdlUnionType 64 65SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'DELETER'] 66STANDARD_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 76class 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 100class 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_function 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 180class 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 205class 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 220class 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_attributes(child) 234 else: 235 raise ValueError('Unrecognized node class: %s' % child_class) 236 237 238################################################################################ 239# Enumerations 240################################################################################ 241 242class 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 255class 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 312class 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_attributes(child) 337 elif child_class == 'ExceptionOperation': 338 self.operations.append(IdlOperation.from_exception_operation_node(child)) 339 else: 340 raise ValueError('Unrecognized node class: %s' % child_class) 341 342 343################################################################################ 344# Attributes 345################################################################################ 346 347class 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_attributes(child) 363 else: 364 raise ValueError('Unrecognized node class: %s' % child_class) 365 366 367################################################################################ 368# Constants 369################################################################################ 370 371class 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_attributes(ext_attributes_node) 392 else: 393 self.extended_attributes = {} 394 395 396################################################################################ 397# Literals 398################################################################################ 399 400class 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 418class 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 428def 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 453class 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_attributes(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_attributes(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 526class 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_attributes(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 553def 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 568def 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 most 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 Arguments 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 639def 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_node) 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', arguments_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('NamedConstructor', 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 671def 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 685def 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 array []), 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_nullable=is_nullable) 705 706 707def type_node_inner_to_type(node, is_array=False, is_nullable=False): 708 # FIXME: remove is_array and is_nullable once have IdlArrayType and IdlNullableType 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_nullable, 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 730def 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(children)) 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 742def 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(children)) 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 753def 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) 757