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': 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_blacklisted_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_blacklisted_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 'Unforgeable' in self.extended_attributes: 421 raise ValueError('[Unforgeable] cannot appear on interfaces.') 422 423 if constructor_operations or custom_constructor_operations: 424 if self.constructors or self.custom_constructors: 425 raise ValueError('Detected mixed [Constructor] and consructor ' 426 'operations. Do not use both in a single ' 427 'interface.') 428 extended_attributes = ( 429 convert_constructor_operations_extended_attributes( 430 constructor_operations_extended_attributes)) 431 if any(name in extended_attributes.keys() 432 for name in self.extended_attributes.keys()): 433 raise ValueError('Detected mixed extended attributes for ' 434 'both [Constructor] and constructor ' 435 'operations. Do not use both in a single ' 436 'interface') 437 self.constructors = constructor_operations 438 self.custom_constructors = custom_constructor_operations 439 self.extended_attributes.update(extended_attributes) 440 441 def accept(self, visitor): 442 visitor.visit_interface(self) 443 for attribute in self.attributes: 444 attribute.accept(visitor) 445 for constant in self.constants: 446 constant.accept(visitor) 447 for constructor in self.constructors: 448 constructor.accept(visitor) 449 for custom_constructor in self.custom_constructors: 450 custom_constructor.accept(visitor) 451 for operation in self.operations: 452 operation.accept(visitor) 453 if self.iterable: 454 self.iterable.accept(visitor) 455 elif self.maplike: 456 self.maplike.accept(visitor) 457 elif self.setlike: 458 self.setlike.accept(visitor) 459 460 def process_stringifier(self): 461 """Add the stringifier's attribute or named operation child, if it has 462 one, as a regular attribute/operation of this interface.""" 463 if self.stringifier.attribute: 464 self.attributes.append(self.stringifier.attribute) 465 elif self.stringifier.operation: 466 self.operations.append(self.stringifier.operation) 467 468 def merge(self, other): 469 """Merge in another interface's members (e.g., partial interface)""" 470 self.attributes.extend(other.attributes) 471 self.constants.extend(other.constants) 472 self.operations.extend(other.operations) 473 if self.stringifier is None: 474 self.stringifier = other.stringifier 475 476 477################################################################################ 478# Attributes 479################################################################################ 480 481 482class IdlAttribute(TypedObject): 483 def __init__(self, node=None): 484 self.is_read_only = bool( 485 node.GetProperty('READONLY')) if node else False 486 self.is_static = bool(node.GetProperty('STATIC')) if node else False 487 self.name = node.GetName() if node else None 488 self.idl_type = None 489 self.extended_attributes = {} 490 # In what interface the attribute is (originally) defined when the 491 # attribute is inherited from an ancestor interface. 492 self.defined_in = None 493 494 if node: 495 children = node.GetChildren() 496 for child in children: 497 child_class = child.GetClass() 498 if child_class == 'Type': 499 self.idl_type = type_node_to_type(child) 500 elif child_class == 'ExtAttributes': 501 self.extended_attributes = ext_attributes_node_to_extended_attributes( 502 child) 503 else: 504 raise ValueError( 505 'Unrecognized node class: %s' % child_class) 506 507 if 'Unforgeable' in self.extended_attributes and self.is_static: 508 raise ValueError( 509 '[Unforgeable] cannot appear on static attributes.') 510 511 def accept(self, visitor): 512 visitor.visit_attribute(self) 513 514 515################################################################################ 516# Constants 517################################################################################ 518 519 520class IdlConstant(TypedObject): 521 def __init__(self, node): 522 children = node.GetChildren() 523 num_children = len(children) 524 if num_children < 2 or num_children > 3: 525 raise ValueError('Expected 2 or 3 children, got %s' % num_children) 526 type_node = children[0] 527 value_node = children[1] 528 value_node_class = value_node.GetClass() 529 if value_node_class != 'Value': 530 raise ValueError('Expected Value node, got %s' % value_node_class) 531 532 self.name = node.GetName() 533 # ConstType is more limited than Type, so subtree is smaller and 534 # we don't use the full type_node_to_type function. 535 self.idl_type = type_node_inner_to_type(type_node) 536 self.value = value_node.GetProperty('VALUE') 537 # In what interface the attribute is (originally) defined when the 538 # attribute is inherited from an ancestor interface. 539 self.defined_in = None 540 541 if num_children == 3: 542 ext_attributes_node = children[2] 543 self.extended_attributes = ext_attributes_node_to_extended_attributes( 544 ext_attributes_node) 545 else: 546 self.extended_attributes = {} 547 548 def accept(self, visitor): 549 visitor.visit_constant(self) 550 551 552################################################################################ 553# Literals 554################################################################################ 555 556 557class IdlLiteral(object): 558 def __init__(self, idl_type, value): 559 self.idl_type = idl_type 560 self.value = value 561 self.is_null = False 562 563 def __str__(self): 564 if self.idl_type == 'DOMString': 565 if self.value: 566 return '"%s"' % self.value 567 else: 568 return 'WTF::g_empty_string' 569 if self.idl_type == 'integer': 570 return '%d' % self.value 571 if self.idl_type == 'float': 572 return '%g' % self.value 573 if self.idl_type == 'boolean': 574 return 'true' if self.value else 'false' 575 if self.idl_type == 'dictionary': 576 return self.value 577 raise ValueError('Unsupported literal type: %s' % self.idl_type) 578 579 580class IdlLiteralNull(IdlLiteral): 581 def __init__(self): 582 self.idl_type = 'NULL' 583 self.value = None 584 self.is_null = True 585 586 def __str__(self): 587 return 'nullptr' 588 589 590def default_node_to_idl_literal(node): 591 idl_type = node.GetProperty('TYPE') 592 value = node.GetProperty('VALUE') 593 if idl_type == 'DOMString': 594 if '"' in value or '\\' in value: 595 raise ValueError('Unsupported string value: %r' % value) 596 return IdlLiteral(idl_type, value) 597 if idl_type == 'integer': 598 return IdlLiteral(idl_type, int(value, base=0)) 599 if idl_type == 'float': 600 return IdlLiteral(idl_type, float(value)) 601 if idl_type in ['boolean', 'sequence']: 602 return IdlLiteral(idl_type, value) 603 if idl_type == 'NULL': 604 return IdlLiteralNull() 605 if idl_type == 'dictionary': 606 return IdlLiteral(idl_type, value) 607 raise ValueError('Unrecognized default value type: %s' % idl_type) 608 609 610################################################################################ 611# Operations 612################################################################################ 613 614 615class IdlOperation(TypedObject): 616 def __init__(self, node=None): 617 self.arguments = [] 618 self.extended_attributes = {} 619 self.specials = [] 620 self.is_constructor = False 621 self.idl_type = None 622 self.is_static = False 623 # In what interface the attribute is (originally) defined when the 624 # attribute is inherited from an ancestor interface. 625 self.defined_in = None 626 627 if not node: 628 return 629 630 self.name = node.GetName() 631 632 self.is_static = bool(node.GetProperty('STATIC')) 633 property_dictionary = node.GetProperties() 634 for special_keyword in SPECIAL_KEYWORD_LIST: 635 if special_keyword in property_dictionary: 636 self.specials.append(special_keyword.lower()) 637 638 children = node.GetChildren() 639 for child in children: 640 child_class = child.GetClass() 641 if child_class == 'Arguments': 642 self.arguments = arguments_node_to_arguments(child) 643 elif child_class == 'Type': 644 self.idl_type = type_node_to_type(child) 645 elif child_class == 'ExtAttributes': 646 self.extended_attributes = ext_attributes_node_to_extended_attributes( 647 child) 648 else: 649 raise ValueError('Unrecognized node class: %s' % child_class) 650 651 if 'Unforgeable' in self.extended_attributes and self.is_static: 652 raise ValueError( 653 '[Unforgeable] cannot appear on static operations.') 654 655 @classmethod 656 def constructor_from_arguments_node(cls, name, arguments_node): 657 constructor = cls() 658 constructor.name = name 659 constructor.arguments = arguments_node_to_arguments(arguments_node) 660 constructor.is_constructor = True 661 return constructor 662 663 def accept(self, visitor): 664 visitor.visit_operation(self) 665 for argument in self.arguments: 666 argument.accept(visitor) 667 668 669################################################################################ 670# Arguments 671################################################################################ 672 673 674class IdlArgument(TypedObject): 675 def __init__(self, node=None): 676 self.extended_attributes = {} 677 self.idl_type = None 678 self.is_optional = False # syntax: (optional T) 679 self.is_variadic = False # syntax: (T...) 680 self.default_value = None 681 682 if not node: 683 return 684 685 self.is_optional = node.GetProperty('OPTIONAL') 686 self.name = node.GetName() 687 688 children = node.GetChildren() 689 for child in children: 690 child_class = child.GetClass() 691 if child_class == 'Type': 692 self.idl_type = type_node_to_type(child) 693 elif child_class == 'ExtAttributes': 694 self.extended_attributes = ext_attributes_node_to_extended_attributes( 695 child) 696 elif child_class == 'Argument': 697 child_name = child.GetName() 698 if child_name != '...': 699 raise ValueError( 700 'Unrecognized Argument node; expected "...", got "%s"' 701 % child_name) 702 self.is_variadic = bool(child.GetProperty('ELLIPSIS')) 703 elif child_class == 'Default': 704 self.default_value = default_node_to_idl_literal(child) 705 else: 706 raise ValueError('Unrecognized node class: %s' % child_class) 707 708 def accept(self, visitor): 709 visitor.visit_argument(self) 710 711 712def arguments_node_to_arguments(node): 713 # [Constructor] and [CustomConstructor] without arguments (the bare form) 714 # have None instead of an arguments node, but have the same meaning as using 715 # an empty argument list, [Constructor()], so special-case this. 716 # http://www.w3.org/TR/WebIDL/#Constructor 717 if node is None: 718 return [] 719 return [IdlArgument(argument_node) for argument_node in node.GetChildren()] 720 721 722################################################################################ 723# Stringifiers 724################################################################################ 725 726 727class IdlStringifier(object): 728 def __init__(self, node): 729 self.attribute = None 730 self.operation = None 731 self.extended_attributes = {} 732 733 for child in node.GetChildren(): 734 child_class = child.GetClass() 735 if child_class == 'Attribute': 736 self.attribute = IdlAttribute(child) 737 elif child_class == 'Operation': 738 operation = IdlOperation(child) 739 if operation.name: 740 self.operation = operation 741 elif child_class == 'ExtAttributes': 742 self.extended_attributes = ext_attributes_node_to_extended_attributes( 743 child) 744 else: 745 raise ValueError('Unrecognized node class: %s' % child_class) 746 747 # Copy the stringifier's extended attributes (such as [Unforgable]) onto 748 # the underlying attribute or operation, if there is one. 749 if self.attribute or self.operation: 750 (self.attribute or self.operation).extended_attributes.update( 751 self.extended_attributes) 752 753 754################################################################################ 755# Iterable, Maplike, Setlike 756################################################################################ 757 758 759class IdlIterableOrMaplikeOrSetlike(TypedObject): 760 def __init__(self, node): 761 self.extended_attributes = {} 762 self.type_children = [] 763 764 for child in node.GetChildren(): 765 child_class = child.GetClass() 766 if child_class == 'ExtAttributes': 767 self.extended_attributes = ext_attributes_node_to_extended_attributes( 768 child) 769 elif child_class == 'Type': 770 self.type_children.append(child) 771 else: 772 raise ValueError('Unrecognized node class: %s' % child_class) 773 774 775class IdlIterable(IdlIterableOrMaplikeOrSetlike): 776 idl_type_attributes = ('key_type', 'value_type') 777 778 def __init__(self, node): 779 super(IdlIterable, self).__init__(node) 780 781 if len(self.type_children) == 1: 782 self.key_type = None 783 self.value_type = type_node_to_type(self.type_children[0]) 784 elif len(self.type_children) == 2: 785 self.key_type = type_node_to_type(self.type_children[0]) 786 self.value_type = type_node_to_type(self.type_children[1]) 787 else: 788 raise ValueError('Unexpected number of type children: %d' % len( 789 self.type_children)) 790 del self.type_children 791 792 def accept(self, visitor): 793 visitor.visit_iterable(self) 794 795 796class IdlMaplike(IdlIterableOrMaplikeOrSetlike): 797 idl_type_attributes = ('key_type', 'value_type') 798 799 def __init__(self, node): 800 super(IdlMaplike, self).__init__(node) 801 802 self.is_read_only = bool(node.GetProperty('READONLY')) 803 804 if len(self.type_children) == 2: 805 self.key_type = type_node_to_type(self.type_children[0]) 806 self.value_type = type_node_to_type(self.type_children[1]) 807 else: 808 raise ValueError( 809 'Unexpected number of children: %d' % len(self.type_children)) 810 del self.type_children 811 812 def accept(self, visitor): 813 visitor.visit_maplike(self) 814 815 816class IdlSetlike(IdlIterableOrMaplikeOrSetlike): 817 idl_type_attributes = ('value_type', ) 818 819 def __init__(self, node): 820 super(IdlSetlike, self).__init__(node) 821 822 self.is_read_only = bool(node.GetProperty('READONLY')) 823 824 if len(self.type_children) == 1: 825 self.value_type = type_node_to_type(self.type_children[0]) 826 else: 827 raise ValueError( 828 'Unexpected number of children: %d' % len(self.type_children)) 829 del self.type_children 830 831 def accept(self, visitor): 832 visitor.visit_setlike(self) 833 834 835################################################################################ 836# Includes statements 837################################################################################ 838 839 840class IdlIncludes(object): 841 def __init__(self, node): 842 self.interface = node.GetName() 843 self.mixin = node.GetProperty('REFERENCE') 844 845 def accept(self, visitor): 846 visitor.visit_include(self) 847 848 849################################################################################ 850# Extended attributes 851################################################################################ 852 853 854class Exposure: 855 """An Exposure holds one Exposed or RuntimeEnabled condition. 856 Each exposure has two properties: exposed and runtime_enabled. 857 Exposure(e, r) corresponds to [Exposed(e r)]. Exposure(e) corresponds to 858 [Exposed=e]. 859 """ 860 861 def __init__(self, exposed, runtime_enabled=None): 862 self.exposed = exposed 863 self.runtime_enabled = runtime_enabled 864 865 866def ext_attributes_node_to_extended_attributes(node): 867 """ 868 Returns: 869 Dictionary of {ExtAttributeName: ExtAttributeValue}. 870 Value is usually a string, with these exceptions: 871 Constructors: value is a list of Arguments nodes, corresponding to 872 possible signatures of the constructor. 873 CustomConstructors: value is a list of Arguments nodes, corresponding to 874 possible signatures of the custom constructor. 875 NamedConstructor: value is a Call node, corresponding to the single 876 signature of the named constructor. 877 """ 878 # Primarily just make a dictionary from the children. 879 # The only complexity is handling various types of constructors: 880 # Constructors and Custom Constructors can have duplicate entries due to 881 # overloading, and thus are stored in temporary lists. 882 # However, Named Constructors cannot be overloaded, and thus do not have 883 # a list. 884 # TODO(bashi): Remove |constructors| and |custom_constructors|. 885 constructors = [] 886 custom_constructors = [] 887 extended_attributes = {} 888 889 def child_node(extended_attribute_node): 890 children = extended_attribute_node.GetChildren() 891 if not children: 892 return None 893 if len(children) > 1: 894 raise ValueError( 895 'ExtAttributes node with %s children, expected at most 1' % 896 len(children)) 897 return children[0] 898 899 extended_attribute_node_list = node.GetChildren() 900 for extended_attribute_node in extended_attribute_node_list: 901 name = extended_attribute_node.GetName() 902 child = child_node(extended_attribute_node) 903 child_class = child and child.GetClass() 904 if name == 'Constructor': 905 raise ValueError('[Constructor] is deprecated. Use constructor ' 906 'operations') 907 elif name == 'CustomConstructor': 908 raise ValueError('[CustomConstructor] is deprecated. Use ' 909 'constructor operations with [Custom]') 910 elif name == 'NamedConstructor': 911 if child_class and child_class != 'Call': 912 raise ValueError( 913 '[NamedConstructor] only supports Call as child, but has child of class: %s' 914 % child_class) 915 extended_attributes[name] = child 916 elif name == 'Exposed': 917 if child_class and child_class != 'Arguments': 918 raise ValueError( 919 '[Exposed] only supports Arguments as child, but has child of class: %s' 920 % child_class) 921 exposures = [] 922 if child_class == 'Arguments': 923 exposures = [ 924 Exposure( 925 exposed=str(arg.idl_type), runtime_enabled=arg.name) 926 for arg in arguments_node_to_arguments(child) 927 ] 928 else: 929 value = extended_attribute_node.GetProperty('VALUE') 930 if type(value) is str: 931 exposures = [Exposure(exposed=value)] 932 else: 933 exposures = [Exposure(exposed=v) for v in value] 934 extended_attributes[name] = exposures 935 elif child: 936 raise ValueError( 937 'ExtAttributes node with unexpected children: %s' % name) 938 else: 939 value = extended_attribute_node.GetProperty('VALUE') 940 extended_attributes[name] = value 941 942 # Store constructors and custom constructors in special list attributes, 943 # which are deleted later. Note plural in key. 944 if constructors: 945 extended_attributes['Constructors'] = constructors 946 if custom_constructors: 947 extended_attributes['CustomConstructors'] = custom_constructors 948 949 return extended_attributes 950 951 952def extended_attributes_to_constructors(extended_attributes): 953 """Returns constructors and custom_constructors (lists of IdlOperations). 954 955 Auxiliary function for IdlInterface.__init__. 956 """ 957 958 # TODO(bashi): Remove 'Constructors' and 'CustomConstructors'. 959 960 constructor_list = extended_attributes.get('Constructors', []) 961 constructors = [ 962 IdlOperation.constructor_from_arguments_node('Constructor', 963 arguments_node) 964 for arguments_node in constructor_list 965 ] 966 967 custom_constructor_list = extended_attributes.get('CustomConstructors', []) 968 custom_constructors = [ 969 IdlOperation.constructor_from_arguments_node('CustomConstructor', 970 arguments_node) 971 for arguments_node in custom_constructor_list 972 ] 973 974 if 'NamedConstructor' in extended_attributes: 975 # FIXME: support overloaded named constructors, and make homogeneous 976 name = 'NamedConstructor' 977 call_node = extended_attributes['NamedConstructor'] 978 extended_attributes['NamedConstructor'] = call_node.GetName() 979 children = call_node.GetChildren() 980 if len(children) != 1: 981 raise ValueError('NamedConstructor node expects 1 child, got %s.' % 982 len(children)) 983 arguments_node = children[0] 984 named_constructor = IdlOperation.constructor_from_arguments_node( 985 'NamedConstructor', arguments_node) 986 # FIXME: should return named_constructor separately; appended for Perl 987 constructors.append(named_constructor) 988 989 return constructors, custom_constructors 990 991 992class ConstructorOperation(object): 993 """Represents a constructor operation. This is a tentative object used to 994 create constructors in IdlInterface. 995 """ 996 997 def __init__(self, constructor, extended_attributes, is_custom): 998 self.constructor = constructor 999 self.extended_attributes = extended_attributes 1000 self.is_custom = is_custom 1001 1002 1003def constructor_operation_from_node(node): 1004 """Creates a ConstructorOperation from the given |node|. 1005 """ 1006 1007 arguments_node = None 1008 extended_attributes = {} 1009 1010 for child in node.GetChildren(): 1011 child_class = child.GetClass() 1012 if child_class == 'Arguments': 1013 arguments_node = child 1014 elif child_class == 'ExtAttributes': 1015 extended_attributes = ext_attributes_node_to_extended_attributes( 1016 child) 1017 else: 1018 raise ValueError('Unrecognized node class: %s' % child_class) 1019 1020 if not arguments_node: 1021 raise ValueError('Expected Arguments node for constructor operation') 1022 1023 if 'Custom' in extended_attributes: 1024 if extended_attributes['Custom']: 1025 raise ValueError('[Custom] should not have a value on constructor ' 1026 'operations') 1027 del extended_attributes['Custom'] 1028 constructor = IdlOperation.constructor_from_arguments_node( 1029 'CustomConstructor', arguments_node) 1030 return ConstructorOperation( 1031 constructor, extended_attributes, is_custom=True) 1032 else: 1033 constructor = IdlOperation.constructor_from_arguments_node( 1034 'Constructor', arguments_node) 1035 return ConstructorOperation( 1036 constructor, extended_attributes, is_custom=False) 1037 1038 1039def check_constructor_operations_extended_attributes(current_attrs, new_attrs): 1040 """Raises a ValueError if two extended attribute lists have different values 1041 of constructor related attributes. 1042 """ 1043 1044 attrs_to_check = ['CallWith', 'RaisesException'] 1045 for attr in attrs_to_check: 1046 if current_attrs.get(attr) != new_attrs.get(attr): 1047 raise ValueError('[{}] should have the same value on all ' 1048 'constructor operations'.format(attr)) 1049 1050 1051def convert_constructor_operations_extended_attributes(extended_attributes): 1052 """Converts extended attributes specified on constructor operations to 1053 extended attributes for an interface definition (e.g. [ConstructorCallWith]) 1054 """ 1055 1056 converted = {} 1057 for name, value in extended_attributes.items(): 1058 if name == "CallWith": 1059 converted["ConstructorCallWith"] = value 1060 elif name == "RaisesException": 1061 if value: 1062 raise ValueError( 1063 '[RaisesException] should not have a value on ' 1064 'constructor operations') 1065 converted["RaisesException"] = 'Constructor' 1066 elif name == "MeasureAs": 1067 converted["MeasureAs"] = value 1068 elif name == "Measure": 1069 converted["Measure"] = None 1070 else: 1071 raise ValueError( 1072 '[{}] is not supported on constructor operations'.format(name)) 1073 1074 return converted 1075 1076 1077def clear_constructor_attributes(extended_attributes): 1078 # Deletes Constructor*s* (plural), sets Constructor (singular) 1079 if 'Constructors' in extended_attributes: 1080 del extended_attributes['Constructors'] 1081 extended_attributes['Constructor'] = None 1082 if 'CustomConstructors' in extended_attributes: 1083 del extended_attributes['CustomConstructors'] 1084 extended_attributes['CustomConstructor'] = None 1085 1086 1087################################################################################ 1088# Types 1089################################################################################ 1090 1091 1092def type_node_to_type(node): 1093 children = node.GetChildren() 1094 if len(children) != 1 and len(children) != 2: 1095 raise ValueError( 1096 'Type node expects 1 or 2 child(ren), got %d.' % len(children)) 1097 1098 base_type = type_node_inner_to_type(children[0]) 1099 if len(children) == 2: 1100 extended_attributes = ext_attributes_node_to_extended_attributes( 1101 children[1]) 1102 base_type = IdlAnnotatedType(base_type, extended_attributes) 1103 1104 if node.GetProperty('NULLABLE'): 1105 base_type = IdlNullableType(base_type) 1106 1107 return base_type 1108 1109 1110def type_node_inner_to_type(node): 1111 node_class = node.GetClass() 1112 # Note Type*r*ef, not Typedef, meaning the type is an identifier, thus 1113 # either a typedef shorthand (but not a Typedef declaration itself) or an 1114 # interface type. We do not distinguish these, and just use the type name. 1115 if node_class in ['PrimitiveType', 'StringType', 'Typeref']: 1116 # unrestricted syntax: unrestricted double | unrestricted float 1117 is_unrestricted = bool(node.GetProperty('UNRESTRICTED')) 1118 return IdlType(node.GetName(), is_unrestricted=is_unrestricted) 1119 elif node_class == 'Any': 1120 return IdlType('any') 1121 elif node_class in ['Sequence', 'FrozenArray']: 1122 return sequence_node_to_type(node) 1123 elif node_class == 'UnionType': 1124 return union_type_node_to_idl_union_type(node) 1125 elif node_class == 'Promise': 1126 return IdlType('Promise') 1127 elif node_class == 'Record': 1128 return record_node_to_type(node) 1129 raise ValueError('Unrecognized node class: %s' % node_class) 1130 1131 1132def record_node_to_type(node): 1133 children = node.GetChildren() 1134 if len(children) != 2: 1135 raise ValueError('record<K,V> node expects exactly 2 children, got %d' 1136 % (len(children))) 1137 key_child = children[0] 1138 value_child = children[1] 1139 if key_child.GetClass() != 'StringType': 1140 raise ValueError('Keys in record<K,V> nodes must be string types.') 1141 if value_child.GetClass() != 'Type': 1142 raise ValueError('Unrecognized node class for record<K,V> value: %s' % 1143 value_child.GetClass()) 1144 return IdlRecordType( 1145 IdlType(key_child.GetName()), type_node_to_type(value_child)) 1146 1147 1148def sequence_node_to_type(node): 1149 children = node.GetChildren() 1150 class_name = node.GetClass() 1151 if len(children) != 1: 1152 raise ValueError('%s node expects exactly 1 child, got %s' % 1153 (class_name, len(children))) 1154 sequence_child = children[0] 1155 sequence_child_class = sequence_child.GetClass() 1156 if sequence_child_class != 'Type': 1157 raise ValueError('Unrecognized node class: %s' % sequence_child_class) 1158 element_type = type_node_to_type(sequence_child) 1159 if class_name == 'Sequence': 1160 sequence_type = IdlSequenceType(element_type) 1161 elif class_name == 'FrozenArray': 1162 sequence_type = IdlFrozenArrayType(element_type) 1163 else: 1164 raise ValueError('Unexpected node: %s' % class_name) 1165 if node.GetProperty('NULLABLE'): 1166 return IdlNullableType(sequence_type) 1167 return sequence_type 1168 1169 1170def typedef_node_to_type(node): 1171 children = node.GetChildren() 1172 if len(children) != 1: 1173 raise ValueError( 1174 'Typedef node with %s children, expected 1' % len(children)) 1175 child = children[0] 1176 child_class = child.GetClass() 1177 if child_class != 'Type': 1178 raise ValueError('Unrecognized node class: %s' % child_class) 1179 return type_node_to_type(child) 1180 1181 1182def union_type_node_to_idl_union_type(node): 1183 member_types = [ 1184 type_node_to_type(member_type_node) 1185 for member_type_node in node.GetChildren() 1186 ] 1187 return IdlUnionType(member_types) 1188 1189 1190################################################################################ 1191# Visitor 1192################################################################################ 1193 1194 1195class Visitor(object): 1196 """Abstract visitor class for IDL definitions traverse.""" 1197 1198 def visit_definitions(self, definitions): 1199 pass 1200 1201 def visit_typed_object(self, typed_object): 1202 pass 1203 1204 def visit_callback_function(self, callback_function): 1205 self.visit_typed_object(callback_function) 1206 1207 def visit_dictionary(self, dictionary): 1208 pass 1209 1210 def visit_dictionary_member(self, member): 1211 self.visit_typed_object(member) 1212 1213 def visit_enumeration(self, enumeration): 1214 pass 1215 1216 def visit_include(self, include): 1217 pass 1218 1219 def visit_interface(self, interface): 1220 pass 1221 1222 def visit_typedef(self, typedef): 1223 self.visit_typed_object(typedef) 1224 1225 def visit_attribute(self, attribute): 1226 self.visit_typed_object(attribute) 1227 1228 def visit_constant(self, constant): 1229 self.visit_typed_object(constant) 1230 1231 def visit_operation(self, operation): 1232 self.visit_typed_object(operation) 1233 1234 def visit_argument(self, argument): 1235 self.visit_typed_object(argument) 1236 1237 def visit_iterable(self, iterable): 1238 self.visit_typed_object(iterable) 1239 1240 def visit_maplike(self, maplike): 1241 self.visit_typed_object(maplike) 1242 1243 def visit_setlike(self, setlike): 1244 self.visit_typed_object(setlike) 1245