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# pylint: disable=relative-import 30"""Blink IDL Intermediate Representation (IR) classes. 31 32Classes are primarily constructors, which build an IdlDefinitions object 33(and various contained objects) from an AST (produced by blink_idl_parser). 34 35IR stores typedefs and they are resolved by the code generator. 36 37Typedef resolution uses some auxiliary classes and OOP techniques to make this 38a generic call. See TypedefResolver class in code_generator_v8.py. 39 40Class hierarchy (mostly containment, '<' for inheritance): 41 42IdlDefinitions 43 IdlCallbackFunction < TypedObject 44 IdlEnum :: FIXME: remove, just use a dict for enums 45 IdlInterface 46 IdlAttribute < TypedObject 47 IdlConstant < TypedObject 48 IdlLiteral 49 IdlOperation < TypedObject 50 IdlArgument < TypedObject 51 IdlStringifier 52 IdlIterable < IdlIterableOrMaplikeOrSetlike 53 IdlMaplike < IdlIterableOrMaplikeOrSetlike 54 IdlSetlike < IdlIterableOrMaplikeOrSetlike 55 56TypedObject :: Object with one or more attributes that is a type. 57 58IdlArgument is 'picklable', as it is stored in interfaces_info. 59 60Design doc: http://www.chromium.org/developers/design-documents/idl-compiler 61""" 62 63import abc 64 65from idl_types import IdlAnnotatedType 66from idl_types import IdlFrozenArrayType 67from idl_types import IdlNullableType 68from idl_types import IdlRecordType 69from idl_types import IdlSequenceType 70from idl_types import IdlType 71from idl_types import IdlUnionType 72 73SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'DELETER'] 74 75################################################################################ 76# TypedObject 77################################################################################ 78 79 80class TypedObject(object): 81 """Object with a type, such as an Attribute or Operation (return value). 82 83 The type can be an actual type, or can be a typedef, which must be resolved 84 by the TypedefResolver before passing data to the code generator. 85 """ 86 __metaclass__ = abc.ABCMeta 87 idl_type_attributes = ('idl_type', ) 88 89 90################################################################################ 91# Definitions (main container class) 92################################################################################ 93 94 95class IdlDefinitions(object): 96 def __init__(self, node): 97 """Args: node: AST root node, class == 'File'""" 98 self.callback_functions = {} 99 self.dictionaries = {} 100 self.enumerations = {} 101 self.includes = [] 102 self.interfaces = {} 103 self.first_name = None 104 self.typedefs = {} 105 106 node_class = node.GetClass() 107 if node_class != 'File': 108 raise ValueError('Unrecognized node class: %s' % node_class) 109 110 children = node.GetChildren() 111 for child in children: 112 child_class = child.GetClass() 113 if child_class == 'Interface' or child_class == 'Namespace': 114 interface = IdlInterface(child) 115 self.interfaces[interface.name] = interface 116 if not self.first_name: 117 self.first_name = interface.name 118 elif child_class == 'Typedef': 119 typedef = IdlTypedef(child) 120 self.typedefs[typedef.name] = typedef 121 elif child_class == 'Enum': 122 enumeration = IdlEnum(child) 123 self.enumerations[enumeration.name] = enumeration 124 elif child_class == 'Callback': 125 callback_function = IdlCallbackFunction(child) 126 self.callback_functions[callback_function. 127 name] = callback_function 128 elif child_class == 'Includes': 129 self.includes.append(IdlIncludes(child)) 130 elif child_class == 'Dictionary': 131 dictionary = IdlDictionary(child) 132 self.dictionaries[dictionary.name] = dictionary 133 if not self.first_name: 134 self.first_name = dictionary.name 135 else: 136 raise ValueError('Unrecognized node class: %s' % child_class) 137 138 def accept(self, visitor): 139 visitor.visit_definitions(self) 140 for interface in self.interfaces.values(): 141 interface.accept(visitor) 142 for callback_function in self.callback_functions.values(): 143 callback_function.accept(visitor) 144 for dictionary in self.dictionaries.values(): 145 dictionary.accept(visitor) 146 for enumeration in self.enumerations.values(): 147 enumeration.accept(visitor) 148 for include in self.includes: 149 include.accept(visitor) 150 for typedef in self.typedefs.values(): 151 typedef.accept(visitor) 152 153 def update(self, other): 154 """Update with additional IdlDefinitions.""" 155 for interface_name, new_interface in other.interfaces.items(): 156 if not new_interface.is_partial: 157 # Add as new interface 158 self.interfaces[interface_name] = new_interface 159 continue 160 161 # Merge partial to existing interface 162 try: 163 self.interfaces[interface_name].merge(new_interface) 164 except KeyError: 165 raise Exception('Tried to merge partial interface for {0}, ' 166 'but no existing interface by that name'. 167 format(interface_name)) 168 169 # Merge callbacks and enumerations 170 self.enumerations.update(other.enumerations) 171 self.callback_functions.update(other.callback_functions) 172 173 174################################################################################ 175# Callback Functions 176################################################################################ 177 178 179class IdlCallbackFunction(TypedObject): 180 def __init__(self, node): 181 children = node.GetChildren() 182 num_children = len(children) 183 if num_children < 2 or num_children > 3: 184 raise ValueError('Expected 2 or 3 children, got %s' % num_children) 185 type_node = children[0] 186 arguments_node = children[1] 187 if num_children == 3: 188 ext_attributes_node = children[2] 189 self.extended_attributes = ( 190 ext_attributes_node_to_extended_attributes(ext_attributes_node) 191 ) 192 else: 193 self.extended_attributes = {} 194 arguments_node_class = arguments_node.GetClass() 195 if arguments_node_class != 'Arguments': 196 raise ValueError( 197 'Expected Arguments node, got %s' % arguments_node_class) 198 199 self.name = node.GetName() 200 self.idl_type = type_node_to_type(type_node) 201 self.arguments = arguments_node_to_arguments(arguments_node) 202 203 def accept(self, visitor): 204 visitor.visit_callback_function(self) 205 for argument in self.arguments: 206 argument.accept(visitor) 207 208 209################################################################################ 210# Dictionary 211################################################################################ 212 213 214class IdlDictionary(object): 215 def __init__(self, node): 216 self.extended_attributes = {} 217 self.is_partial = bool(node.GetProperty('PARTIAL')) 218 self.name = node.GetName() 219 self.members = [] 220 self.parent = None 221 for child in node.GetChildren(): 222 child_class = child.GetClass() 223 if child_class == 'Inherit': 224 self.parent = child.GetName() 225 elif child_class == 'Key': 226 self.members.append(IdlDictionaryMember(child)) 227 elif child_class == 'ExtAttributes': 228 self.extended_attributes = ( 229 ext_attributes_node_to_extended_attributes(child)) 230 else: 231 raise ValueError('Unrecognized node class: %s' % child_class) 232 233 def accept(self, visitor): 234 visitor.visit_dictionary(self) 235 for member in self.members: 236 member.accept(visitor) 237 238 239class IdlDictionaryMember(TypedObject): 240 def __init__(self, node): 241 self.default_value = None 242 self.extended_attributes = {} 243 self.idl_type = None 244 self.is_required = bool(node.GetProperty('REQUIRED')) 245 self.name = node.GetName() 246 for child in node.GetChildren(): 247 child_class = child.GetClass() 248 if child_class == 'Type': 249 self.idl_type = type_node_to_type(child) 250 elif child_class == 'Default': 251 self.default_value = default_node_to_idl_literal(child) 252 elif child_class == 'ExtAttributes': 253 self.extended_attributes = ( 254 ext_attributes_node_to_extended_attributes(child)) 255 else: 256 raise ValueError('Unrecognized node class: %s' % child_class) 257 258 def accept(self, visitor): 259 visitor.visit_dictionary_member(self) 260 261 262################################################################################ 263# Enumerations 264################################################################################ 265 266 267class IdlEnum(object): 268 def __init__(self, node): 269 self.name = node.GetName() 270 self.values = [] 271 for child in node.GetChildren(): 272 self.values.append(child.GetName()) 273 274 def accept(self, visitor): 275 visitor.visit_enumeration(self) 276 277 278################################################################################ 279# Typedefs 280################################################################################ 281 282 283class IdlTypedef(object): 284 idl_type_attributes = ('idl_type', ) 285 286 def __init__(self, node): 287 self.name = node.GetName() 288 self.idl_type = typedef_node_to_type(node) 289 290 def accept(self, visitor): 291 visitor.visit_typedef(self) 292 293 294################################################################################ 295# Interfaces 296################################################################################ 297 298 299class IdlInterface(object): 300 def __init__(self, node): 301 self.attributes = [] 302 self.constants = [] 303 self.constructors = [] 304 self.custom_constructors = [] 305 self.extended_attributes = {} 306 self.operations = [] 307 self.parent = None 308 self.stringifier = None 309 self.iterable = None 310 self.has_indexed_elements = False 311 self.has_named_property_getter = False 312 self.maplike = None 313 self.setlike = None 314 self.original_interface = None 315 self.partial_interfaces = [] 316 317 self.is_callback = bool(node.GetProperty('CALLBACK')) 318 self.is_partial = bool(node.GetProperty('PARTIAL')) 319 self.is_mixin = bool(node.GetProperty('MIXIN')) 320 self.name = node.GetName() 321 self.idl_type = IdlType(self.name) 322 323 has_indexed_property_getter = False 324 has_integer_typed_length = False 325 326 # These are used to support both constructor operations and old style 327 # [Constructor] extended attributes. Ideally we should do refactoring 328 # for constructor code generation but we will use a new code generator 329 # soon so this kind of workaround should be fine. 330 constructor_operations = [] 331 custom_constructor_operations = [] 332 constructor_operations_extended_attributes = {} 333 334 def is_invalid_attribute_type(idl_type): 335 return idl_type.is_callback_function or \ 336 idl_type.is_dictionary or \ 337 idl_type.is_record_type or \ 338 idl_type.is_sequence_type 339 340 children = node.GetChildren() 341 for child in children: 342 child_class = child.GetClass() 343 if child_class == 'Attribute': 344 attr = IdlAttribute(child) 345 if is_invalid_attribute_type(attr.idl_type): 346 raise ValueError( 347 'Type "%s" cannot be used as an attribute.' % 348 attr.idl_type) 349 if attr.idl_type.is_integer_type and attr.name == 'length': 350 has_integer_typed_length = True 351 self.attributes.append(attr) 352 elif child_class == 'Const': 353 self.constants.append(IdlConstant(child)) 354 elif child_class == 'ExtAttributes': 355 extended_attributes = ext_attributes_node_to_extended_attributes( 356 child) 357 self.constructors, self.custom_constructors = ( 358 extended_attributes_to_constructors(extended_attributes)) 359 clear_constructor_attributes(extended_attributes) 360 self.extended_attributes = extended_attributes 361 elif child_class == 'Operation': 362 op = IdlOperation(child) 363 if 'getter' in op.specials: 364 if str(op.arguments[0].idl_type) == 'unsigned long': 365 has_indexed_property_getter = True 366 elif str(op.arguments[0].idl_type) == 'DOMString': 367 self.has_named_property_getter = True 368 self.operations.append(op) 369 elif child_class == 'Constructor': 370 operation = constructor_operation_from_node(child) 371 if operation.is_custom: 372 custom_constructor_operations.append(operation.constructor) 373 else: 374 # Check extended attributes consistency when we previously 375 # handle constructor operations. 376 if constructor_operations: 377 check_constructor_operations_extended_attributes( 378 constructor_operations_extended_attributes, 379 operation.extended_attributes) 380 constructor_operations.append(operation.constructor) 381 constructor_operations_extended_attributes.update( 382 operation.extended_attributes) 383 elif child_class == 'Inherit': 384 self.parent = child.GetName() 385 elif child_class == 'Stringifier': 386 self.stringifier = IdlStringifier(child) 387 self.process_stringifier() 388 elif child_class == 'Iterable': 389 self.iterable = IdlIterable(child) 390 elif child_class == 'Maplike': 391 self.maplike = IdlMaplike(child) 392 elif child_class == 'Setlike': 393 self.setlike = IdlSetlike(child) 394 else: 395 raise ValueError('Unrecognized node class: %s' % child_class) 396 397 if len(filter(None, [self.iterable, self.maplike, self.setlike])) > 1: 398 raise ValueError( 399 'Interface can only have one of iterable<>, maplike<> and setlike<>.' 400 ) 401 402 # TODO(rakuco): This validation logic should be in v8_interface according to bashi@. 403 # At the moment, doing so does not work because several IDL files are partial Window 404 # interface definitions, and interface_dependency_resolver.py doesn't seem to have any logic 405 # to prevent these partial interfaces from resetting has_named_property to False. 406 if 'LegacyUnenumerableNamedProperties' in self.extended_attributes and \ 407 not self.has_named_property_getter: 408 raise ValueError( 409 '[LegacyUnenumerableNamedProperties] can be used only in interfaces ' 410 'that support named properties.') 411 412 if has_integer_typed_length and has_indexed_property_getter: 413 self.has_indexed_elements = True 414 else: 415 if self.iterable is not None and self.iterable.key_type is None: 416 raise ValueError( 417 'Value iterators (iterable<V>) must be accompanied by an indexed ' 418 'property getter and an integer-typed length attribute.') 419 420 if 'LegacyUnforgeable' in self.extended_attributes: 421 raise ValueError( 422 '[LegacyUnforgeable] cannot appear on interfaces.') 423 424 if constructor_operations or custom_constructor_operations: 425 if self.constructors or self.custom_constructors: 426 raise ValueError('Detected mixed [Constructor] and consructor ' 427 'operations. Do not use both in a single ' 428 'interface.') 429 extended_attributes = ( 430 convert_constructor_operations_extended_attributes( 431 constructor_operations_extended_attributes)) 432 if any(name in extended_attributes.keys() 433 for name in self.extended_attributes.keys()): 434 raise ValueError('Detected mixed extended attributes for ' 435 'both [Constructor] and constructor ' 436 'operations. Do not use both in a single ' 437 'interface') 438 self.constructors = constructor_operations 439 self.custom_constructors = custom_constructor_operations 440 self.extended_attributes.update(extended_attributes) 441 442 def accept(self, visitor): 443 visitor.visit_interface(self) 444 for attribute in self.attributes: 445 attribute.accept(visitor) 446 for constant in self.constants: 447 constant.accept(visitor) 448 for constructor in self.constructors: 449 constructor.accept(visitor) 450 for custom_constructor in self.custom_constructors: 451 custom_constructor.accept(visitor) 452 for operation in self.operations: 453 operation.accept(visitor) 454 if self.iterable: 455 self.iterable.accept(visitor) 456 elif self.maplike: 457 self.maplike.accept(visitor) 458 elif self.setlike: 459 self.setlike.accept(visitor) 460 461 def process_stringifier(self): 462 """Add the stringifier's attribute or named operation child, if it has 463 one, as a regular attribute/operation of this interface.""" 464 if self.stringifier.attribute: 465 self.attributes.append(self.stringifier.attribute) 466 elif self.stringifier.operation: 467 self.operations.append(self.stringifier.operation) 468 469 def merge(self, other): 470 """Merge in another interface's members (e.g., partial interface)""" 471 self.attributes.extend(other.attributes) 472 self.constants.extend(other.constants) 473 self.operations.extend(other.operations) 474 if self.stringifier is None: 475 self.stringifier = other.stringifier 476 477 478################################################################################ 479# Attributes 480################################################################################ 481 482 483class IdlAttribute(TypedObject): 484 def __init__(self, node=None): 485 self.is_read_only = bool( 486 node.GetProperty('READONLY')) if node else False 487 self.is_static = bool(node.GetProperty('STATIC')) if node else False 488 self.name = node.GetName() if node else None 489 self.idl_type = None 490 self.extended_attributes = {} 491 # In what interface the attribute is (originally) defined when the 492 # attribute is inherited from an ancestor interface. 493 self.defined_in = None 494 495 if node: 496 children = node.GetChildren() 497 for child in children: 498 child_class = child.GetClass() 499 if child_class == 'Type': 500 self.idl_type = type_node_to_type(child) 501 elif child_class == 'ExtAttributes': 502 self.extended_attributes = ext_attributes_node_to_extended_attributes( 503 child) 504 else: 505 raise ValueError( 506 'Unrecognized node class: %s' % child_class) 507 508 if 'LegacyUnforgeable' in self.extended_attributes and self.is_static: 509 raise ValueError( 510 '[LegacyUnforgeable] cannot appear on static attributes.') 511 512 def accept(self, visitor): 513 visitor.visit_attribute(self) 514 515 516################################################################################ 517# Constants 518################################################################################ 519 520 521class IdlConstant(TypedObject): 522 def __init__(self, node): 523 children = node.GetChildren() 524 num_children = len(children) 525 if num_children < 2 or num_children > 3: 526 raise ValueError('Expected 2 or 3 children, got %s' % num_children) 527 type_node = children[0] 528 value_node = children[1] 529 value_node_class = value_node.GetClass() 530 if value_node_class != 'Value': 531 raise ValueError('Expected Value node, got %s' % value_node_class) 532 533 self.name = node.GetName() 534 # ConstType is more limited than Type, so subtree is smaller and 535 # we don't use the full type_node_to_type function. 536 self.idl_type = type_node_inner_to_type(type_node) 537 self.value = value_node.GetProperty('VALUE') 538 # In what interface the attribute is (originally) defined when the 539 # attribute is inherited from an ancestor interface. 540 self.defined_in = None 541 542 if num_children == 3: 543 ext_attributes_node = children[2] 544 self.extended_attributes = ext_attributes_node_to_extended_attributes( 545 ext_attributes_node) 546 else: 547 self.extended_attributes = {} 548 549 def accept(self, visitor): 550 visitor.visit_constant(self) 551 552 553################################################################################ 554# Literals 555################################################################################ 556 557 558class IdlLiteral(object): 559 def __init__(self, idl_type, value): 560 self.idl_type = idl_type 561 self.value = value 562 self.is_null = False 563 564 def __str__(self): 565 if self.idl_type == 'DOMString': 566 if self.value: 567 return '"%s"' % self.value 568 else: 569 return 'WTF::g_empty_string' 570 if self.idl_type == 'integer': 571 return '%d' % self.value 572 if self.idl_type == 'float': 573 return '%g' % self.value 574 if self.idl_type == 'boolean': 575 return 'true' if self.value else 'false' 576 if self.idl_type == 'dictionary': 577 return self.value 578 raise ValueError('Unsupported literal type: %s' % self.idl_type) 579 580 581class IdlLiteralNull(IdlLiteral): 582 def __init__(self): 583 self.idl_type = 'NULL' 584 self.value = None 585 self.is_null = True 586 587 def __str__(self): 588 return 'nullptr' 589 590 591def default_node_to_idl_literal(node): 592 idl_type = node.GetProperty('TYPE') 593 value = node.GetProperty('VALUE') 594 if idl_type == 'DOMString': 595 if '"' in value or '\\' in value: 596 raise ValueError('Unsupported string value: %r' % value) 597 return IdlLiteral(idl_type, value) 598 if idl_type == 'integer': 599 return IdlLiteral(idl_type, int(value, base=0)) 600 if idl_type == 'float': 601 return IdlLiteral(idl_type, float(value)) 602 if idl_type in ['boolean', 'sequence']: 603 return IdlLiteral(idl_type, value) 604 if idl_type == 'NULL': 605 return IdlLiteralNull() 606 if idl_type == 'dictionary': 607 return IdlLiteral(idl_type, value) 608 raise ValueError('Unrecognized default value type: %s' % idl_type) 609 610 611################################################################################ 612# Operations 613################################################################################ 614 615 616class IdlOperation(TypedObject): 617 def __init__(self, node=None): 618 self.arguments = [] 619 self.extended_attributes = {} 620 self.specials = [] 621 self.is_constructor = False 622 self.idl_type = None 623 self.is_static = False 624 # In what interface the attribute is (originally) defined when the 625 # attribute is inherited from an ancestor interface. 626 self.defined_in = None 627 628 if not node: 629 return 630 631 self.name = node.GetName() 632 633 self.is_static = bool(node.GetProperty('STATIC')) 634 property_dictionary = node.GetProperties() 635 for special_keyword in SPECIAL_KEYWORD_LIST: 636 if special_keyword in property_dictionary: 637 self.specials.append(special_keyword.lower()) 638 639 children = node.GetChildren() 640 for child in children: 641 child_class = child.GetClass() 642 if child_class == 'Arguments': 643 self.arguments = arguments_node_to_arguments(child) 644 elif child_class == 'Type': 645 self.idl_type = type_node_to_type(child) 646 elif child_class == 'ExtAttributes': 647 self.extended_attributes = ext_attributes_node_to_extended_attributes( 648 child) 649 else: 650 raise ValueError('Unrecognized node class: %s' % child_class) 651 652 if 'LegacyUnforgeable' in self.extended_attributes and self.is_static: 653 raise ValueError( 654 '[LegacyUnforgeable] cannot appear on static operations.') 655 656 @classmethod 657 def constructor_from_arguments_node(cls, name, arguments_node): 658 constructor = cls() 659 constructor.name = name 660 constructor.arguments = arguments_node_to_arguments(arguments_node) 661 constructor.is_constructor = True 662 return constructor 663 664 def accept(self, visitor): 665 visitor.visit_operation(self) 666 for argument in self.arguments: 667 argument.accept(visitor) 668 669 670################################################################################ 671# Arguments 672################################################################################ 673 674 675class IdlArgument(TypedObject): 676 def __init__(self, node=None): 677 self.extended_attributes = {} 678 self.idl_type = None 679 self.is_optional = False # syntax: (optional T) 680 self.is_variadic = False # syntax: (T...) 681 self.default_value = None 682 683 if not node: 684 return 685 686 self.is_optional = node.GetProperty('OPTIONAL') 687 self.name = node.GetName() 688 689 children = node.GetChildren() 690 for child in children: 691 child_class = child.GetClass() 692 if child_class == 'Type': 693 self.idl_type = type_node_to_type(child) 694 elif child_class == 'ExtAttributes': 695 self.extended_attributes = ext_attributes_node_to_extended_attributes( 696 child) 697 elif child_class == 'Argument': 698 child_name = child.GetName() 699 if child_name != '...': 700 raise ValueError( 701 'Unrecognized Argument node; expected "...", got "%s"' 702 % child_name) 703 self.is_variadic = bool(child.GetProperty('ELLIPSIS')) 704 elif child_class == 'Default': 705 self.default_value = default_node_to_idl_literal(child) 706 else: 707 raise ValueError('Unrecognized node class: %s' % child_class) 708 709 def accept(self, visitor): 710 visitor.visit_argument(self) 711 712 713def arguments_node_to_arguments(node): 714 # [Constructor] and [CustomConstructor] without arguments (the bare form) 715 # have None instead of an arguments node, but have the same meaning as using 716 # an empty argument list, [Constructor()], so special-case this. 717 # http://www.w3.org/TR/WebIDL/#Constructor 718 if node is None: 719 return [] 720 return [IdlArgument(argument_node) for argument_node in node.GetChildren()] 721 722 723################################################################################ 724# Stringifiers 725################################################################################ 726 727 728class IdlStringifier(object): 729 def __init__(self, node): 730 self.attribute = None 731 self.operation = None 732 self.extended_attributes = {} 733 734 for child in node.GetChildren(): 735 child_class = child.GetClass() 736 if child_class == 'Attribute': 737 self.attribute = IdlAttribute(child) 738 elif child_class == 'Operation': 739 operation = IdlOperation(child) 740 if operation.name: 741 self.operation = operation 742 elif child_class == 'ExtAttributes': 743 self.extended_attributes = ext_attributes_node_to_extended_attributes( 744 child) 745 else: 746 raise ValueError('Unrecognized node class: %s' % child_class) 747 748 # Copy the stringifier's extended attributes (such as [Unforgable]) onto 749 # the underlying attribute or operation, if there is one. 750 if self.attribute or self.operation: 751 (self.attribute or self.operation).extended_attributes.update( 752 self.extended_attributes) 753 754 755################################################################################ 756# Iterable, Maplike, Setlike 757################################################################################ 758 759 760class IdlIterableOrMaplikeOrSetlike(TypedObject): 761 def __init__(self, node): 762 self.extended_attributes = {} 763 self.type_children = [] 764 765 for child in node.GetChildren(): 766 child_class = child.GetClass() 767 if child_class == 'ExtAttributes': 768 self.extended_attributes = ext_attributes_node_to_extended_attributes( 769 child) 770 elif child_class == 'Type': 771 self.type_children.append(child) 772 else: 773 raise ValueError('Unrecognized node class: %s' % child_class) 774 775 776class IdlIterable(IdlIterableOrMaplikeOrSetlike): 777 idl_type_attributes = ('key_type', 'value_type') 778 779 def __init__(self, node): 780 super(IdlIterable, self).__init__(node) 781 782 if len(self.type_children) == 1: 783 self.key_type = None 784 self.value_type = type_node_to_type(self.type_children[0]) 785 elif len(self.type_children) == 2: 786 self.key_type = type_node_to_type(self.type_children[0]) 787 self.value_type = type_node_to_type(self.type_children[1]) 788 else: 789 raise ValueError('Unexpected number of type children: %d' % len( 790 self.type_children)) 791 del self.type_children 792 793 def accept(self, visitor): 794 visitor.visit_iterable(self) 795 796 797class IdlMaplike(IdlIterableOrMaplikeOrSetlike): 798 idl_type_attributes = ('key_type', 'value_type') 799 800 def __init__(self, node): 801 super(IdlMaplike, self).__init__(node) 802 803 self.is_read_only = bool(node.GetProperty('READONLY')) 804 805 if len(self.type_children) == 2: 806 self.key_type = type_node_to_type(self.type_children[0]) 807 self.value_type = type_node_to_type(self.type_children[1]) 808 else: 809 raise ValueError( 810 'Unexpected number of children: %d' % len(self.type_children)) 811 del self.type_children 812 813 def accept(self, visitor): 814 visitor.visit_maplike(self) 815 816 817class IdlSetlike(IdlIterableOrMaplikeOrSetlike): 818 idl_type_attributes = ('value_type', ) 819 820 def __init__(self, node): 821 super(IdlSetlike, self).__init__(node) 822 823 self.is_read_only = bool(node.GetProperty('READONLY')) 824 825 if len(self.type_children) == 1: 826 self.value_type = type_node_to_type(self.type_children[0]) 827 else: 828 raise ValueError( 829 'Unexpected number of children: %d' % len(self.type_children)) 830 del self.type_children 831 832 def accept(self, visitor): 833 visitor.visit_setlike(self) 834 835 836################################################################################ 837# Includes statements 838################################################################################ 839 840 841class IdlIncludes(object): 842 def __init__(self, node): 843 self.interface = node.GetName() 844 self.mixin = node.GetProperty('REFERENCE') 845 846 def accept(self, visitor): 847 visitor.visit_include(self) 848 849 850################################################################################ 851# Extended attributes 852################################################################################ 853 854 855class Exposure: 856 """An Exposure holds one Exposed or RuntimeEnabled condition. 857 Each exposure has two properties: exposed and runtime_enabled. 858 Exposure(e, r) corresponds to [Exposed(e r)]. Exposure(e) corresponds to 859 [Exposed=e]. 860 """ 861 862 def __init__(self, exposed, runtime_enabled=None): 863 self.exposed = exposed 864 self.runtime_enabled = runtime_enabled 865 866 867def ext_attributes_node_to_extended_attributes(node): 868 """ 869 Returns: 870 Dictionary of {ExtAttributeName: ExtAttributeValue}. 871 Value is usually a string, with these exceptions: 872 Constructors: value is a list of Arguments nodes, corresponding to 873 possible signatures of the constructor. 874 CustomConstructors: value is a list of Arguments nodes, corresponding to 875 possible signatures of the custom constructor. 876 NamedConstructor: value is a Call node, corresponding to the single 877 signature of the named constructor. 878 """ 879 # Primarily just make a dictionary from the children. 880 # The only complexity is handling various types of constructors: 881 # Constructors and Custom Constructors can have duplicate entries due to 882 # overloading, and thus are stored in temporary lists. 883 # However, Named Constructors cannot be overloaded, and thus do not have 884 # a list. 885 # TODO(bashi): Remove |constructors| and |custom_constructors|. 886 constructors = [] 887 custom_constructors = [] 888 extended_attributes = {} 889 890 def child_node(extended_attribute_node): 891 children = extended_attribute_node.GetChildren() 892 if not children: 893 return None 894 if len(children) > 1: 895 raise ValueError( 896 'ExtAttributes node with %s children, expected at most 1' % 897 len(children)) 898 return children[0] 899 900 extended_attribute_node_list = node.GetChildren() 901 for extended_attribute_node in extended_attribute_node_list: 902 name = extended_attribute_node.GetName() 903 child = child_node(extended_attribute_node) 904 child_class = child and child.GetClass() 905 if name == 'Constructor': 906 raise ValueError('[Constructor] is deprecated. Use constructor ' 907 'operations') 908 elif name == 'CustomConstructor': 909 raise ValueError('[CustomConstructor] is deprecated. Use ' 910 'constructor operations with [Custom]') 911 elif name == 'NamedConstructor': 912 if child_class and child_class != 'Call': 913 raise ValueError( 914 '[NamedConstructor] only supports Call as child, but has child of class: %s' 915 % child_class) 916 extended_attributes[name] = child 917 elif name == 'Exposed': 918 if child_class and child_class != 'Arguments': 919 raise ValueError( 920 '[Exposed] only supports Arguments as child, but has child of class: %s' 921 % child_class) 922 exposures = [] 923 if child_class == 'Arguments': 924 exposures = [ 925 Exposure( 926 exposed=str(arg.idl_type), runtime_enabled=arg.name) 927 for arg in arguments_node_to_arguments(child) 928 ] 929 else: 930 value = extended_attribute_node.GetProperty('VALUE') 931 if type(value) is str: 932 exposures = [Exposure(exposed=value)] 933 else: 934 exposures = [Exposure(exposed=v) for v in value] 935 extended_attributes[name] = exposures 936 elif child: 937 raise ValueError( 938 'ExtAttributes node with unexpected children: %s' % name) 939 else: 940 value = extended_attribute_node.GetProperty('VALUE') 941 extended_attributes[name] = value 942 943 # Store constructors and custom constructors in special list attributes, 944 # which are deleted later. Note plural in key. 945 if constructors: 946 extended_attributes['Constructors'] = constructors 947 if custom_constructors: 948 extended_attributes['CustomConstructors'] = custom_constructors 949 950 return extended_attributes 951 952 953def extended_attributes_to_constructors(extended_attributes): 954 """Returns constructors and custom_constructors (lists of IdlOperations). 955 956 Auxiliary function for IdlInterface.__init__. 957 """ 958 959 # TODO(bashi): Remove 'Constructors' and 'CustomConstructors'. 960 961 constructor_list = extended_attributes.get('Constructors', []) 962 constructors = [ 963 IdlOperation.constructor_from_arguments_node('Constructor', 964 arguments_node) 965 for arguments_node in constructor_list 966 ] 967 968 custom_constructor_list = extended_attributes.get('CustomConstructors', []) 969 custom_constructors = [ 970 IdlOperation.constructor_from_arguments_node('CustomConstructor', 971 arguments_node) 972 for arguments_node in custom_constructor_list 973 ] 974 975 if 'NamedConstructor' in extended_attributes: 976 # FIXME: support overloaded named constructors, and make homogeneous 977 name = 'NamedConstructor' 978 call_node = extended_attributes['NamedConstructor'] 979 extended_attributes['NamedConstructor'] = call_node.GetName() 980 children = call_node.GetChildren() 981 if len(children) != 1: 982 raise ValueError('NamedConstructor node expects 1 child, got %s.' % 983 len(children)) 984 arguments_node = children[0] 985 named_constructor = IdlOperation.constructor_from_arguments_node( 986 'NamedConstructor', arguments_node) 987 # FIXME: should return named_constructor separately; appended for Perl 988 constructors.append(named_constructor) 989 990 return constructors, custom_constructors 991 992 993class ConstructorOperation(object): 994 """Represents a constructor operation. This is a tentative object used to 995 create constructors in IdlInterface. 996 """ 997 998 def __init__(self, constructor, extended_attributes, is_custom): 999 self.constructor = constructor 1000 self.extended_attributes = extended_attributes 1001 self.is_custom = is_custom 1002 1003 1004def constructor_operation_from_node(node): 1005 """Creates a ConstructorOperation from the given |node|. 1006 """ 1007 1008 arguments_node = None 1009 extended_attributes = {} 1010 1011 for child in node.GetChildren(): 1012 child_class = child.GetClass() 1013 if child_class == 'Arguments': 1014 arguments_node = child 1015 elif child_class == 'ExtAttributes': 1016 extended_attributes = ext_attributes_node_to_extended_attributes( 1017 child) 1018 else: 1019 raise ValueError('Unrecognized node class: %s' % child_class) 1020 1021 if not arguments_node: 1022 raise ValueError('Expected Arguments node for constructor operation') 1023 1024 if 'Custom' in extended_attributes: 1025 if extended_attributes['Custom']: 1026 raise ValueError('[Custom] should not have a value on constructor ' 1027 'operations') 1028 del extended_attributes['Custom'] 1029 constructor = IdlOperation.constructor_from_arguments_node( 1030 'CustomConstructor', arguments_node) 1031 return ConstructorOperation( 1032 constructor, extended_attributes, is_custom=True) 1033 else: 1034 constructor = IdlOperation.constructor_from_arguments_node( 1035 'Constructor', arguments_node) 1036 return ConstructorOperation( 1037 constructor, extended_attributes, is_custom=False) 1038 1039 1040def check_constructor_operations_extended_attributes(current_attrs, new_attrs): 1041 """Raises a ValueError if two extended attribute lists have different values 1042 of constructor related attributes. 1043 """ 1044 1045 attrs_to_check = ['CallWith', 'RaisesException'] 1046 for attr in attrs_to_check: 1047 if current_attrs.get(attr) != new_attrs.get(attr): 1048 raise ValueError('[{}] should have the same value on all ' 1049 'constructor operations'.format(attr)) 1050 1051 1052def convert_constructor_operations_extended_attributes(extended_attributes): 1053 """Converts extended attributes specified on constructor operations to 1054 extended attributes for an interface definition (e.g. [ConstructorCallWith]) 1055 """ 1056 1057 converted = {} 1058 for name, value in extended_attributes.items(): 1059 if name == "CallWith": 1060 converted["ConstructorCallWith"] = value 1061 elif name == "RaisesException": 1062 if value: 1063 raise ValueError( 1064 '[RaisesException] should not have a value on ' 1065 'constructor operations') 1066 converted["RaisesException"] = 'Constructor' 1067 elif name == "MeasureAs": 1068 converted["MeasureAs"] = value 1069 elif name == "Measure": 1070 converted["Measure"] = None 1071 else: 1072 raise ValueError( 1073 '[{}] is not supported on constructor operations'.format(name)) 1074 1075 return converted 1076 1077 1078def clear_constructor_attributes(extended_attributes): 1079 # Deletes Constructor*s* (plural), sets Constructor (singular) 1080 if 'Constructors' in extended_attributes: 1081 del extended_attributes['Constructors'] 1082 extended_attributes['Constructor'] = None 1083 if 'CustomConstructors' in extended_attributes: 1084 del extended_attributes['CustomConstructors'] 1085 extended_attributes['CustomConstructor'] = None 1086 1087 1088################################################################################ 1089# Types 1090################################################################################ 1091 1092 1093def type_node_to_type(node): 1094 children = node.GetChildren() 1095 if len(children) != 1 and len(children) != 2: 1096 raise ValueError( 1097 'Type node expects 1 or 2 child(ren), got %d.' % len(children)) 1098 1099 base_type = type_node_inner_to_type(children[0]) 1100 if len(children) == 2: 1101 extended_attributes = ext_attributes_node_to_extended_attributes( 1102 children[1]) 1103 base_type = IdlAnnotatedType(base_type, extended_attributes) 1104 1105 if node.GetProperty('NULLABLE'): 1106 base_type = IdlNullableType(base_type) 1107 1108 return base_type 1109 1110 1111def type_node_inner_to_type(node): 1112 node_class = node.GetClass() 1113 # Note Type*r*ef, not Typedef, meaning the type is an identifier, thus 1114 # either a typedef shorthand (but not a Typedef declaration itself) or an 1115 # interface type. We do not distinguish these, and just use the type name. 1116 if node_class in ['PrimitiveType', 'StringType', 'Typeref']: 1117 # unrestricted syntax: unrestricted double | unrestricted float 1118 is_unrestricted = bool(node.GetProperty('UNRESTRICTED')) 1119 return IdlType(node.GetName(), is_unrestricted=is_unrestricted) 1120 elif node_class == 'Any': 1121 return IdlType('any') 1122 elif node_class in ['Sequence', 'FrozenArray']: 1123 return sequence_node_to_type(node) 1124 elif node_class == 'UnionType': 1125 return union_type_node_to_idl_union_type(node) 1126 elif node_class == 'Promise': 1127 return IdlType('Promise') 1128 elif node_class == 'Record': 1129 return record_node_to_type(node) 1130 raise ValueError('Unrecognized node class: %s' % node_class) 1131 1132 1133def record_node_to_type(node): 1134 children = node.GetChildren() 1135 if len(children) != 2: 1136 raise ValueError('record<K,V> node expects exactly 2 children, got %d' 1137 % (len(children))) 1138 key_child = children[0] 1139 value_child = children[1] 1140 if key_child.GetClass() != 'StringType': 1141 raise ValueError('Keys in record<K,V> nodes must be string types.') 1142 if value_child.GetClass() != 'Type': 1143 raise ValueError('Unrecognized node class for record<K,V> value: %s' % 1144 value_child.GetClass()) 1145 return IdlRecordType( 1146 IdlType(key_child.GetName()), type_node_to_type(value_child)) 1147 1148 1149def sequence_node_to_type(node): 1150 children = node.GetChildren() 1151 class_name = node.GetClass() 1152 if len(children) != 1: 1153 raise ValueError('%s node expects exactly 1 child, got %s' % 1154 (class_name, len(children))) 1155 sequence_child = children[0] 1156 sequence_child_class = sequence_child.GetClass() 1157 if sequence_child_class != 'Type': 1158 raise ValueError('Unrecognized node class: %s' % sequence_child_class) 1159 element_type = type_node_to_type(sequence_child) 1160 if class_name == 'Sequence': 1161 sequence_type = IdlSequenceType(element_type) 1162 elif class_name == 'FrozenArray': 1163 sequence_type = IdlFrozenArrayType(element_type) 1164 else: 1165 raise ValueError('Unexpected node: %s' % class_name) 1166 if node.GetProperty('NULLABLE'): 1167 return IdlNullableType(sequence_type) 1168 return sequence_type 1169 1170 1171def typedef_node_to_type(node): 1172 children = node.GetChildren() 1173 if len(children) != 1: 1174 raise ValueError( 1175 'Typedef node with %s children, expected 1' % len(children)) 1176 child = children[0] 1177 child_class = child.GetClass() 1178 if child_class != 'Type': 1179 raise ValueError('Unrecognized node class: %s' % child_class) 1180 return type_node_to_type(child) 1181 1182 1183def union_type_node_to_idl_union_type(node): 1184 member_types = [ 1185 type_node_to_type(member_type_node) 1186 for member_type_node in node.GetChildren() 1187 ] 1188 return IdlUnionType(member_types) 1189 1190 1191################################################################################ 1192# Visitor 1193################################################################################ 1194 1195 1196class Visitor(object): 1197 """Abstract visitor class for IDL definitions traverse.""" 1198 1199 def visit_definitions(self, definitions): 1200 pass 1201 1202 def visit_typed_object(self, typed_object): 1203 pass 1204 1205 def visit_callback_function(self, callback_function): 1206 self.visit_typed_object(callback_function) 1207 1208 def visit_dictionary(self, dictionary): 1209 pass 1210 1211 def visit_dictionary_member(self, member): 1212 self.visit_typed_object(member) 1213 1214 def visit_enumeration(self, enumeration): 1215 pass 1216 1217 def visit_include(self, include): 1218 pass 1219 1220 def visit_interface(self, interface): 1221 pass 1222 1223 def visit_typedef(self, typedef): 1224 self.visit_typed_object(typedef) 1225 1226 def visit_attribute(self, attribute): 1227 self.visit_typed_object(attribute) 1228 1229 def visit_constant(self, constant): 1230 self.visit_typed_object(constant) 1231 1232 def visit_operation(self, operation): 1233 self.visit_typed_object(operation) 1234 1235 def visit_argument(self, argument): 1236 self.visit_typed_object(argument) 1237 1238 def visit_iterable(self, iterable): 1239 self.visit_typed_object(iterable) 1240 1241 def visit_maplike(self, maplike): 1242 self.visit_typed_object(maplike) 1243 1244 def visit_setlike(self, setlike): 1245 self.visit_typed_object(setlike) 1246