WebIDL.py (335448B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 """ A WebIDL parser. """ 6 7 import copy 8 import math 9 import os 10 import re 11 import string 12 import traceback 13 from collections import OrderedDict, defaultdict 14 from itertools import chain 15 16 from ply import lex, yacc 17 18 # Machinery 19 20 21 def parseInt(literal): 22 string = literal 23 sign = 0 24 base = 0 25 26 if string[0] == "-": 27 sign = -1 28 string = string[1:] 29 else: 30 sign = 1 31 32 if string[0] == "0" and len(string) > 1: 33 if string[1] == "x" or string[1] == "X": 34 base = 16 35 string = string[2:] 36 else: 37 base = 8 38 string = string[1:] 39 else: 40 base = 10 41 42 value = int(string, base) 43 return value * sign 44 45 46 # This is surprisingly faster than using the enum.IntEnum type (which doesn't 47 # support 'base' anyway) 48 def enum(*names, base=None): 49 if base is not None: 50 names = base.attrs + names 51 52 class CustomEnumType(object): 53 attrs = names 54 55 def __setattr__(self, name, value): # this makes it read-only 56 raise NotImplementedError 57 58 for v, k in enumerate(names): 59 setattr(CustomEnumType, k, v) 60 61 return CustomEnumType() 62 63 64 class WebIDLError(Exception): 65 def __init__(self, message, locations, warning=False): 66 self.message = message 67 self.locations = [str(loc) for loc in locations] 68 self.warning = warning 69 70 def __str__(self): 71 return "%s: %s%s%s" % ( 72 self.warning and "warning" or "error", 73 self.message, 74 ", " if len(self.locations) != 0 else "", 75 "\n".join(self.locations), 76 ) 77 78 79 class Location(object): 80 def __init__(self, lexer, lineno, lexpos, filename): 81 self._line = None 82 self._lineno = lineno 83 self._lexpos = lexpos 84 self._lexdata = lexer.lexdata 85 self.filename = filename if filename else "<unknown>" 86 87 def __eq__(self, other): 88 return self._lexpos == other._lexpos and self.filename == other.filename 89 90 def resolve(self): 91 if self._line: 92 return 93 94 startofline = self._lexdata.rfind("\n", 0, self._lexpos) + 1 95 endofline = self._lexdata.find("\n", self._lexpos, self._lexpos + 80) 96 if endofline != -1: 97 self._line = self._lexdata[startofline:endofline] 98 else: 99 self._line = self._lexdata[startofline:] 100 self._colno = self._lexpos - startofline 101 102 # Our line number seems to point to the start of self._lexdata 103 self._lineno += self._lexdata.count("\n", 0, startofline) 104 105 def get(self): 106 self.resolve() 107 return "%s line %s:%s" % (self.filename, self._lineno, self._colno) 108 109 def _pointerline(self): 110 return " " * self._colno + "^" 111 112 def __str__(self): 113 self.resolve() 114 return "%s line %s:%s\n%s\n%s" % ( 115 self.filename, 116 self._lineno, 117 self._colno, 118 self._line, 119 self._pointerline(), 120 ) 121 122 123 class BuiltinLocation(object): 124 __slots__ = "msg", "filename" 125 126 def __init__(self, text): 127 self.msg = text + "\n" 128 self.filename = "<builtin>" 129 130 def __eq__(self, other): 131 return isinstance(other, BuiltinLocation) and self.msg == other.msg 132 133 def resolve(self): 134 pass 135 136 def get(self): 137 return self.msg 138 139 def __str__(self): 140 return self.get() 141 142 143 # Data Model 144 145 146 class IDLObject(object): 147 __slots__ = "location", "userData", "filename" 148 149 def __init__(self, location): 150 self.location = location 151 self.userData = {} 152 self.filename = location and location.filename 153 154 def isInterface(self): 155 return False 156 157 def isNamespace(self): 158 return False 159 160 def isInterfaceMixin(self): 161 return False 162 163 def isEnum(self): 164 return False 165 166 def isCallback(self): 167 return False 168 169 def isType(self): 170 return False 171 172 def isDictionary(self): 173 return False 174 175 def isUnion(self): 176 return False 177 178 def isTypedef(self): 179 return False 180 181 def getUserData(self, key, default): 182 return self.userData.get(key, default) 183 184 def setUserData(self, key, value): 185 self.userData[key] = value 186 187 def addExtendedAttributes(self, attrs): 188 assert False # Override me! 189 190 def handleExtendedAttribute(self, attr): 191 assert False # Override me! 192 193 def _getDependentObjects(self): 194 assert False # Override me! 195 196 def getDeps(self, visited=None): 197 """Return a set of files that this object depends on. If any of 198 these files are changed the parser needs to be rerun to regenerate 199 a new IDLObject. 200 201 The visited argument is a set of all the objects already visited. 202 We must test to see if we are in it, and if so, do nothing. This 203 prevents infinite recursion.""" 204 205 # NB: We can't use visited=set() above because the default value is 206 # evaluated when the def statement is evaluated, not when the function 207 # is executed, so there would be one set for all invocations. 208 if visited is None: 209 visited = set() 210 211 if self in visited: 212 return set() 213 214 visited.add(self) 215 216 deps = set() 217 if self.filename != "<builtin>": 218 deps.add(self.filename) 219 220 for d in self._getDependentObjects(): 221 deps.update(d.getDeps(visited)) 222 223 return deps 224 225 226 class IDLScope(IDLObject): 227 __slots__ = "parentScope", "_name", "_dict", "globalNames", "globalNameMapping" 228 229 def __init__(self, location, parentScope, identifier): 230 IDLObject.__init__(self, location) 231 232 self.parentScope = parentScope 233 if identifier: 234 assert isinstance(identifier, IDLIdentifier) 235 self._name = identifier 236 else: 237 self._name = None 238 239 self._dict = {} 240 self.globalNames = set() 241 # A mapping from global name to the set of global interfaces 242 # that have that global name. 243 self.globalNameMapping = defaultdict(set) 244 245 def __str__(self): 246 return self.QName() 247 248 def QName(self): 249 # It's possible for us to be called before __init__ has been called, for 250 # the IDLObjectWithScope case. In that case, self._name won't be set yet. 251 if hasattr(self, "_name"): 252 name = self._name 253 else: 254 name = None 255 if name: 256 return name.QName() + "::" 257 return "::" 258 259 def ensureUnique(self, identifier, object): 260 """ 261 Ensure that there is at most one 'identifier' in scope ('self'). 262 Note that object can be None. This occurs if we end up here for an 263 interface type we haven't seen yet. 264 """ 265 assert isinstance(identifier, IDLUnresolvedIdentifier) 266 assert not object or isinstance(object, IDLObjectWithIdentifier) 267 assert not object or object.identifier == identifier 268 269 if identifier.name in self._dict: 270 if not object: 271 return 272 273 # ensureUnique twice with the same object is not allowed 274 assert id(object) != id(self._dict[identifier.name]) 275 276 replacement = self.resolveIdentifierConflict( 277 self, identifier, self._dict[identifier.name], object 278 ) 279 self._dict[identifier.name] = replacement 280 return 281 282 self.addNewIdentifier(identifier, object) 283 284 def addNewIdentifier(self, identifier, object): 285 assert object 286 287 self._dict[identifier.name] = object 288 289 def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): 290 if ( 291 isinstance(originalObject, IDLExternalInterface) 292 and isinstance(newObject, IDLExternalInterface) 293 and originalObject.identifier.name == newObject.identifier.name 294 ): 295 return originalObject 296 297 if isinstance(originalObject, IDLExternalInterface) or isinstance( 298 newObject, IDLExternalInterface 299 ): 300 raise WebIDLError( 301 "Name collision between " 302 "interface declarations for identifier '%s' at '%s' and '%s'" 303 % (identifier.name, originalObject.location, newObject.location), 304 [], 305 ) 306 307 if isinstance(originalObject, IDLDictionary) or isinstance( 308 newObject, IDLDictionary 309 ): 310 raise WebIDLError( 311 "Name collision between dictionary declarations for " 312 "identifier '%s'.\n%s\n%s" 313 % (identifier.name, originalObject.location, newObject.location), 314 [], 315 ) 316 317 # We do the merging of overloads here as opposed to in IDLInterface 318 # because we need to merge overloads of LegacyFactoryFunctions and we need to 319 # detect conflicts in those across interfaces. See also the comment in 320 # IDLInterface.addExtendedAttributes for "LegacyFactoryFunction". 321 if isinstance(originalObject, IDLMethod) and isinstance(newObject, IDLMethod): 322 return originalObject.addOverload(newObject) 323 324 # Default to throwing, derived classes can override. 325 raise self.createIdentifierConflictError(identifier, originalObject, newObject) 326 327 def createIdentifierConflictError(self, identifier, originalObject, newObject): 328 conflictdesc = "\n\t%s at %s\n\t%s at %s" % ( 329 originalObject, 330 originalObject.location, 331 newObject, 332 newObject.location, 333 ) 334 335 return WebIDLError( 336 "Multiple unresolvable definitions of identifier '%s' in scope '%s'%s" 337 % (identifier.name, str(self), conflictdesc), 338 [], 339 ) 340 341 def _lookupIdentifier(self, identifier): 342 return self._dict[identifier.name] 343 344 def lookupIdentifier(self, identifier): 345 assert isinstance(identifier, IDLIdentifier) 346 assert identifier.scope == self 347 return self._lookupIdentifier(identifier) 348 349 def addIfaceGlobalNames(self, interfaceName, globalNames): 350 """Record the global names (from |globalNames|) that can be used in 351 [Exposed] to expose things in a global named |interfaceName|""" 352 self.globalNames.update(globalNames) 353 for name in globalNames: 354 self.globalNameMapping[name].add(interfaceName) 355 356 357 class IDLIdentifier(IDLObject): 358 __slots__ = "name", "scope" 359 360 def __init__(self, location, scope, name): 361 IDLObject.__init__(self, location) 362 363 self.name = name 364 assert isinstance(scope, IDLScope) 365 self.scope = scope 366 367 def __str__(self): 368 return self.QName() 369 370 def QName(self): 371 return self.scope.QName() + self.name 372 373 def __hash__(self): 374 return self.QName().__hash__() 375 376 def __eq__(self, other): 377 return self.QName() == other.QName() 378 379 def object(self): 380 return self.scope.lookupIdentifier(self) 381 382 383 class IDLUnresolvedIdentifier(IDLObject): 384 __slots__ = ("name",) 385 386 def __init__( 387 self, location, name, allowDoubleUnderscore=False, allowForbidden=False 388 ): 389 IDLObject.__init__(self, location) 390 391 assert name 392 393 if name == "__noSuchMethod__": 394 raise WebIDLError("__noSuchMethod__ is deprecated", [location]) 395 396 if name[:2] == "__" and not allowDoubleUnderscore: 397 raise WebIDLError("Identifiers beginning with __ are reserved", [location]) 398 if name[0] == "_" and not allowDoubleUnderscore: 399 name = name[1:] 400 if name in ["constructor", "toString"] and not allowForbidden: 401 raise WebIDLError( 402 "Cannot use reserved identifier '%s'" % (name), [location] 403 ) 404 405 self.name = name 406 407 def __str__(self): 408 return self.QName() 409 410 def QName(self): 411 return "<unresolved scope>::" + self.name 412 413 def resolve(self, scope, object): 414 assert isinstance(scope, IDLScope) 415 assert not object or isinstance(object, IDLObjectWithIdentifier) 416 assert not object or object.identifier == self 417 418 scope.ensureUnique(self, object) 419 420 identifier = IDLIdentifier(self.location, scope, self.name) 421 if object: 422 object.identifier = identifier 423 return identifier 424 425 def finish(self): 426 assert False # Should replace with a resolved identifier first. 427 428 429 class IDLObjectWithIdentifier(IDLObject): 430 # no slots, incompatible with multiple inheritance 431 def __init__(self, location, parentScope, identifier): 432 IDLObject.__init__(self, location) 433 434 assert isinstance(identifier, IDLUnresolvedIdentifier) 435 436 self.identifier = identifier 437 438 if parentScope: 439 self.resolve(parentScope) 440 441 def resolve(self, parentScope): 442 assert isinstance(parentScope, IDLScope) 443 assert isinstance(self.identifier, IDLUnresolvedIdentifier) 444 self.identifier.resolve(parentScope, self) 445 446 447 class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope): 448 __slots__ = () 449 450 def __init__(self, location, parentScope, identifier): 451 assert isinstance(identifier, IDLUnresolvedIdentifier) 452 453 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) 454 IDLScope.__init__(self, location, parentScope, self.identifier) 455 456 457 class IDLIdentifierPlaceholder(IDLObjectWithIdentifier): 458 __slots__ = () 459 460 def __init__(self, location, identifier): 461 assert isinstance(identifier, IDLUnresolvedIdentifier) 462 IDLObjectWithIdentifier.__init__(self, location, None, identifier) 463 464 def finish(self, scope): 465 try: 466 scope._lookupIdentifier(self.identifier) 467 except Exception: 468 raise WebIDLError( 469 "Unresolved type '%s'." % self.identifier, [self.location] 470 ) 471 472 obj = self.identifier.resolve(scope, None) 473 return scope.lookupIdentifier(obj) 474 475 476 class IDLExposureMixins: 477 # no slots, incompatible with multiple inheritance 478 def __init__(self, location): 479 # _exposureGlobalNames are the global names listed in our [Exposed] 480 # extended attribute. exposureSet is the exposure set as defined in the 481 # Web IDL spec: it contains interface names. 482 self._exposureGlobalNames = set() 483 self.exposureSet = set() 484 self._location = location 485 self._globalScope = None 486 487 def finish(self, scope): 488 assert scope.parentScope is None 489 self._globalScope = scope 490 491 if "*" in self._exposureGlobalNames: 492 self._exposureGlobalNames = scope.globalNames 493 else: 494 # Verify that our [Exposed] value, if any, makes sense. 495 for globalName in self._exposureGlobalNames: 496 if globalName not in scope.globalNames: 497 raise WebIDLError( 498 "Unknown [Exposed] value %s" % globalName, [self._location] 499 ) 500 501 # Verify that we are exposed _somwhere_ if we have some place to be 502 # exposed. We don't want to assert that we're definitely exposed 503 # because a lot of our parser tests have small-enough IDL snippets that 504 # they don't include any globals, and we don't really want to go through 505 # and add global interfaces and [Exposed] annotations to all those 506 # tests. 507 if len(scope.globalNames) != 0 and len(self._exposureGlobalNames) == 0: 508 raise WebIDLError( 509 ( 510 "'%s' is not exposed anywhere even though we have " 511 "globals to be exposed to" 512 ) 513 % self, 514 [self.location], 515 ) 516 517 globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposureSet) 518 519 def isExposedInWindow(self): 520 return "Window" in self.exposureSet 521 522 def isExposedInAnyWorker(self): 523 return len(self.getWorkerExposureSet()) > 0 524 525 def isExposedInWorkerDebugger(self): 526 return len(self.getWorkerDebuggerExposureSet()) > 0 527 528 def isExposedInAnyWorklet(self): 529 return len(self.getWorkletExposureSet()) > 0 530 531 def isExposedInSomeButNotAllWorkers(self): 532 """ 533 Returns true if the Exposed extended attribute for this interface 534 exposes it in some worker globals but not others. The return value does 535 not depend on whether the interface is exposed in Window or System 536 globals. 537 """ 538 if not self.isExposedInAnyWorker(): 539 return False 540 workerScopes = self.parentScope.globalNameMapping["Worker"] 541 return len(workerScopes.difference(self.exposureSet)) > 0 542 543 def isExposedInShadowRealms(self): 544 return "ShadowRealmGlobalScope" in self.exposureSet 545 546 def getWorkerExposureSet(self): 547 workerScopes = self._globalScope.globalNameMapping["Worker"] 548 return workerScopes.intersection(self.exposureSet) 549 550 def getWorkletExposureSet(self): 551 workletScopes = self._globalScope.globalNameMapping["Worklet"] 552 return workletScopes.intersection(self.exposureSet) 553 554 def getWorkerDebuggerExposureSet(self): 555 workerDebuggerScopes = self._globalScope.globalNameMapping["WorkerDebugger"] 556 return workerDebuggerScopes.intersection(self.exposureSet) 557 558 559 class IDLExternalInterface(IDLObjectWithIdentifier): 560 __slots__ = ("parent",) 561 562 def __init__(self, location, parentScope, identifier): 563 assert isinstance(identifier, IDLUnresolvedIdentifier) 564 assert isinstance(parentScope, IDLScope) 565 self.parent = None 566 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) 567 IDLObjectWithIdentifier.resolve(self, parentScope) 568 569 def finish(self, scope): 570 pass 571 572 def validate(self): 573 pass 574 575 def isIteratorInterface(self): 576 return False 577 578 def isAsyncIteratorInterface(self): 579 return False 580 581 def isExternal(self): 582 return True 583 584 def isInterface(self): 585 return True 586 587 def addExtendedAttributes(self, attrs): 588 if len(attrs) != 0: 589 raise WebIDLError( 590 "There are no extended attributes that are " 591 "allowed on external interfaces", 592 [attrs[0].location, self.location], 593 ) 594 595 def resolve(self, parentScope): 596 pass 597 598 def getJSImplementation(self): 599 return None 600 601 def isJSImplemented(self): 602 return False 603 604 def hasProbablyShortLivingWrapper(self): 605 return False 606 607 def _getDependentObjects(self): 608 return set() 609 610 611 class IDLPartialDictionary(IDLObject): 612 __slots__ = "identifier", "members", "_nonPartialDictionary", "_finished" 613 614 def __init__(self, location, name, members, nonPartialDictionary): 615 assert isinstance(name, IDLUnresolvedIdentifier) 616 617 IDLObject.__init__(self, location) 618 self.identifier = name 619 self.members = members 620 self._nonPartialDictionary = nonPartialDictionary 621 self._finished = False 622 nonPartialDictionary.addPartialDictionary(self) 623 624 def addExtendedAttributes(self, attrs): 625 pass 626 627 def finish(self, scope): 628 if self._finished: 629 return 630 self._finished = True 631 632 # Need to make sure our non-partial dictionary gets 633 # finished so it can report cases when we only have partial 634 # dictionaries. 635 self._nonPartialDictionary.finish(scope) 636 637 def validate(self): 638 pass 639 640 641 class IDLPartialInterfaceOrNamespace(IDLObject): 642 __slots__ = ( 643 "identifier", 644 "members", 645 "propagatedExtendedAttrs", 646 "_haveSecureContextExtendedAttribute", 647 "_nonPartialInterfaceOrNamespace", 648 "_finished", 649 ) 650 651 def __init__(self, location, name, members, nonPartialInterfaceOrNamespace): 652 assert isinstance(name, IDLUnresolvedIdentifier) 653 654 IDLObject.__init__(self, location) 655 self.identifier = name 656 self.members = members 657 # propagatedExtendedAttrs are the ones that should get 658 # propagated to our non-partial interface. 659 self.propagatedExtendedAttrs = [] 660 self._haveSecureContextExtendedAttribute = False 661 self._nonPartialInterfaceOrNamespace = nonPartialInterfaceOrNamespace 662 self._finished = False 663 nonPartialInterfaceOrNamespace.addPartial(self) 664 665 def addExtendedAttributes(self, attrs): 666 for attr in attrs: 667 identifier = attr.identifier() 668 669 if identifier == "LegacyFactoryFunction": 670 self.propagatedExtendedAttrs.append(attr) 671 elif identifier == "SecureContext": 672 self._haveSecureContextExtendedAttribute = True 673 # This gets propagated to all our members. 674 for member in self.members: 675 if member.getExtendedAttribute("SecureContext"): 676 typeName = self._nonPartialInterfaceOrNamespace.typeName() 677 raise WebIDLError( 678 "[SecureContext] specified on both a partial %s member " 679 "and on the partial %s itself" % (typeName, typeName), 680 [member.location, attr.location], 681 ) 682 member.addExtendedAttributes([attr]) 683 elif identifier == "Exposed": 684 # This just gets propagated to all our members. 685 for member in self.members: 686 if len(member._exposureGlobalNames) != 0: 687 typeName = self._nonPartialInterfaceOrNamespace.typeName() 688 raise WebIDLError( 689 "[Exposed] specified on both a partial %s member and " 690 "on the partial %s itself" % (typeName, typeName), 691 [member.location, attr.location], 692 ) 693 member.addExtendedAttributes([attr]) 694 else: 695 raise WebIDLError( 696 "Unknown extended attribute %s on partial %s" 697 % (identifier, self._nonPartialInterfaceOrNamespace.typeName()), 698 [attr.location], 699 ) 700 701 def finish(self, scope): 702 if self._finished: 703 return 704 self._finished = True 705 if ( 706 not self._haveSecureContextExtendedAttribute 707 and self._nonPartialInterfaceOrNamespace.getExtendedAttribute( 708 "SecureContext" 709 ) 710 ): 711 # This gets propagated to all our members. 712 for member in self.members: 713 if member.getExtendedAttribute("SecureContext"): 714 raise WebIDLError( 715 "[SecureContext] specified on both a " 716 "partial interface member and on the " 717 "non-partial interface", 718 [ 719 member.location, 720 self._nonPartialInterfaceOrNamespace.location, 721 ], 722 ) 723 member.addExtendedAttributes( 724 [ 725 IDLExtendedAttribute( 726 self._nonPartialInterfaceOrNamespace.location, 727 ("SecureContext",), 728 ) 729 ] 730 ) 731 # Need to make sure our non-partial interface or namespace gets 732 # finished so it can report cases when we only have partial 733 # interfaces/namespaces. 734 self._nonPartialInterfaceOrNamespace.finish(scope) 735 736 def validate(self): 737 pass 738 739 740 def convertExposedAttrToGlobalNameSet(exposedAttr, targetSet): 741 assert len(targetSet) == 0 742 if exposedAttr.hasValue(): 743 targetSet.add(exposedAttr.value()) 744 else: 745 assert exposedAttr.hasArgs() 746 targetSet.update(exposedAttr.args()) 747 748 749 def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): 750 for name in nameSet: 751 exposureSet.update(globalScope.globalNameMapping[name]) 752 753 754 # Because WebIDL allows static and regular operations with the same identifier 755 # we use a special class to be able to store them both in the scope for the 756 # same identifier. 757 class IDLOperations: 758 __slots__ = "static", "regular" 759 760 def __init__(self, static=None, regular=None): 761 self.static = static 762 self.regular = regular 763 764 765 class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins): 766 __slots__ = ( 767 "_finished", 768 "members", 769 "_partials", 770 "_extendedAttrDict", 771 "_isKnownNonPartial", 772 ) 773 774 def __init__(self, location, parentScope, name): 775 assert isinstance(parentScope, IDLScope) 776 assert isinstance(name, IDLUnresolvedIdentifier) 777 778 self._finished = False 779 self.members = [] 780 self._partials = [] 781 self._extendedAttrDict = {} 782 self._isKnownNonPartial = False 783 784 IDLObjectWithScope.__init__(self, location, parentScope, name) 785 IDLExposureMixins.__init__(self, location) 786 787 def finish(self, scope): 788 if not self._isKnownNonPartial: 789 raise WebIDLError( 790 "%s does not have a non-partial declaration" % str(self), 791 [self.location], 792 ) 793 794 IDLExposureMixins.finish(self, scope) 795 796 # Now go ahead and merge in our partials. 797 for partial in self._partials: 798 partial.finish(scope) 799 self.addExtendedAttributes(partial.propagatedExtendedAttrs) 800 self.members.extend(partial.members) 801 802 def addNewIdentifier(self, identifier, object): 803 if isinstance(object, IDLMethod): 804 if object.isStatic(): 805 object = IDLOperations(static=object) 806 else: 807 object = IDLOperations(regular=object) 808 809 IDLScope.addNewIdentifier(self, identifier, object) 810 811 def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): 812 assert isinstance(scope, IDLScope) 813 assert isinstance(newObject, IDLInterfaceMember) 814 815 # The identifier of a regular operation or static operation must not be 816 # the same as the identifier of a constant or attribute. 817 if isinstance(newObject, IDLMethod) != isinstance( 818 originalObject, IDLOperations 819 ): 820 if isinstance(originalObject, IDLOperations): 821 if originalObject.regular is not None: 822 originalObject = originalObject.regular 823 else: 824 assert originalObject.static is not None 825 originalObject = originalObject.static 826 827 raise self.createIdentifierConflictError( 828 identifier, originalObject, newObject 829 ) 830 831 if isinstance(newObject, IDLMethod): 832 originalOperations = originalObject 833 if newObject.isStatic(): 834 if originalOperations.static is None: 835 originalOperations.static = newObject 836 return originalOperations 837 838 originalObject = originalOperations.static 839 else: 840 if originalOperations.regular is None: 841 originalOperations.regular = newObject 842 return originalOperations 843 844 originalObject = originalOperations.regular 845 846 assert isinstance(originalObject, IDLMethod) 847 else: 848 assert isinstance(originalObject, IDLInterfaceMember) 849 850 retval = IDLScope.resolveIdentifierConflict( 851 self, scope, identifier, originalObject, newObject 852 ) 853 854 if isinstance(newObject, IDLMethod): 855 if newObject.isStatic(): 856 originalOperations.static = retval 857 else: 858 originalOperations.regular = retval 859 860 retval = originalOperations 861 862 # Might be a ctor, which isn't in self.members 863 if newObject in self.members: 864 self.members.remove(newObject) 865 return retval 866 867 def typeName(self): 868 if self.isInterface(): 869 return "interface" 870 if self.isNamespace(): 871 return "namespace" 872 assert self.isInterfaceMixin() 873 return "interface mixin" 874 875 def addExtendedAttributes(self, attrs): 876 for attr in attrs: 877 self.handleExtendedAttribute(attr) 878 attrlist = attr.listValue() 879 self._extendedAttrDict[attr.identifier()] = ( 880 attrlist if len(attrlist) else True 881 ) 882 883 def handleExtendedAttribute(self, attr): 884 identifier = attr.identifier() 885 if identifier == "Exposed": 886 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) 887 elif identifier == "SecureContext": 888 if not attr.noArguments(): 889 raise WebIDLError( 890 "[SecureContext] must take no arguments", [attr.location] 891 ) 892 # This gets propagated to all our members. 893 for member in self.members: 894 if member.getExtendedAttribute("SecureContext"): 895 typeName = self.typeName() 896 raise WebIDLError( 897 "[SecureContext] specified on both an %s member and on " 898 "%s itself" % (typeName, typeName), 899 [member.location, attr.location], 900 ) 901 member.addExtendedAttributes([attr]) 902 else: 903 raise WebIDLError( 904 "Unknown extended attribute %s on %s" % (identifier, self.typeName()), 905 [attr.location], 906 ) 907 908 def getExtendedAttribute(self, name): 909 return self._extendedAttrDict.get(name, None) 910 911 def setNonPartial(self, location, members): 912 if self._isKnownNonPartial: 913 raise WebIDLError( 914 "Two non-partial definitions for the same %s" % self.typeName(), 915 [location, self.location], 916 ) 917 self._isKnownNonPartial = True 918 # Now make it look like we were parsed at this new location, since 919 # that's the place where the interface is "really" defined 920 self.location = location 921 # Put the new members at the beginning 922 self.members = members + self.members 923 924 def addPartial(self, partial): 925 assert self.identifier.name == partial.identifier.name 926 self._partials.append(partial) 927 928 def getPartials(self): 929 # Don't let people mutate our guts. 930 return list(self._partials) 931 932 def finishMembers(self, scope): 933 # Assuming we've merged in our partials, set the _exposureGlobalNames on 934 # any members that don't have it set yet. Note that any partial 935 # interfaces that had [Exposed] set have already set up 936 # _exposureGlobalNames on all the members coming from them, so this is 937 # just implementing the "members default to interface or interface mixin 938 # that defined them" and "partial interfaces or interface mixins default 939 # to interface or interface mixin they're a partial for" rules from the 940 # spec. 941 for m in self.members: 942 # If m, or the partial m came from, had [Exposed] 943 # specified, it already has a nonempty exposure global names set. 944 if len(m._exposureGlobalNames) == 0: 945 m._exposureGlobalNames.update(self._exposureGlobalNames) 946 if m.isAttr() and m.stringifier: 947 m.expand(self.members) 948 949 # resolve() will modify self.members, so we need to iterate 950 # over a copy of the member list here. 951 for member in list(self.members): 952 member.resolve(self) 953 954 for member in self.members: 955 member.finish(scope) 956 957 # Now that we've finished our members, which has updated their exposure 958 # sets, make sure they aren't exposed in places where we are not. 959 for member in self.members: 960 if not member.exposureSet.issubset(self.exposureSet): 961 raise WebIDLError( 962 "Interface or interface mixin member has " 963 "larger exposure set than its container", 964 [member.location, self.location], 965 ) 966 967 def isExternal(self): 968 return False 969 970 971 class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): 972 __slots__ = ("actualExposureGlobalNames",) 973 974 def __init__(self, location, parentScope, name, members, isKnownNonPartial): 975 self.actualExposureGlobalNames = set() 976 977 assert isKnownNonPartial or not members 978 IDLInterfaceOrInterfaceMixinOrNamespace.__init__( 979 self, location, parentScope, name 980 ) 981 982 if isKnownNonPartial: 983 self.setNonPartial(location, members) 984 985 def __str__(self): 986 return "Interface mixin '%s'" % self.identifier.name 987 988 def isInterfaceMixin(self): 989 return True 990 991 def finish(self, scope): 992 if self._finished: 993 return 994 self._finished = True 995 996 # Expose to the globals of interfaces that includes this mixin if this 997 # mixin has no explicit [Exposed] so that its members can be exposed 998 # based on the base interface exposure set. 999 # 1000 # Make sure this is done before IDLExposureMixins.finish call, since 1001 # that converts our set of exposure global names to an actual exposure 1002 # set. 1003 hasImplicitExposure = len(self._exposureGlobalNames) == 0 1004 if hasImplicitExposure: 1005 self._exposureGlobalNames.update(self.actualExposureGlobalNames) 1006 1007 IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope) 1008 1009 self.finishMembers(scope) 1010 1011 def validate(self): 1012 for member in self.members: 1013 if member.isAttr(): 1014 if member.inherit: 1015 raise WebIDLError( 1016 "Interface mixin member cannot include " 1017 "an inherited attribute", 1018 [member.location, self.location], 1019 ) 1020 if member.isStatic(): 1021 raise WebIDLError( 1022 "Interface mixin member cannot include a static member", 1023 [member.location, self.location], 1024 ) 1025 1026 if member.isMethod(): 1027 if member.isStatic(): 1028 raise WebIDLError( 1029 "Interface mixin member cannot include a static operation", 1030 [member.location, self.location], 1031 ) 1032 if ( 1033 member.isGetter() 1034 or member.isSetter() 1035 or member.isDeleter() 1036 or member.isLegacycaller() 1037 ): 1038 raise WebIDLError( 1039 "Interface mixin member cannot include a special operation", 1040 [member.location, self.location], 1041 ) 1042 1043 def _getDependentObjects(self): 1044 return set(self.members) 1045 1046 1047 class ReflectedHTMLAttributesReturningFrozenArray(object): 1048 __slots__ = ( 1049 "slotIndex", 1050 "totalMembersInSlots", 1051 ) 1052 1053 def __init__(self, slotIndex): 1054 self.slotIndex = slotIndex 1055 self.totalMembersInSlots = 0 1056 1057 1058 class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): 1059 __slots__ = ( 1060 "parent", 1061 "_callback", 1062 "maplikeOrSetlikeOrIterable", 1063 "legacyFactoryFunctions", 1064 "legacyWindowAliases", 1065 "includedMixins", 1066 "interfacesBasedOnSelf", 1067 "_hasChildInterfaces", 1068 "_isOnGlobalProtoChain", 1069 "totalMembersInSlots", 1070 "_ownMembersInSlots", 1071 "reflectedHTMLAttributesReturningFrozenArray", 1072 "iterableInterface", 1073 "asyncIterableInterface", 1074 "hasCrossOriginMembers", 1075 "hasDescendantWithCrossOriginMembers", 1076 ) 1077 1078 def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial): 1079 assert isKnownNonPartial or not parent 1080 assert isKnownNonPartial or not members 1081 1082 self.parent = None 1083 self._callback = False 1084 self.maplikeOrSetlikeOrIterable = None 1085 # legacyFactoryFunctions needs deterministic ordering because bindings code 1086 # outputs the constructs in the order that legacyFactoryFunctions enumerates 1087 # them. 1088 self.legacyFactoryFunctions = [] 1089 self.legacyWindowAliases = [] 1090 self.includedMixins = set() 1091 # self.interfacesBasedOnSelf is the set of interfaces that inherit from 1092 # self, including self itself. 1093 # Used for distinguishability checking. 1094 self.interfacesBasedOnSelf = {self} 1095 self._hasChildInterfaces = False 1096 self._isOnGlobalProtoChain = False 1097 1098 # Tracking of the number of reserved slots we need for our members and 1099 # those of ancestor interfaces. Note that reflected HTML attributes that 1100 # have a FrozenArray<Element> return value also need to be stored in 1101 # slots. Because we don't want to use a lot of memory to store them when 1102 # they are not in use we use two levels of storage, the slot points to 1103 # an array of slots, so these have two indices. These attributes share 1104 # 1 slot in totalMembersInSlots, and count for 1 slot each in 1105 # reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots. 1106 self.totalMembersInSlots = 0 1107 # Tracking of the number of own own members we have in slots 1108 self._ownMembersInSlots = 0 1109 # Tracking the slot in the binding object for reflected HTML attributes 1110 # that return a FrozenArray, and the slot in the array stored in that 1111 # slot in the binding object. 1112 self.reflectedHTMLAttributesReturningFrozenArray = None 1113 # If this is an iterator interface, we need to know what iterable 1114 # interface we're iterating for in order to get its nativeType. 1115 self.iterableInterface = None 1116 self.asyncIterableInterface = None 1117 # True if we have cross-origin members. 1118 self.hasCrossOriginMembers = False 1119 # True if some descendant (including ourselves) has cross-origin members 1120 self.hasDescendantWithCrossOriginMembers = False 1121 1122 IDLInterfaceOrInterfaceMixinOrNamespace.__init__( 1123 self, location, parentScope, name 1124 ) 1125 1126 if isKnownNonPartial: 1127 self.setNonPartial(location, parent, members) 1128 1129 def ctor(self): 1130 identifier = IDLUnresolvedIdentifier( 1131 self.location, "constructor", allowForbidden=True 1132 ) 1133 try: 1134 return self._lookupIdentifier(identifier).static 1135 except Exception: 1136 return None 1137 1138 def isIterable(self): 1139 return ( 1140 self.maplikeOrSetlikeOrIterable 1141 and self.maplikeOrSetlikeOrIterable.isIterable() 1142 ) 1143 1144 def isAsyncIterable(self): 1145 return ( 1146 self.maplikeOrSetlikeOrIterable 1147 and self.maplikeOrSetlikeOrIterable.isAsyncIterable() 1148 ) 1149 1150 def isIteratorInterface(self): 1151 return self.iterableInterface is not None 1152 1153 def isAsyncIteratorInterface(self): 1154 return self.asyncIterableInterface is not None 1155 1156 def getClassName(self): 1157 return self.identifier.name 1158 1159 def finish(self, scope): 1160 if self._finished: 1161 return 1162 1163 self._finished = True 1164 1165 IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope) 1166 1167 if len(self.legacyWindowAliases) > 0: 1168 if not self.hasInterfaceObject(): 1169 raise WebIDLError( 1170 "Interface %s unexpectedly has [LegacyWindowAlias] " 1171 "and [LegacyNoInterfaceObject] together" % self.identifier.name, 1172 [self.location], 1173 ) 1174 if not self.isExposedInWindow(): 1175 raise WebIDLError( 1176 "Interface %s has [LegacyWindowAlias] " 1177 "but not exposed in Window" % self.identifier.name, 1178 [self.location], 1179 ) 1180 1181 # Generate maplike/setlike interface members. Since generated members 1182 # need to be treated like regular interface members, do this before 1183 # things like exposure setting. 1184 for member in self.members: 1185 if member.isMaplikeOrSetlikeOrIterable(): 1186 if self.isJSImplemented(): 1187 raise WebIDLError( 1188 "%s declaration used on " 1189 "interface that is implemented in JS" 1190 % (member.maplikeOrSetlikeOrIterableType), 1191 [member.location], 1192 ) 1193 if member.valueType.isObservableArray() or ( 1194 member.hasKeyType() and member.keyType.isObservableArray() 1195 ): 1196 raise WebIDLError( 1197 "%s declaration uses ObservableArray as value or key type" 1198 % (member.maplikeOrSetlikeOrIterableType), 1199 [member.location], 1200 ) 1201 # Check that we only have one interface declaration (currently 1202 # there can only be one maplike/setlike declaration per 1203 # interface) 1204 if self.maplikeOrSetlikeOrIterable: 1205 raise WebIDLError( 1206 "%s declaration used on " 1207 "interface that already has %s " 1208 "declaration" 1209 % ( 1210 member.maplikeOrSetlikeOrIterableType, 1211 self.maplikeOrSetlikeOrIterable.maplikeOrSetlikeOrIterableType, 1212 ), 1213 [self.maplikeOrSetlikeOrIterable.location, member.location], 1214 ) 1215 self.maplikeOrSetlikeOrIterable = member 1216 # If we've got a maplike or setlike declaration, we'll be building all of 1217 # our required methods in Codegen. Generate members now. 1218 self.maplikeOrSetlikeOrIterable.expand(self.members) 1219 1220 assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder) 1221 parent = self.parent.finish(scope) if self.parent else None 1222 if parent and isinstance(parent, IDLExternalInterface): 1223 raise WebIDLError( 1224 "%s inherits from %s which does not have " 1225 "a definition" % (self.identifier.name, self.parent.identifier.name), 1226 [self.location], 1227 ) 1228 if parent and not isinstance(parent, IDLInterface): 1229 raise WebIDLError( 1230 "%s inherits from %s which is not an interface " 1231 % (self.identifier.name, self.parent.identifier.name), 1232 [self.location, parent.location], 1233 ) 1234 1235 self.parent = parent 1236 1237 assert iter(self.members) 1238 1239 if self.isNamespace(): 1240 assert not self.parent 1241 for m in self.members: 1242 if m.isAttr() or m.isMethod(): 1243 if m.isStatic(): 1244 raise WebIDLError( 1245 "Don't mark things explicitly static in namespaces", 1246 [self.location, m.location], 1247 ) 1248 # Just mark all our methods/attributes as static. The other 1249 # option is to duplicate the relevant InterfaceMembers 1250 # production bits but modified to produce static stuff to 1251 # start with, but that sounds annoying. 1252 m.forceStatic() 1253 1254 if self.parent: 1255 self.parent.finish(scope) 1256 self.parent._hasChildInterfaces = True 1257 1258 self.totalMembersInSlots = self.parent.totalMembersInSlots 1259 1260 # Interfaces with [Global] must not have anything inherit from them 1261 if self.parent.getExtendedAttribute("Global"): 1262 # Note: This is not a self.parent.isOnGlobalProtoChain() check 1263 # because ancestors of a [Global] interface can have other 1264 # descendants. 1265 raise WebIDLError( 1266 "[Global] interface has another interface inheriting from it", 1267 [self.location, self.parent.location], 1268 ) 1269 1270 # Make sure that we're not exposed in places where our parent is not 1271 if not self.exposureSet.issubset(self.parent.exposureSet): 1272 raise WebIDLError( 1273 "Interface %s is exposed in globals where its " 1274 "parent interface %s is not exposed." 1275 % (self.identifier.name, self.parent.identifier.name), 1276 [self.location, self.parent.location], 1277 ) 1278 1279 # Callbacks must not inherit from non-callbacks. 1280 # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending. 1281 if self.isCallback(): 1282 if not self.parent.isCallback(): 1283 raise WebIDLError( 1284 "Callback interface %s inheriting from " 1285 "non-callback interface %s" 1286 % (self.identifier.name, self.parent.identifier.name), 1287 [self.location, self.parent.location], 1288 ) 1289 elif self.parent.isCallback(): 1290 raise WebIDLError( 1291 "Non-callback interface %s inheriting from " 1292 "callback interface %s" 1293 % (self.identifier.name, self.parent.identifier.name), 1294 [self.location, self.parent.location], 1295 ) 1296 1297 # Interfaces which have interface objects can't inherit 1298 # from [LegacyNoInterfaceObject] interfaces. 1299 if self.parent.getExtendedAttribute( 1300 "LegacyNoInterfaceObject" 1301 ) and not self.getExtendedAttribute("LegacyNoInterfaceObject"): 1302 raise WebIDLError( 1303 "Interface %s does not have " 1304 "[LegacyNoInterfaceObject] but inherits from " 1305 "interface %s which does" 1306 % (self.identifier.name, self.parent.identifier.name), 1307 [self.location, self.parent.location], 1308 ) 1309 1310 # Interfaces that are not [SecureContext] can't inherit 1311 # from [SecureContext] interfaces. 1312 if self.parent.getExtendedAttribute( 1313 "SecureContext" 1314 ) and not self.getExtendedAttribute("SecureContext"): 1315 raise WebIDLError( 1316 "Interface %s does not have " 1317 "[SecureContext] but inherits from " 1318 "interface %s which does" 1319 % (self.identifier.name, self.parent.identifier.name), 1320 [self.location, self.parent.location], 1321 ) 1322 1323 for mixin in self.includedMixins: 1324 mixin.finish(scope) 1325 1326 cycleInGraph = self.findInterfaceLoopPoint(self) 1327 if cycleInGraph: 1328 raise WebIDLError( 1329 "Interface %s has itself as ancestor" % self.identifier.name, 1330 [self.location, cycleInGraph.location], 1331 ) 1332 1333 self.finishMembers(scope) 1334 1335 ctor = self.ctor() 1336 if ctor is not None: 1337 if not self.hasInterfaceObject(): 1338 raise WebIDLError( 1339 "Can't have both a constructor and [LegacyNoInterfaceObject]", 1340 [self.location, ctor.location], 1341 ) 1342 1343 if self.globalNames: 1344 raise WebIDLError( 1345 "Can't have both a constructor and [Global]", 1346 [self.location, ctor.location], 1347 ) 1348 1349 assert ctor._exposureGlobalNames == self._exposureGlobalNames 1350 ctor._exposureGlobalNames.update(self._exposureGlobalNames) 1351 # Remove the constructor operation from our member list so 1352 # it doesn't get in the way later. 1353 self.members.remove(ctor) 1354 1355 for ctor in self.legacyFactoryFunctions: 1356 if self.globalNames: 1357 raise WebIDLError( 1358 "Can't have both a legacy factory function and [Global]", 1359 [self.location, ctor.location], 1360 ) 1361 assert len(ctor._exposureGlobalNames) == 0 1362 ctor._exposureGlobalNames.update(self._exposureGlobalNames) 1363 ctor.finish(scope) 1364 1365 # Make a copy of our member list, so things that implement us 1366 # can get those without all the stuff we implement ourselves 1367 # admixed. 1368 self.originalMembers = list(self.members) 1369 1370 for mixin in sorted(self.includedMixins, key=lambda x: x.identifier.name): 1371 for mixinMember in mixin.members: 1372 for member in self.members: 1373 if mixinMember.identifier.name == member.identifier.name and ( 1374 not mixinMember.isMethod() 1375 or not member.isMethod() 1376 or mixinMember.isStatic() == member.isStatic() 1377 ): 1378 raise WebIDLError( 1379 "Multiple definitions of %s on %s coming from 'includes' statements" 1380 % (member.identifier.name, self), 1381 [mixinMember.location, member.location], 1382 ) 1383 self.members.extend(mixin.members) 1384 1385 for ancestor in self.getInheritedInterfaces(): 1386 ancestor.interfacesBasedOnSelf.add(self) 1387 if ( 1388 ancestor.maplikeOrSetlikeOrIterable is not None 1389 and self.maplikeOrSetlikeOrIterable is not None 1390 ): 1391 raise WebIDLError( 1392 "Cannot have maplike/setlike on %s that " 1393 "inherits %s, which is already " 1394 "maplike/setlike" 1395 % (self.identifier.name, ancestor.identifier.name), 1396 [ 1397 self.maplikeOrSetlikeOrIterable.location, 1398 ancestor.maplikeOrSetlikeOrIterable.location, 1399 ], 1400 ) 1401 1402 # Deal with interfaces marked [LegacyUnforgeable], now that we have our full 1403 # member list, except unforgeables pulled in from parents. We want to 1404 # do this before we set "originatingInterface" on our unforgeable 1405 # members. 1406 if self.getExtendedAttribute("LegacyUnforgeable"): 1407 # Check that the interface already has all the things the 1408 # spec would otherwise require us to synthesize and is 1409 # missing the ones we plan to synthesize. 1410 if not any(m.isMethod() and m.isStringifier() for m in self.members): 1411 raise WebIDLError( 1412 "LegacyUnforgeable interface %s does not have a " 1413 "stringifier" % self.identifier.name, 1414 [self.location], 1415 ) 1416 1417 for m in self.members: 1418 if m.identifier.name == "toJSON": 1419 raise WebIDLError( 1420 "LegacyUnforgeable interface %s has a " 1421 "toJSON so we won't be able to add " 1422 "one ourselves" % self.identifier.name, 1423 [self.location, m.location], 1424 ) 1425 1426 if m.identifier.name == "valueOf" and not m.isStatic(): 1427 raise WebIDLError( 1428 "LegacyUnforgeable interface %s has a valueOf " 1429 "member so we won't be able to add one " 1430 "ourselves" % self.identifier.name, 1431 [self.location, m.location], 1432 ) 1433 1434 for member in self.members: 1435 if ( 1436 (member.isAttr() or member.isMethod()) 1437 and member.isLegacyUnforgeable() 1438 and not hasattr(member, "originatingInterface") 1439 ): 1440 member.originatingInterface = self 1441 1442 for member in self.members: 1443 if ( 1444 member.isMethod() and member.getExtendedAttribute("CrossOriginCallable") 1445 ) or ( 1446 member.isAttr() 1447 and ( 1448 member.getExtendedAttribute("CrossOriginReadable") 1449 or member.getExtendedAttribute("CrossOriginWritable") 1450 ) 1451 ): 1452 self.hasCrossOriginMembers = True 1453 break 1454 1455 if self.hasCrossOriginMembers: 1456 parent = self 1457 while parent: 1458 parent.hasDescendantWithCrossOriginMembers = True 1459 parent = parent.parent 1460 1461 # Compute slot indices for our members before we pull in unforgeable 1462 # members from our parent. Also, maplike/setlike declarations get a 1463 # slot to hold their backing object. 1464 for member in self.members: 1465 if ( 1466 member.isAttr() 1467 and ( 1468 member.getExtendedAttribute("StoreInSlot") 1469 or member.getExtendedAttribute("Cached") 1470 or member.type.isObservableArray() 1471 or member.getExtendedAttribute( 1472 "ReflectedHTMLAttributeReturningFrozenArray" 1473 ) 1474 ) 1475 ) or member.isMaplikeOrSetlike(): 1476 if self.isJSImplemented() and not member.isMaplikeOrSetlike(): 1477 raise WebIDLError( 1478 "Interface %s is JS-implemented and we " 1479 "don't support [Cached] or [StoreInSlot] or ObservableArray " 1480 "on JS-implemented interfaces" % self.identifier.name, 1481 [self.location, member.location], 1482 ) 1483 if member.slotIndices is None: 1484 member.slotIndices = dict() 1485 if member.getExtendedAttribute( 1486 "ReflectedHTMLAttributeReturningFrozenArray" 1487 ): 1488 parent = self.parent 1489 while parent: 1490 if self.parent.reflectedHTMLAttributesReturningFrozenArray: 1491 raise WebIDLError( 1492 "Interface %s has at least one attribute marked " 1493 "as[ReflectedHTMLAttributeReturningFrozenArray]," 1494 "but one of its ancestors also has an attribute " 1495 "marked as " 1496 "[ReflectedHTMLAttributeReturningFrozenArray]" 1497 % self.identifier.name, 1498 [self.location, member.location, parent.location], 1499 ) 1500 parent = parent.parent 1501 1502 if not self.reflectedHTMLAttributesReturningFrozenArray: 1503 self.reflectedHTMLAttributesReturningFrozenArray = ( 1504 ReflectedHTMLAttributesReturningFrozenArray( 1505 self.totalMembersInSlots 1506 ) 1507 ) 1508 self.totalMembersInSlots += 1 1509 member.slotIndices[self.identifier.name] = ( 1510 self.reflectedHTMLAttributesReturningFrozenArray.slotIndex, 1511 self.reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots, 1512 ) 1513 self.reflectedHTMLAttributesReturningFrozenArray.totalMembersInSlots += ( 1514 1 1515 ) 1516 else: 1517 member.slotIndices[self.identifier.name] = self.totalMembersInSlots 1518 self.totalMembersInSlots += 1 1519 if member.getExtendedAttribute("StoreInSlot"): 1520 self._ownMembersInSlots += 1 1521 1522 if self.parent: 1523 # Make sure we don't shadow any of the [LegacyUnforgeable] attributes on our 1524 # ancestor interfaces. We don't have to worry about mixins here, because 1525 # those have already been imported into the relevant .members lists. And 1526 # we don't have to worry about anything other than our parent, because it 1527 # has already imported its ancestors' unforgeable attributes into its 1528 # member list. 1529 for unforgeableMember in ( 1530 member 1531 for member in self.parent.members 1532 if (member.isAttr() or member.isMethod()) 1533 and member.isLegacyUnforgeable() 1534 ): 1535 shadows = [ 1536 m 1537 for m in self.members 1538 if (m.isAttr() or m.isMethod()) 1539 and not m.isStatic() 1540 and m.identifier.name == unforgeableMember.identifier.name 1541 ] 1542 if len(shadows) != 0: 1543 locs = [unforgeableMember.location] + [s.location for s in shadows] 1544 raise WebIDLError( 1545 "Interface %s shadows [LegacyUnforgeable] " 1546 "members of %s" 1547 % (self.identifier.name, ancestor.identifier.name), 1548 locs, 1549 ) 1550 # And now just stick it in our members, since we won't be 1551 # inheriting this down the proto chain. If we really cared we 1552 # could try to do something where we set up the unforgeable 1553 # attributes/methods of ancestor interfaces, with their 1554 # corresponding getters, on our interface, but that gets pretty 1555 # complicated and seems unnecessary. 1556 self.members.append(unforgeableMember) 1557 1558 # At this point, we have all of our members. If the current interface 1559 # uses maplike/setlike, check for collisions anywhere in the current 1560 # interface or higher in the inheritance chain. 1561 if self.maplikeOrSetlikeOrIterable: 1562 testInterface = self 1563 isAncestor = False 1564 while testInterface: 1565 self.maplikeOrSetlikeOrIterable.checkCollisions( 1566 testInterface.members, isAncestor 1567 ) 1568 isAncestor = True 1569 testInterface = testInterface.parent 1570 1571 # Ensure that there's at most one of each {named,indexed} 1572 # {getter,setter,deleter}, at most one stringifier, 1573 # and at most one legacycaller. Note that this last is not 1574 # quite per spec, but in practice no one overloads 1575 # legacycallers. Also note that in practice we disallow 1576 # indexed deleters, but it simplifies some other code to 1577 # treat deleter analogously to getter/setter by 1578 # prefixing it with "named". 1579 specialMembersSeen = {} 1580 for member in self.members: 1581 if not member.isMethod(): 1582 continue 1583 1584 if member.isGetter(): 1585 memberType = "getters" 1586 elif member.isSetter(): 1587 memberType = "setters" 1588 elif member.isDeleter(): 1589 memberType = "deleters" 1590 elif member.isStringifier(): 1591 memberType = "stringifiers" 1592 elif member.isLegacycaller(): 1593 memberType = "legacycallers" 1594 else: 1595 continue 1596 1597 if memberType != "stringifiers" and memberType != "legacycallers": 1598 if member.isNamed(): 1599 memberType = "named " + memberType 1600 else: 1601 assert member.isIndexed() 1602 memberType = "indexed " + memberType 1603 1604 if memberType in specialMembersSeen: 1605 raise WebIDLError( 1606 "Multiple " + memberType + " on %s" % (self), 1607 [ 1608 self.location, 1609 specialMembersSeen[memberType].location, 1610 member.location, 1611 ], 1612 ) 1613 1614 specialMembersSeen[memberType] = member 1615 1616 if self.getExtendedAttribute("LegacyUnenumerableNamedProperties"): 1617 # Check that we have a named getter. 1618 if "named getters" not in specialMembersSeen: 1619 raise WebIDLError( 1620 "Interface with [LegacyUnenumerableNamedProperties] does " 1621 "not have a named getter", 1622 [self.location], 1623 ) 1624 ancestor = self.parent 1625 while ancestor: 1626 if ancestor.getExtendedAttribute("LegacyUnenumerableNamedProperties"): 1627 raise WebIDLError( 1628 "Interface with [LegacyUnenumerableNamedProperties] " 1629 "inherits from another interface with " 1630 "[LegacyUnenumerableNamedProperties]", 1631 [self.location, ancestor.location], 1632 ) 1633 ancestor = ancestor.parent 1634 1635 if self._isOnGlobalProtoChain: 1636 # Make sure we have no named setters or deleters 1637 for memberType in ["setter", "deleter"]: 1638 memberId = "named " + memberType + "s" 1639 if memberId in specialMembersSeen: 1640 raise WebIDLError( 1641 "Interface with [Global] has a named %s" % memberType, 1642 [self.location, specialMembersSeen[memberId].location], 1643 ) 1644 # Make sure we're not [LegacyOverrideBuiltIns] 1645 if self.getExtendedAttribute("LegacyOverrideBuiltIns"): 1646 raise WebIDLError( 1647 "Interface with [Global] also has [LegacyOverrideBuiltIns]", 1648 [self.location], 1649 ) 1650 # Mark all of our ancestors as being on the global's proto chain too 1651 parent = self.parent 1652 while parent: 1653 # Must not inherit from an interface with [LegacyOverrideBuiltIns] 1654 if parent.getExtendedAttribute("LegacyOverrideBuiltIns"): 1655 raise WebIDLError( 1656 "Interface with [Global] inherits from " 1657 "interface with [LegacyOverrideBuiltIns]", 1658 [self.location, parent.location], 1659 ) 1660 parent._isOnGlobalProtoChain = True 1661 parent = parent.parent 1662 1663 def validate(self): 1664 def checkDuplicateNames(member, name, attributeName): 1665 for m in self.members: 1666 if m.identifier.name == name: 1667 raise WebIDLError( 1668 "[%s=%s] has same name as interface member" 1669 % (attributeName, name), 1670 [member.location, m.location], 1671 ) 1672 if m.isMethod() and m != member and name in m.aliases: 1673 raise WebIDLError( 1674 "conflicting [%s=%s] definitions" % (attributeName, name), 1675 [member.location, m.location], 1676 ) 1677 if m.isAttr() and m != member and name in m.bindingAliases: 1678 raise WebIDLError( 1679 "conflicting [%s=%s] definitions" % (attributeName, name), 1680 [member.location, m.location], 1681 ) 1682 1683 # We also don't support inheriting from unforgeable interfaces. 1684 if self.getExtendedAttribute("LegacyUnforgeable") and self.hasChildInterfaces(): 1685 locations = [self.location] + list( 1686 i.location for i in self.interfacesBasedOnSelf if i.parent == self 1687 ) 1688 raise WebIDLError( 1689 "%s is an unforgeable ancestor interface" % self.identifier.name, 1690 locations, 1691 ) 1692 1693 ctor = self.ctor() 1694 if ctor is not None: 1695 ctor.validate() 1696 for namedCtor in self.legacyFactoryFunctions: 1697 namedCtor.validate() 1698 1699 indexedGetter = None 1700 hasLengthAttribute = False 1701 for member in self.members: 1702 member.validate() 1703 1704 if self.isCallback() and member.getExtendedAttribute("Replaceable"): 1705 raise WebIDLError( 1706 "[Replaceable] used on an attribute on " 1707 "interface %s which is a callback interface" % self.identifier.name, 1708 [self.location, member.location], 1709 ) 1710 1711 # Check that PutForwards refers to another attribute and that no 1712 # cycles exist in forwarded assignments. Also check for a 1713 # integer-typed "length" attribute. 1714 if member.isAttr(): 1715 if member.identifier.name == "length" and member.type.isInteger(): 1716 hasLengthAttribute = True 1717 1718 iface = self 1719 attr = member 1720 putForwards = attr.getExtendedAttribute("PutForwards") 1721 if putForwards and self.isCallback(): 1722 raise WebIDLError( 1723 "[PutForwards] used on an attribute " 1724 "on interface %s which is a callback " 1725 "interface" % self.identifier.name, 1726 [self.location, member.location], 1727 ) 1728 1729 while putForwards is not None: 1730 1731 def findForwardedAttr(iface): 1732 while iface: 1733 for m in iface.members: 1734 if ( 1735 not m.isAttr() 1736 or m.identifier.name != putForwards[0] 1737 ): 1738 continue 1739 if m == member: 1740 raise WebIDLError( 1741 "Cycle detected in forwarded " 1742 "assignments for attribute %s on " 1743 "%s" % (member.identifier.name, self), 1744 [member.location], 1745 ) 1746 return (iface, m) 1747 1748 iface = iface.parent 1749 1750 return (None, None) 1751 1752 (forwardIface, forwardAttr) = findForwardedAttr( 1753 attr.type.unroll().inner 1754 ) 1755 if forwardAttr is None: 1756 raise WebIDLError( 1757 "Attribute %s on %s forwards to " 1758 "missing attribute %s" 1759 % (attr.identifier.name, iface, putForwards), 1760 [attr.location], 1761 ) 1762 1763 iface = forwardIface 1764 attr = forwardAttr 1765 putForwards = attr.getExtendedAttribute("PutForwards") 1766 1767 # Check that the name of an [Alias] doesn't conflict with an 1768 # interface member and whether we support indexed properties. 1769 if member.isMethod(): 1770 if member.isGetter() and member.isIndexed(): 1771 indexedGetter = member 1772 1773 for alias in member.aliases: 1774 if self.isOnGlobalProtoChain(): 1775 raise WebIDLError( 1776 "[Alias] must not be used on a " 1777 "[Global] interface operation", 1778 [member.location], 1779 ) 1780 if ( 1781 member.getExtendedAttribute("Exposed") 1782 or member.getExtendedAttribute("ChromeOnly") 1783 or member.getExtendedAttribute("Pref") 1784 or member.getExtendedAttribute("Func") 1785 or member.getExtendedAttribute("Trial") 1786 or member.getExtendedAttribute("SecureContext") 1787 ): 1788 raise WebIDLError( 1789 "[Alias] must not be used on a " 1790 "conditionally exposed operation", 1791 [member.location], 1792 ) 1793 if member.isStatic(): 1794 raise WebIDLError( 1795 "[Alias] must not be used on a static operation", 1796 [member.location], 1797 ) 1798 if member.isIdentifierLess(): 1799 raise WebIDLError( 1800 "[Alias] must not be used on an " 1801 "identifierless operation", 1802 [member.location], 1803 ) 1804 if member.isLegacyUnforgeable(): 1805 raise WebIDLError( 1806 "[Alias] must not be used on an " 1807 "[LegacyUnforgeable] operation", 1808 [member.location], 1809 ) 1810 1811 checkDuplicateNames(member, alias, "Alias") 1812 1813 # Check that the name of a [BindingAlias] doesn't conflict with an 1814 # interface member. 1815 if member.isAttr(): 1816 for bindingAlias in member.bindingAliases: 1817 checkDuplicateNames(member, bindingAlias, "BindingAlias") 1818 1819 # Conditional exposure makes no sense for interfaces with no 1820 # interface object. 1821 # And SecureContext makes sense for interfaces with no interface object, 1822 # since it is also propagated to interface members. 1823 if ( 1824 self.isExposedConditionally(exclusions=["SecureContext"]) 1825 and not self.hasInterfaceObject() 1826 ): 1827 raise WebIDLError( 1828 "Interface with no interface object is exposed conditionally", 1829 [self.location], 1830 ) 1831 1832 # Value iterators are only allowed on interfaces with indexed getters, 1833 # and pair iterators are only allowed on interfaces without indexed 1834 # getters. 1835 if self.isIterable(): 1836 iterableDecl = self.maplikeOrSetlikeOrIterable 1837 if iterableDecl.isValueIterator(): 1838 if not indexedGetter: 1839 raise WebIDLError( 1840 "Interface with value iterator does not " 1841 "support indexed properties", 1842 [self.location, iterableDecl.location], 1843 ) 1844 1845 if iterableDecl.valueType != indexedGetter.signatures()[0][0]: 1846 raise WebIDLError( 1847 "Iterable type does not match indexed getter type", 1848 [iterableDecl.location, indexedGetter.location], 1849 ) 1850 1851 if not hasLengthAttribute: 1852 raise WebIDLError( 1853 "Interface with value iterator does not " 1854 'have an integer-typed "length" attribute', 1855 [self.location, iterableDecl.location], 1856 ) 1857 else: 1858 assert iterableDecl.isPairIterator() 1859 if indexedGetter: 1860 raise WebIDLError( 1861 "Interface with pair iterator supports indexed properties", 1862 [self.location, iterableDecl.location, indexedGetter.location], 1863 ) 1864 1865 if indexedGetter and not hasLengthAttribute: 1866 raise WebIDLError( 1867 "Interface with an indexed getter does not have " 1868 'an integer-typed "length" attribute', 1869 [self.location, indexedGetter.location], 1870 ) 1871 1872 def setCallback(self, value): 1873 self._callback = value 1874 1875 def isCallback(self): 1876 return self._callback 1877 1878 def isSingleOperationInterface(self): 1879 assert self.isCallback() or self.isJSImplemented() 1880 return ( 1881 # JS-implemented things should never need the 1882 # this-handling weirdness of single-operation interfaces. 1883 not self.isJSImplemented() 1884 and 1885 # Not inheriting from another interface 1886 not self.parent 1887 and 1888 # No attributes of any kinds 1889 not any(m.isAttr() for m in self.members) 1890 and 1891 # There is at least one regular operation, and all regular 1892 # operations have the same identifier 1893 len( 1894 set( 1895 m.identifier.name 1896 for m in self.members 1897 if m.isMethod() and not m.isStatic() 1898 ) 1899 ) 1900 == 1 1901 ) 1902 1903 def inheritanceDepth(self): 1904 depth = 0 1905 parent = self.parent 1906 while parent: 1907 depth = depth + 1 1908 parent = parent.parent 1909 return depth 1910 1911 def hasConstants(self): 1912 return any(m.isConst() for m in self.members) 1913 1914 def hasInterfaceObject(self): 1915 if self.isCallback(): 1916 return self.hasConstants() 1917 return not hasattr(self, "_noInterfaceObject") and not self.getUserData( 1918 "hasOrdinaryObjectPrototype", False 1919 ) 1920 1921 def hasInterfacePrototypeObject(self): 1922 return ( 1923 not self.isCallback() 1924 and not self.isNamespace() 1925 and self.getUserData("hasConcreteDescendant", False) 1926 and not self.getUserData("hasOrdinaryObjectPrototype", False) 1927 ) 1928 1929 def addIncludedMixin(self, includedMixin): 1930 assert isinstance(includedMixin, IDLInterfaceMixin) 1931 self.includedMixins.add(includedMixin) 1932 1933 def getInheritedInterfaces(self): 1934 """ 1935 Returns a list of the interfaces this interface inherits from 1936 (not including this interface itself). The list is in order 1937 from most derived to least derived. 1938 """ 1939 assert self._finished 1940 if not self.parent: 1941 return [] 1942 parentInterfaces = self.parent.getInheritedInterfaces() 1943 parentInterfaces.insert(0, self.parent) 1944 return parentInterfaces 1945 1946 def findInterfaceLoopPoint(self, otherInterface): 1947 """ 1948 Finds an interface amongst our ancestors that inherits from otherInterface. 1949 If there is no such interface, returns None. 1950 """ 1951 if self.parent: 1952 if self.parent == otherInterface: 1953 return self 1954 loopPoint = self.parent.findInterfaceLoopPoint(otherInterface) 1955 if loopPoint: 1956 return loopPoint 1957 return None 1958 1959 def setNonPartial(self, location, parent, members): 1960 assert not parent or isinstance(parent, IDLIdentifierPlaceholder) 1961 IDLInterfaceOrInterfaceMixinOrNamespace.setNonPartial(self, location, members) 1962 assert not self.parent 1963 self.parent = parent 1964 1965 def getJSImplementation(self): 1966 classId = self.getExtendedAttribute("JSImplementation") 1967 if not classId: 1968 return classId 1969 assert isinstance(classId, list) 1970 assert len(classId) == 1 1971 return classId[0] 1972 1973 def isJSImplemented(self): 1974 return bool(self.getJSImplementation()) 1975 1976 def hasProbablyShortLivingWrapper(self): 1977 current = self 1978 while current: 1979 if current.getExtendedAttribute("ProbablyShortLivingWrapper"): 1980 return True 1981 current = current.parent 1982 return False 1983 1984 def hasChildInterfaces(self): 1985 return self._hasChildInterfaces 1986 1987 def isOnGlobalProtoChain(self): 1988 return self._isOnGlobalProtoChain 1989 1990 def _getDependentObjects(self): 1991 deps = set(self.members) 1992 deps.update(self.includedMixins) 1993 if self.parent: 1994 deps.add(self.parent) 1995 return deps 1996 1997 def hasMembersInSlots(self): 1998 return self._ownMembersInSlots != 0 1999 2000 conditionExtendedAttributes = [ 2001 "Pref", 2002 "ChromeOnly", 2003 "Func", 2004 "Trial", 2005 "SecureContext", 2006 ] 2007 2008 def isExposedConditionally(self, exclusions=[]): 2009 return any( 2010 ((a not in exclusions) and self.getExtendedAttribute(a)) 2011 for a in self.conditionExtendedAttributes 2012 ) 2013 2014 2015 class IDLInterface(IDLInterfaceOrNamespace): 2016 __slots__ = ("classNameOverride",) 2017 2018 def __init__( 2019 self, 2020 location, 2021 parentScope, 2022 name, 2023 parent, 2024 members, 2025 isKnownNonPartial, 2026 classNameOverride=None, 2027 ): 2028 IDLInterfaceOrNamespace.__init__( 2029 self, location, parentScope, name, parent, members, isKnownNonPartial 2030 ) 2031 self.classNameOverride = classNameOverride 2032 2033 def __str__(self): 2034 return "Interface '%s'" % self.identifier.name 2035 2036 def isInterface(self): 2037 return True 2038 2039 def getClassName(self): 2040 if self.classNameOverride: 2041 return self.classNameOverride 2042 return IDLInterfaceOrNamespace.getClassName(self) 2043 2044 def handleExtendedAttribute(self, attr): 2045 identifier = attr.identifier() 2046 # Special cased attrs 2047 if identifier == "TreatNonCallableAsNull": 2048 raise WebIDLError( 2049 "TreatNonCallableAsNull cannot be specified on interfaces", 2050 [attr.location, self.location], 2051 ) 2052 if identifier == "LegacyTreatNonObjectAsNull": 2053 raise WebIDLError( 2054 "LegacyTreatNonObjectAsNull cannot be specified on interfaces", 2055 [attr.location, self.location], 2056 ) 2057 elif identifier == "LegacyNoInterfaceObject": 2058 if not attr.noArguments(): 2059 raise WebIDLError( 2060 "[LegacyNoInterfaceObject] must take no arguments", 2061 [attr.location], 2062 ) 2063 2064 self._noInterfaceObject = True 2065 elif identifier == "LegacyFactoryFunction": 2066 if not attr.hasValue(): 2067 raise WebIDLError( 2068 ( 2069 "LegacyFactoryFunction must either take an " 2070 "identifier or take a named argument list" 2071 ), 2072 [attr.location], 2073 ) 2074 2075 args = attr.args() if attr.hasArgs() else [] 2076 2077 method = IDLConstructor(attr.location, args, attr.value()) 2078 method.reallyInit(self) 2079 2080 # Legacy factory functions are always assumed to be able to 2081 # throw (since there's no way to indicate otherwise). 2082 method.addExtendedAttributes( 2083 [IDLExtendedAttribute(self.location, ("Throws",))] 2084 ) 2085 2086 # We need to detect conflicts for LegacyFactoryFunctions across 2087 # interfaces. We first call resolve on the parentScope, 2088 # which will merge all LegacyFactoryFunctions with the same 2089 # identifier accross interfaces as overloads. 2090 method.resolve(self.parentScope) 2091 2092 # Then we look up the identifier on the parentScope. If the 2093 # result is the same as the method we're adding then it 2094 # hasn't been added as an overload and it's the first time 2095 # we've encountered a LegacyFactoryFunction with that identifier. 2096 # If the result is not the same as the method we're adding 2097 # then it has been added as an overload and we need to check 2098 # whether the result is actually one of our existing 2099 # LegacyFactoryFunctions. 2100 newMethod = self.parentScope.lookupIdentifier(method.identifier) 2101 if newMethod == method: 2102 self.legacyFactoryFunctions.append(method) 2103 elif newMethod not in self.legacyFactoryFunctions: 2104 raise WebIDLError( 2105 "LegacyFactoryFunction conflicts with a " 2106 "LegacyFactoryFunction of a different interface", 2107 [method.location, newMethod.location], 2108 ) 2109 elif identifier == "ExceptionClass": 2110 if not attr.noArguments(): 2111 raise WebIDLError( 2112 "[ExceptionClass] must take no arguments", [attr.location] 2113 ) 2114 if self.parent: 2115 raise WebIDLError( 2116 "[ExceptionClass] must not be specified on " 2117 "an interface with inherited interfaces", 2118 [attr.location, self.location], 2119 ) 2120 elif identifier == "Global": 2121 if attr.hasValue(): 2122 self.globalNames = [attr.value()] 2123 elif attr.hasArgs(): 2124 self.globalNames = attr.args() 2125 else: 2126 raise WebIDLError( 2127 "[Global] must either take an identifier or take an identifier list", 2128 [attr.location, self.location], 2129 ) 2130 self.parentScope.addIfaceGlobalNames(self.identifier.name, self.globalNames) 2131 self._isOnGlobalProtoChain = True 2132 elif identifier == "LegacyWindowAlias": 2133 if attr.hasValue(): 2134 self.legacyWindowAliases = [attr.value()] 2135 elif attr.hasArgs(): 2136 self.legacyWindowAliases = attr.args() 2137 else: 2138 raise WebIDLError( 2139 "[%s] must either take an identifier " 2140 "or take an identifier list" % identifier, 2141 [attr.location], 2142 ) 2143 for alias in self.legacyWindowAliases: 2144 unresolved = IDLUnresolvedIdentifier(attr.location, alias) 2145 IDLObjectWithIdentifier(attr.location, self.parentScope, unresolved) 2146 elif ( 2147 identifier == "NeedResolve" 2148 or identifier == "LegacyOverrideBuiltIns" 2149 or identifier == "ChromeOnly" 2150 or identifier == "LegacyUnforgeable" 2151 or identifier == "LegacyEventInit" 2152 or identifier == "ProbablyShortLivingWrapper" 2153 or identifier == "LegacyUnenumerableNamedProperties" 2154 or identifier == "RunConstructorInCallerCompartment" 2155 or identifier == "WantsEventListenerHooks" 2156 or identifier == "Serializable" 2157 ): 2158 # Known extended attributes that do not take values 2159 if not attr.noArguments(): 2160 raise WebIDLError( 2161 "[%s] must take no arguments" % identifier, [attr.location] 2162 ) 2163 elif ( 2164 identifier == "Pref" 2165 or identifier == "JSImplementation" 2166 or identifier == "HeaderFile" 2167 or identifier == "Func" 2168 or identifier == "Trial" 2169 or identifier == "Deprecated" 2170 ): 2171 # Known extended attributes that take a string value 2172 if not attr.hasValue(): 2173 raise WebIDLError( 2174 "[%s] must have a value" % identifier, [attr.location] 2175 ) 2176 elif identifier == "InstrumentedProps": 2177 # Known extended attributes that take a list 2178 if not attr.hasArgs(): 2179 raise WebIDLError( 2180 "[%s] must have arguments" % identifier, [attr.location] 2181 ) 2182 else: 2183 IDLInterfaceOrNamespace.handleExtendedAttribute(self, attr) 2184 2185 def implementedWithProxy(self): 2186 if self.parent and self.parent.implementedWithProxy(): 2187 return True 2188 return self.hasCrossOriginMembers or any( 2189 member.isMethod() 2190 and member.isGetter() 2191 and (member.isIndexed() or member.isNamed()) 2192 for member in self.members 2193 ) 2194 2195 def validate(self): 2196 IDLInterfaceOrNamespace.validate(self) 2197 if ( 2198 self.getExtendedAttribute("InstrumentedProps") 2199 and not self.implementedWithProxy() 2200 ): 2201 raise WebIDLError( 2202 "IntrumentedProps attribute can't be used for non-proxy-based interfaces." 2203 "Proxy is used if the interface has any named/indexed getters or has cross origin members.", 2204 [self.location], 2205 ) 2206 if self.parent and self.isSerializable() and not self.parent.isSerializable(): 2207 raise WebIDLError( 2208 "Serializable interface inherits from non-serializable " 2209 "interface. Per spec, that means the object should not be " 2210 "serializable, so chances are someone made a mistake here " 2211 "somewhere.", 2212 [self.location, self.parent.location], 2213 ) 2214 2215 def isSerializable(self): 2216 return self.getExtendedAttribute("Serializable") 2217 2218 def setNonPartial(self, location, parent, members): 2219 # Before we do anything else, finish initializing any constructors that 2220 # might be in "members", so we don't have partially-initialized objects 2221 # hanging around. We couldn't do it before now because we needed to have 2222 # to have the IDLInterface on hand to properly set the return type. 2223 for member in members: 2224 if isinstance(member, IDLConstructor): 2225 member.reallyInit(self) 2226 2227 IDLInterfaceOrNamespace.setNonPartial(self, location, parent, members) 2228 2229 2230 class IDLNamespace(IDLInterfaceOrNamespace): 2231 __slots__ = () 2232 2233 def __init__(self, location, parentScope, name, members, isKnownNonPartial): 2234 IDLInterfaceOrNamespace.__init__( 2235 self, location, parentScope, name, None, members, isKnownNonPartial 2236 ) 2237 2238 def __str__(self): 2239 return "Namespace '%s'" % self.identifier.name 2240 2241 def isNamespace(self): 2242 return True 2243 2244 def handleExtendedAttribute(self, attr): 2245 # The set of things namespaces support is small enough it's simpler 2246 # to factor out into a separate method than it is to sprinkle 2247 # isNamespace() checks all through 2248 # IDLInterfaceOrNamespace.handleExtendedAttribute. 2249 identifier = attr.identifier() 2250 if identifier == "ClassString": 2251 # Takes a string value to override the default "Object" if 2252 # desired. 2253 if not attr.hasValue(): 2254 raise WebIDLError( 2255 "[%s] must have a value" % identifier, [attr.location] 2256 ) 2257 elif identifier == "ProtoObjectHack" or identifier == "ChromeOnly": 2258 if not attr.noArguments(): 2259 raise WebIDLError( 2260 "[%s] must not have arguments" % identifier, [attr.location] 2261 ) 2262 elif ( 2263 identifier == "Pref" 2264 or identifier == "HeaderFile" 2265 or identifier == "Func" 2266 or identifier == "Trial" 2267 ): 2268 # Known extended attributes that take a string value 2269 if not attr.hasValue(): 2270 raise WebIDLError( 2271 "[%s] must have a value" % identifier, [attr.location] 2272 ) 2273 else: 2274 IDLInterfaceOrNamespace.handleExtendedAttribute(self, attr) 2275 2276 def isSerializable(self): 2277 return False 2278 2279 2280 class IDLDictionary(IDLObjectWithScope): 2281 __slots__ = ( 2282 "parent", 2283 "_finished", 2284 "members", 2285 "_partialDictionaries", 2286 "_extendedAttrDict", 2287 "needsConversionToJS", 2288 "needsConversionFromJS", 2289 "needsEqualityOperator", 2290 ) 2291 2292 def __init__(self, location, parentScope, name, parent, members): 2293 assert isinstance(parentScope, IDLScope) 2294 assert isinstance(name, IDLUnresolvedIdentifier) 2295 assert not parent or isinstance(parent, IDLIdentifierPlaceholder) 2296 2297 self.parent = parent 2298 self._finished = False 2299 self.members = list(members) 2300 self._partialDictionaries = [] 2301 self._extendedAttrDict = {} 2302 self.needsConversionToJS = False 2303 self.needsConversionFromJS = False 2304 self.needsEqualityOperator = None 2305 2306 IDLObjectWithScope.__init__(self, location, parentScope, name) 2307 2308 def __str__(self): 2309 return "Dictionary '%s'" % self.identifier.name 2310 2311 def isDictionary(self): 2312 return True 2313 2314 def canBeEmpty(self): 2315 """ 2316 Returns true if this dictionary can be empty (that is, it has no 2317 required members and neither do any of its ancestors). 2318 """ 2319 return all(member.optional for member in self.members) and ( 2320 not self.parent or self.parent.canBeEmpty() 2321 ) 2322 2323 def finish(self, scope): 2324 if self._finished: 2325 return 2326 2327 self._finished = True 2328 2329 if self.parent: 2330 assert isinstance(self.parent, IDLIdentifierPlaceholder) 2331 oldParent = self.parent 2332 self.parent = self.parent.finish(scope) 2333 if not isinstance(self.parent, IDLDictionary): 2334 raise WebIDLError( 2335 "Dictionary %s has parent that is not a dictionary" 2336 % self.identifier.name, 2337 [oldParent.location, self.parent.location], 2338 ) 2339 2340 # Make sure the parent resolves all its members before we start 2341 # looking at them. 2342 self.parent.finish(scope) 2343 2344 # Now go ahead and merge in our partial dictionaries. 2345 for partial in self._partialDictionaries: 2346 partial.finish(scope) 2347 self.members.extend(partial.members) 2348 2349 for member in self.members: 2350 member.resolve(self) 2351 if not member.isComplete(): 2352 member.complete(scope) 2353 assert member.type.isComplete() 2354 2355 # Members of a dictionary are sorted in lexicographic order, 2356 # unless the dictionary opts out. 2357 if not self.getExtendedAttribute("Unsorted"): 2358 self.members.sort(key=lambda x: x.identifier.name) 2359 2360 inheritedMembers = [] 2361 ancestor = self.parent 2362 while ancestor: 2363 if ancestor == self: 2364 raise WebIDLError( 2365 "Dictionary %s has itself as an ancestor" % self.identifier.name, 2366 [self.identifier.location], 2367 ) 2368 inheritedMembers.extend(ancestor.members) 2369 if ( 2370 self.getExtendedAttribute("GenerateEqualityOperator") 2371 and ancestor.needsEqualityOperator is None 2372 ): 2373 # Store the dictionary that has the [GenerateEqualityOperator] 2374 # extended attribute, so we can use it when generating error 2375 # messages. 2376 ancestor.needsEqualityOperator = self 2377 ancestor = ancestor.parent 2378 2379 # Catch name duplication 2380 for inheritedMember in inheritedMembers: 2381 for member in self.members: 2382 if member.identifier.name == inheritedMember.identifier.name: 2383 raise WebIDLError( 2384 "Dictionary %s has two members with name %s" 2385 % (self.identifier.name, member.identifier.name), 2386 [member.location, inheritedMember.location], 2387 ) 2388 2389 def validate(self): 2390 def typeContainsDictionary(memberType, dictionary): 2391 """ 2392 Returns a tuple whose: 2393 2394 - First element is a Boolean value indicating whether 2395 memberType contains dictionary. 2396 2397 - Second element is: 2398 A list of locations that leads from the type that was passed in 2399 the memberType argument, to the dictionary being validated, 2400 if the boolean value in the first element is True. 2401 2402 None, if the boolean value in the first element is False. 2403 """ 2404 2405 if ( 2406 memberType.nullable() 2407 or memberType.isSequence() 2408 or memberType.isRecord() 2409 ): 2410 return typeContainsDictionary(memberType.inner, dictionary) 2411 2412 if memberType.isDictionary(): 2413 if memberType.inner == dictionary: 2414 return (True, [memberType.location]) 2415 2416 (contains, locations) = dictionaryContainsDictionary( 2417 memberType.inner, dictionary 2418 ) 2419 if contains: 2420 return (True, [memberType.location] + locations) 2421 2422 if memberType.isUnion(): 2423 for member in memberType.flatMemberTypes: 2424 (contains, locations) = typeContainsDictionary(member, dictionary) 2425 if contains: 2426 return (True, locations) 2427 2428 return (False, None) 2429 2430 def dictionaryContainsDictionary(dictMember, dictionary): 2431 for member in dictMember.members: 2432 (contains, locations) = typeContainsDictionary(member.type, dictionary) 2433 if contains: 2434 return (True, [member.location] + locations) 2435 2436 if dictMember.parent: 2437 if dictMember.parent == dictionary: 2438 return (True, [dictMember.location]) 2439 else: 2440 (contains, locations) = dictionaryContainsDictionary( 2441 dictMember.parent, dictionary 2442 ) 2443 if contains: 2444 return (True, [dictMember.location] + locations) 2445 2446 return (False, None) 2447 2448 for member in self.members: 2449 if member.type.isDictionary() and member.type.nullable(): 2450 raise WebIDLError( 2451 "Dictionary %s has member with nullable " 2452 "dictionary type" % self.identifier.name, 2453 [member.location], 2454 ) 2455 (contains, locations) = typeContainsDictionary(member.type, self) 2456 if contains: 2457 raise WebIDLError( 2458 "Dictionary %s has member with itself as type." 2459 % self.identifier.name, 2460 [member.location] + locations, 2461 ) 2462 2463 if member.type.isUndefined(): 2464 raise WebIDLError( 2465 "Dictionary %s has member with undefined as its type." 2466 % self.identifier.name, 2467 [member.location], 2468 ) 2469 elif member.type.isUnion(): 2470 for unionMember in member.type.unroll().flatMemberTypes: 2471 if unionMember.isUndefined(): 2472 raise WebIDLError( 2473 "Dictionary %s has member with a union containing " 2474 "undefined as a type." % self.identifier.name, 2475 [unionMember.location], 2476 ) 2477 2478 def getExtendedAttribute(self, name): 2479 return self._extendedAttrDict.get(name, None) 2480 2481 def addExtendedAttributes(self, attrs): 2482 for attr in attrs: 2483 identifier = attr.identifier() 2484 2485 if identifier == "GenerateInitFromJSON" or identifier == "GenerateInit": 2486 if not attr.noArguments(): 2487 raise WebIDLError( 2488 "[%s] must not have arguments" % identifier, [attr.location] 2489 ) 2490 self.needsConversionFromJS = True 2491 elif ( 2492 identifier == "GenerateConversionToJS" or identifier == "GenerateToJSON" 2493 ): 2494 if not attr.noArguments(): 2495 raise WebIDLError( 2496 "[%s] must not have arguments" % identifier, [attr.location] 2497 ) 2498 # ToJSON methods require to-JS conversion, because we 2499 # implement ToJSON by converting to a JS object and 2500 # then using JSON.stringify. 2501 self.needsConversionToJS = True 2502 elif identifier == "GenerateEqualityOperator": 2503 if not attr.noArguments(): 2504 raise WebIDLError( 2505 "[GenerateEqualityOperator] must take no arguments", 2506 [attr.location], 2507 ) 2508 self.needsEqualityOperator = self 2509 elif identifier == "Unsorted": 2510 if not attr.noArguments(): 2511 raise WebIDLError( 2512 "[Unsorted] must take no arguments", [attr.location] 2513 ) 2514 else: 2515 raise WebIDLError( 2516 "[%s] extended attribute not allowed on " 2517 "dictionaries" % identifier, 2518 [attr.location], 2519 ) 2520 2521 self._extendedAttrDict[identifier] = True 2522 2523 def _getDependentObjects(self): 2524 deps = set(self.members) 2525 if self.parent: 2526 deps.add(self.parent) 2527 return deps 2528 2529 def addPartialDictionary(self, partial): 2530 assert self.identifier.name == partial.identifier.name 2531 self._partialDictionaries.append(partial) 2532 2533 2534 class IDLEnum(IDLObjectWithIdentifier): 2535 __slots__ = ("_values",) 2536 2537 def __init__(self, location, parentScope, name, values): 2538 assert isinstance(parentScope, IDLScope) 2539 assert isinstance(name, IDLUnresolvedIdentifier) 2540 2541 if len(values) != len(set(values)): 2542 raise WebIDLError( 2543 "Enum %s has multiple identical strings" % name.name, [location] 2544 ) 2545 2546 IDLObjectWithIdentifier.__init__(self, location, parentScope, name) 2547 self._values = values 2548 2549 def values(self): 2550 return self._values 2551 2552 def finish(self, scope): 2553 pass 2554 2555 def validate(self): 2556 pass 2557 2558 def isEnum(self): 2559 return True 2560 2561 def addExtendedAttributes(self, attrs): 2562 if len(attrs) != 0: 2563 raise WebIDLError( 2564 "There are no extended attributes that are allowed on enums", 2565 [attrs[0].location, self.location], 2566 ) 2567 2568 def _getDependentObjects(self): 2569 return set() 2570 2571 2572 class IDLType(IDLObject): 2573 Tags = enum( 2574 # The integer types 2575 "int8", 2576 "uint8", 2577 "int16", 2578 "uint16", 2579 "int32", 2580 "uint32", 2581 "int64", 2582 "uint64", 2583 # Additional primitive types 2584 "bool", 2585 "unrestricted_float", 2586 "float", 2587 "unrestricted_double", 2588 # "double" last primitive type to match IDLBuiltinType 2589 "double", 2590 # Other types 2591 "any", 2592 "undefined", 2593 "domstring", 2594 "bytestring", 2595 "usvstring", 2596 "utf8string", 2597 "jsstring", 2598 "object", 2599 # Funny stuff 2600 "interface", 2601 "dictionary", 2602 "enum", 2603 "callback", 2604 "union", 2605 "sequence", 2606 "record", 2607 "promise", 2608 "observablearray", 2609 ) 2610 2611 __slots__ = ( 2612 "name", 2613 "builtin", 2614 "legacyNullToEmptyString", 2615 "_clamp", 2616 "_enforceRange", 2617 "_allowShared", 2618 "_extendedAttrDict", 2619 ) 2620 2621 def __init__(self, location, name): 2622 IDLObject.__init__(self, location) 2623 self.name = name 2624 self.builtin = False 2625 self.legacyNullToEmptyString = False 2626 self._clamp = False 2627 self._enforceRange = False 2628 self._allowShared = False 2629 self._extendedAttrDict = {} 2630 2631 def __hash__(self): 2632 return ( 2633 hash(self.builtin) 2634 + hash(self.name) 2635 + hash(self._clamp) 2636 + hash(self._enforceRange) 2637 + hash(self.legacyNullToEmptyString) 2638 + hash(self._allowShared) 2639 ) 2640 2641 def __eq__(self, other): 2642 return ( 2643 other 2644 and self.builtin == other.builtin 2645 and self.name == other.name 2646 and self._clamp == other.hasClamp() 2647 and self._enforceRange == other.hasEnforceRange() 2648 and self.legacyNullToEmptyString == other.legacyNullToEmptyString 2649 and self._allowShared == other.hasAllowShared() 2650 ) 2651 2652 def __ne__(self, other): 2653 return not self == other 2654 2655 def __str__(self): 2656 return str(self.name) 2657 2658 def prettyName(self): 2659 """ 2660 A name that looks like what this type is named in the IDL spec. By default 2661 this is just our .name, but types that have more interesting spec 2662 representations should override this. 2663 """ 2664 return str(self.name) 2665 2666 def isType(self): 2667 return True 2668 2669 def nullable(self): 2670 return False 2671 2672 def isPrimitive(self): 2673 return False 2674 2675 def isBoolean(self): 2676 return False 2677 2678 def isNumeric(self): 2679 return False 2680 2681 def isString(self): 2682 return False 2683 2684 def isByteString(self): 2685 return False 2686 2687 def isDOMString(self): 2688 return False 2689 2690 def isUSVString(self): 2691 return False 2692 2693 def isUTF8String(self): 2694 return False 2695 2696 def isJSString(self): 2697 return False 2698 2699 def isInteger(self): 2700 return False 2701 2702 def isUndefined(self): 2703 return False 2704 2705 def isSequence(self): 2706 return False 2707 2708 def isRecord(self): 2709 return False 2710 2711 def isArrayBuffer(self): 2712 return False 2713 2714 def isArrayBufferView(self): 2715 return False 2716 2717 def isTypedArray(self): 2718 return False 2719 2720 def isBufferSource(self): 2721 return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray() 2722 2723 def isCallbackInterface(self): 2724 return False 2725 2726 def isNonCallbackInterface(self): 2727 return False 2728 2729 def isGeckoInterface(self): 2730 """Returns a boolean indicating whether this type is an 'interface' 2731 type that is implemented in Gecko. At the moment, this returns 2732 true for all interface types that are not types from the TypedArray 2733 spec.""" 2734 return self.isInterface() and not self.isSpiderMonkeyInterface() 2735 2736 def isSpiderMonkeyInterface(self): 2737 """Returns a boolean indicating whether this type is an 'interface' 2738 type that is implemented in SpiderMonkey.""" 2739 return self.isInterface() and self.isBufferSource() 2740 2741 def isAny(self): 2742 return self.tag() == IDLType.Tags.any 2743 2744 def isObject(self): 2745 return self.tag() == IDLType.Tags.object 2746 2747 def isPromise(self): 2748 return False 2749 2750 def isComplete(self): 2751 return True 2752 2753 def includesRestrictedFloat(self): 2754 return False 2755 2756 def isFloat(self): 2757 return False 2758 2759 def isUnrestricted(self): 2760 # Should only call this on float types 2761 assert self.isFloat() 2762 2763 def isJSONType(self): 2764 return False 2765 2766 def isObservableArray(self): 2767 return False 2768 2769 def isDictionaryLike(self): 2770 return self.isDictionary() or self.isRecord() or self.isCallbackInterface() 2771 2772 def hasClamp(self): 2773 return self._clamp 2774 2775 def hasEnforceRange(self): 2776 return self._enforceRange 2777 2778 def hasAllowShared(self): 2779 return self._allowShared 2780 2781 def tag(self): 2782 assert False # Override me! 2783 2784 def treatNonCallableAsNull(self): 2785 assert self.tag() == IDLType.Tags.callback 2786 return self.nullable() and self.inner.callback._treatNonCallableAsNull 2787 2788 def treatNonObjectAsNull(self): 2789 assert self.tag() == IDLType.Tags.callback 2790 return self.nullable() and self.inner.callback._treatNonObjectAsNull 2791 2792 def withExtendedAttributes(self, attrs): 2793 if len(attrs) > 0: 2794 raise WebIDLError( 2795 "Extended attributes on types only supported for builtins", 2796 [attrs[0].location, self.location], 2797 ) 2798 return self 2799 2800 def getExtendedAttribute(self, name): 2801 return self._extendedAttrDict.get(name, None) 2802 2803 def resolveType(self, parentScope): 2804 pass 2805 2806 def unroll(self): 2807 return self 2808 2809 def isDistinguishableFrom(self, other): 2810 raise TypeError( 2811 "Can't tell whether a generic type is or is not " 2812 "distinguishable from other things" 2813 ) 2814 2815 def isExposedInAllOf(self, exposureSet): 2816 return True 2817 2818 2819 class IDLUnresolvedType(IDLType): 2820 """ 2821 Unresolved types are interface types 2822 """ 2823 2824 __slots__ = ("extraTypeAttributes",) 2825 2826 def __init__(self, location, name, attrs=[]): 2827 IDLType.__init__(self, location, name) 2828 self.extraTypeAttributes = attrs 2829 2830 def isComplete(self): 2831 return False 2832 2833 def complete(self, scope): 2834 obj = None 2835 try: 2836 obj = scope._lookupIdentifier(self.name) 2837 except Exception: 2838 raise WebIDLError("Unresolved type '%s'." % self.name, [self.location]) 2839 2840 assert obj 2841 assert not obj.isType() 2842 if obj.isTypedef(): 2843 assert self.name.name == obj.identifier.name 2844 typedefType = IDLTypedefType( 2845 self.location, obj.innerType, obj.identifier 2846 ).withExtendedAttributes(self.extraTypeAttributes) 2847 assert not typedefType.isComplete() 2848 return typedefType.complete(scope) 2849 elif obj.isCallback() and not obj.isInterface(): 2850 assert self.name.name == obj.identifier.name 2851 return IDLCallbackType(self.location, obj) 2852 2853 return IDLWrapperType(self.location, obj) 2854 2855 def withExtendedAttributes(self, attrs): 2856 return IDLUnresolvedType(self.location, self.name, attrs) 2857 2858 def isDistinguishableFrom(self, other): 2859 raise TypeError( 2860 "Can't tell whether an unresolved type is or is not " 2861 "distinguishable from other things" 2862 ) 2863 2864 2865 class IDLParametrizedType(IDLType): 2866 __slots__ = "builtin", "inner" 2867 2868 def __init__(self, location, name, innerType): 2869 IDLType.__init__(self, location, name) 2870 self.builtin = False 2871 self.inner = innerType 2872 2873 def includesRestrictedFloat(self): 2874 return self.inner.includesRestrictedFloat() 2875 2876 def resolveType(self, parentScope): 2877 assert isinstance(parentScope, IDLScope) 2878 self.inner.resolveType(parentScope) 2879 2880 def isComplete(self): 2881 return self.inner.isComplete() 2882 2883 def unroll(self): 2884 return self.inner.unroll() 2885 2886 def _getDependentObjects(self): 2887 return self.inner._getDependentObjects() 2888 2889 2890 class IDLNullableType(IDLParametrizedType): 2891 __slots__ = () 2892 2893 def __init__(self, location, innerType): 2894 assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] 2895 2896 IDLParametrizedType.__init__(self, location, None, innerType) 2897 2898 def __hash__(self): 2899 return hash(self.inner) 2900 2901 def __eq__(self, other): 2902 return isinstance(other, IDLNullableType) and self.inner == other.inner 2903 2904 def __str__(self): 2905 return self.inner.__str__() + "OrNull" 2906 2907 def prettyName(self): 2908 return self.inner.prettyName() + "?" 2909 2910 def nullable(self): 2911 return True 2912 2913 def isCallback(self): 2914 return self.inner.isCallback() 2915 2916 def isPrimitive(self): 2917 return self.inner.isPrimitive() 2918 2919 def isBoolean(self): 2920 return self.inner.isBoolean() 2921 2922 def isNumeric(self): 2923 return self.inner.isNumeric() 2924 2925 def isString(self): 2926 return self.inner.isString() 2927 2928 def isByteString(self): 2929 return self.inner.isByteString() 2930 2931 def isDOMString(self): 2932 return self.inner.isDOMString() 2933 2934 def isUSVString(self): 2935 return self.inner.isUSVString() 2936 2937 def isUTF8String(self): 2938 return self.inner.isUTF8String() 2939 2940 def isJSString(self): 2941 return self.inner.isJSString() 2942 2943 def isFloat(self): 2944 return self.inner.isFloat() 2945 2946 def isUnrestricted(self): 2947 return self.inner.isUnrestricted() 2948 2949 def isInteger(self): 2950 return self.inner.isInteger() 2951 2952 def isUndefined(self): 2953 return self.inner.isUndefined() 2954 2955 def isSequence(self): 2956 return self.inner.isSequence() 2957 2958 def isRecord(self): 2959 return self.inner.isRecord() 2960 2961 def isArrayBuffer(self): 2962 return self.inner.isArrayBuffer() 2963 2964 def isArrayBufferView(self): 2965 return self.inner.isArrayBufferView() 2966 2967 def isTypedArray(self): 2968 return self.inner.isTypedArray() 2969 2970 def isDictionary(self): 2971 return self.inner.isDictionary() 2972 2973 def isInterface(self): 2974 return self.inner.isInterface() 2975 2976 def isPromise(self): 2977 # There is no such thing as a nullable Promise. 2978 assert not self.inner.isPromise() 2979 return False 2980 2981 def isCallbackInterface(self): 2982 return self.inner.isCallbackInterface() 2983 2984 def isNonCallbackInterface(self): 2985 return self.inner.isNonCallbackInterface() 2986 2987 def isEnum(self): 2988 return self.inner.isEnum() 2989 2990 def isUnion(self): 2991 return self.inner.isUnion() 2992 2993 def isJSONType(self): 2994 return self.inner.isJSONType() 2995 2996 def isObservableArray(self): 2997 return self.inner.isObservableArray() 2998 2999 def hasClamp(self): 3000 return self.inner.hasClamp() 3001 3002 def hasEnforceRange(self): 3003 return self.inner.hasEnforceRange() 3004 3005 def hasAllowShared(self): 3006 return self.inner.hasAllowShared() 3007 3008 def isComplete(self): 3009 return self.name is not None 3010 3011 def tag(self): 3012 return self.inner.tag() 3013 3014 def complete(self, scope): 3015 if not self.inner.isComplete(): 3016 self.inner = self.inner.complete(scope) 3017 assert self.inner.isComplete() 3018 3019 if self.inner.nullable(): 3020 raise WebIDLError( 3021 "The inner type of a nullable type must not be a nullable type", 3022 [self.location, self.inner.location], 3023 ) 3024 if self.inner.isUnion(): 3025 if self.inner.hasNullableType: 3026 raise WebIDLError( 3027 "The inner type of a nullable type must not " 3028 "be a union type that itself has a nullable " 3029 "type as a member type", 3030 [self.location], 3031 ) 3032 if self.inner.isDOMString(): 3033 if self.inner.legacyNullToEmptyString: 3034 raise WebIDLError( 3035 "[LegacyNullToEmptyString] not allowed on a nullable DOMString", 3036 [self.location, self.inner.location], 3037 ) 3038 if self.inner.isObservableArray(): 3039 raise WebIDLError( 3040 "The inner type of a nullable type must not be an ObservableArray type", 3041 [self.location, self.inner.location], 3042 ) 3043 3044 self.name = self.inner.name + "OrNull" 3045 return self 3046 3047 def isDistinguishableFrom(self, other): 3048 if ( 3049 other.nullable() 3050 or other.isDictionary() 3051 or ( 3052 other.isUnion() and (other.hasNullableType or other.hasDictionaryType()) 3053 ) 3054 ): 3055 # Can't tell which type null should become 3056 return False 3057 return self.inner.isDistinguishableFrom(other) 3058 3059 def withExtendedAttributes(self, attrs): 3060 # See https://github.com/heycam/webidl/issues/827#issuecomment-565131350 3061 # Allowing extended attributes to apply to a nullable type is an intermediate solution. 3062 # A potential longer term solution is to introduce a null type and get rid of nullables. 3063 # For example, we could do `([Clamp] long or null) foo` in the future. 3064 return IDLNullableType(self.location, self.inner.withExtendedAttributes(attrs)) 3065 3066 3067 class IDLSequenceType(IDLParametrizedType): 3068 __slots__ = ("name",) 3069 3070 def __init__(self, location, parameterType): 3071 assert not parameterType.isUndefined() 3072 3073 IDLParametrizedType.__init__(self, location, parameterType.name, parameterType) 3074 # Need to set self.name up front if our inner type is already complete, 3075 # since in that case our .complete() won't be called. 3076 if self.inner.isComplete(): 3077 self.name = self.inner.name + "Sequence" 3078 3079 def __hash__(self): 3080 return hash(self.inner) 3081 3082 def __eq__(self, other): 3083 return isinstance(other, IDLSequenceType) and self.inner == other.inner 3084 3085 def __str__(self): 3086 return self.inner.__str__() + "Sequence" 3087 3088 def prettyName(self): 3089 return "sequence<%s>" % self.inner.prettyName() 3090 3091 def isSequence(self): 3092 return True 3093 3094 def isJSONType(self): 3095 return self.inner.isJSONType() 3096 3097 def tag(self): 3098 return IDLType.Tags.sequence 3099 3100 def complete(self, scope): 3101 if self.inner.isObservableArray(): 3102 raise WebIDLError( 3103 "The inner type of a sequence type must not be an ObservableArray type", 3104 [self.location, self.inner.location], 3105 ) 3106 3107 self.inner = self.inner.complete(scope) 3108 self.name = self.inner.name + "Sequence" 3109 return self 3110 3111 def isDistinguishableFrom(self, other): 3112 if other.isPromise(): 3113 return False 3114 if other.isUnion(): 3115 # Just forward to the union; it'll deal 3116 return other.isDistinguishableFrom(self) 3117 return ( 3118 other.isUndefined() 3119 or other.isPrimitive() 3120 or other.isString() 3121 or other.isEnum() 3122 or other.isInterface() 3123 or other.isDictionary() 3124 or other.isCallback() 3125 or other.isRecord() 3126 ) 3127 3128 3129 class IDLRecordType(IDLParametrizedType): 3130 __slots__ = "keyType", "name" 3131 3132 def __init__(self, location, keyType, valueType): 3133 assert keyType.isString() 3134 assert keyType.isComplete() 3135 3136 if valueType.isUndefined(): 3137 raise WebIDLError( 3138 "We don't support undefined as a Record's values' type", 3139 [location, valueType.location], 3140 ) 3141 3142 IDLParametrizedType.__init__(self, location, valueType.name, valueType) 3143 self.keyType = keyType 3144 3145 # Need to set self.name up front if our inner type is already complete, 3146 # since in that case our .complete() won't be called. 3147 if self.inner.isComplete(): 3148 self.name = self.keyType.name + self.inner.name + "Record" 3149 3150 def __hash__(self): 3151 return hash(self.inner) 3152 3153 def __eq__(self, other): 3154 return isinstance(other, IDLRecordType) and self.inner == other.inner 3155 3156 def __str__(self): 3157 return self.keyType.__str__() + self.inner.__str__() + "Record" 3158 3159 def prettyName(self): 3160 return "record<%s, %s>" % (self.keyType.prettyName(), self.inner.prettyName()) 3161 3162 def isRecord(self): 3163 return True 3164 3165 def isJSONType(self): 3166 return self.inner.isJSONType() 3167 3168 def tag(self): 3169 return IDLType.Tags.record 3170 3171 def complete(self, scope): 3172 if self.inner.isObservableArray(): 3173 raise WebIDLError( 3174 "The value type of a record type must not be an ObservableArray type", 3175 [self.location, self.inner.location], 3176 ) 3177 3178 self.inner = self.inner.complete(scope) 3179 self.name = self.keyType.name + self.inner.name + "Record" 3180 return self 3181 3182 def unroll(self): 3183 # We do not unroll our inner. Just stop at ourselves. That 3184 # lets us add headers for both ourselves and our inner as 3185 # needed. 3186 return self 3187 3188 def isDistinguishableFrom(self, other): 3189 if other.isPromise(): 3190 return False 3191 if other.isUnion(): 3192 # Just forward to the union; it'll deal 3193 return other.isDistinguishableFrom(self) 3194 if other.isCallback(): 3195 # Let other determine if it's a LegacyTreatNonObjectAsNull callback 3196 return other.isDistinguishableFrom(self) 3197 return ( 3198 other.isPrimitive() 3199 or other.isString() 3200 or other.isEnum() 3201 or other.isNonCallbackInterface() 3202 or other.isSequence() 3203 ) 3204 3205 def isExposedInAllOf(self, exposureSet): 3206 return self.inner.unroll().isExposedInAllOf(exposureSet) 3207 3208 3209 class IDLObservableArrayType(IDLParametrizedType): 3210 __slots__ = () 3211 3212 def __init__(self, location, innerType): 3213 assert not innerType.isUndefined() 3214 IDLParametrizedType.__init__(self, location, None, innerType) 3215 3216 def __hash__(self): 3217 return hash(self.inner) 3218 3219 def __eq__(self, other): 3220 return isinstance(other, IDLObservableArrayType) and self.inner == other.inner 3221 3222 def __str__(self): 3223 return self.inner.__str__() + "ObservableArray" 3224 3225 def prettyName(self): 3226 return "ObservableArray<%s>" % self.inner.prettyName() 3227 3228 def isJSONType(self): 3229 return self.inner.isJSONType() 3230 3231 def isObservableArray(self): 3232 return True 3233 3234 def isComplete(self): 3235 return self.name is not None 3236 3237 def tag(self): 3238 return IDLType.Tags.observablearray 3239 3240 def complete(self, scope): 3241 if not self.inner.isComplete(): 3242 self.inner = self.inner.complete(scope) 3243 assert self.inner.isComplete() 3244 3245 if self.inner.isDictionary(): 3246 raise WebIDLError( 3247 "The inner type of an ObservableArray type must not " 3248 "be a dictionary type", 3249 [self.location, self.inner.location], 3250 ) 3251 if self.inner.isSequence(): 3252 raise WebIDLError( 3253 "The inner type of an ObservableArray type must not " 3254 "be a sequence type", 3255 [self.location, self.inner.location], 3256 ) 3257 if self.inner.isRecord(): 3258 raise WebIDLError( 3259 "The inner type of an ObservableArray type must not be a record type", 3260 [self.location, self.inner.location], 3261 ) 3262 if self.inner.isObservableArray(): 3263 raise WebIDLError( 3264 "The inner type of an ObservableArray type must not " 3265 "be an ObservableArray type", 3266 [self.location, self.inner.location], 3267 ) 3268 3269 self.name = self.inner.name + "ObservableArray" 3270 return self 3271 3272 def isDistinguishableFrom(self, other): 3273 # ObservableArrays are not distinguishable from anything. 3274 return False 3275 3276 3277 class IDLUnionType(IDLType): 3278 __slots__ = ( 3279 "memberTypes", 3280 "hasNullableType", 3281 "_dictionaryType", 3282 "flatMemberTypes", 3283 "builtin", 3284 ) 3285 3286 def __init__(self, location, memberTypes): 3287 IDLType.__init__(self, location, "") 3288 self.memberTypes = memberTypes 3289 self.hasNullableType = False 3290 self._dictionaryType = None 3291 self.flatMemberTypes = None 3292 self.builtin = False 3293 3294 def __eq__(self, other): 3295 return isinstance(other, IDLUnionType) and self.memberTypes == other.memberTypes 3296 3297 def __hash__(self): 3298 assert self.isComplete() 3299 return self.name.__hash__() 3300 3301 def prettyName(self): 3302 return "(" + " or ".join(m.prettyName() for m in self.memberTypes) + ")" 3303 3304 def isUnion(self): 3305 return True 3306 3307 def isJSONType(self): 3308 return all(m.isJSONType() for m in self.memberTypes) 3309 3310 def includesRestrictedFloat(self): 3311 return any(t.includesRestrictedFloat() for t in self.memberTypes) 3312 3313 def tag(self): 3314 return IDLType.Tags.union 3315 3316 def resolveType(self, parentScope): 3317 assert isinstance(parentScope, IDLScope) 3318 for t in self.memberTypes: 3319 t.resolveType(parentScope) 3320 3321 def isComplete(self): 3322 return self.flatMemberTypes is not None 3323 3324 def complete(self, scope): 3325 def typeName(type): 3326 if isinstance(type, IDLNullableType): 3327 return typeName(type.inner) + "OrNull" 3328 if isinstance(type, IDLWrapperType): 3329 return typeName(type._identifier.object()) 3330 if isinstance(type, IDLObjectWithIdentifier): 3331 return typeName(type.identifier) 3332 if isinstance(type, IDLBuiltinType) and type.hasAllowShared(): 3333 assert type.isBufferSource() 3334 return "MaybeShared" + type.name 3335 return type.name 3336 3337 for i, type in enumerate(self.memberTypes): 3338 if not type.isComplete(): 3339 self.memberTypes[i] = type.complete(scope) 3340 3341 self.name = "Or".join(typeName(type) for type in self.memberTypes) 3342 self.flatMemberTypes = list(self.memberTypes) 3343 i = 0 3344 while i < len(self.flatMemberTypes): 3345 if self.flatMemberTypes[i].nullable(): 3346 if self.hasNullableType: 3347 raise WebIDLError( 3348 "Can't have more than one nullable types in a union", 3349 [nullableType.location, self.flatMemberTypes[i].location], 3350 ) 3351 if self.hasDictionaryType(): 3352 raise WebIDLError( 3353 "Can't have a nullable type and a " 3354 "dictionary type in a union", 3355 [ 3356 self._dictionaryType.location, 3357 self.flatMemberTypes[i].location, 3358 ], 3359 ) 3360 self.hasNullableType = True 3361 nullableType = self.flatMemberTypes[i] 3362 self.flatMemberTypes[i] = self.flatMemberTypes[i].inner 3363 continue 3364 if self.flatMemberTypes[i].isDictionary(): 3365 if self.hasNullableType: 3366 raise WebIDLError( 3367 "Can't have a nullable type and a " 3368 "dictionary type in a union", 3369 [nullableType.location, self.flatMemberTypes[i].location], 3370 ) 3371 self._dictionaryType = self.flatMemberTypes[i] 3372 self.flatMemberTypes[i].inner.needsConversionFromJS = True 3373 elif self.flatMemberTypes[i].isUnion(): 3374 self.flatMemberTypes[i : i + 1] = self.flatMemberTypes[i].memberTypes 3375 continue 3376 i += 1 3377 3378 for i, t in enumerate(self.flatMemberTypes[:-1]): 3379 for u in self.flatMemberTypes[i + 1 :]: 3380 if not t.isDistinguishableFrom(u): 3381 raise WebIDLError( 3382 "Flat member types of a union should be " 3383 "distinguishable, " + str(t) + " is not " 3384 "distinguishable from " + str(u), 3385 [self.location, t.location, u.location], 3386 ) 3387 3388 return self 3389 3390 def isDistinguishableFrom(self, other): 3391 if self.hasNullableType and other.nullable(): 3392 # Can't tell which type null should become 3393 return False 3394 if other.isUnion(): 3395 otherTypes = other.unroll().memberTypes 3396 else: 3397 otherTypes = [other] 3398 # For every type in otherTypes, check that it's distinguishable from 3399 # every type in our types 3400 for u in otherTypes: 3401 if any(not t.isDistinguishableFrom(u) for t in self.memberTypes): 3402 return False 3403 return True 3404 3405 def isExposedInAllOf(self, exposureSet): 3406 # We could have different member types in different globals. 3407 # Just make sure that each thing in exposureSet has one of our member types exposed in it. 3408 for globalName in exposureSet: 3409 if not any( 3410 t.unroll().isExposedInAllOf(set([globalName])) 3411 for t in self.flatMemberTypes 3412 ): 3413 return False 3414 return True 3415 3416 def hasDictionaryType(self): 3417 return self._dictionaryType is not None 3418 3419 def hasPossiblyEmptyDictionaryType(self): 3420 return ( 3421 self._dictionaryType is not None and self._dictionaryType.inner.canBeEmpty() 3422 ) 3423 3424 def _getDependentObjects(self): 3425 return set(self.memberTypes) 3426 3427 def withExtendedAttributes(self, attrs): 3428 memberTypes = list(self.memberTypes) 3429 for idx, memberType in enumerate(self.memberTypes): 3430 memberTypes[idx] = memberType.withExtendedAttributes(attrs) 3431 return IDLUnionType(self.location, memberTypes) 3432 3433 3434 class IDLTypedefType(IDLType): 3435 __slots__ = "inner", "builtin" 3436 3437 def __init__(self, location, innerType, name): 3438 IDLType.__init__(self, location, name) 3439 self.inner = innerType 3440 self.builtin = False 3441 3442 def __hash__(self): 3443 return hash(self.inner) 3444 3445 def __eq__(self, other): 3446 return isinstance(other, IDLTypedefType) and self.inner == other.inner 3447 3448 def __str__(self): 3449 return self.name 3450 3451 def nullable(self): 3452 return self.inner.nullable() 3453 3454 def isPrimitive(self): 3455 return self.inner.isPrimitive() 3456 3457 def isBoolean(self): 3458 return self.inner.isBoolean() 3459 3460 def isNumeric(self): 3461 return self.inner.isNumeric() 3462 3463 def isString(self): 3464 return self.inner.isString() 3465 3466 def isByteString(self): 3467 return self.inner.isByteString() 3468 3469 def isDOMString(self): 3470 return self.inner.isDOMString() 3471 3472 def isUSVString(self): 3473 return self.inner.isUSVString() 3474 3475 def isUTF8String(self): 3476 return self.inner.isUTF8String() 3477 3478 def isJSString(self): 3479 return self.inner.isJSString() 3480 3481 def isUndefined(self): 3482 return self.inner.isUndefined() 3483 3484 def isJSONType(self): 3485 return self.inner.isJSONType() 3486 3487 def isSequence(self): 3488 return self.inner.isSequence() 3489 3490 def isRecord(self): 3491 return self.inner.isRecord() 3492 3493 def isDictionary(self): 3494 return self.inner.isDictionary() 3495 3496 def isArrayBuffer(self): 3497 return self.inner.isArrayBuffer() 3498 3499 def isArrayBufferView(self): 3500 return self.inner.isArrayBufferView() 3501 3502 def isTypedArray(self): 3503 return self.inner.isTypedArray() 3504 3505 def isInterface(self): 3506 return self.inner.isInterface() 3507 3508 def isCallbackInterface(self): 3509 return self.inner.isCallbackInterface() 3510 3511 def isNonCallbackInterface(self): 3512 return self.inner.isNonCallbackInterface() 3513 3514 def isComplete(self): 3515 return False 3516 3517 def complete(self, parentScope): 3518 if not self.inner.isComplete(): 3519 self.inner = self.inner.complete(parentScope) 3520 assert self.inner.isComplete() 3521 return self.inner 3522 3523 # Do we need a resolveType impl? I don't think it's particularly useful.... 3524 3525 def tag(self): 3526 return self.inner.tag() 3527 3528 def unroll(self): 3529 return self.inner.unroll() 3530 3531 def isDistinguishableFrom(self, other): 3532 return self.inner.isDistinguishableFrom(other) 3533 3534 def _getDependentObjects(self): 3535 return self.inner._getDependentObjects() 3536 3537 def withExtendedAttributes(self, attrs): 3538 return IDLTypedefType( 3539 self.location, self.inner.withExtendedAttributes(attrs), self.name 3540 ) 3541 3542 3543 class IDLTypedef(IDLObjectWithIdentifier): 3544 __slots__ = ("innerType",) 3545 3546 innerType: IDLType 3547 3548 def __init__(self, location, parentScope, innerType: IDLType, identifier): 3549 # Set self.innerType first, because IDLObjectWithIdentifier.__init__ 3550 # will call our __str__, which wants to use it. 3551 self.innerType = innerType 3552 IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) 3553 3554 def __str__(self): 3555 return "Typedef %s %s" % (self.identifier.name, self.innerType) 3556 3557 def finish(self, parentScope): 3558 if not self.innerType.isComplete(): 3559 self.innerType = self.innerType.complete(parentScope) 3560 3561 def validate(self): 3562 pass 3563 3564 def isTypedef(self): 3565 return True 3566 3567 def addExtendedAttributes(self, attrs): 3568 if len(attrs) != 0: 3569 raise WebIDLError( 3570 "There are no extended attributes that are allowed on typedefs", 3571 [attrs[0].location, self.location], 3572 ) 3573 3574 def _getDependentObjects(self): 3575 return self.innerType._getDependentObjects() 3576 3577 3578 class IDLWrapperType(IDLType): 3579 __slots__ = "inner", "_identifier", "builtin" 3580 3581 def __init__(self, location, inner): 3582 IDLType.__init__(self, location, inner.identifier.name) 3583 self.inner = inner 3584 self._identifier = inner.identifier 3585 self.builtin = False 3586 3587 def __hash__(self): 3588 return hash(self._identifier) + hash(self.builtin) 3589 3590 def __eq__(self, other): 3591 return ( 3592 isinstance(other, IDLWrapperType) 3593 and self._identifier == other._identifier 3594 and self.builtin == other.builtin 3595 ) 3596 3597 def __str__(self): 3598 return str(self.name) + " (Wrapper)" 3599 3600 def isDictionary(self): 3601 return isinstance(self.inner, IDLDictionary) 3602 3603 def isInterface(self): 3604 return isinstance(self.inner, IDLInterface) or isinstance( 3605 self.inner, IDLExternalInterface 3606 ) 3607 3608 def isCallbackInterface(self): 3609 return self.isInterface() and self.inner.isCallback() 3610 3611 def isNonCallbackInterface(self): 3612 return self.isInterface() and not self.inner.isCallback() 3613 3614 def isEnum(self): 3615 return isinstance(self.inner, IDLEnum) 3616 3617 def isJSONType(self): 3618 if self.isInterface(): 3619 if self.inner.isExternal(): 3620 return False 3621 iface = self.inner 3622 while iface: 3623 if any(m.isMethod() and m.isToJSON() for m in iface.members): 3624 return True 3625 iface = iface.parent 3626 return False 3627 elif self.isEnum(): 3628 return True 3629 elif self.isDictionary(): 3630 dictionary = self.inner 3631 while dictionary: 3632 if not all(m.type.isJSONType() for m in dictionary.members): 3633 return False 3634 dictionary = dictionary.parent 3635 return True 3636 else: 3637 raise WebIDLError( 3638 "IDLWrapperType wraps type %s that we don't know if " 3639 "is serializable" % type(self.inner), 3640 [self.location], 3641 ) 3642 3643 def resolveType(self, parentScope): 3644 assert isinstance(parentScope, IDLScope) 3645 self.inner.resolve(parentScope) 3646 3647 def isComplete(self): 3648 return True 3649 3650 def tag(self): 3651 if self.isInterface(): 3652 return IDLType.Tags.interface 3653 elif self.isEnum(): 3654 return IDLType.Tags.enum 3655 elif self.isDictionary(): 3656 return IDLType.Tags.dictionary 3657 else: 3658 assert False 3659 3660 def isDistinguishableFrom(self, other): 3661 if other.isPromise(): 3662 return False 3663 if other.isUnion(): 3664 # Just forward to the union; it'll deal 3665 return other.isDistinguishableFrom(self) 3666 assert self.isInterface() or self.isEnum() or self.isDictionary() 3667 if self.isEnum(): 3668 return ( 3669 other.isUndefined() 3670 or other.isPrimitive() 3671 or other.isInterface() 3672 or other.isObject() 3673 or other.isCallback() 3674 or other.isDictionary() 3675 or other.isSequence() 3676 or other.isRecord() 3677 ) 3678 if self.isDictionary() and other.nullable(): 3679 return False 3680 if ( 3681 other.isPrimitive() 3682 or other.isString() 3683 or other.isEnum() 3684 or other.isSequence() 3685 ): 3686 return True 3687 3688 # If this needs to handle other dictionary-like types we probably need 3689 # some additional checks first. 3690 assert self.isDictionaryLike() == ( 3691 self.isDictionary() or self.isCallbackInterface() 3692 ) 3693 if self.isDictionaryLike(): 3694 if other.isCallback(): 3695 # Let other determine if it's a LegacyTreatNonObjectAsNull callback 3696 return other.isDistinguishableFrom(self) 3697 3698 assert ( 3699 other.isNonCallbackInterface() 3700 or other.isAny() 3701 or other.isUndefined() 3702 or other.isObject() 3703 or other.isDictionaryLike() 3704 ) 3705 # At this point, dictionary-like (for 'self') and interface-like 3706 # (for 'other') are the only two that are distinguishable. 3707 # any is the union of all non-union types, so it's not distinguishable 3708 # from other unions (because it is a union itself), or from all 3709 # non-union types (because it has all of them as its members). 3710 return other.isNonCallbackInterface() 3711 3712 assert self.isNonCallbackInterface() 3713 3714 if other.isUndefined() or other.isDictionaryLike() or other.isCallback(): 3715 return True 3716 3717 if other.isNonCallbackInterface(): 3718 if other.isSpiderMonkeyInterface(): 3719 # Just let |other| handle things 3720 return other.isDistinguishableFrom(self) 3721 3722 assert self.isGeckoInterface() and other.isGeckoInterface() 3723 if self.inner.isExternal() or other.unroll().inner.isExternal(): 3724 return self != other 3725 return ( 3726 len( 3727 self.inner.interfacesBasedOnSelf 3728 & other.unroll().inner.interfacesBasedOnSelf 3729 ) 3730 == 0 3731 ) 3732 3733 # Not much else |other| can be. 3734 # any is the union of all non-union types, so it's not distinguishable 3735 # from other unions (because it is a union itself), or from all 3736 # non-union types (because it has all of them as its members). 3737 assert other.isAny() or other.isObject() 3738 return False 3739 3740 def isExposedInAllOf(self, exposureSet): 3741 if not self.isInterface(): 3742 return True 3743 iface = self.inner 3744 if iface.isExternal(): 3745 # Let's say true, so we don't have to implement exposure mixins on 3746 # external interfaces and sprinkle [Exposed=Window] on every single 3747 # external interface declaration. 3748 return True 3749 return iface.exposureSet.issuperset(exposureSet) 3750 3751 def _getDependentObjects(self): 3752 # NB: The codegen for an interface type depends on 3753 # a) That the identifier is in fact an interface (as opposed to 3754 # a dictionary or something else). 3755 # b) The native type of the interface. 3756 # If we depend on the interface object we will also depend on 3757 # anything the interface depends on which is undesirable. We 3758 # considered implementing a dependency just on the interface type 3759 # file, but then every modification to an interface would cause this 3760 # to be regenerated which is still undesirable. We decided not to 3761 # depend on anything, reasoning that: 3762 # 1) Changing the concrete type of the interface requires modifying 3763 # Bindings.conf, which is still a global dependency. 3764 # 2) Changing an interface to a dictionary (or vice versa) with the 3765 # same identifier should be incredibly rare. 3766 # 3767 # On the other hand, if our type is a dictionary, we should 3768 # depend on it, because the member types of a dictionary 3769 # affect whether a method taking the dictionary as an argument 3770 # takes a JSContext* argument or not. 3771 if self.isDictionary(): 3772 return set([self.inner]) 3773 return set() 3774 3775 3776 class IDLPromiseType(IDLParametrizedType): 3777 __slots__ = () 3778 3779 def __init__(self, location, innerType): 3780 IDLParametrizedType.__init__(self, location, "Promise", innerType) 3781 3782 def __hash__(self): 3783 return hash(self.promiseInnerType()) 3784 3785 def __eq__(self, other): 3786 return ( 3787 isinstance(other, IDLPromiseType) 3788 and self.promiseInnerType() == other.promiseInnerType() 3789 ) 3790 3791 def __str__(self): 3792 return self.inner.__str__() + "Promise" 3793 3794 def prettyName(self): 3795 return "Promise<%s>" % self.inner.prettyName() 3796 3797 def isPromise(self): 3798 return True 3799 3800 def promiseInnerType(self): 3801 return self.inner 3802 3803 def tag(self): 3804 return IDLType.Tags.promise 3805 3806 def complete(self, scope): 3807 if self.inner.isObservableArray(): 3808 raise WebIDLError( 3809 "The inner type of a promise type must not be an ObservableArray type", 3810 [self.location, self.inner.location], 3811 ) 3812 3813 self.inner = self.promiseInnerType().complete(scope) 3814 return self 3815 3816 def unroll(self): 3817 # We do not unroll our inner. Just stop at ourselves. That 3818 # lets us add headers for both ourselves and our inner as 3819 # needed. 3820 return self 3821 3822 def isDistinguishableFrom(self, other): 3823 # Promises are not distinguishable from anything. 3824 return False 3825 3826 def isExposedInAllOf(self, exposureSet): 3827 # Check the internal type 3828 return self.promiseInnerType().unroll().isExposedInAllOf(exposureSet) 3829 3830 3831 class IDLBuiltinType(IDLType): 3832 Types = enum( 3833 # The integer types 3834 "byte", 3835 "octet", 3836 "short", 3837 "unsigned_short", 3838 "long", 3839 "unsigned_long", 3840 "long_long", 3841 "unsigned_long_long", 3842 # Additional primitive types 3843 "boolean", 3844 "unrestricted_float", 3845 "float", 3846 "unrestricted_double", 3847 # IMPORTANT: "double" must be the last primitive type listed 3848 "double", 3849 # Other types 3850 "any", 3851 "undefined", 3852 "domstring", 3853 "bytestring", 3854 "usvstring", 3855 "utf8string", 3856 "jsstring", 3857 "object", 3858 # Funny stuff 3859 "ArrayBuffer", 3860 "ArrayBufferView", 3861 "Int8Array", 3862 "Uint8Array", 3863 "Uint8ClampedArray", 3864 "Int16Array", 3865 "Uint16Array", 3866 "Int32Array", 3867 "Uint32Array", 3868 "Float32Array", 3869 "Float64Array", 3870 "BigInt64Array", 3871 "BigUint64Array", 3872 ) 3873 3874 TagLookup = { 3875 Types.byte: IDLType.Tags.int8, 3876 Types.octet: IDLType.Tags.uint8, 3877 Types.short: IDLType.Tags.int16, 3878 Types.unsigned_short: IDLType.Tags.uint16, 3879 Types.long: IDLType.Tags.int32, 3880 Types.unsigned_long: IDLType.Tags.uint32, 3881 Types.long_long: IDLType.Tags.int64, 3882 Types.unsigned_long_long: IDLType.Tags.uint64, 3883 Types.boolean: IDLType.Tags.bool, 3884 Types.unrestricted_float: IDLType.Tags.unrestricted_float, 3885 Types.float: IDLType.Tags.float, 3886 Types.unrestricted_double: IDLType.Tags.unrestricted_double, 3887 Types.double: IDLType.Tags.double, 3888 Types.any: IDLType.Tags.any, 3889 Types.undefined: IDLType.Tags.undefined, 3890 Types.domstring: IDLType.Tags.domstring, 3891 Types.bytestring: IDLType.Tags.bytestring, 3892 Types.usvstring: IDLType.Tags.usvstring, 3893 Types.utf8string: IDLType.Tags.utf8string, 3894 Types.jsstring: IDLType.Tags.jsstring, 3895 Types.object: IDLType.Tags.object, 3896 Types.ArrayBuffer: IDLType.Tags.interface, 3897 Types.ArrayBufferView: IDLType.Tags.interface, 3898 Types.Int8Array: IDLType.Tags.interface, 3899 Types.Uint8Array: IDLType.Tags.interface, 3900 Types.Uint8ClampedArray: IDLType.Tags.interface, 3901 Types.Int16Array: IDLType.Tags.interface, 3902 Types.Uint16Array: IDLType.Tags.interface, 3903 Types.Int32Array: IDLType.Tags.interface, 3904 Types.Uint32Array: IDLType.Tags.interface, 3905 Types.Float32Array: IDLType.Tags.interface, 3906 Types.Float64Array: IDLType.Tags.interface, 3907 Types.BigInt64Array: IDLType.Tags.interface, 3908 Types.BigUint64Array: IDLType.Tags.interface, 3909 } 3910 3911 PrettyNames = { 3912 Types.byte: "byte", 3913 Types.octet: "octet", 3914 Types.short: "short", 3915 Types.unsigned_short: "unsigned short", 3916 Types.long: "long", 3917 Types.unsigned_long: "unsigned long", 3918 Types.long_long: "long long", 3919 Types.unsigned_long_long: "unsigned long long", 3920 Types.boolean: "boolean", 3921 Types.unrestricted_float: "unrestricted float", 3922 Types.float: "float", 3923 Types.unrestricted_double: "unrestricted double", 3924 Types.double: "double", 3925 Types.any: "any", 3926 Types.undefined: "undefined", 3927 Types.domstring: "DOMString", 3928 Types.bytestring: "ByteString", 3929 Types.usvstring: "USVString", 3930 Types.utf8string: "USVString", # That's what it is in spec terms 3931 Types.jsstring: "USVString", # Again, that's what it is in spec terms 3932 Types.object: "object", 3933 Types.ArrayBuffer: "ArrayBuffer", 3934 Types.ArrayBufferView: "ArrayBufferView", 3935 Types.Int8Array: "Int8Array", 3936 Types.Uint8Array: "Uint8Array", 3937 Types.Uint8ClampedArray: "Uint8ClampedArray", 3938 Types.Int16Array: "Int16Array", 3939 Types.Uint16Array: "Uint16Array", 3940 Types.Int32Array: "Int32Array", 3941 Types.Uint32Array: "Uint32Array", 3942 Types.Float32Array: "Float32Array", 3943 Types.Float64Array: "Float64Array", 3944 Types.BigInt64Array: "BigInt64Array", 3945 Types.BigUint64Array: "BigUint64Array", 3946 } 3947 3948 __slots__ = ( 3949 "_typeTag", 3950 "_clamped", 3951 "_rangeEnforced", 3952 "_withLegacyNullToEmptyString", 3953 "_withAllowShared", 3954 ) 3955 3956 def __init__( 3957 self, 3958 location, 3959 name, 3960 type, 3961 clamp=False, 3962 enforceRange=False, 3963 legacyNullToEmptyString=False, 3964 allowShared=False, 3965 attrLocation=[], 3966 ): 3967 """ 3968 The mutually exclusive clamp/enforceRange/legacyNullToEmptyString/allowShared arguments 3969 are used to create instances of this type with the appropriate attributes attached. Use 3970 .clamped(), .rangeEnforced(), .withLegacyNullToEmptyString() and .withAllowShared(). 3971 3972 attrLocation is an array of source locations of these attributes for error reporting. 3973 """ 3974 IDLType.__init__(self, location, name) 3975 self.builtin = True 3976 self._typeTag = type 3977 self._clamped = None 3978 self._rangeEnforced = None 3979 self._withLegacyNullToEmptyString = None 3980 self._withAllowShared = None 3981 if self.isInteger(): 3982 if clamp: 3983 self._clamp = True 3984 self.name = "Clamped" + self.name 3985 self._extendedAttrDict["Clamp"] = True 3986 elif enforceRange: 3987 self._enforceRange = True 3988 self.name = "RangeEnforced" + self.name 3989 self._extendedAttrDict["EnforceRange"] = True 3990 elif clamp or enforceRange: 3991 raise WebIDLError( 3992 "Non-integer types cannot be [Clamp] or [EnforceRange]", attrLocation 3993 ) 3994 if self.isDOMString() or self.isUTF8String(): 3995 if legacyNullToEmptyString: 3996 self.legacyNullToEmptyString = True 3997 self.name = "NullIsEmpty" + self.name 3998 self._extendedAttrDict["LegacyNullToEmptyString"] = True 3999 elif legacyNullToEmptyString: 4000 raise WebIDLError( 4001 "Non-string types cannot be [LegacyNullToEmptyString]", attrLocation 4002 ) 4003 if self.isBufferSource(): 4004 if allowShared: 4005 self._allowShared = True 4006 self._extendedAttrDict["AllowShared"] = True 4007 elif allowShared: 4008 raise WebIDLError( 4009 "Types that are not buffer source types cannot be [AllowShared]", 4010 attrLocation, 4011 ) 4012 4013 def __str__(self): 4014 if self._allowShared: 4015 assert self.isBufferSource() 4016 return "MaybeShared" + str(self.name) 4017 return str(self.name) 4018 4019 def prettyName(self): 4020 return IDLBuiltinType.PrettyNames[self._typeTag] 4021 4022 def clamped(self, attrLocation): 4023 if not self._clamped: 4024 self._clamped = IDLBuiltinType( 4025 self.location, 4026 self.name, 4027 self._typeTag, 4028 clamp=True, 4029 attrLocation=attrLocation, 4030 ) 4031 return self._clamped 4032 4033 def rangeEnforced(self, attrLocation): 4034 if not self._rangeEnforced: 4035 self._rangeEnforced = IDLBuiltinType( 4036 self.location, 4037 self.name, 4038 self._typeTag, 4039 enforceRange=True, 4040 attrLocation=attrLocation, 4041 ) 4042 return self._rangeEnforced 4043 4044 def withLegacyNullToEmptyString(self, attrLocation): 4045 if not self._withLegacyNullToEmptyString: 4046 self._withLegacyNullToEmptyString = IDLBuiltinType( 4047 self.location, 4048 self.name, 4049 self._typeTag, 4050 legacyNullToEmptyString=True, 4051 attrLocation=attrLocation, 4052 ) 4053 return self._withLegacyNullToEmptyString 4054 4055 def withAllowShared(self, attrLocation): 4056 if not self._withAllowShared: 4057 self._withAllowShared = IDLBuiltinType( 4058 self.location, 4059 self.name, 4060 self._typeTag, 4061 allowShared=True, 4062 attrLocation=attrLocation, 4063 ) 4064 return self._withAllowShared 4065 4066 def isPrimitive(self): 4067 return self._typeTag <= IDLBuiltinType.Types.double 4068 4069 def isBoolean(self): 4070 return self._typeTag == IDLBuiltinType.Types.boolean 4071 4072 def isUndefined(self): 4073 return self._typeTag == IDLBuiltinType.Types.undefined 4074 4075 def isNumeric(self): 4076 return self.isPrimitive() and not self.isBoolean() 4077 4078 def isString(self): 4079 return ( 4080 self._typeTag == IDLBuiltinType.Types.domstring 4081 or self._typeTag == IDLBuiltinType.Types.bytestring 4082 or self._typeTag == IDLBuiltinType.Types.usvstring 4083 or self._typeTag == IDLBuiltinType.Types.utf8string 4084 or self._typeTag == IDLBuiltinType.Types.jsstring 4085 ) 4086 4087 def isByteString(self): 4088 return self._typeTag == IDLBuiltinType.Types.bytestring 4089 4090 def isDOMString(self): 4091 return self._typeTag == IDLBuiltinType.Types.domstring 4092 4093 def isUSVString(self): 4094 return self._typeTag == IDLBuiltinType.Types.usvstring 4095 4096 def isUTF8String(self): 4097 return self._typeTag == IDLBuiltinType.Types.utf8string 4098 4099 def isJSString(self): 4100 return self._typeTag == IDLBuiltinType.Types.jsstring 4101 4102 def isInteger(self): 4103 return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long 4104 4105 def isArrayBuffer(self): 4106 return self._typeTag == IDLBuiltinType.Types.ArrayBuffer 4107 4108 def isArrayBufferView(self): 4109 return self._typeTag == IDLBuiltinType.Types.ArrayBufferView 4110 4111 def isTypedArray(self): 4112 return ( 4113 self._typeTag >= IDLBuiltinType.Types.Int8Array 4114 and self._typeTag <= IDLBuiltinType.Types.BigUint64Array 4115 ) 4116 4117 def isInterface(self): 4118 # TypedArray things are interface types per the TypedArray spec, 4119 # but we handle them as builtins because SpiderMonkey implements 4120 # all of it internally. 4121 return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray() 4122 4123 def isNonCallbackInterface(self): 4124 # All the interfaces we can be are non-callback 4125 return self.isInterface() 4126 4127 def isFloat(self): 4128 return ( 4129 self._typeTag == IDLBuiltinType.Types.float 4130 or self._typeTag == IDLBuiltinType.Types.double 4131 or self._typeTag == IDLBuiltinType.Types.unrestricted_float 4132 or self._typeTag == IDLBuiltinType.Types.unrestricted_double 4133 ) 4134 4135 def isUnrestricted(self): 4136 assert self.isFloat() 4137 return ( 4138 self._typeTag == IDLBuiltinType.Types.unrestricted_float 4139 or self._typeTag == IDLBuiltinType.Types.unrestricted_double 4140 ) 4141 4142 def isJSONType(self): 4143 return self.isPrimitive() or self.isString() or self.isObject() 4144 4145 def includesRestrictedFloat(self): 4146 return self.isFloat() and not self.isUnrestricted() 4147 4148 def tag(self): 4149 return IDLBuiltinType.TagLookup[self._typeTag] 4150 4151 def isDistinguishableFrom(self, other): 4152 if other.isPromise(): 4153 return False 4154 if other.isUnion(): 4155 # Just forward to the union; it'll deal 4156 return other.isDistinguishableFrom(self) 4157 if self.isUndefined(): 4158 return not (other.isUndefined() or other.isDictionaryLike()) 4159 if self.isPrimitive(): 4160 if ( 4161 other.isUndefined() 4162 or other.isString() 4163 or other.isEnum() 4164 or other.isInterface() 4165 or other.isObject() 4166 or other.isCallback() 4167 or other.isDictionary() 4168 or other.isSequence() 4169 or other.isRecord() 4170 ): 4171 return True 4172 if self.isBoolean(): 4173 return other.isNumeric() 4174 assert self.isNumeric() 4175 return other.isBoolean() 4176 if self.isString(): 4177 return ( 4178 other.isUndefined() 4179 or other.isPrimitive() 4180 or other.isInterface() 4181 or other.isObject() 4182 or other.isCallback() 4183 or other.isDictionary() 4184 or other.isSequence() 4185 or other.isRecord() 4186 ) 4187 if self.isAny(): 4188 # Can't tell "any" apart from anything 4189 return False 4190 if self.isObject(): 4191 return ( 4192 other.isUndefined() 4193 or other.isPrimitive() 4194 or other.isString() 4195 or other.isEnum() 4196 ) 4197 # Not much else we could be! 4198 assert self.isSpiderMonkeyInterface() 4199 # Like interfaces, but we know we're not a callback 4200 return ( 4201 other.isUndefined() 4202 or other.isPrimitive() 4203 or other.isString() 4204 or other.isEnum() 4205 or other.isCallback() 4206 or other.isDictionary() 4207 or other.isSequence() 4208 or other.isRecord() 4209 or ( 4210 other.isInterface() 4211 and ( 4212 # ArrayBuffer is distinguishable from everything 4213 # that's not an ArrayBuffer or a callback interface 4214 (self.isArrayBuffer() and not other.isArrayBuffer()) 4215 or 4216 # ArrayBufferView is distinguishable from everything 4217 # that's not an ArrayBufferView or typed array. 4218 ( 4219 self.isArrayBufferView() 4220 and not other.isArrayBufferView() 4221 and not other.isTypedArray() 4222 ) 4223 or 4224 # Typed arrays are distinguishable from everything 4225 # except ArrayBufferView and the same type of typed 4226 # array 4227 ( 4228 self.isTypedArray() 4229 and not other.isArrayBufferView() 4230 and not (other.isTypedArray() and other.name == self.name) 4231 ) 4232 ) 4233 ) 4234 ) 4235 4236 def _getDependentObjects(self): 4237 return set() 4238 4239 def withExtendedAttributes(self, attrs): 4240 ret = self 4241 for attribute in attrs: 4242 identifier = attribute.identifier() 4243 if identifier == "Clamp": 4244 if not attribute.noArguments(): 4245 raise WebIDLError( 4246 "[Clamp] must take no arguments", [attribute.location] 4247 ) 4248 if ret.hasEnforceRange() or self._enforceRange: 4249 raise WebIDLError( 4250 "[EnforceRange] and [Clamp] are mutually exclusive", 4251 [self.location, attribute.location], 4252 ) 4253 ret = self.clamped([self.location, attribute.location]) 4254 elif identifier == "EnforceRange": 4255 if not attribute.noArguments(): 4256 raise WebIDLError( 4257 "[EnforceRange] must take no arguments", [attribute.location] 4258 ) 4259 if ret.hasClamp() or self._clamp: 4260 raise WebIDLError( 4261 "[EnforceRange] and [Clamp] are mutually exclusive", 4262 [self.location, attribute.location], 4263 ) 4264 ret = self.rangeEnforced([self.location, attribute.location]) 4265 elif identifier == "LegacyNullToEmptyString": 4266 if not (self.isDOMString() or self.isUTF8String()): 4267 raise WebIDLError( 4268 "[LegacyNullToEmptyString] only allowed on DOMStrings and UTF8Strings", 4269 [self.location, attribute.location], 4270 ) 4271 assert not self.nullable() 4272 if attribute.hasValue(): 4273 raise WebIDLError( 4274 "[LegacyNullToEmptyString] must take no identifier argument", 4275 [attribute.location], 4276 ) 4277 ret = self.withLegacyNullToEmptyString( 4278 [self.location, attribute.location] 4279 ) 4280 elif identifier == "AllowShared": 4281 if not attribute.noArguments(): 4282 raise WebIDLError( 4283 "[AllowShared] must take no arguments", [attribute.location] 4284 ) 4285 if not self.isBufferSource(): 4286 raise WebIDLError( 4287 "[AllowShared] only allowed on buffer source types", 4288 [self.location, attribute.location], 4289 ) 4290 ret = self.withAllowShared([self.location, attribute.location]) 4291 4292 else: 4293 raise WebIDLError( 4294 "Unhandled extended attribute on type", 4295 [self.location, attribute.location], 4296 ) 4297 return ret 4298 4299 4300 BuiltinTypes = { 4301 IDLBuiltinType.Types.byte: IDLBuiltinType( 4302 BuiltinLocation("<builtin type>"), "Byte", IDLBuiltinType.Types.byte 4303 ), 4304 IDLBuiltinType.Types.octet: IDLBuiltinType( 4305 BuiltinLocation("<builtin type>"), "Octet", IDLBuiltinType.Types.octet 4306 ), 4307 IDLBuiltinType.Types.short: IDLBuiltinType( 4308 BuiltinLocation("<builtin type>"), "Short", IDLBuiltinType.Types.short 4309 ), 4310 IDLBuiltinType.Types.unsigned_short: IDLBuiltinType( 4311 BuiltinLocation("<builtin type>"), 4312 "UnsignedShort", 4313 IDLBuiltinType.Types.unsigned_short, 4314 ), 4315 IDLBuiltinType.Types.long: IDLBuiltinType( 4316 BuiltinLocation("<builtin type>"), "Long", IDLBuiltinType.Types.long 4317 ), 4318 IDLBuiltinType.Types.unsigned_long: IDLBuiltinType( 4319 BuiltinLocation("<builtin type>"), 4320 "UnsignedLong", 4321 IDLBuiltinType.Types.unsigned_long, 4322 ), 4323 IDLBuiltinType.Types.long_long: IDLBuiltinType( 4324 BuiltinLocation("<builtin type>"), "LongLong", IDLBuiltinType.Types.long_long 4325 ), 4326 IDLBuiltinType.Types.unsigned_long_long: IDLBuiltinType( 4327 BuiltinLocation("<builtin type>"), 4328 "UnsignedLongLong", 4329 IDLBuiltinType.Types.unsigned_long_long, 4330 ), 4331 IDLBuiltinType.Types.undefined: IDLBuiltinType( 4332 BuiltinLocation("<builtin type>"), "Undefined", IDLBuiltinType.Types.undefined 4333 ), 4334 IDLBuiltinType.Types.boolean: IDLBuiltinType( 4335 BuiltinLocation("<builtin type>"), "Boolean", IDLBuiltinType.Types.boolean 4336 ), 4337 IDLBuiltinType.Types.float: IDLBuiltinType( 4338 BuiltinLocation("<builtin type>"), "Float", IDLBuiltinType.Types.float 4339 ), 4340 IDLBuiltinType.Types.unrestricted_float: IDLBuiltinType( 4341 BuiltinLocation("<builtin type>"), 4342 "UnrestrictedFloat", 4343 IDLBuiltinType.Types.unrestricted_float, 4344 ), 4345 IDLBuiltinType.Types.double: IDLBuiltinType( 4346 BuiltinLocation("<builtin type>"), "Double", IDLBuiltinType.Types.double 4347 ), 4348 IDLBuiltinType.Types.unrestricted_double: IDLBuiltinType( 4349 BuiltinLocation("<builtin type>"), 4350 "UnrestrictedDouble", 4351 IDLBuiltinType.Types.unrestricted_double, 4352 ), 4353 IDLBuiltinType.Types.any: IDLBuiltinType( 4354 BuiltinLocation("<builtin type>"), "Any", IDLBuiltinType.Types.any 4355 ), 4356 IDLBuiltinType.Types.domstring: IDLBuiltinType( 4357 BuiltinLocation("<builtin type>"), "String", IDLBuiltinType.Types.domstring 4358 ), 4359 IDLBuiltinType.Types.bytestring: IDLBuiltinType( 4360 BuiltinLocation("<builtin type>"), "ByteString", IDLBuiltinType.Types.bytestring 4361 ), 4362 IDLBuiltinType.Types.usvstring: IDLBuiltinType( 4363 BuiltinLocation("<builtin type>"), "USVString", IDLBuiltinType.Types.usvstring 4364 ), 4365 IDLBuiltinType.Types.utf8string: IDLBuiltinType( 4366 BuiltinLocation("<builtin type>"), "UTF8String", IDLBuiltinType.Types.utf8string 4367 ), 4368 IDLBuiltinType.Types.jsstring: IDLBuiltinType( 4369 BuiltinLocation("<builtin type>"), "JSString", IDLBuiltinType.Types.jsstring 4370 ), 4371 IDLBuiltinType.Types.object: IDLBuiltinType( 4372 BuiltinLocation("<builtin type>"), "Object", IDLBuiltinType.Types.object 4373 ), 4374 IDLBuiltinType.Types.ArrayBuffer: IDLBuiltinType( 4375 BuiltinLocation("<builtin type>"), 4376 "ArrayBuffer", 4377 IDLBuiltinType.Types.ArrayBuffer, 4378 ), 4379 IDLBuiltinType.Types.ArrayBufferView: IDLBuiltinType( 4380 BuiltinLocation("<builtin type>"), 4381 "ArrayBufferView", 4382 IDLBuiltinType.Types.ArrayBufferView, 4383 ), 4384 IDLBuiltinType.Types.Int8Array: IDLBuiltinType( 4385 BuiltinLocation("<builtin type>"), "Int8Array", IDLBuiltinType.Types.Int8Array 4386 ), 4387 IDLBuiltinType.Types.Uint8Array: IDLBuiltinType( 4388 BuiltinLocation("<builtin type>"), "Uint8Array", IDLBuiltinType.Types.Uint8Array 4389 ), 4390 IDLBuiltinType.Types.Uint8ClampedArray: IDLBuiltinType( 4391 BuiltinLocation("<builtin type>"), 4392 "Uint8ClampedArray", 4393 IDLBuiltinType.Types.Uint8ClampedArray, 4394 ), 4395 IDLBuiltinType.Types.Int16Array: IDLBuiltinType( 4396 BuiltinLocation("<builtin type>"), "Int16Array", IDLBuiltinType.Types.Int16Array 4397 ), 4398 IDLBuiltinType.Types.Uint16Array: IDLBuiltinType( 4399 BuiltinLocation("<builtin type>"), 4400 "Uint16Array", 4401 IDLBuiltinType.Types.Uint16Array, 4402 ), 4403 IDLBuiltinType.Types.Int32Array: IDLBuiltinType( 4404 BuiltinLocation("<builtin type>"), "Int32Array", IDLBuiltinType.Types.Int32Array 4405 ), 4406 IDLBuiltinType.Types.Uint32Array: IDLBuiltinType( 4407 BuiltinLocation("<builtin type>"), 4408 "Uint32Array", 4409 IDLBuiltinType.Types.Uint32Array, 4410 ), 4411 IDLBuiltinType.Types.Float32Array: IDLBuiltinType( 4412 BuiltinLocation("<builtin type>"), 4413 "Float32Array", 4414 IDLBuiltinType.Types.Float32Array, 4415 ), 4416 IDLBuiltinType.Types.Float64Array: IDLBuiltinType( 4417 BuiltinLocation("<builtin type>"), 4418 "Float64Array", 4419 IDLBuiltinType.Types.Float64Array, 4420 ), 4421 IDLBuiltinType.Types.BigInt64Array: IDLBuiltinType( 4422 BuiltinLocation("<builtin type>"), 4423 "BigInt64Array", 4424 IDLBuiltinType.Types.BigInt64Array, 4425 ), 4426 IDLBuiltinType.Types.BigUint64Array: IDLBuiltinType( 4427 BuiltinLocation("<builtin type>"), 4428 "BigUint64Array", 4429 IDLBuiltinType.Types.BigUint64Array, 4430 ), 4431 } 4432 4433 4434 integerTypeSizes = { 4435 IDLBuiltinType.Types.byte: (-128, 127), 4436 IDLBuiltinType.Types.octet: (0, 255), 4437 IDLBuiltinType.Types.short: (-32768, 32767), 4438 IDLBuiltinType.Types.unsigned_short: (0, 65535), 4439 IDLBuiltinType.Types.long: (-2147483648, 2147483647), 4440 IDLBuiltinType.Types.unsigned_long: (0, 4294967295), 4441 IDLBuiltinType.Types.long_long: (-9223372036854775808, 9223372036854775807), 4442 IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615), 4443 } 4444 4445 4446 def matchIntegerValueToType(value): 4447 for type, extremes in integerTypeSizes.items(): 4448 (min, max) = extremes 4449 if value <= max and value >= min: 4450 return BuiltinTypes[type] 4451 4452 return None 4453 4454 4455 class NoCoercionFoundError(WebIDLError): 4456 """ 4457 A class we use to indicate generic coercion failures because none of the 4458 types worked out in IDLValue.coerceToType. 4459 """ 4460 4461 4462 class IDLValue(IDLObject): 4463 __slots__ = ( 4464 "type", 4465 "value", 4466 ) 4467 4468 def __init__(self, location, type, value): 4469 IDLObject.__init__(self, location) 4470 self.type = type 4471 assert isinstance(type, IDLType) 4472 4473 self.value = value 4474 4475 def coerceToType(self, type, location): 4476 if type == self.type: 4477 return self # Nothing to do 4478 4479 # We first check for unions to ensure that even if the union is nullable 4480 # we end up with the right flat member type, not the union's type. 4481 if type.isUnion(): 4482 # We use the flat member types here, because if we have a nullable 4483 # member type, or a nested union, we want the type the value 4484 # actually coerces to, not the nullable or nested union type. 4485 for subtype in type.unroll().flatMemberTypes: 4486 try: 4487 coercedValue = self.coerceToType(subtype, location) 4488 # Create a new IDLValue to make sure that we have the 4489 # correct float/double type. This is necessary because we 4490 # use the value's type when it is a default value of a 4491 # union, and the union cares about the exact float type. 4492 return IDLValue(self.location, subtype, coercedValue.value) 4493 except Exception as e: 4494 # Make sure to propagate out WebIDLErrors that are not the 4495 # generic "hey, we could not coerce to this type at all" 4496 # exception, because those are specific "coercion failed for 4497 # reason X" exceptions. Note that we want to swallow 4498 # non-WebIDLErrors here, because those can just happen if 4499 # "type" is not something that can have a default value at 4500 # all. 4501 if isinstance(e, WebIDLError) and not isinstance( 4502 e, NoCoercionFoundError 4503 ): 4504 raise e 4505 4506 # If the type allows null, rerun this matching on the inner type, except 4507 # nullable enums. We handle those specially, because we want our 4508 # default string values to stay strings even when assigned to a nullable 4509 # enum. 4510 elif type.nullable() and not type.isEnum(): 4511 innerValue = self.coerceToType(type.inner, location) 4512 return IDLValue(self.location, type, innerValue.value) 4513 4514 elif self.type.isInteger() and type.isInteger(): 4515 # We're both integer types. See if we fit. 4516 4517 (min, max) = integerTypeSizes[type._typeTag] 4518 if self.value <= max and self.value >= min: 4519 # Promote 4520 return IDLValue(self.location, type, self.value) 4521 else: 4522 raise WebIDLError( 4523 "Value %s is out of range for type %s." % (self.value, type), 4524 [location], 4525 ) 4526 elif self.type.isInteger() and type.isFloat(): 4527 # Convert an integer literal into float 4528 if -(2**24) <= self.value <= 2**24: 4529 return IDLValue(self.location, type, float(self.value)) 4530 else: 4531 raise WebIDLError( 4532 "Converting value %s to %s will lose precision." 4533 % (self.value, type), 4534 [location], 4535 ) 4536 elif self.type.isString() and type.isEnum(): 4537 # Just keep our string, but make sure it's a valid value for this enum 4538 enum = type.unroll().inner 4539 if self.value not in enum.values(): 4540 raise WebIDLError( 4541 "'%s' is not a valid default value for enum %s" 4542 % (self.value, enum.identifier.name), 4543 [location, enum.location], 4544 ) 4545 return self 4546 elif self.type.isFloat() and type.isFloat(): 4547 if not type.isUnrestricted() and ( 4548 self.value == float("inf") 4549 or self.value == float("-inf") 4550 or math.isnan(self.value) 4551 ): 4552 raise WebIDLError( 4553 "Trying to convert unrestricted value %s to non-unrestricted" 4554 % self.value, 4555 [location], 4556 ) 4557 return IDLValue(self.location, type, self.value) 4558 elif self.type.isString() and type.isUSVString(): 4559 # Allow USVStrings to use default value just like 4560 # DOMString. No coercion is required in this case as Codegen.py 4561 # treats USVString just like DOMString, but with an 4562 # extra normalization step. 4563 assert self.type.isDOMString() 4564 return self 4565 elif self.type.isString() and ( 4566 type.isByteString() or type.isJSString() or type.isUTF8String() 4567 ): 4568 # Allow ByteStrings, UTF8String, and JSStrings to use a default 4569 # value like DOMString. 4570 # No coercion is required as Codegen.py will handle the 4571 # extra steps. We want to make sure that our string contains 4572 # only valid characters, so we check that here. 4573 valid_ascii_lit = ( 4574 " " + string.ascii_letters + string.digits + string.punctuation 4575 ) 4576 for idx, c in enumerate(self.value): 4577 if c not in valid_ascii_lit: 4578 raise WebIDLError( 4579 "Coercing this string literal %s to a ByteString is not supported yet. " 4580 "Coercion failed due to an unsupported byte %d at index %d." 4581 % (self.value.__repr__(), ord(c), idx), 4582 [location], 4583 ) 4584 4585 return IDLValue(self.location, type, self.value) 4586 elif self.type.isDOMString() and type.legacyNullToEmptyString: 4587 # LegacyNullToEmptyString is a different type for resolution reasons, 4588 # however once you have a value it doesn't matter 4589 return self 4590 4591 raise NoCoercionFoundError( 4592 "Cannot coerce type %s to type %s." % (self.type, type), [location] 4593 ) 4594 4595 def _getDependentObjects(self): 4596 return set() 4597 4598 4599 class IDLNullValue(IDLObject): 4600 __slots__ = "type", "value" 4601 4602 def __init__(self, location): 4603 IDLObject.__init__(self, location) 4604 self.type = None 4605 self.value = None 4606 4607 def coerceToType(self, type, location): 4608 if ( 4609 not isinstance(type, IDLNullableType) 4610 and not (type.isUnion() and type.hasNullableType) 4611 and not type.isAny() 4612 ): 4613 raise WebIDLError("Cannot coerce null value to type %s." % type, [location]) 4614 4615 nullValue = IDLNullValue(self.location) 4616 if type.isUnion() and not type.nullable() and type.hasDictionaryType(): 4617 # We're actually a default value for the union's dictionary member. 4618 # Use its type. 4619 for t in type.flatMemberTypes: 4620 if t.isDictionary(): 4621 nullValue.type = t 4622 return nullValue 4623 nullValue.type = type 4624 return nullValue 4625 4626 def _getDependentObjects(self): 4627 return set() 4628 4629 4630 class IDLEmptySequenceValue(IDLObject): 4631 __slots__ = "type", "value" 4632 4633 def __init__(self, location): 4634 IDLObject.__init__(self, location) 4635 self.type = None 4636 self.value = None 4637 4638 def coerceToType(self, type, location): 4639 if type.isUnion(): 4640 # We use the flat member types here, because if we have a nullable 4641 # member type, or a nested union, we want the type the value 4642 # actually coerces to, not the nullable or nested union type. 4643 for subtype in type.unroll().flatMemberTypes: 4644 try: 4645 return self.coerceToType(subtype, location) 4646 except Exception: 4647 pass 4648 4649 if not type.isSequence(): 4650 raise WebIDLError( 4651 "Cannot coerce empty sequence value to type %s." % type, [location] 4652 ) 4653 4654 emptySequenceValue = IDLEmptySequenceValue(self.location) 4655 emptySequenceValue.type = type 4656 return emptySequenceValue 4657 4658 def _getDependentObjects(self): 4659 return set() 4660 4661 4662 class IDLDefaultDictionaryValue(IDLObject): 4663 __slots__ = "type", "value" 4664 4665 def __init__(self, location): 4666 IDLObject.__init__(self, location) 4667 self.type = None 4668 self.value = None 4669 4670 def coerceToType(self, type, location): 4671 if type.isUnion(): 4672 # We use the flat member types here, because if we have a nullable 4673 # member type, or a nested union, we want the type the value 4674 # actually coerces to, not the nullable or nested union type. 4675 for subtype in type.unroll().flatMemberTypes: 4676 try: 4677 return self.coerceToType(subtype, location) 4678 except Exception: 4679 pass 4680 4681 if not type.isDictionary(): 4682 raise WebIDLError( 4683 "Cannot coerce default dictionary value to type %s." % type, [location] 4684 ) 4685 4686 defaultDictionaryValue = IDLDefaultDictionaryValue(self.location) 4687 defaultDictionaryValue.type = type 4688 return defaultDictionaryValue 4689 4690 def _getDependentObjects(self): 4691 return set() 4692 4693 4694 class IDLUndefinedValue(IDLObject): 4695 __slots__ = "type", "value" 4696 4697 def __init__(self, location): 4698 IDLObject.__init__(self, location) 4699 self.type = None 4700 self.value = None 4701 4702 def coerceToType(self, type, location): 4703 if not type.isAny(): 4704 raise WebIDLError( 4705 "Cannot coerce undefined value to type %s." % type, [location] 4706 ) 4707 4708 undefinedValue = IDLUndefinedValue(self.location) 4709 undefinedValue.type = type 4710 return undefinedValue 4711 4712 def _getDependentObjects(self): 4713 return set() 4714 4715 4716 class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): 4717 Tags = enum( 4718 "Const", "Attr", "Method", "MaplikeOrSetlike", "AsyncIterable", "Iterable" 4719 ) 4720 4721 Special = enum("Static", "Stringifier") 4722 4723 AffectsValues = ("Nothing", "Everything") 4724 DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything") 4725 4726 # no slots : multiple inheritance 4727 def __init__(self, location, identifier, tag, extendedAttrDict=None): 4728 IDLObjectWithIdentifier.__init__(self, location, None, identifier) 4729 IDLExposureMixins.__init__(self, location) 4730 self.tag = tag 4731 if extendedAttrDict is None: 4732 self._extendedAttrDict = {} 4733 else: 4734 self._extendedAttrDict = extendedAttrDict 4735 4736 def isMethod(self): 4737 return self.tag == IDLInterfaceMember.Tags.Method 4738 4739 def isAttr(self): 4740 return self.tag == IDLInterfaceMember.Tags.Attr 4741 4742 def isConst(self): 4743 return self.tag == IDLInterfaceMember.Tags.Const 4744 4745 def isMaplikeOrSetlikeOrIterable(self): 4746 return ( 4747 self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike 4748 or self.tag == IDLInterfaceMember.Tags.AsyncIterable 4749 or self.tag == IDLInterfaceMember.Tags.Iterable 4750 ) 4751 4752 def isMaplikeOrSetlike(self): 4753 return self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike 4754 4755 def addExtendedAttributes(self, attrs): 4756 for attr in attrs: 4757 self.handleExtendedAttribute(attr) 4758 attrlist = attr.listValue() 4759 self._extendedAttrDict[attr.identifier()] = ( 4760 attrlist if len(attrlist) else True 4761 ) 4762 4763 def handleExtendedAttribute(self, attr): 4764 pass 4765 4766 def getExtendedAttribute(self, name): 4767 return self._extendedAttrDict.get(name, None) 4768 4769 def finish(self, scope): 4770 IDLExposureMixins.finish(self, scope) 4771 4772 def validate(self): 4773 if self.isAttr() or self.isMethod(): 4774 if self.affects == "Everything" and self.dependsOn != "Everything": 4775 raise WebIDLError( 4776 "Interface member is flagged as affecting " 4777 "everything but not depending on everything. " 4778 "That seems rather unlikely.", 4779 [self.location], 4780 ) 4781 4782 if self.getExtendedAttribute("NewObject"): 4783 if self.dependsOn == "Nothing" or self.dependsOn == "DOMState": 4784 raise WebIDLError( 4785 "A [NewObject] method is not idempotent, " 4786 "so it has to depend on something other than DOM state.", 4787 [self.location], 4788 ) 4789 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute( 4790 "StoreInSlot" 4791 ): 4792 raise WebIDLError( 4793 "A [NewObject] attribute shouldnt be " 4794 "[Cached] or [StoreInSlot], since the point " 4795 "of those is to keep returning the same " 4796 "thing across multiple calls, which is not " 4797 "what [NewObject] does.", 4798 [self.location], 4799 ) 4800 4801 def _setDependsOn(self, dependsOn): 4802 if self.dependsOn != "Everything": 4803 raise WebIDLError( 4804 "Trying to specify multiple different DependsOn, " 4805 "Pure, or Constant extended attributes for " 4806 "attribute", 4807 [self.location], 4808 ) 4809 if dependsOn not in IDLInterfaceMember.DependsOnValues: 4810 raise WebIDLError( 4811 "Invalid [DependsOn=%s] on attribute" % dependsOn, [self.location] 4812 ) 4813 self.dependsOn = dependsOn 4814 4815 def _setAffects(self, affects): 4816 if self.affects != "Everything": 4817 raise WebIDLError( 4818 "Trying to specify multiple different Affects, " 4819 "Pure, or Constant extended attributes for " 4820 "attribute", 4821 [self.location], 4822 ) 4823 if affects not in IDLInterfaceMember.AffectsValues: 4824 raise WebIDLError( 4825 "Invalid [Affects=%s] on attribute" % affects, [self.location] 4826 ) 4827 self.affects = affects 4828 4829 def _addAlias(self, alias): 4830 if alias in self.aliases: 4831 raise WebIDLError( 4832 "Duplicate [Alias=%s] on attribute" % alias, [self.location] 4833 ) 4834 self.aliases.append(alias) 4835 4836 def _addBindingAlias(self, bindingAlias): 4837 if bindingAlias in self.bindingAliases: 4838 raise WebIDLError( 4839 "Duplicate [BindingAlias=%s] on attribute" % bindingAlias, 4840 [self.location], 4841 ) 4842 self.bindingAliases.append(bindingAlias) 4843 4844 4845 class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): 4846 __slots__ = ( 4847 "keyType", 4848 "valueType", 4849 "maplikeOrSetlikeOrIterableType", 4850 "disallowedMemberNames", 4851 "disallowedNonMethodNames", 4852 ) 4853 4854 def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind): 4855 IDLInterfaceMember.__init__(self, location, identifier, ifaceKind) 4856 if keyType is not None: 4857 assert isinstance(keyType, IDLType) 4858 else: 4859 assert valueType is not None 4860 assert ifaceType in ["maplike", "setlike", "iterable", "asynciterable"] 4861 if valueType is not None: 4862 assert isinstance(valueType, IDLType) 4863 self.keyType = keyType 4864 self.valueType = valueType 4865 self.maplikeOrSetlikeOrIterableType = ifaceType 4866 self.disallowedMemberNames = [] 4867 self.disallowedNonMethodNames = [] 4868 4869 def isMaplike(self): 4870 return self.maplikeOrSetlikeOrIterableType == "maplike" 4871 4872 def isSetlike(self): 4873 return self.maplikeOrSetlikeOrIterableType == "setlike" 4874 4875 def isIterable(self): 4876 return self.maplikeOrSetlikeOrIterableType == "iterable" 4877 4878 def isAsyncIterable(self): 4879 return self.maplikeOrSetlikeOrIterableType == "asynciterable" 4880 4881 def hasKeyType(self): 4882 return self.keyType is not None 4883 4884 def hasValueType(self): 4885 return self.valueType is not None 4886 4887 def checkCollisions(self, members, isAncestor): 4888 for member in members: 4889 # Check that there are no disallowed members 4890 if member.identifier.name in self.disallowedMemberNames and not ( 4891 ( 4892 member.isMethod() 4893 and ( 4894 member.isStatic() or member.isMaplikeOrSetlikeOrIterableMethod() 4895 ) 4896 ) 4897 or (member.isAttr() and member.isMaplikeOrSetlikeAttr()) 4898 ): 4899 raise WebIDLError( 4900 "Member '%s' conflicts " 4901 "with reserved %s name." 4902 % (member.identifier.name, self.maplikeOrSetlikeOrIterableType), 4903 [self.location, member.location], 4904 ) 4905 # Check that there are no disallowed non-method members. 4906 # Ancestor members are always disallowed here; own members 4907 # are disallowed only if they're non-methods. 4908 if ( 4909 isAncestor or member.isAttr() or member.isConst() 4910 ) and member.identifier.name in self.disallowedNonMethodNames: 4911 raise WebIDLError( 4912 "Member '%s' conflicts " 4913 "with reserved %s method." 4914 % (member.identifier.name, self.maplikeOrSetlikeOrIterableType), 4915 [self.location, member.location], 4916 ) 4917 4918 def addMethod( 4919 self, 4920 name, 4921 members, 4922 allowExistingOperations, 4923 returnType, 4924 args=[], 4925 chromeOnly=False, 4926 isPure=False, 4927 affectsNothing=False, 4928 newObject=False, 4929 isIteratorAlias=False, 4930 ): 4931 """ 4932 Create an IDLMethod based on the parameters passed in. 4933 4934 - members is the member list to add this function to, since this is 4935 called during the member expansion portion of interface object 4936 building. 4937 4938 - chromeOnly is only True for read-only js implemented classes, to 4939 implement underscore prefixed convenience functions which would 4940 otherwise not be available, unlike the case of C++ bindings. 4941 4942 - isPure is only True for idempotent functions, so it is not valid for 4943 things like keys, values, etc. that return a new object every time. 4944 4945 - affectsNothing means that nothing changes due to this method, which 4946 affects JIT optimization behavior 4947 4948 - newObject means the method creates and returns a new object. 4949 4950 """ 4951 # Only add name to lists for collision checks if it's not chrome 4952 # only. 4953 if chromeOnly: 4954 name = "__" + name 4955 else: 4956 if not allowExistingOperations: 4957 self.disallowedMemberNames.append(name) 4958 else: 4959 self.disallowedNonMethodNames.append(name) 4960 # If allowExistingOperations is True, and another operation exists 4961 # with the same name as the one we're trying to add, don't add the 4962 # maplike/setlike operation. 4963 if allowExistingOperations: 4964 for m in members: 4965 if m.identifier.name == name and m.isMethod() and not m.isStatic(): 4966 return 4967 method = IDLMethod( 4968 self.location, 4969 IDLUnresolvedIdentifier( 4970 self.location, name, allowDoubleUnderscore=chromeOnly 4971 ), 4972 returnType, 4973 args, 4974 maplikeOrSetlikeOrIterable=self, 4975 ) 4976 # We need to be able to throw from declaration methods 4977 method.addExtendedAttributes([IDLExtendedAttribute(self.location, ("Throws",))]) 4978 if chromeOnly: 4979 method.addExtendedAttributes( 4980 [IDLExtendedAttribute(self.location, ("ChromeOnly",))] 4981 ) 4982 if isPure: 4983 method.addExtendedAttributes( 4984 [IDLExtendedAttribute(self.location, ("Pure",))] 4985 ) 4986 # Following attributes are used for keys/values/entries. Can't mark 4987 # them pure, since they return a new object each time they are run. 4988 if affectsNothing: 4989 method.addExtendedAttributes( 4990 [ 4991 IDLExtendedAttribute(self.location, ("DependsOn", "Everything")), 4992 IDLExtendedAttribute(self.location, ("Affects", "Nothing")), 4993 ] 4994 ) 4995 if newObject: 4996 method.addExtendedAttributes( 4997 [IDLExtendedAttribute(self.location, ("NewObject",))] 4998 ) 4999 if isIteratorAlias: 5000 if not self.isAsyncIterable(): 5001 method.addExtendedAttributes( 5002 [IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))] 5003 ) 5004 else: 5005 method.addExtendedAttributes( 5006 [IDLExtendedAttribute(self.location, ("Alias", "@@asyncIterator"))] 5007 ) 5008 members.append(method) 5009 5010 def resolve(self, parentScope): 5011 if self.keyType: 5012 self.keyType.resolveType(parentScope) 5013 if self.valueType: 5014 self.valueType.resolveType(parentScope) 5015 5016 def finish(self, scope): 5017 IDLInterfaceMember.finish(self, scope) 5018 if self.keyType and not self.keyType.isComplete(): 5019 t = self.keyType.complete(scope) 5020 5021 assert not isinstance(t, IDLUnresolvedType) 5022 assert not isinstance(t, IDLTypedefType) 5023 assert not isinstance(t.name, IDLUnresolvedIdentifier) 5024 self.keyType = t 5025 if self.valueType and not self.valueType.isComplete(): 5026 t = self.valueType.complete(scope) 5027 5028 assert not isinstance(t, IDLUnresolvedType) 5029 assert not isinstance(t, IDLTypedefType) 5030 assert not isinstance(t.name, IDLUnresolvedIdentifier) 5031 self.valueType = t 5032 5033 def validate(self): 5034 IDLInterfaceMember.validate(self) 5035 5036 def handleExtendedAttribute(self, attr): 5037 IDLInterfaceMember.handleExtendedAttribute(self, attr) 5038 5039 def _getDependentObjects(self): 5040 deps = set() 5041 if self.keyType: 5042 deps.add(self.keyType) 5043 if self.valueType: 5044 deps.add(self.valueType) 5045 return deps 5046 5047 def getForEachArguments(self): 5048 return [ 5049 IDLArgument( 5050 self.location, 5051 IDLUnresolvedIdentifier( 5052 BuiltinLocation("<auto-generated-identifier>"), "callback" 5053 ), 5054 BuiltinTypes[IDLBuiltinType.Types.object], 5055 ), 5056 IDLArgument( 5057 self.location, 5058 IDLUnresolvedIdentifier( 5059 BuiltinLocation("<auto-generated-identifier>"), "thisArg" 5060 ), 5061 BuiltinTypes[IDLBuiltinType.Types.any], 5062 optional=True, 5063 ), 5064 ] 5065 5066 5067 # Iterable adds ES6 iterator style functions and traits 5068 # (keys/values/entries/@@iterator) to an interface. 5069 class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): 5070 __slots__ = ("iteratorType",) 5071 5072 def __init__(self, location, identifier, keyType, valueType, scope): 5073 IDLMaplikeOrSetlikeOrIterableBase.__init__( 5074 self, 5075 location, 5076 identifier, 5077 "iterable", 5078 keyType, 5079 valueType, 5080 IDLInterfaceMember.Tags.Iterable, 5081 ) 5082 self.iteratorType = None 5083 5084 def __str__(self): 5085 return "declared iterable with key '%s' and value '%s'" % ( 5086 self.keyType, 5087 self.valueType, 5088 ) 5089 5090 def expand(self, members): 5091 """ 5092 In order to take advantage of all of the method machinery in Codegen, 5093 we generate our functions as if they were part of the interface 5094 specification during parsing. 5095 """ 5096 # We only need to add entries/keys/values here if we're a pair iterator. 5097 # Value iterators just copy these from %ArrayPrototype% instead. 5098 if not self.isPairIterator(): 5099 return 5100 5101 # object entries() 5102 self.addMethod( 5103 "entries", 5104 members, 5105 False, 5106 self.iteratorType, 5107 affectsNothing=True, 5108 newObject=True, 5109 isIteratorAlias=True, 5110 ) 5111 # object keys() 5112 self.addMethod( 5113 "keys", 5114 members, 5115 False, 5116 self.iteratorType, 5117 affectsNothing=True, 5118 newObject=True, 5119 ) 5120 # object values() 5121 self.addMethod( 5122 "values", 5123 members, 5124 False, 5125 self.iteratorType, 5126 affectsNothing=True, 5127 newObject=True, 5128 ) 5129 5130 # undefined forEach(callback(valueType, keyType), optional any thisArg) 5131 self.addMethod( 5132 "forEach", 5133 members, 5134 False, 5135 BuiltinTypes[IDLBuiltinType.Types.undefined], 5136 self.getForEachArguments(), 5137 ) 5138 5139 def isValueIterator(self): 5140 return not self.isPairIterator() 5141 5142 def isPairIterator(self): 5143 return self.hasKeyType() 5144 5145 5146 class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): 5147 __slots__ = "iteratorType", "argList" 5148 5149 def __init__(self, location, identifier, keyType, valueType, argList, scope): 5150 for arg in argList: 5151 if not arg.optional: 5152 raise WebIDLError( 5153 "The arguments of the asynchronously iterable declaration on " 5154 "%s must all be optional arguments." % identifier, 5155 [arg.location], 5156 ) 5157 5158 IDLMaplikeOrSetlikeOrIterableBase.__init__( 5159 self, 5160 location, 5161 identifier, 5162 "asynciterable", 5163 keyType, 5164 valueType, 5165 IDLInterfaceMember.Tags.AsyncIterable, 5166 ) 5167 self.iteratorType = None 5168 self.argList = argList 5169 5170 def __str__(self): 5171 return "declared async_iterable with key '%s' and value '%s'" % ( 5172 self.keyType, 5173 self.valueType, 5174 ) 5175 5176 def expand(self, members): 5177 """ 5178 In order to take advantage of all of the method machinery in Codegen, 5179 we generate our functions as if they were part of the interface 5180 specification during parsing. 5181 """ 5182 # object values() 5183 self.addMethod( 5184 "values", 5185 members, 5186 False, 5187 self.iteratorType, 5188 self.argList, 5189 affectsNothing=True, 5190 newObject=True, 5191 isIteratorAlias=(not self.isPairIterator()), 5192 ) 5193 5194 # We only need to add entries/keys here if we're a pair iterator. 5195 if not self.isPairIterator(): 5196 return 5197 5198 # Methods can't share their IDLArguments, so we need to make copies here. 5199 def copyArgList(argList): 5200 return map(copy.copy, argList) 5201 5202 # object entries() 5203 self.addMethod( 5204 "entries", 5205 members, 5206 False, 5207 self.iteratorType, 5208 copyArgList(self.argList), 5209 affectsNothing=True, 5210 newObject=True, 5211 isIteratorAlias=True, 5212 ) 5213 # object keys() 5214 self.addMethod( 5215 "keys", 5216 members, 5217 False, 5218 self.iteratorType, 5219 copyArgList(self.argList), 5220 affectsNothing=True, 5221 newObject=True, 5222 ) 5223 5224 def isValueIterator(self): 5225 return not self.isPairIterator() 5226 5227 def isPairIterator(self): 5228 return self.hasKeyType() 5229 5230 5231 # MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface. 5232 class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): 5233 __slots__ = "readonly", "slotIndices", "prefix" 5234 5235 def __init__( 5236 self, location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType 5237 ): 5238 IDLMaplikeOrSetlikeOrIterableBase.__init__( 5239 self, 5240 location, 5241 identifier, 5242 maplikeOrSetlikeType, 5243 keyType, 5244 valueType, 5245 IDLInterfaceMember.Tags.MaplikeOrSetlike, 5246 ) 5247 self.readonly = readonly 5248 self.slotIndices = None 5249 5250 # When generating JSAPI access code, we need to know the backing object 5251 # type prefix to create the correct function. Generate here for reuse. 5252 if self.isMaplike(): 5253 self.prefix = "Map" 5254 elif self.isSetlike(): 5255 self.prefix = "Set" 5256 5257 def __str__(self): 5258 return "declared '%s' with key '%s'" % ( 5259 self.maplikeOrSetlikeOrIterableType, 5260 self.keyType, 5261 ) 5262 5263 def expand(self, members): 5264 """ 5265 In order to take advantage of all of the method machinery in Codegen, 5266 we generate our functions as if they were part of the interface 5267 specification during parsing. 5268 """ 5269 # Both maplike and setlike have a size attribute 5270 members.append( 5271 IDLAttribute( 5272 self.location, 5273 IDLUnresolvedIdentifier( 5274 BuiltinLocation("<auto-generated-identifier>"), "size" 5275 ), 5276 BuiltinTypes[IDLBuiltinType.Types.unsigned_long], 5277 True, 5278 maplikeOrSetlike=self, 5279 ) 5280 ) 5281 self.reserved_ro_names = ["size"] 5282 self.disallowedMemberNames.append("size") 5283 5284 # object entries() 5285 self.addMethod( 5286 "entries", 5287 members, 5288 False, 5289 BuiltinTypes[IDLBuiltinType.Types.object], 5290 affectsNothing=True, 5291 isIteratorAlias=self.isMaplike(), 5292 ) 5293 # object keys() 5294 self.addMethod( 5295 "keys", 5296 members, 5297 False, 5298 BuiltinTypes[IDLBuiltinType.Types.object], 5299 affectsNothing=True, 5300 ) 5301 # object values() 5302 self.addMethod( 5303 "values", 5304 members, 5305 False, 5306 BuiltinTypes[IDLBuiltinType.Types.object], 5307 affectsNothing=True, 5308 isIteratorAlias=self.isSetlike(), 5309 ) 5310 5311 # undefined forEach(callback(valueType, keyType), thisVal) 5312 self.addMethod( 5313 "forEach", 5314 members, 5315 False, 5316 BuiltinTypes[IDLBuiltinType.Types.undefined], 5317 self.getForEachArguments(), 5318 ) 5319 5320 def getKeyArg(): 5321 return IDLArgument( 5322 self.location, 5323 IDLUnresolvedIdentifier(self.location, "key"), 5324 self.keyType, 5325 ) 5326 5327 # boolean has(keyType key) 5328 self.addMethod( 5329 "has", 5330 members, 5331 False, 5332 BuiltinTypes[IDLBuiltinType.Types.boolean], 5333 [getKeyArg()], 5334 isPure=True, 5335 ) 5336 5337 if not self.readonly: 5338 # undefined clear() 5339 self.addMethod( 5340 "clear", members, True, BuiltinTypes[IDLBuiltinType.Types.undefined], [] 5341 ) 5342 # boolean delete(keyType key) 5343 self.addMethod( 5344 "delete", 5345 members, 5346 True, 5347 BuiltinTypes[IDLBuiltinType.Types.boolean], 5348 [getKeyArg()], 5349 ) 5350 5351 if self.isSetlike(): 5352 if not self.readonly: 5353 # Add returns the set object it just added to. 5354 # object add(keyType key) 5355 5356 self.addMethod( 5357 "add", 5358 members, 5359 True, 5360 BuiltinTypes[IDLBuiltinType.Types.object], 5361 [getKeyArg()], 5362 ) 5363 return 5364 5365 # If we get this far, we're a maplike declaration. 5366 5367 # valueType get(keyType key) 5368 # 5369 # Note that instead of the value type, we're using any here. The 5370 # validity checks should happen as things are inserted into the map, 5371 # and using any as the return type makes code generation much simpler. 5372 # 5373 # TODO: Bug 1155340 may change this to use specific type to provide 5374 # more info to JIT. 5375 self.addMethod( 5376 "get", 5377 members, 5378 False, 5379 BuiltinTypes[IDLBuiltinType.Types.any], 5380 [getKeyArg()], 5381 isPure=True, 5382 ) 5383 5384 def getValueArg(): 5385 return IDLArgument( 5386 self.location, 5387 IDLUnresolvedIdentifier(self.location, "value"), 5388 self.valueType, 5389 ) 5390 5391 if not self.readonly: 5392 self.addMethod( 5393 "set", 5394 members, 5395 True, 5396 BuiltinTypes[IDLBuiltinType.Types.object], 5397 [getKeyArg(), getValueArg()], 5398 ) 5399 5400 5401 class IDLConst(IDLInterfaceMember): 5402 __slots__ = "type", "value" 5403 5404 def __init__(self, location, identifier, type, value): 5405 IDLInterfaceMember.__init__( 5406 self, location, identifier, IDLInterfaceMember.Tags.Const 5407 ) 5408 5409 assert isinstance(type, IDLType) 5410 if type.isDictionary(): 5411 raise WebIDLError( 5412 "A constant cannot be of a dictionary type", [self.location] 5413 ) 5414 if type.isRecord(): 5415 raise WebIDLError("A constant cannot be of a record type", [self.location]) 5416 self.type = type 5417 self.value = value 5418 5419 if identifier.name == "prototype": 5420 raise WebIDLError( 5421 "The identifier of a constant must not be 'prototype'", [location] 5422 ) 5423 5424 def __str__(self): 5425 return "'%s' const '%s'" % (self.type, self.identifier) 5426 5427 def finish(self, scope): 5428 IDLInterfaceMember.finish(self, scope) 5429 5430 if not self.type.isComplete(): 5431 type = self.type.complete(scope) 5432 if not type.isPrimitive() and not type.isString(): 5433 locations = [self.type.location, type.location] 5434 try: 5435 locations.append(type.inner.location) 5436 except Exception: 5437 pass 5438 raise WebIDLError("Incorrect type for constant", locations) 5439 self.type = type 5440 5441 # The value might not match the type 5442 coercedValue = self.value.coerceToType(self.type, self.location) 5443 assert coercedValue 5444 5445 self.value = coercedValue 5446 5447 def validate(self): 5448 IDLInterfaceMember.validate(self) 5449 5450 def handleExtendedAttribute(self, attr): 5451 identifier = attr.identifier() 5452 if identifier == "Exposed": 5453 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) 5454 elif ( 5455 identifier == "Pref" 5456 or identifier == "ChromeOnly" 5457 or identifier == "Func" 5458 or identifier == "Trial" 5459 or identifier == "SecureContext" 5460 or identifier == "NonEnumerable" 5461 ): 5462 # Known attributes that we don't need to do anything with here 5463 pass 5464 else: 5465 raise WebIDLError( 5466 "Unknown extended attribute %s on constant" % identifier, 5467 [attr.location], 5468 ) 5469 IDLInterfaceMember.handleExtendedAttribute(self, attr) 5470 5471 def _getDependentObjects(self): 5472 return set([self.type, self.value]) 5473 5474 5475 class IDLAttribute(IDLInterfaceMember): 5476 __slots__ = ( 5477 "type", 5478 "readonly", 5479 "inherit", 5480 "_static", 5481 "legacyLenientThis", 5482 "_legacyUnforgeable", 5483 "stringifier", 5484 "slotIndices", 5485 "maplikeOrSetlike", 5486 "dependsOn", 5487 "affects", 5488 "bindingAliases", 5489 ) 5490 5491 def __init__( 5492 self, 5493 location, 5494 identifier, 5495 type, 5496 readonly, 5497 inherit=False, 5498 static=False, 5499 stringifier=False, 5500 maplikeOrSetlike=None, 5501 extendedAttrDict=None, 5502 ): 5503 IDLInterfaceMember.__init__( 5504 self, 5505 location, 5506 identifier, 5507 IDLInterfaceMember.Tags.Attr, 5508 extendedAttrDict=extendedAttrDict, 5509 ) 5510 5511 assert isinstance(type, IDLType) 5512 self.type = type 5513 self.readonly = readonly 5514 self.inherit = inherit 5515 self._static = static 5516 self.legacyLenientThis = False 5517 self._legacyUnforgeable = False 5518 self.stringifier = stringifier 5519 # slotIndices can be a dictionary mapping concrete interface name to 5520 # either a slot index in the binding object, or to a tuple of the slot 5521 # index in the binding object and an index in the array that's stored 5522 # in that slot. 5523 self.slotIndices = None 5524 assert maplikeOrSetlike is None or isinstance( 5525 maplikeOrSetlike, IDLMaplikeOrSetlike 5526 ) 5527 self.maplikeOrSetlike = maplikeOrSetlike 5528 self.dependsOn = "Everything" 5529 self.affects = "Everything" 5530 self.bindingAliases = [] 5531 5532 if static and identifier.name == "prototype": 5533 raise WebIDLError( 5534 "The identifier of a static attribute must not be 'prototype'", 5535 [location], 5536 ) 5537 5538 if readonly and inherit: 5539 raise WebIDLError( 5540 "An attribute cannot be both 'readonly' and 'inherit'", [self.location] 5541 ) 5542 5543 def isStatic(self): 5544 return self._static 5545 5546 def forceStatic(self): 5547 self._static = True 5548 5549 def __str__(self): 5550 return "'%s' attribute '%s'" % (self.type, self.identifier) 5551 5552 def finish(self, scope): 5553 IDLInterfaceMember.finish(self, scope) 5554 5555 if not self.type.isComplete(): 5556 t = self.type.complete(scope) 5557 5558 assert not isinstance(t, IDLUnresolvedType) 5559 assert not isinstance(t, IDLTypedefType) 5560 assert not isinstance(t.name, IDLUnresolvedIdentifier) 5561 self.type = t 5562 5563 if self.readonly and ( 5564 self.type.hasClamp() 5565 or self.type.hasEnforceRange() 5566 or self.type.hasAllowShared() 5567 or self.type.legacyNullToEmptyString 5568 ): 5569 raise WebIDLError( 5570 "A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]", 5571 [self.location], 5572 ) 5573 if self.type.isDictionary() and not self.getExtendedAttribute("Cached"): 5574 raise WebIDLError( 5575 "An attribute cannot be of a dictionary type", [self.location] 5576 ) 5577 if self.type.isSequence() and not ( 5578 self.getExtendedAttribute("Cached") 5579 or self.getExtendedAttribute("ReflectedHTMLAttributeReturningFrozenArray") 5580 ): 5581 raise WebIDLError( 5582 "A non-cached attribute cannot be of a sequence type", 5583 [self.location], 5584 ) 5585 if self.type.isRecord() and not self.getExtendedAttribute("Cached"): 5586 raise WebIDLError( 5587 "A non-cached attribute cannot be of a record type", [self.location] 5588 ) 5589 if self.type.isUnion(): 5590 for f in self.type.unroll().flatMemberTypes: 5591 if f.isDictionary(): 5592 raise WebIDLError( 5593 "An attribute cannot be of a union " 5594 "type if one of its member types (or " 5595 "one of its member types's member " 5596 "types, and so on) is a dictionary " 5597 "type", 5598 [self.location, f.location], 5599 ) 5600 if f.isSequence(): 5601 raise WebIDLError( 5602 "An attribute cannot be of a union " 5603 "type if one of its member types (or " 5604 "one of its member types's member " 5605 "types, and so on) is a sequence " 5606 "type", 5607 [self.location, f.location], 5608 ) 5609 if f.isRecord(): 5610 raise WebIDLError( 5611 "An attribute cannot be of a union " 5612 "type if one of its member types (or " 5613 "one of its member types's member " 5614 "types, and so on) is a record " 5615 "type", 5616 [self.location, f.location], 5617 ) 5618 if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"): 5619 raise WebIDLError( 5620 "An attribute with [PutForwards] must have an " 5621 "interface type as its type", 5622 [self.location], 5623 ) 5624 5625 if not self.type.isInterface() and self.getExtendedAttribute("SameObject"): 5626 raise WebIDLError( 5627 "An attribute with [SameObject] must have an " 5628 "interface type as its type", 5629 [self.location], 5630 ) 5631 5632 if self.type.isPromise() and not self.readonly: 5633 raise WebIDLError( 5634 "Promise-returning attributes must be readonly", [self.location] 5635 ) 5636 5637 if self.type.isObservableArray(): 5638 if self.isStatic(): 5639 raise WebIDLError( 5640 "A static attribute cannot have an ObservableArray type", 5641 [self.location], 5642 ) 5643 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute( 5644 "StoreInSlot" 5645 ): 5646 raise WebIDLError( 5647 "[Cached] and [StoreInSlot] must not be used " 5648 "on an attribute whose type is ObservableArray", 5649 [self.location], 5650 ) 5651 5652 def validate(self): 5653 def typeContainsChromeOnlyDictionaryMember(type): 5654 if type.nullable() or type.isSequence() or type.isRecord(): 5655 return typeContainsChromeOnlyDictionaryMember(type.inner) 5656 5657 if type.isUnion(): 5658 for memberType in type.flatMemberTypes: 5659 (contains, location) = typeContainsChromeOnlyDictionaryMember( 5660 memberType 5661 ) 5662 if contains: 5663 return (True, location) 5664 5665 if type.isDictionary(): 5666 dictionary = type.inner 5667 while dictionary: 5668 (contains, location) = dictionaryContainsChromeOnlyMember( 5669 dictionary 5670 ) 5671 if contains: 5672 return (True, location) 5673 dictionary = dictionary.parent 5674 5675 return (False, None) 5676 5677 def dictionaryContainsChromeOnlyMember(dictionary): 5678 for member in dictionary.members: 5679 if member.getExtendedAttribute("ChromeOnly"): 5680 return (True, member.location) 5681 (contains, location) = typeContainsChromeOnlyDictionaryMember( 5682 member.type 5683 ) 5684 if contains: 5685 return (True, location) 5686 return (False, None) 5687 5688 IDLInterfaceMember.validate(self) 5689 5690 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute( 5691 "StoreInSlot" 5692 ): 5693 if not self.affects == "Nothing": 5694 raise WebIDLError( 5695 "Cached attributes and attributes stored in " 5696 "slots must be Constant or Pure or " 5697 "Affects=Nothing, since the getter won't always " 5698 "be called.", 5699 [self.location], 5700 ) 5701 (contains, location) = typeContainsChromeOnlyDictionaryMember(self.type) 5702 if contains: 5703 raise WebIDLError( 5704 "[Cached] and [StoreInSlot] must not be used " 5705 "on an attribute whose type contains a " 5706 "[ChromeOnly] dictionary member", 5707 [self.location, location], 5708 ) 5709 if self.getExtendedAttribute("Frozen"): 5710 if ( 5711 not self.type.isSequence() 5712 and not self.type.isDictionary() 5713 and not self.type.isRecord() 5714 ): 5715 raise WebIDLError( 5716 "[Frozen] is only allowed on " 5717 "sequence-valued, dictionary-valued, and " 5718 "record-valued attributes", 5719 [self.location], 5720 ) 5721 if self.getExtendedAttribute("ReflectedHTMLAttributeReturningFrozenArray"): 5722 if self.getExtendedAttribute("Cached") or self.getExtendedAttribute( 5723 "StoreInSlot" 5724 ): 5725 raise WebIDLError( 5726 "[ReflectedHTMLAttributeReturningFrozenArray] can't be combined " 5727 "with [Cached] or [StoreInSlot]", 5728 [self.location], 5729 ) 5730 if not self.type.isSequence(): 5731 raise WebIDLError( 5732 "[ReflectedHTMLAttributeReturningFrozenArray] is only allowed on " 5733 "sequence-valued attributes", 5734 [self.location], 5735 ) 5736 5737 def interfaceTypeIsOrInheritsFromElement(type): 5738 return type.identifier.name == "Element" or ( 5739 type.parent is not None 5740 and interfaceTypeIsOrInheritsFromElement(type.parent) 5741 ) 5742 5743 sequenceMemberType = self.type.unroll() 5744 if ( 5745 not sequenceMemberType.isInterface() 5746 or not interfaceTypeIsOrInheritsFromElement(sequenceMemberType.inner) 5747 ): 5748 raise WebIDLError( 5749 "[ReflectedHTMLAttributeReturningFrozenArray] is only allowed on " 5750 "sequence-valued attributes containing interface values of type " 5751 "Element or an interface inheriting from Element", 5752 [self.location], 5753 ) 5754 if not self.type.unroll().isExposedInAllOf(self.exposureSet): 5755 raise WebIDLError( 5756 "Attribute returns a type that is not exposed " 5757 "everywhere where the attribute is exposed", 5758 [self.location], 5759 ) 5760 if self.getExtendedAttribute("CEReactions"): 5761 if self.readonly: 5762 raise WebIDLError( 5763 "[CEReactions] is not allowed on readonly attributes", 5764 [self.location], 5765 ) 5766 5767 def handleExtendedAttribute(self, attr): 5768 identifier = attr.identifier() 5769 if ( 5770 identifier == "SetterThrows" 5771 or identifier == "SetterCanOOM" 5772 or identifier == "SetterNeedsSubjectPrincipal" 5773 ) and self.readonly: 5774 raise WebIDLError( 5775 "Readonly attributes must not be flagged as [%s]" % identifier, 5776 [self.location], 5777 ) 5778 elif identifier == "BindingAlias": 5779 if not attr.hasValue(): 5780 raise WebIDLError( 5781 "[BindingAlias] takes an identifier or string", [attr.location] 5782 ) 5783 self._addBindingAlias(attr.value()) 5784 elif ( 5785 ( 5786 identifier == "Throws" 5787 or identifier == "GetterThrows" 5788 or identifier == "CanOOM" 5789 or identifier == "GetterCanOOM" 5790 ) 5791 and self.getExtendedAttribute("StoreInSlot") 5792 ) or ( 5793 identifier == "StoreInSlot" 5794 and ( 5795 self.getExtendedAttribute("Throws") 5796 or self.getExtendedAttribute("GetterThrows") 5797 or self.getExtendedAttribute("CanOOM") 5798 or self.getExtendedAttribute("GetterCanOOM") 5799 ) 5800 ): 5801 raise WebIDLError("Throwing things can't be [StoreInSlot]", [attr.location]) 5802 elif identifier == "LegacyLenientThis": 5803 if not attr.noArguments(): 5804 raise WebIDLError( 5805 "[LegacyLenientThis] must take no arguments", [attr.location] 5806 ) 5807 if self.isStatic(): 5808 raise WebIDLError( 5809 "[LegacyLenientThis] is only allowed on non-static attributes", 5810 [attr.location, self.location], 5811 ) 5812 if self.getExtendedAttribute("CrossOriginReadable"): 5813 raise WebIDLError( 5814 "[LegacyLenientThis] is not allowed in combination " 5815 "with [CrossOriginReadable]", 5816 [attr.location, self.location], 5817 ) 5818 if self.getExtendedAttribute("CrossOriginWritable"): 5819 raise WebIDLError( 5820 "[LegacyLenientThis] is not allowed in combination " 5821 "with [CrossOriginWritable]", 5822 [attr.location, self.location], 5823 ) 5824 self.legacyLenientThis = True 5825 elif identifier == "LegacyUnforgeable": 5826 if self.isStatic(): 5827 raise WebIDLError( 5828 "[LegacyUnforgeable] is only allowed on non-static attributes", 5829 [attr.location, self.location], 5830 ) 5831 self._legacyUnforgeable = True 5832 elif identifier == "SameObject" and not self.readonly: 5833 raise WebIDLError( 5834 "[SameObject] only allowed on readonly attributes", 5835 [attr.location, self.location], 5836 ) 5837 elif identifier == "Constant" and not self.readonly: 5838 raise WebIDLError( 5839 "[Constant] only allowed on readonly attributes", 5840 [attr.location, self.location], 5841 ) 5842 elif identifier == "PutForwards": 5843 if not self.readonly: 5844 raise WebIDLError( 5845 "[PutForwards] is only allowed on readonly attributes", 5846 [attr.location, self.location], 5847 ) 5848 if self.type.isPromise(): 5849 raise WebIDLError( 5850 "[PutForwards] is not allowed on Promise-typed attributes", 5851 [attr.location, self.location], 5852 ) 5853 if self.isStatic(): 5854 raise WebIDLError( 5855 "[PutForwards] is only allowed on non-static attributes", 5856 [attr.location, self.location], 5857 ) 5858 if self.getExtendedAttribute("Replaceable") is not None: 5859 raise WebIDLError( 5860 "[PutForwards] and [Replaceable] can't both " 5861 "appear on the same attribute", 5862 [attr.location, self.location], 5863 ) 5864 if not attr.hasValue(): 5865 raise WebIDLError( 5866 "[PutForwards] takes an identifier", [attr.location, self.location] 5867 ) 5868 elif identifier == "Replaceable": 5869 if not attr.noArguments(): 5870 raise WebIDLError( 5871 "[Replaceable] must take no arguments", [attr.location] 5872 ) 5873 if not self.readonly: 5874 raise WebIDLError( 5875 "[Replaceable] is only allowed on readonly attributes", 5876 [attr.location, self.location], 5877 ) 5878 if self.type.isPromise(): 5879 raise WebIDLError( 5880 "[Replaceable] is not allowed on Promise-typed attributes", 5881 [attr.location, self.location], 5882 ) 5883 if self.isStatic(): 5884 raise WebIDLError( 5885 "[Replaceable] is only allowed on non-static attributes", 5886 [attr.location, self.location], 5887 ) 5888 if self.getExtendedAttribute("PutForwards") is not None: 5889 raise WebIDLError( 5890 "[PutForwards] and [Replaceable] can't both " 5891 "appear on the same attribute", 5892 [attr.location, self.location], 5893 ) 5894 elif identifier == "LegacyLenientSetter": 5895 if not attr.noArguments(): 5896 raise WebIDLError( 5897 "[LegacyLenientSetter] must take no arguments", [attr.location] 5898 ) 5899 if not self.readonly: 5900 raise WebIDLError( 5901 "[LegacyLenientSetter] is only allowed on readonly attributes", 5902 [attr.location, self.location], 5903 ) 5904 if self.type.isPromise(): 5905 raise WebIDLError( 5906 "[LegacyLenientSetter] is not allowed on " 5907 "Promise-typed attributes", 5908 [attr.location, self.location], 5909 ) 5910 if self.isStatic(): 5911 raise WebIDLError( 5912 "[LegacyLenientSetter] is only allowed on non-static attributes", 5913 [attr.location, self.location], 5914 ) 5915 if self.getExtendedAttribute("PutForwards") is not None: 5916 raise WebIDLError( 5917 "[LegacyLenientSetter] and [PutForwards] can't both " 5918 "appear on the same attribute", 5919 [attr.location, self.location], 5920 ) 5921 if self.getExtendedAttribute("Replaceable") is not None: 5922 raise WebIDLError( 5923 "[LegacyLenientSetter] and [Replaceable] can't both " 5924 "appear on the same attribute", 5925 [attr.location, self.location], 5926 ) 5927 elif identifier == "LenientFloat": 5928 if self.readonly: 5929 raise WebIDLError( 5930 "[LenientFloat] used on a readonly attribute", 5931 [attr.location, self.location], 5932 ) 5933 if not self.type.includesRestrictedFloat(): 5934 raise WebIDLError( 5935 "[LenientFloat] used on an attribute with a " 5936 "non-restricted-float type", 5937 [attr.location, self.location], 5938 ) 5939 elif identifier == "StoreInSlot": 5940 if self.getExtendedAttribute("Cached"): 5941 raise WebIDLError( 5942 "[StoreInSlot] and [Cached] must not be " 5943 "specified on the same attribute", 5944 [attr.location, self.location], 5945 ) 5946 elif identifier == "Cached": 5947 if self.getExtendedAttribute("StoreInSlot"): 5948 raise WebIDLError( 5949 "[Cached] and [StoreInSlot] must not be " 5950 "specified on the same attribute", 5951 [attr.location, self.location], 5952 ) 5953 elif identifier == "CrossOriginReadable" or identifier == "CrossOriginWritable": 5954 if not attr.noArguments(): 5955 raise WebIDLError( 5956 "[%s] must take no arguments" % identifier, [attr.location] 5957 ) 5958 if self.isStatic(): 5959 raise WebIDLError( 5960 "[%s] is only allowed on non-static attributes" % identifier, 5961 [attr.location, self.location], 5962 ) 5963 if self.getExtendedAttribute("LegacyLenientThis"): 5964 raise WebIDLError( 5965 "[LegacyLenientThis] is not allowed in combination " 5966 "with [%s]" % identifier, 5967 [attr.location, self.location], 5968 ) 5969 elif identifier == "Exposed": 5970 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) 5971 elif identifier == "Pure": 5972 if not attr.noArguments(): 5973 raise WebIDLError("[Pure] must take no arguments", [attr.location]) 5974 self._setDependsOn("DOMState") 5975 self._setAffects("Nothing") 5976 elif identifier == "Constant" or identifier == "SameObject": 5977 if not attr.noArguments(): 5978 raise WebIDLError( 5979 "[%s] must take no arguments" % identifier, [attr.location] 5980 ) 5981 self._setDependsOn("Nothing") 5982 self._setAffects("Nothing") 5983 elif identifier == "Affects": 5984 if not attr.hasValue(): 5985 raise WebIDLError("[Affects] takes an identifier", [attr.location]) 5986 self._setAffects(attr.value()) 5987 elif identifier == "DependsOn": 5988 if not attr.hasValue(): 5989 raise WebIDLError("[DependsOn] takes an identifier", [attr.location]) 5990 if ( 5991 attr.value() != "Everything" 5992 and attr.value() != "DOMState" 5993 and not self.readonly 5994 ): 5995 raise WebIDLError( 5996 "[DependsOn=%s] only allowed on " 5997 "readonly attributes" % attr.value(), 5998 [attr.location, self.location], 5999 ) 6000 self._setDependsOn(attr.value()) 6001 elif identifier == "UseCounter": 6002 if self.stringifier: 6003 raise WebIDLError( 6004 "[UseCounter] must not be used on a stringifier attribute", 6005 [attr.location, self.location], 6006 ) 6007 elif identifier == "Unscopable": 6008 if not attr.noArguments(): 6009 raise WebIDLError( 6010 "[Unscopable] must take no arguments", [attr.location] 6011 ) 6012 if self.isStatic(): 6013 raise WebIDLError( 6014 "[Unscopable] is only allowed on non-static " 6015 "attributes and operations", 6016 [attr.location, self.location], 6017 ) 6018 elif identifier == "CEReactions": 6019 if not attr.noArguments(): 6020 raise WebIDLError( 6021 "[CEReactions] must take no arguments", [attr.location] 6022 ) 6023 elif ( 6024 identifier == "Pref" 6025 or identifier == "Deprecated" 6026 or identifier == "SetterThrows" 6027 or identifier == "Throws" 6028 or identifier == "GetterThrows" 6029 or identifier == "SetterCanOOM" 6030 or identifier == "CanOOM" 6031 or identifier == "GetterCanOOM" 6032 or identifier == "ChromeOnly" 6033 or identifier == "Func" 6034 or identifier == "Trial" 6035 or identifier == "SecureContext" 6036 or identifier == "Frozen" 6037 or identifier == "NewObject" 6038 or identifier == "NeedsSubjectPrincipal" 6039 or identifier == "SetterNeedsSubjectPrincipal" 6040 or identifier == "GetterNeedsSubjectPrincipal" 6041 or identifier == "NeedsCallerType" 6042 or identifier == "BinaryName" 6043 or identifier == "NonEnumerable" 6044 or identifier == "BindingTemplate" 6045 or identifier == "ReflectedHTMLAttributeReturningFrozenArray" 6046 ): 6047 # Known attributes that we don't need to do anything with here 6048 pass 6049 else: 6050 raise WebIDLError( 6051 "Unknown extended attribute %s on attribute" % identifier, 6052 [attr.location], 6053 ) 6054 IDLInterfaceMember.handleExtendedAttribute(self, attr) 6055 6056 def getExtendedAttributes(self): 6057 return self._extendedAttrDict 6058 6059 def resolve(self, parentScope): 6060 assert isinstance(parentScope, IDLScope) 6061 self.type.resolveType(parentScope) 6062 IDLObjectWithIdentifier.resolve(self, parentScope) 6063 6064 def hasLegacyLenientThis(self): 6065 return self.legacyLenientThis 6066 6067 def isMaplikeOrSetlikeAttr(self): 6068 """ 6069 True if this attribute was generated from an interface with 6070 maplike/setlike (e.g. this is the size attribute for 6071 maplike/setlike) 6072 """ 6073 return self.maplikeOrSetlike is not None 6074 6075 def isLegacyUnforgeable(self): 6076 return self._legacyUnforgeable 6077 6078 def _getDependentObjects(self): 6079 return set([self.type]) 6080 6081 def expand(self, members): 6082 assert self.stringifier 6083 if ( 6084 not self.type.isDOMString() 6085 and not self.type.isUSVString() 6086 and not self.type.isUTF8String() 6087 ): 6088 raise WebIDLError( 6089 "The type of a stringifer attribute must be " 6090 "either DOMString, USVString or UTF8String", 6091 [self.location], 6092 ) 6093 identifier = IDLUnresolvedIdentifier( 6094 self.location, "__stringifier", allowDoubleUnderscore=True 6095 ) 6096 method = IDLMethod( 6097 self.location, 6098 identifier, 6099 returnType=self.type, 6100 arguments=[], 6101 stringifier=True, 6102 underlyingAttr=self, 6103 ) 6104 allowedExtAttrs = ["Throws", "NeedsSubjectPrincipal", "Pure"] 6105 # Safe to ignore these as they are only meaningful for attributes 6106 attributeOnlyExtAttrs = [ 6107 "CEReactions", 6108 "CrossOriginWritable", 6109 "SetterThrows", 6110 ] 6111 for key, value in self._extendedAttrDict.items(): 6112 if key in allowedExtAttrs: 6113 if value is not True: 6114 raise WebIDLError( 6115 "[%s] with a value is currently " 6116 "unsupported in stringifier attributes, " 6117 "please file a bug to add support" % key, 6118 [self.location], 6119 ) 6120 method.addExtendedAttributes( 6121 [IDLExtendedAttribute(self.location, (key,))] 6122 ) 6123 elif key not in attributeOnlyExtAttrs: 6124 raise WebIDLError( 6125 "[%s] is currently unsupported in " 6126 "stringifier attributes, please file a bug " 6127 "to add support" % key, 6128 [self.location], 6129 ) 6130 members.append(method) 6131 6132 6133 class IDLArgument(IDLObjectWithIdentifier): 6134 __slots__ = ( 6135 "type", 6136 "optional", 6137 "defaultValue", 6138 "variadic", 6139 "dictionaryMember", 6140 "_isComplete", 6141 "_allowTreatNonCallableAsNull", 6142 "_extendedAttrDict", 6143 "allowTypeAttributes", 6144 ) 6145 6146 def __init__( 6147 self, 6148 location, 6149 identifier, 6150 type, 6151 optional=False, 6152 defaultValue=None, 6153 variadic=False, 6154 dictionaryMember=False, 6155 allowTypeAttributes=False, 6156 ): 6157 IDLObjectWithIdentifier.__init__(self, location, None, identifier) 6158 6159 assert isinstance(type, IDLType) 6160 self.type = type 6161 6162 self.optional = optional 6163 self.defaultValue = defaultValue 6164 self.variadic = variadic 6165 self.dictionaryMember = dictionaryMember 6166 self._isComplete = False 6167 self._allowTreatNonCallableAsNull = False 6168 self._extendedAttrDict = {} 6169 self.allowTypeAttributes = allowTypeAttributes 6170 6171 assert not variadic or optional 6172 assert not variadic or not defaultValue 6173 6174 def addExtendedAttributes(self, attrs): 6175 for attribute in attrs: 6176 identifier = attribute.identifier() 6177 if self.allowTypeAttributes and ( 6178 identifier == "EnforceRange" 6179 or identifier == "Clamp" 6180 or identifier == "LegacyNullToEmptyString" 6181 or identifier == "AllowShared" 6182 ): 6183 self.type = self.type.withExtendedAttributes([attribute]) 6184 elif identifier == "TreatNonCallableAsNull": 6185 self._allowTreatNonCallableAsNull = True 6186 elif self.dictionaryMember and ( 6187 identifier == "ChromeOnly" 6188 or identifier == "Func" 6189 or identifier == "Trial" 6190 or identifier == "Pref" 6191 ): 6192 if not self.optional: 6193 raise WebIDLError( 6194 "[%s] must not be used on a required " 6195 "dictionary member" % identifier, 6196 [attribute.location], 6197 ) 6198 elif self.dictionaryMember and identifier == "BinaryType": 6199 if not len(attribute.listValue()) == 1: 6200 raise WebIDLError( 6201 "[%s] BinaryType must take one argument" % identifier, 6202 [attribute.location], 6203 ) 6204 if not self.defaultValue: 6205 raise WebIDLError( 6206 "[%s] BinaryType can't be used without default value" 6207 % identifier, 6208 [attribute.location], 6209 ) 6210 else: 6211 raise WebIDLError( 6212 "Unhandled extended attribute on %s" 6213 % ( 6214 "a dictionary member" 6215 if self.dictionaryMember 6216 else "an argument" 6217 ), 6218 [attribute.location], 6219 ) 6220 attrlist = attribute.listValue() 6221 self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True 6222 6223 def getExtendedAttribute(self, name): 6224 return self._extendedAttrDict.get(name, None) 6225 6226 def isComplete(self): 6227 return self._isComplete 6228 6229 def complete(self, scope): 6230 if self._isComplete: 6231 return 6232 6233 self._isComplete = True 6234 6235 if not self.type.isComplete(): 6236 type = self.type.complete(scope) 6237 assert not isinstance(type, IDLUnresolvedType) 6238 assert not isinstance(type, IDLTypedefType) 6239 assert not isinstance(type.name, IDLUnresolvedIdentifier) 6240 self.type = type 6241 6242 if self.type.isUndefined(): 6243 raise WebIDLError( 6244 "undefined must not be used as the type of an argument in any circumstance", 6245 [self.location], 6246 ) 6247 6248 if self.type.isAny(): 6249 assert self.defaultValue is None or isinstance( 6250 self.defaultValue, IDLNullValue 6251 ) 6252 # optional 'any' values always have a default value 6253 if self.optional and not self.defaultValue and not self.variadic: 6254 # Set the default value to undefined, for simplicity, so the 6255 # codegen doesn't have to special-case this. 6256 self.defaultValue = IDLUndefinedValue(self.location) 6257 6258 if self.dictionaryMember and self.type.legacyNullToEmptyString: 6259 raise WebIDLError( 6260 "Dictionary members cannot be [LegacyNullToEmptyString]", 6261 [self.location], 6262 ) 6263 if self.type.isObservableArray(): 6264 raise WebIDLError( 6265 "%s cannot have an ObservableArray type" 6266 % ("Dictionary members" if self.dictionaryMember else "Arguments"), 6267 [self.location], 6268 ) 6269 # Now do the coercing thing; this needs to happen after the 6270 # above creation of a default value. 6271 if self.defaultValue: 6272 self.defaultValue = self.defaultValue.coerceToType(self.type, self.location) 6273 assert self.defaultValue 6274 6275 def allowTreatNonCallableAsNull(self): 6276 return self._allowTreatNonCallableAsNull 6277 6278 def _getDependentObjects(self): 6279 deps = set([self.type]) 6280 if self.defaultValue: 6281 deps.add(self.defaultValue) 6282 return deps 6283 6284 def canHaveMissingValue(self): 6285 return self.optional and not self.defaultValue 6286 6287 6288 class IDLCallback(IDLObjectWithScope): 6289 __slots__ = ( 6290 "_returnType", 6291 "_arguments", 6292 "_treatNonCallableAsNull", 6293 "_treatNonObjectAsNull", 6294 "_isRunScriptBoundary", 6295 "_isConstructor", 6296 ) 6297 6298 def __init__( 6299 self, location, parentScope, identifier, returnType, arguments, isConstructor 6300 ): 6301 assert isinstance(returnType, IDLType) 6302 6303 self._returnType = returnType 6304 # Clone the list 6305 self._arguments = list(arguments) 6306 6307 IDLObjectWithScope.__init__(self, location, parentScope, identifier) 6308 6309 for returnType, arguments in self.signatures(): 6310 for argument in arguments: 6311 argument.resolve(self) 6312 6313 self._treatNonCallableAsNull = False 6314 self._treatNonObjectAsNull = False 6315 self._isRunScriptBoundary = False 6316 self._isConstructor = isConstructor 6317 6318 def isCallback(self): 6319 return True 6320 6321 def isConstructor(self): 6322 return self._isConstructor 6323 6324 def signatures(self): 6325 return [(self._returnType, self._arguments)] 6326 6327 def finish(self, scope): 6328 if not self._returnType.isComplete(): 6329 type = self._returnType.complete(scope) 6330 6331 assert not isinstance(type, IDLUnresolvedType) 6332 assert not isinstance(type, IDLTypedefType) 6333 assert not isinstance(type.name, IDLUnresolvedIdentifier) 6334 self._returnType = type 6335 6336 for argument in self._arguments: 6337 if argument.type.isComplete(): 6338 continue 6339 6340 type = argument.type.complete(scope) 6341 6342 assert not isinstance(type, IDLUnresolvedType) 6343 assert not isinstance(type, IDLTypedefType) 6344 assert not isinstance(type.name, IDLUnresolvedIdentifier) 6345 argument.type = type 6346 6347 def validate(self): 6348 for argument in self._arguments: 6349 if argument.type.isUndefined(): 6350 raise WebIDLError( 6351 "undefined must not be used as the type of an argument in any circumstance", 6352 [self.location], 6353 ) 6354 6355 def addExtendedAttributes(self, attrs): 6356 unhandledAttrs = [] 6357 for attr in attrs: 6358 if attr.identifier() == "TreatNonCallableAsNull": 6359 self._treatNonCallableAsNull = True 6360 elif attr.identifier() == "LegacyTreatNonObjectAsNull": 6361 if self._isConstructor: 6362 raise WebIDLError( 6363 "[LegacyTreatNonObjectAsNull] is not supported " 6364 "on constructors", 6365 [self.location], 6366 ) 6367 self._treatNonObjectAsNull = True 6368 elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY": 6369 if self._isConstructor: 6370 raise WebIDLError( 6371 "[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not " 6372 "permitted on constructors", 6373 [self.location], 6374 ) 6375 self._isRunScriptBoundary = True 6376 else: 6377 unhandledAttrs.append(attr) 6378 if self._treatNonCallableAsNull and self._treatNonObjectAsNull: 6379 raise WebIDLError( 6380 "Cannot specify both [TreatNonCallableAsNull] " 6381 "and [LegacyTreatNonObjectAsNull]", 6382 [self.location], 6383 ) 6384 if len(unhandledAttrs) != 0: 6385 IDLType.addExtendedAttributes(self, unhandledAttrs) 6386 6387 def _getDependentObjects(self): 6388 return set([self._returnType] + self._arguments) 6389 6390 def isRunScriptBoundary(self): 6391 return self._isRunScriptBoundary 6392 6393 6394 class IDLCallbackType(IDLType): 6395 __slots__ = ("callback",) 6396 6397 def __init__(self, location, callback): 6398 IDLType.__init__(self, location, callback.identifier.name) 6399 self.callback = callback 6400 6401 def isCallback(self): 6402 return True 6403 6404 def tag(self): 6405 return IDLType.Tags.callback 6406 6407 def isDistinguishableFrom(self, other): 6408 if other.isPromise(): 6409 return False 6410 if other.isUnion(): 6411 # Just forward to the union; it'll deal 6412 return other.isDistinguishableFrom(self) 6413 # Callbacks without `LegacyTreatNonObjectAsNull` are distinguishable from Dictionary likes 6414 if other.isDictionaryLike(): 6415 return not self.callback._treatNonObjectAsNull 6416 return ( 6417 other.isUndefined() 6418 or other.isPrimitive() 6419 or other.isString() 6420 or other.isEnum() 6421 or other.isNonCallbackInterface() 6422 or other.isSequence() 6423 ) 6424 6425 def _getDependentObjects(self): 6426 return self.callback._getDependentObjects() 6427 6428 6429 class IDLMethodOverload: 6430 """ 6431 A class that represents a single overload of a WebIDL method. This is not 6432 quite the same as an element of the "effective overload set" in the spec, 6433 because separate IDLMethodOverloads are not created based on arguments being 6434 optional. Rather, when multiple methods have the same name, there is an 6435 IDLMethodOverload for each one, all hanging off an IDLMethod representing 6436 the full set of overloads. 6437 """ 6438 6439 __slots__ = "returnType", "arguments", "location" 6440 6441 def __init__(self, returnType, arguments, location): 6442 self.returnType = returnType 6443 # Clone the list of arguments, just in case 6444 self.arguments = list(arguments) 6445 self.location = location 6446 6447 def _getDependentObjects(self): 6448 deps = set(self.arguments) 6449 deps.add(self.returnType) 6450 return deps 6451 6452 def includesRestrictedFloatArgument(self): 6453 return any(arg.type.includesRestrictedFloat() for arg in self.arguments) 6454 6455 6456 class IDLMethod(IDLInterfaceMember, IDLScope): 6457 Special = enum( 6458 "Getter", "Setter", "Deleter", "LegacyCaller", base=IDLInterfaceMember.Special 6459 ) 6460 6461 NamedOrIndexed = enum("Neither", "Named", "Indexed") 6462 6463 __slots__ = ( 6464 "_hasOverloads", 6465 "_overloads", 6466 "_static", 6467 "_getter", 6468 "_setter", 6469 "_deleter", 6470 "_legacycaller", 6471 "_stringifier", 6472 "maplikeOrSetlikeOrIterable", 6473 "_htmlConstructor", 6474 "underlyingAttr", 6475 "_specialType", 6476 "_legacyUnforgeable", 6477 "dependsOn", 6478 "affects", 6479 "aliases", 6480 ) 6481 6482 def __init__( 6483 self, 6484 location, 6485 identifier, 6486 returnType, 6487 arguments, 6488 static=False, 6489 getter=False, 6490 setter=False, 6491 deleter=False, 6492 specialType=NamedOrIndexed.Neither, 6493 legacycaller=False, 6494 stringifier=False, 6495 maplikeOrSetlikeOrIterable=None, 6496 underlyingAttr=None, 6497 ): 6498 # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. 6499 IDLInterfaceMember.__init__( 6500 self, location, identifier, IDLInterfaceMember.Tags.Method 6501 ) 6502 6503 self._hasOverloads = False 6504 6505 assert isinstance(returnType, IDLType) 6506 6507 # self._overloads is a list of IDLMethodOverloads 6508 self._overloads = [IDLMethodOverload(returnType, arguments, location)] 6509 6510 assert isinstance(static, bool) 6511 self._static = static 6512 assert isinstance(getter, bool) 6513 self._getter = getter 6514 assert isinstance(setter, bool) 6515 self._setter = setter 6516 assert isinstance(deleter, bool) 6517 self._deleter = deleter 6518 assert isinstance(legacycaller, bool) 6519 self._legacycaller = legacycaller 6520 assert isinstance(stringifier, bool) 6521 self._stringifier = stringifier 6522 assert maplikeOrSetlikeOrIterable is None or isinstance( 6523 maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase 6524 ) 6525 self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable 6526 self._htmlConstructor = False 6527 self.underlyingAttr = underlyingAttr 6528 self._specialType = specialType 6529 self._legacyUnforgeable = False 6530 self.dependsOn = "Everything" 6531 self.affects = "Everything" 6532 self.aliases = [] 6533 6534 if static and identifier.name == "prototype": 6535 raise WebIDLError( 6536 "The identifier of a static operation must not be 'prototype'", 6537 [location], 6538 ) 6539 6540 # See https://github.com/whatwg/webidl/issues/1516 6541 if (setter or deleter) and not returnType.isUndefined(): 6542 raise WebIDLError( 6543 "The return type of a setter or deleter operation must be 'undefined'", 6544 [location], 6545 ) 6546 6547 self.assertSignatureConstraints() 6548 6549 def __str__(self): 6550 return "Method '%s'" % self.identifier 6551 6552 def assertSignatureConstraints(self): 6553 if self._getter or self._deleter: 6554 assert len(self._overloads) == 1 6555 overload = self._overloads[0] 6556 arguments = overload.arguments 6557 assert len(arguments) == 1 6558 assert ( 6559 arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] 6560 or arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] 6561 ) 6562 assert not arguments[0].optional and not arguments[0].variadic 6563 assert not self._getter or not overload.returnType.isUndefined() 6564 6565 if self._setter: 6566 assert len(self._overloads) == 1 6567 arguments = self._overloads[0].arguments 6568 assert len(arguments) == 2 6569 assert ( 6570 arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] 6571 or arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] 6572 ) 6573 assert not arguments[0].optional and not arguments[0].variadic 6574 assert not arguments[1].optional and not arguments[1].variadic 6575 6576 if self._stringifier: 6577 assert len(self._overloads) == 1 6578 overload = self._overloads[0] 6579 assert len(overload.arguments) == 0 6580 if not self.underlyingAttr: 6581 assert ( 6582 overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] 6583 ) 6584 6585 def isStatic(self): 6586 return self._static 6587 6588 def forceStatic(self): 6589 self._static = True 6590 6591 def isGetter(self): 6592 return self._getter 6593 6594 def isSetter(self): 6595 return self._setter 6596 6597 def isDeleter(self): 6598 return self._deleter 6599 6600 def isNamed(self): 6601 assert ( 6602 self._specialType == IDLMethod.NamedOrIndexed.Named 6603 or self._specialType == IDLMethod.NamedOrIndexed.Indexed 6604 ) 6605 return self._specialType == IDLMethod.NamedOrIndexed.Named 6606 6607 def isIndexed(self): 6608 assert ( 6609 self._specialType == IDLMethod.NamedOrIndexed.Named 6610 or self._specialType == IDLMethod.NamedOrIndexed.Indexed 6611 ) 6612 return self._specialType == IDLMethod.NamedOrIndexed.Indexed 6613 6614 def isLegacycaller(self): 6615 return self._legacycaller 6616 6617 def isStringifier(self): 6618 return self._stringifier 6619 6620 def isToJSON(self): 6621 return self.identifier.name == "toJSON" 6622 6623 def isDefaultToJSON(self): 6624 return self.isToJSON() and self.getExtendedAttribute("Default") 6625 6626 def isMaplikeOrSetlikeOrIterableMethod(self): 6627 """ 6628 True if this method was generated as part of a 6629 maplike/setlike/etc interface (e.g. has/get methods) 6630 """ 6631 return self.maplikeOrSetlikeOrIterable is not None 6632 6633 def isSpecial(self): 6634 return ( 6635 self.isGetter() 6636 or self.isSetter() 6637 or self.isDeleter() 6638 or self.isLegacycaller() 6639 or self.isStringifier() 6640 ) 6641 6642 def isHTMLConstructor(self): 6643 return self._htmlConstructor 6644 6645 def hasOverloads(self): 6646 return self._hasOverloads 6647 6648 def isIdentifierLess(self): 6649 """ 6650 True if the method name started with __, and if the method is not a 6651 maplike/setlike method. Interfaces with maplike/setlike will generate 6652 methods starting with __ for chrome only backing object access in JS 6653 implemented interfaces, so while these functions use what is considered 6654 an non-identifier name, they actually DO have an identifier. 6655 """ 6656 return ( 6657 self.identifier.name[:2] == "__" 6658 and not self.isMaplikeOrSetlikeOrIterableMethod() 6659 ) 6660 6661 def resolve(self, parentScope): 6662 assert isinstance(parentScope, IDLScope) 6663 IDLObjectWithIdentifier.resolve(self, parentScope) 6664 IDLScope.__init__(self, self.location, parentScope, self.identifier) 6665 for returnType, arguments in self.signatures(): 6666 for argument in arguments: 6667 argument.resolve(self) 6668 6669 def addOverload(self, method): 6670 assert len(method._overloads) == 1 6671 6672 if self._extendedAttrDict != method._extendedAttrDict: 6673 extendedAttrDiff = set(self._extendedAttrDict.keys()) ^ set( 6674 method._extendedAttrDict.keys() 6675 ) 6676 6677 if extendedAttrDiff == {"LenientFloat"}: 6678 if "LenientFloat" not in self._extendedAttrDict: 6679 for overload in self._overloads: 6680 if overload.includesRestrictedFloatArgument(): 6681 raise WebIDLError( 6682 "Restricted float behavior differs on different " 6683 "overloads of %s" % method.identifier, 6684 [overload.location, method.location], 6685 ) 6686 self._extendedAttrDict["LenientFloat"] = method._extendedAttrDict[ 6687 "LenientFloat" 6688 ] 6689 elif method._overloads[0].includesRestrictedFloatArgument(): 6690 raise WebIDLError( 6691 "Restricted float behavior differs on different " 6692 "overloads of %s" % method.identifier, 6693 [self.location, method.location], 6694 ) 6695 else: 6696 raise WebIDLError( 6697 "Extended attributes differ on different " 6698 "overloads of %s" % method.identifier, 6699 [self.location, method.location], 6700 ) 6701 6702 self._overloads.extend(method._overloads) 6703 6704 self._hasOverloads = True 6705 6706 if self.isStatic() != method.isStatic(): 6707 raise WebIDLError( 6708 "Overloaded identifier %s appears with different values of the 'static' attribute" 6709 % method.identifier, 6710 [method.location], 6711 ) 6712 6713 if self.isLegacycaller() != method.isLegacycaller(): 6714 raise WebIDLError( 6715 ( 6716 "Overloaded identifier %s appears with different " 6717 "values of the 'legacycaller' attribute" % method.identifier 6718 ), 6719 [method.location], 6720 ) 6721 6722 # Can't overload special things! 6723 if ( 6724 self.isGetter() 6725 or method.isGetter() 6726 or self.isSetter() 6727 or method.isSetter() 6728 or self.isDeleter() 6729 or method.isDeleter() 6730 or self.isStringifier() 6731 or method.isStringifier() 6732 ): 6733 raise WebIDLError( 6734 ("Can't overload a special operation"), 6735 [self.location, method.location], 6736 ) 6737 if self.isHTMLConstructor() or method.isHTMLConstructor(): 6738 raise WebIDLError( 6739 ( 6740 "An interface must contain only a single operation annotated with HTMLConstructor, and no others" 6741 ), 6742 [self.location, method.location], 6743 ) 6744 6745 return self 6746 6747 def signatures(self): 6748 return [ 6749 (overload.returnType, overload.arguments) for overload in self._overloads 6750 ] 6751 6752 def finish(self, scope): 6753 IDLInterfaceMember.finish(self, scope) 6754 6755 for overload in self._overloads: 6756 returnType = overload.returnType 6757 if not returnType.isComplete(): 6758 returnType = returnType.complete(scope) 6759 assert not isinstance(returnType, IDLUnresolvedType) 6760 assert not isinstance(returnType, IDLTypedefType) 6761 assert not isinstance(returnType.name, IDLUnresolvedIdentifier) 6762 overload.returnType = returnType 6763 6764 for argument in overload.arguments: 6765 if not argument.isComplete(): 6766 argument.complete(scope) 6767 assert argument.type.isComplete() 6768 6769 # Now compute various information that will be used by the 6770 # WebIDL overload resolution algorithm. 6771 self.maxArgCount = max(len(s[1]) for s in self.signatures()) 6772 self.allowedArgCounts = [ 6773 i 6774 for i in range(self.maxArgCount + 1) 6775 if len(self.signaturesForArgCount(i)) != 0 6776 ] 6777 6778 def validate(self): 6779 IDLInterfaceMember.validate(self) 6780 6781 # Make sure our overloads are properly distinguishable and don't have 6782 # different argument types before the distinguishing args. 6783 for argCount in self.allowedArgCounts: 6784 possibleOverloads = self.overloadsForArgCount(argCount) 6785 if len(possibleOverloads) == 1: 6786 continue 6787 distinguishingIndex = self.distinguishingIndexForArgCount(argCount) 6788 for idx in range(distinguishingIndex): 6789 firstSigType = possibleOverloads[0].arguments[idx].type 6790 for overload in possibleOverloads[1:]: 6791 if overload.arguments[idx].type != firstSigType: 6792 raise WebIDLError( 6793 "Signatures for method '%s' with %d arguments have " 6794 "different types of arguments at index %d, which " 6795 "is before distinguishing index %d" 6796 % ( 6797 self.identifier.name, 6798 argCount, 6799 idx, 6800 distinguishingIndex, 6801 ), 6802 [self.location, overload.location], 6803 ) 6804 6805 overloadWithPromiseReturnType = None 6806 overloadWithoutPromiseReturnType = None 6807 for overload in self._overloads: 6808 returnType = overload.returnType 6809 if not returnType.unroll().isExposedInAllOf(self.exposureSet): 6810 raise WebIDLError( 6811 "Overload returns a type that is not exposed " 6812 "everywhere where the method is exposed", 6813 [overload.location], 6814 ) 6815 6816 variadicArgument = None 6817 6818 arguments = overload.arguments 6819 for idx, argument in enumerate(arguments): 6820 assert argument.type.isComplete() 6821 6822 if ( 6823 argument.type.isDictionary() 6824 and argument.type.unroll().inner.canBeEmpty() 6825 ) or ( 6826 argument.type.isUnion() 6827 and argument.type.unroll().hasPossiblyEmptyDictionaryType() 6828 ): 6829 # Optional dictionaries and unions containing optional 6830 # dictionaries at the end of the list or followed by 6831 # optional arguments must be optional. 6832 if not argument.optional and all( 6833 arg.optional for arg in arguments[idx + 1 :] 6834 ): 6835 raise WebIDLError( 6836 "Dictionary argument without any " 6837 "required fields or union argument " 6838 "containing such dictionary not " 6839 "followed by a required argument " 6840 "must be optional", 6841 [argument.location], 6842 ) 6843 6844 if not argument.defaultValue and all( 6845 arg.optional for arg in arguments[idx + 1 :] 6846 ): 6847 raise WebIDLError( 6848 "Dictionary argument without any " 6849 "required fields or union argument " 6850 "containing such dictionary not " 6851 "followed by a required argument " 6852 "must have a default value", 6853 [argument.location], 6854 ) 6855 6856 # An argument cannot be a nullable dictionary or a 6857 # nullable union containing a dictionary. 6858 if argument.type.nullable() and ( 6859 argument.type.isDictionary() 6860 or ( 6861 argument.type.isUnion() 6862 and argument.type.unroll().hasDictionaryType() 6863 ) 6864 ): 6865 raise WebIDLError( 6866 "An argument cannot be a nullable " 6867 "dictionary or nullable union " 6868 "containing a dictionary", 6869 [argument.location], 6870 ) 6871 6872 # Only the last argument can be variadic 6873 if variadicArgument: 6874 raise WebIDLError( 6875 "Variadic argument is not last argument", 6876 [variadicArgument.location], 6877 ) 6878 if argument.variadic: 6879 variadicArgument = argument 6880 6881 if returnType.isPromise(): 6882 overloadWithPromiseReturnType = overload 6883 else: 6884 overloadWithoutPromiseReturnType = overload 6885 6886 # Make sure either all our overloads return Promises or none do 6887 if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType: 6888 raise WebIDLError( 6889 "We have overloads with both Promise and non-Promise return types", 6890 [ 6891 overloadWithPromiseReturnType.location, 6892 overloadWithoutPromiseReturnType.location, 6893 ], 6894 ) 6895 6896 if overloadWithPromiseReturnType and self._legacycaller: 6897 raise WebIDLError( 6898 "May not have a Promise return type for a legacycaller.", 6899 [overloadWithPromiseReturnType.location], 6900 ) 6901 6902 if self.getExtendedAttribute("StaticClassOverride") and not ( 6903 self.identifier.scope.isJSImplemented() and self.isStatic() 6904 ): 6905 raise WebIDLError( 6906 "StaticClassOverride can be applied to static" 6907 " methods on JS-implemented classes only.", 6908 [self.location], 6909 ) 6910 6911 # Ensure that toJSON methods satisfy the spec constraints on them. 6912 if self.identifier.name == "toJSON": 6913 if len(self.signatures()) != 1: 6914 raise WebIDLError( 6915 "toJSON method has multiple overloads", 6916 [self._overloads[0].location, self._overloads[1].location], 6917 ) 6918 if len(self.signatures()[0][1]) != 0: 6919 raise WebIDLError("toJSON method has arguments", [self.location]) 6920 if not self.signatures()[0][0].isJSONType(): 6921 raise WebIDLError( 6922 "toJSON method has non-JSON return type", [self.location] 6923 ) 6924 6925 def overloadsForArgCount(self, argc): 6926 return [ 6927 overload 6928 for overload in self._overloads 6929 if len(overload.arguments) == argc 6930 or ( 6931 len(overload.arguments) > argc 6932 and all(arg.optional for arg in overload.arguments[argc:]) 6933 ) 6934 or ( 6935 len(overload.arguments) < argc 6936 and len(overload.arguments) > 0 6937 and overload.arguments[-1].variadic 6938 ) 6939 ] 6940 6941 def signaturesForArgCount(self, argc): 6942 return [ 6943 (overload.returnType, overload.arguments) 6944 for overload in self.overloadsForArgCount(argc) 6945 ] 6946 6947 def locationsForArgCount(self, argc): 6948 return [overload.location for overload in self.overloadsForArgCount(argc)] 6949 6950 def distinguishingIndexForArgCount(self, argc): 6951 def isValidDistinguishingIndex(idx, signatures): 6952 for firstSigIndex, (firstRetval, firstArgs) in enumerate(signatures[:-1]): 6953 for secondRetval, secondArgs in signatures[firstSigIndex + 1 :]: 6954 if idx < len(firstArgs): 6955 firstType = firstArgs[idx].type 6956 else: 6957 assert firstArgs[-1].variadic 6958 firstType = firstArgs[-1].type 6959 if idx < len(secondArgs): 6960 secondType = secondArgs[idx].type 6961 else: 6962 assert secondArgs[-1].variadic 6963 secondType = secondArgs[-1].type 6964 if not firstType.isDistinguishableFrom(secondType): 6965 return False 6966 return True 6967 6968 signatures = self.signaturesForArgCount(argc) 6969 for idx in range(argc): 6970 if isValidDistinguishingIndex(idx, signatures): 6971 return idx 6972 # No valid distinguishing index. Time to throw 6973 locations = self.locationsForArgCount(argc) 6974 raise WebIDLError( 6975 "Signatures with %d arguments for method '%s' are not " 6976 "distinguishable" % (argc, self.identifier.name), 6977 locations, 6978 ) 6979 6980 def handleExtendedAttribute(self, attr): 6981 identifier = attr.identifier() 6982 if ( 6983 identifier == "GetterThrows" 6984 or identifier == "SetterThrows" 6985 or identifier == "GetterCanOOM" 6986 or identifier == "SetterCanOOM" 6987 or identifier == "SetterNeedsSubjectPrincipal" 6988 or identifier == "GetterNeedsSubjectPrincipal" 6989 ): 6990 raise WebIDLError( 6991 "Methods must not be flagged as [%s]" % identifier, 6992 [attr.location, self.location], 6993 ) 6994 elif identifier == "LegacyUnforgeable": 6995 if self.isStatic(): 6996 raise WebIDLError( 6997 "[LegacyUnforgeable] is only allowed on non-static methods", 6998 [attr.location, self.location], 6999 ) 7000 self._legacyUnforgeable = True 7001 elif identifier == "SameObject": 7002 raise WebIDLError( 7003 "Methods must not be flagged as [SameObject]", 7004 [attr.location, self.location], 7005 ) 7006 elif identifier == "Constant": 7007 raise WebIDLError( 7008 "Methods must not be flagged as [Constant]", 7009 [attr.location, self.location], 7010 ) 7011 elif identifier == "PutForwards": 7012 raise WebIDLError( 7013 "Only attributes support [PutForwards]", [attr.location, self.location] 7014 ) 7015 elif identifier == "LegacyLenientSetter": 7016 raise WebIDLError( 7017 "Only attributes support [LegacyLenientSetter]", 7018 [attr.location, self.location], 7019 ) 7020 elif identifier == "LenientFloat": 7021 # This is called before we've done overload resolution 7022 overloads = self._overloads 7023 assert len(overloads) == 1 7024 if not overloads[0].returnType.isUndefined(): 7025 raise WebIDLError( 7026 "[LenientFloat] used on a non-undefined method", 7027 [attr.location, self.location], 7028 ) 7029 if not overloads[0].includesRestrictedFloatArgument(): 7030 raise WebIDLError( 7031 "[LenientFloat] used on an operation with no " 7032 "restricted float type arguments", 7033 [attr.location, self.location], 7034 ) 7035 elif identifier == "Exposed": 7036 convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) 7037 elif ( 7038 identifier == "CrossOriginCallable" 7039 or identifier == "WebGLHandlesContextLoss" 7040 ): 7041 # Known no-argument attributes. 7042 if not attr.noArguments(): 7043 raise WebIDLError( 7044 "[%s] must take no arguments" % identifier, [attr.location] 7045 ) 7046 if identifier == "CrossOriginCallable" and self.isStatic(): 7047 raise WebIDLError( 7048 "[CrossOriginCallable] is only allowed on non-static attributes", 7049 [attr.location, self.location], 7050 ) 7051 elif identifier == "Pure": 7052 if not attr.noArguments(): 7053 raise WebIDLError("[Pure] must take no arguments", [attr.location]) 7054 self._setDependsOn("DOMState") 7055 self._setAffects("Nothing") 7056 elif identifier == "Affects": 7057 if not attr.hasValue(): 7058 raise WebIDLError("[Affects] takes an identifier", [attr.location]) 7059 self._setAffects(attr.value()) 7060 elif identifier == "DependsOn": 7061 if not attr.hasValue(): 7062 raise WebIDLError("[DependsOn] takes an identifier", [attr.location]) 7063 self._setDependsOn(attr.value()) 7064 elif identifier == "Alias": 7065 if not attr.hasValue(): 7066 raise WebIDLError( 7067 "[Alias] takes an identifier or string", [attr.location] 7068 ) 7069 self._addAlias(attr.value()) 7070 elif identifier == "UseCounter": 7071 if self.isSpecial(): 7072 raise WebIDLError( 7073 "[UseCounter] must not be used on a special operation", 7074 [attr.location, self.location], 7075 ) 7076 elif identifier == "Unscopable": 7077 if not attr.noArguments(): 7078 raise WebIDLError( 7079 "[Unscopable] must take no arguments", [attr.location] 7080 ) 7081 if self.isStatic(): 7082 raise WebIDLError( 7083 "[Unscopable] is only allowed on non-static " 7084 "attributes and operations", 7085 [attr.location, self.location], 7086 ) 7087 elif identifier == "CEReactions": 7088 if not attr.noArguments(): 7089 raise WebIDLError( 7090 "[CEReactions] must take no arguments", [attr.location] 7091 ) 7092 7093 if self.isSpecial() and not self.isSetter() and not self.isDeleter(): 7094 raise WebIDLError( 7095 "[CEReactions] is only allowed on operation, " 7096 "attribute, setter, and deleter", 7097 [attr.location, self.location], 7098 ) 7099 elif identifier == "Default": 7100 if not attr.noArguments(): 7101 raise WebIDLError("[Default] must take no arguments", [attr.location]) 7102 7103 if not self.isToJSON(): 7104 raise WebIDLError( 7105 "[Default] is only allowed on toJSON operations", 7106 [attr.location, self.location], 7107 ) 7108 7109 if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]: 7110 raise WebIDLError( 7111 "The return type of the default toJSON " 7112 "operation must be 'object'", 7113 [attr.location, self.location], 7114 ) 7115 elif ( 7116 identifier == "Throws" 7117 or identifier == "CanOOM" 7118 or identifier == "NewObject" 7119 or identifier == "ChromeOnly" 7120 or identifier == "Pref" 7121 or identifier == "Deprecated" 7122 or identifier == "Func" 7123 or identifier == "Trial" 7124 or identifier == "SecureContext" 7125 or identifier == "BinaryName" 7126 or identifier == "NeedsSubjectPrincipal" 7127 or identifier == "NeedsCallerType" 7128 or identifier == "StaticClassOverride" 7129 or identifier == "NonEnumerable" 7130 or identifier == "Unexposed" 7131 or identifier == "WebExtensionStub" 7132 ): 7133 # Known attributes that we don't need to do anything with here 7134 pass 7135 else: 7136 raise WebIDLError( 7137 "Unknown extended attribute %s on method" % identifier, [attr.location] 7138 ) 7139 IDLInterfaceMember.handleExtendedAttribute(self, attr) 7140 7141 def returnsPromise(self): 7142 return self._overloads[0].returnType.isPromise() 7143 7144 def isLegacyUnforgeable(self): 7145 return self._legacyUnforgeable 7146 7147 def _getDependentObjects(self): 7148 deps = set() 7149 for overload in self._overloads: 7150 deps.update(overload._getDependentObjects()) 7151 return deps 7152 7153 7154 class IDLConstructor(IDLMethod): 7155 __slots__ = ( 7156 "_initLocation", 7157 "_initArgs", 7158 "_initName", 7159 "_inited", 7160 "_initExtendedAttrs", 7161 ) 7162 7163 def __init__(self, location, args, name): 7164 # We can't actually init our IDLMethod yet, because we do not know the 7165 # return type yet. Just save the info we have for now and we will init 7166 # it later. 7167 self._initLocation = location 7168 self._initArgs = args 7169 self._initName = name 7170 self._inited = False 7171 self._initExtendedAttrs = [] 7172 7173 def addExtendedAttributes(self, attrs): 7174 if self._inited: 7175 return IDLMethod.addExtendedAttributes(self, attrs) 7176 self._initExtendedAttrs.extend(attrs) 7177 7178 def handleExtendedAttribute(self, attr): 7179 identifier = attr.identifier() 7180 if ( 7181 identifier == "BinaryName" 7182 or identifier == "ChromeOnly" 7183 or identifier == "NewObject" 7184 or identifier == "SecureContext" 7185 or identifier == "Throws" 7186 or identifier == "Func" 7187 or identifier == "Trial" 7188 or identifier == "Pref" 7189 or identifier == "UseCounter" 7190 ): 7191 IDLMethod.handleExtendedAttribute(self, attr) 7192 elif identifier == "HTMLConstructor": 7193 if not attr.noArguments(): 7194 raise WebIDLError( 7195 "[HTMLConstructor] must take no arguments", [attr.location] 7196 ) 7197 # We shouldn't end up here for legacy factory functions. 7198 assert self.identifier.name == "constructor" 7199 7200 if any(len(sig[1]) != 0 for sig in self.signatures()): 7201 raise WebIDLError( 7202 "[HTMLConstructor] must not be applied to a " 7203 "constructor operation that has arguments.", 7204 [attr.location], 7205 ) 7206 self._htmlConstructor = True 7207 else: 7208 raise WebIDLError( 7209 "Unknown extended attribute %s on method" % identifier, [attr.location] 7210 ) 7211 7212 def reallyInit(self, parentInterface): 7213 name = self._initName 7214 location = self._initLocation 7215 identifier = IDLUnresolvedIdentifier(location, name, allowForbidden=True) 7216 retType = IDLWrapperType(parentInterface.location, parentInterface) 7217 IDLMethod.__init__( 7218 self, location, identifier, retType, self._initArgs, static=True 7219 ) 7220 self._inited = True 7221 # Propagate through whatever extended attributes we already had 7222 self.addExtendedAttributes(self._initExtendedAttrs) 7223 self._initExtendedAttrs = [] 7224 # Constructors are always NewObject. Whether they throw or not is 7225 # indicated by [Throws] annotations in the usual way. 7226 self.addExtendedAttributes( 7227 [IDLExtendedAttribute(self.location, ("NewObject",))] 7228 ) 7229 7230 7231 class IDLIncludesStatement(IDLObject): 7232 __slots__ = ("interface", "mixin", "_finished") 7233 7234 def __init__(self, location, interface, mixin): 7235 IDLObject.__init__(self, location) 7236 self.interface = interface 7237 self.mixin = mixin 7238 self._finished = False 7239 7240 def finish(self, scope): 7241 if self._finished: 7242 return 7243 self._finished = True 7244 assert isinstance(self.interface, IDLIdentifierPlaceholder) 7245 assert isinstance(self.mixin, IDLIdentifierPlaceholder) 7246 interface = self.interface.finish(scope) 7247 mixin = self.mixin.finish(scope) 7248 # NOTE: we depend on not setting self.interface and 7249 # self.mixin here to keep track of the original 7250 # locations. 7251 if not isinstance(interface, IDLInterface): 7252 raise WebIDLError( 7253 "Left-hand side of 'includes' is not an interface", 7254 [self.interface.location, interface.location], 7255 ) 7256 if interface.isCallback(): 7257 raise WebIDLError( 7258 "Left-hand side of 'includes' is a callback interface", 7259 [self.interface.location, interface.location], 7260 ) 7261 if not isinstance(mixin, IDLInterfaceMixin): 7262 raise WebIDLError( 7263 "Right-hand side of 'includes' is not an interface mixin", 7264 [self.mixin.location, mixin.location], 7265 ) 7266 7267 mixin.actualExposureGlobalNames.update(interface._exposureGlobalNames) 7268 7269 interface.addIncludedMixin(mixin) 7270 self.interface = interface 7271 self.mixin = mixin 7272 7273 def validate(self): 7274 pass 7275 7276 def addExtendedAttributes(self, attrs): 7277 if len(attrs) != 0: 7278 raise WebIDLError( 7279 "There are no extended attributes that are " 7280 "allowed on includes statements", 7281 [attrs[0].location, self.location], 7282 ) 7283 7284 7285 class IDLExtendedAttribute(IDLObject): 7286 """ 7287 A class to represent IDL extended attributes so we can give them locations 7288 """ 7289 7290 __slots__ = ("_tuple",) 7291 7292 def __init__(self, location, tuple): 7293 IDLObject.__init__(self, location) 7294 self._tuple = tuple 7295 7296 def identifier(self): 7297 return self._tuple[0] 7298 7299 def noArguments(self): 7300 return len(self._tuple) == 1 7301 7302 def hasValue(self): 7303 return len(self._tuple) >= 2 and isinstance(self._tuple[1], str) 7304 7305 def value(self): 7306 assert self.hasValue() 7307 return self._tuple[1] 7308 7309 def hasArgs(self): 7310 return ( 7311 len(self._tuple) == 2 7312 and isinstance(self._tuple[1], list) 7313 or len(self._tuple) == 3 7314 ) 7315 7316 def args(self): 7317 assert self.hasArgs() 7318 # Our args are our last element 7319 return self._tuple[-1] 7320 7321 def listValue(self): 7322 """ 7323 Backdoor for storing random data in _extendedAttrDict 7324 """ 7325 return list(self._tuple)[1:] 7326 7327 7328 # Parser 7329 7330 7331 class Tokenizer(object): 7332 tokens = ["INTEGER", "FLOATLITERAL", "IDENTIFIER", "STRING", "COMMENTS", "OTHER"] 7333 7334 def t_FLOATLITERAL(self, t): 7335 r"(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN" 7336 t.value = float(t.value) 7337 return t 7338 7339 def t_INTEGER(self, t): 7340 r"-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)" 7341 try: 7342 # Can't use int(), because that doesn't handle octal properly. 7343 t.value = parseInt(t.value) 7344 except Exception: 7345 raise WebIDLError( 7346 "Invalid integer literal", 7347 [ 7348 Location( 7349 lexer=self.lexer, 7350 lineno=self.lexer.lineno, 7351 lexpos=self.lexer.lexpos, 7352 filename=self._filename, 7353 ) 7354 ], 7355 ) 7356 return t 7357 7358 def t_IDENTIFIER(self, t): 7359 r"[_-]?[A-Za-z][0-9A-Z_a-z-]*" 7360 t.type = self.keywords.get(t.value, "IDENTIFIER") 7361 return t 7362 7363 def t_STRING(self, t): 7364 r'"[^"]*"' 7365 t.value = t.value[1:-1] 7366 return t 7367 7368 t_ignore = "\t\n\r " 7369 7370 def t_COMMENTS(self, t): 7371 r"//[^\n]*|/\*(?s:.)*?\*/" 7372 pass 7373 7374 def t_ELLIPSIS(self, t): 7375 r"\.\.\." 7376 t.type = "ELLIPSIS" 7377 return t 7378 7379 def t_OTHER(self, t): 7380 r"[^0-9A-Z_a-z]" 7381 t.type = self.keywords.get(t.value, "OTHER") 7382 return t 7383 7384 keywords = { 7385 "interface": "INTERFACE", 7386 "partial": "PARTIAL", 7387 "mixin": "MIXIN", 7388 "dictionary": "DICTIONARY", 7389 "exception": "EXCEPTION", 7390 "enum": "ENUM", 7391 "callback": "CALLBACK", 7392 "typedef": "TYPEDEF", 7393 "includes": "INCLUDES", 7394 "const": "CONST", 7395 "null": "NULL", 7396 "true": "TRUE", 7397 "false": "FALSE", 7398 "serializer": "SERIALIZER", 7399 "stringifier": "STRINGIFIER", 7400 "unrestricted": "UNRESTRICTED", 7401 "attribute": "ATTRIBUTE", 7402 "readonly": "READONLY", 7403 "inherit": "INHERIT", 7404 "static": "STATIC", 7405 "getter": "GETTER", 7406 "setter": "SETTER", 7407 "deleter": "DELETER", 7408 "legacycaller": "LEGACYCALLER", 7409 "optional": "OPTIONAL", 7410 "...": "ELLIPSIS", 7411 "::": "SCOPE", 7412 "DOMString": "DOMSTRING", 7413 "ByteString": "BYTESTRING", 7414 "USVString": "USVSTRING", 7415 "JSString": "JSSTRING", 7416 "UTF8String": "UTF8STRING", 7417 "any": "ANY", 7418 "boolean": "BOOLEAN", 7419 "byte": "BYTE", 7420 "double": "DOUBLE", 7421 "float": "FLOAT", 7422 "long": "LONG", 7423 "object": "OBJECT", 7424 "ObservableArray": "OBSERVABLEARRAY", 7425 "octet": "OCTET", 7426 "Promise": "PROMISE", 7427 "required": "REQUIRED", 7428 "sequence": "SEQUENCE", 7429 "record": "RECORD", 7430 "short": "SHORT", 7431 "unsigned": "UNSIGNED", 7432 "undefined": "UNDEFINED", 7433 ":": "COLON", 7434 ";": "SEMICOLON", 7435 "{": "LBRACE", 7436 "}": "RBRACE", 7437 "(": "LPAREN", 7438 ")": "RPAREN", 7439 "[": "LBRACKET", 7440 "]": "RBRACKET", 7441 "?": "QUESTIONMARK", 7442 "*": "ASTERISK", 7443 ",": "COMMA", 7444 "=": "EQUALS", 7445 "<": "LT", 7446 ">": "GT", 7447 "ArrayBuffer": "ARRAYBUFFER", 7448 "or": "OR", 7449 "maplike": "MAPLIKE", 7450 "setlike": "SETLIKE", 7451 "iterable": "ITERABLE", 7452 "async_iterable": "ASYNC_ITERABLE", 7453 "namespace": "NAMESPACE", 7454 "constructor": "CONSTRUCTOR", 7455 "symbol": "SYMBOL", 7456 } 7457 7458 tokens.extend(keywords.values()) 7459 7460 def t_error(self, t): 7461 raise WebIDLError( 7462 "Unrecognized Input", 7463 [ 7464 Location( 7465 lexer=self.lexer, 7466 lineno=self.lexer.lineno, 7467 lexpos=self.lexer.lexpos, 7468 filename=self._filename, 7469 ) 7470 ], 7471 ) 7472 7473 def __init__(self, outputdir, lexer=None): 7474 if lexer: 7475 self.lexer = lexer 7476 else: 7477 self.lexer = lex.lex(object=self) 7478 7479 7480 class SqueakyCleanLogger(object): 7481 errorWhitelist = [ 7482 # Web IDL defines the COMMENTS token, but doesn't actually 7483 # use it ... so far. 7484 "Token 'COMMENTS' defined, but not used", 7485 # And that means we have an unused token 7486 "There is 1 unused token", 7487 # Web IDL defines a OtherOrComma rule that's only used in 7488 # ExtendedAttributeInner, which we don't use yet. 7489 "Rule 'OtherOrComma' defined, but not used", 7490 # And an unused rule 7491 "There is 1 unused rule", 7492 # And the OtherOrComma grammar symbol is unreachable. 7493 "Symbol 'OtherOrComma' is unreachable", 7494 # Which means the Other symbol is unreachable. 7495 "Symbol 'Other' is unreachable", 7496 ] 7497 7498 def __init__(self): 7499 self.errors = [] 7500 7501 def debug(self, msg, *args, **kwargs): 7502 pass 7503 7504 info = debug 7505 7506 def warning(self, msg, *args, **kwargs): 7507 if ( 7508 msg == "%s:%d: Rule %r defined, but not used" 7509 or msg == "%s:%d: Rule '%s' defined, but not used" 7510 ): 7511 # Munge things so we don't have to hardcode filenames and 7512 # line numbers in our whitelist. 7513 whitelistmsg = "Rule %r defined, but not used" 7514 whitelistargs = args[2:] 7515 else: 7516 whitelistmsg = msg 7517 whitelistargs = args 7518 if (whitelistmsg % whitelistargs) not in SqueakyCleanLogger.errorWhitelist: 7519 self.errors.append(msg % args) 7520 7521 error = warning 7522 7523 def reportGrammarErrors(self): 7524 if self.errors: 7525 raise WebIDLError("\n".join(self.errors), []) 7526 7527 7528 class Parser(Tokenizer): 7529 def getLocation(self, p, i): 7530 return Location(self.lexer, p.lineno(i), p.lexpos(i), self._filename) 7531 7532 def globalScope(self): 7533 return self._globalScope 7534 7535 # The p_Foo functions here must match the WebIDL spec's grammar. 7536 # It's acceptable to split things at '|' boundaries. 7537 def p_Definitions(self, p): 7538 """ 7539 Definitions : ExtendedAttributeList Definition Definitions 7540 """ 7541 if p[2]: 7542 p[0] = [p[2]] 7543 p[2].addExtendedAttributes(p[1]) 7544 else: 7545 assert not p[1] 7546 p[0] = [] 7547 7548 p[0].extend(p[3]) 7549 7550 def p_DefinitionsEmpty(self, p): 7551 """ 7552 Definitions : 7553 """ 7554 p[0] = [] 7555 7556 def p_Definition(self, p): 7557 """ 7558 Definition : CallbackOrInterfaceOrMixin 7559 | Namespace 7560 | Partial 7561 | Dictionary 7562 | Exception 7563 | Enum 7564 | Typedef 7565 | IncludesStatement 7566 """ 7567 p[0] = p[1] 7568 assert p[1] # We might not have implemented something ... 7569 7570 def p_CallbackOrInterfaceOrMixinCallback(self, p): 7571 """ 7572 CallbackOrInterfaceOrMixin : CALLBACK CallbackRestOrInterface 7573 """ 7574 if p[2].isInterface(): 7575 assert isinstance(p[2], IDLInterface) 7576 p[2].setCallback(True) 7577 7578 p[0] = p[2] 7579 7580 def p_CallbackOrInterfaceOrMixinInterfaceOrMixin(self, p): 7581 """ 7582 CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin 7583 """ 7584 p[0] = p[2] 7585 7586 def p_CallbackRestOrInterface(self, p): 7587 """ 7588 CallbackRestOrInterface : CallbackRest 7589 | CallbackConstructorRest 7590 | CallbackInterface 7591 """ 7592 assert p[1] 7593 p[0] = p[1] 7594 7595 def handleNonPartialObject( 7596 self, location, identifier, constructor, constructorArgs, nonPartialArgs 7597 ): 7598 """ 7599 This handles non-partial objects (interfaces, namespaces and 7600 dictionaries) by checking for an existing partial object, and promoting 7601 it to non-partial as needed. The return value is the non-partial 7602 object. 7603 7604 constructorArgs are all the args for the constructor except the last 7605 one: isKnownNonPartial. 7606 7607 nonPartialArgs are the args for the setNonPartial call. 7608 """ 7609 # The name of the class starts with "IDL", so strip that off. 7610 # Also, starts with a capital letter after that, so nix that 7611 # as well. 7612 prettyname = constructor.__name__[3:].lower() 7613 7614 try: 7615 existingObj = self.globalScope()._lookupIdentifier(identifier) 7616 if existingObj: 7617 if not isinstance(existingObj, constructor): 7618 raise WebIDLError( 7619 "%s has the same name as " 7620 "non-%s object" % (prettyname.capitalize(), prettyname), 7621 [location, existingObj.location], 7622 ) 7623 existingObj.setNonPartial(*nonPartialArgs) 7624 return existingObj 7625 except Exception as ex: 7626 if isinstance(ex, WebIDLError): 7627 raise ex 7628 pass 7629 7630 # True for isKnownNonPartial 7631 return constructor(*(constructorArgs + [True])) 7632 7633 def p_InterfaceOrMixin(self, p): 7634 """ 7635 InterfaceOrMixin : InterfaceRest 7636 | MixinRest 7637 """ 7638 p[0] = p[1] 7639 7640 def p_CallbackInterface(self, p): 7641 """ 7642 CallbackInterface : INTERFACE InterfaceRest 7643 """ 7644 p[0] = p[2] 7645 7646 def p_InterfaceRest(self, p): 7647 """ 7648 InterfaceRest : IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON 7649 """ 7650 location = self.getLocation(p, 1) 7651 identifier = IDLUnresolvedIdentifier(location, p[1]) 7652 members = p[4] 7653 parent = p[2] 7654 7655 p[0] = self.handleNonPartialObject( 7656 location, 7657 identifier, 7658 IDLInterface, 7659 [location, self.globalScope(), identifier, parent, members], 7660 [location, parent, members], 7661 ) 7662 7663 def p_InterfaceForwardDecl(self, p): 7664 """ 7665 InterfaceRest : IDENTIFIER SEMICOLON 7666 """ 7667 location = self.getLocation(p, 1) 7668 identifier = IDLUnresolvedIdentifier(location, p[1]) 7669 7670 try: 7671 if self.globalScope()._lookupIdentifier(identifier): 7672 p[0] = self.globalScope()._lookupIdentifier(identifier) 7673 if not isinstance(p[0], IDLExternalInterface): 7674 raise WebIDLError( 7675 "Name collision between external " 7676 "interface declaration for identifier " 7677 "%s and %s" % (identifier.name, p[0]), 7678 [location, p[0].location], 7679 ) 7680 return 7681 except Exception as ex: 7682 if isinstance(ex, WebIDLError): 7683 raise ex 7684 pass 7685 7686 p[0] = IDLExternalInterface(location, self.globalScope(), identifier) 7687 7688 def p_MixinRest(self, p): 7689 """ 7690 MixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON 7691 """ 7692 location = self.getLocation(p, 1) 7693 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 7694 members = p[4] 7695 7696 p[0] = self.handleNonPartialObject( 7697 location, 7698 identifier, 7699 IDLInterfaceMixin, 7700 [location, self.globalScope(), identifier, members], 7701 [location, members], 7702 ) 7703 7704 def p_Namespace(self, p): 7705 """ 7706 Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON 7707 """ 7708 location = self.getLocation(p, 1) 7709 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 7710 members = p[4] 7711 7712 p[0] = self.handleNonPartialObject( 7713 location, 7714 identifier, 7715 IDLNamespace, 7716 [location, self.globalScope(), identifier, members], 7717 [location, None, members], 7718 ) 7719 7720 def p_Partial(self, p): 7721 """ 7722 Partial : PARTIAL PartialDefinition 7723 """ 7724 p[0] = p[2] 7725 7726 def p_PartialDefinitionInterface(self, p): 7727 """ 7728 PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin 7729 """ 7730 p[0] = p[2] 7731 7732 def p_PartialDefinition(self, p): 7733 """ 7734 PartialDefinition : PartialNamespace 7735 | PartialDictionary 7736 """ 7737 p[0] = p[1] 7738 7739 def handlePartialObject( 7740 self, 7741 location, 7742 identifier, 7743 nonPartialConstructor, 7744 nonPartialConstructorArgs, 7745 partialConstructorArgs, 7746 ): 7747 """ 7748 This handles partial objects (interfaces, namespaces and dictionaries) 7749 by checking for an existing non-partial object, and adding ourselves to 7750 it as needed. The return value is our partial object. We use 7751 IDLPartialInterfaceOrNamespace for partial interfaces or namespaces, 7752 and IDLPartialDictionary for partial dictionaries. 7753 7754 nonPartialConstructorArgs are all the args for the non-partial 7755 constructor except the last two: members and isKnownNonPartial. 7756 7757 partialConstructorArgs are the arguments for the partial object 7758 constructor, except the last one (the non-partial object). 7759 """ 7760 # The name of the class starts with "IDL", so strip that off. 7761 # Also, starts with a capital letter after that, so nix that 7762 # as well. 7763 prettyname = nonPartialConstructor.__name__[3:].lower() 7764 7765 nonPartialObject = None 7766 try: 7767 nonPartialObject = self.globalScope()._lookupIdentifier(identifier) 7768 if nonPartialObject: 7769 if not isinstance(nonPartialObject, nonPartialConstructor): 7770 raise WebIDLError( 7771 "Partial %s has the same name as " 7772 "non-%s object" % (prettyname, prettyname), 7773 [location, nonPartialObject.location], 7774 ) 7775 except Exception as ex: 7776 if isinstance(ex, WebIDLError): 7777 raise ex 7778 pass 7779 7780 if not nonPartialObject: 7781 nonPartialObject = nonPartialConstructor( 7782 # No members, False for isKnownNonPartial 7783 *(nonPartialConstructorArgs), 7784 members=[], 7785 isKnownNonPartial=False 7786 ) 7787 7788 partialObject = None 7789 if isinstance(nonPartialObject, IDLDictionary): 7790 partialObject = IDLPartialDictionary( 7791 *(partialConstructorArgs + [nonPartialObject]) 7792 ) 7793 elif isinstance( 7794 nonPartialObject, (IDLInterface, IDLInterfaceMixin, IDLNamespace) 7795 ): 7796 partialObject = IDLPartialInterfaceOrNamespace( 7797 *(partialConstructorArgs + [nonPartialObject]) 7798 ) 7799 else: 7800 raise WebIDLError( 7801 "Unknown partial object type %s" % type(partialObject), [location] 7802 ) 7803 7804 return partialObject 7805 7806 def p_PartialInterfaceOrPartialMixin(self, p): 7807 """ 7808 PartialInterfaceOrPartialMixin : PartialInterfaceRest 7809 | PartialMixinRest 7810 """ 7811 p[0] = p[1] 7812 7813 def p_PartialInterfaceRest(self, p): 7814 """ 7815 PartialInterfaceRest : IDENTIFIER LBRACE PartialInterfaceMembers RBRACE SEMICOLON 7816 """ 7817 location = self.getLocation(p, 1) 7818 identifier = IDLUnresolvedIdentifier(location, p[1]) 7819 members = p[3] 7820 7821 p[0] = self.handlePartialObject( 7822 location, 7823 identifier, 7824 IDLInterface, 7825 [location, self.globalScope(), identifier, None], 7826 [location, identifier, members], 7827 ) 7828 7829 def p_PartialMixinRest(self, p): 7830 """ 7831 PartialMixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON 7832 """ 7833 location = self.getLocation(p, 1) 7834 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 7835 members = p[4] 7836 7837 p[0] = self.handlePartialObject( 7838 location, 7839 identifier, 7840 IDLInterfaceMixin, 7841 [location, self.globalScope(), identifier], 7842 [location, identifier, members], 7843 ) 7844 7845 def p_PartialNamespace(self, p): 7846 """ 7847 PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON 7848 """ 7849 location = self.getLocation(p, 1) 7850 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 7851 members = p[4] 7852 7853 p[0] = self.handlePartialObject( 7854 location, 7855 identifier, 7856 IDLNamespace, 7857 [location, self.globalScope(), identifier], 7858 [location, identifier, members], 7859 ) 7860 7861 def p_PartialDictionary(self, p): 7862 """ 7863 PartialDictionary : DICTIONARY IDENTIFIER LBRACE DictionaryMembers RBRACE SEMICOLON 7864 """ 7865 location = self.getLocation(p, 1) 7866 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 7867 members = p[4] 7868 7869 p[0] = self.handlePartialObject( 7870 location, 7871 identifier, 7872 IDLDictionary, 7873 [location, self.globalScope(), identifier], 7874 [location, identifier, members], 7875 ) 7876 7877 def p_Inheritance(self, p): 7878 """ 7879 Inheritance : COLON ScopedName 7880 """ 7881 p[0] = IDLIdentifierPlaceholder(self.getLocation(p, 2), p[2]) 7882 7883 def p_InheritanceEmpty(self, p): 7884 """ 7885 Inheritance : 7886 """ 7887 pass 7888 7889 def p_InterfaceMembers(self, p): 7890 """ 7891 InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers 7892 """ 7893 p[0] = [p[2]] 7894 7895 assert not p[1] or p[2] 7896 p[2].addExtendedAttributes(p[1]) 7897 7898 p[0].extend(p[3]) 7899 7900 def p_InterfaceMembersEmpty(self, p): 7901 """ 7902 InterfaceMembers : 7903 """ 7904 p[0] = [] 7905 7906 def p_InterfaceMember(self, p): 7907 """ 7908 InterfaceMember : PartialInterfaceMember 7909 | Constructor 7910 """ 7911 p[0] = p[1] 7912 7913 def p_Constructor(self, p): 7914 """ 7915 Constructor : CONSTRUCTOR LPAREN ArgumentList RPAREN SEMICOLON 7916 """ 7917 p[0] = IDLConstructor(self.getLocation(p, 1), p[3], "constructor") 7918 7919 def p_PartialInterfaceMembers(self, p): 7920 """ 7921 PartialInterfaceMembers : ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers 7922 """ 7923 p[0] = [p[2]] 7924 7925 assert not p[1] or p[2] 7926 p[2].addExtendedAttributes(p[1]) 7927 7928 p[0].extend(p[3]) 7929 7930 def p_PartialInterfaceMembersEmpty(self, p): 7931 """ 7932 PartialInterfaceMembers : 7933 """ 7934 p[0] = [] 7935 7936 def p_PartialInterfaceMember(self, p): 7937 """ 7938 PartialInterfaceMember : Const 7939 | AttributeOrOperationOrMaplikeOrSetlikeOrIterable 7940 """ 7941 p[0] = p[1] 7942 7943 def p_MixinMembersEmpty(self, p): 7944 """ 7945 MixinMembers : 7946 """ 7947 p[0] = [] 7948 7949 def p_MixinMembers(self, p): 7950 """ 7951 MixinMembers : ExtendedAttributeList MixinMember MixinMembers 7952 """ 7953 p[0] = [p[2]] 7954 7955 assert not p[1] or p[2] 7956 p[2].addExtendedAttributes(p[1]) 7957 7958 p[0].extend(p[3]) 7959 7960 def p_MixinMember(self, p): 7961 """ 7962 MixinMember : Const 7963 | Attribute 7964 | Operation 7965 """ 7966 p[0] = p[1] 7967 7968 def p_Dictionary(self, p): 7969 """ 7970 Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON 7971 """ 7972 location = self.getLocation(p, 1) 7973 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 7974 members = p[5] 7975 p[0] = IDLDictionary(location, self.globalScope(), identifier, p[3], members) 7976 7977 def p_DictionaryMembers(self, p): 7978 """ 7979 DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers 7980 | 7981 """ 7982 if len(p) == 1: 7983 # We're at the end of the list 7984 p[0] = [] 7985 return 7986 p[2].addExtendedAttributes(p[1]) 7987 p[0] = [p[2]] 7988 p[0].extend(p[3]) 7989 7990 def p_DictionaryMemberRequired(self, p): 7991 """ 7992 DictionaryMember : REQUIRED TypeWithExtendedAttributes IDENTIFIER SEMICOLON 7993 """ 7994 # These quack a lot like required arguments, so just treat them that way. 7995 t = p[2] 7996 assert isinstance(t, IDLType) 7997 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) 7998 7999 p[0] = IDLArgument( 8000 self.getLocation(p, 3), 8001 identifier, 8002 t, 8003 optional=False, 8004 defaultValue=None, 8005 variadic=False, 8006 dictionaryMember=True, 8007 ) 8008 8009 def p_DictionaryMember(self, p): 8010 """ 8011 DictionaryMember : Type IDENTIFIER Default SEMICOLON 8012 """ 8013 # These quack a lot like optional arguments, so just treat them that way. 8014 t = p[1] 8015 assert isinstance(t, IDLType) 8016 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 8017 defaultValue = p[3] 8018 8019 # Any attributes that precede this may apply to the type, so 8020 # we configure the argument to forward type attributes down instead of producing 8021 # a parse error 8022 p[0] = IDLArgument( 8023 self.getLocation(p, 2), 8024 identifier, 8025 t, 8026 optional=True, 8027 defaultValue=defaultValue, 8028 variadic=False, 8029 dictionaryMember=True, 8030 allowTypeAttributes=True, 8031 ) 8032 8033 def p_Default(self, p): 8034 """ 8035 Default : EQUALS DefaultValue 8036 | 8037 """ 8038 if len(p) > 1: 8039 p[0] = p[2] 8040 else: 8041 p[0] = None 8042 8043 def p_DefaultValue(self, p): 8044 """ 8045 DefaultValue : ConstValue 8046 | LBRACKET RBRACKET 8047 | LBRACE RBRACE 8048 """ 8049 if len(p) == 2: 8050 p[0] = p[1] 8051 else: 8052 assert len(p) == 3 # Must be [] or {} 8053 if p[1] == "[": 8054 p[0] = IDLEmptySequenceValue(self.getLocation(p, 1)) 8055 else: 8056 assert p[1] == "{" 8057 p[0] = IDLDefaultDictionaryValue(self.getLocation(p, 1)) 8058 8059 def p_DefaultValueNull(self, p): 8060 """ 8061 DefaultValue : NULL 8062 """ 8063 p[0] = IDLNullValue(self.getLocation(p, 1)) 8064 8065 def p_DefaultValueUndefined(self, p): 8066 """ 8067 DefaultValue : UNDEFINED 8068 """ 8069 p[0] = IDLUndefinedValue(self.getLocation(p, 1)) 8070 8071 def p_Exception(self, p): 8072 """ 8073 Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON 8074 """ 8075 pass 8076 8077 def p_Enum(self, p): 8078 """ 8079 Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON 8080 """ 8081 location = self.getLocation(p, 1) 8082 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 8083 8084 values = p[4] 8085 assert values 8086 p[0] = IDLEnum(location, self.globalScope(), identifier, values) 8087 8088 def p_EnumValueList(self, p): 8089 """ 8090 EnumValueList : STRING EnumValueListComma 8091 """ 8092 p[0] = [p[1]] 8093 p[0].extend(p[2]) 8094 8095 def p_EnumValueListComma(self, p): 8096 """ 8097 EnumValueListComma : COMMA EnumValueListString 8098 """ 8099 p[0] = p[2] 8100 8101 def p_EnumValueListCommaEmpty(self, p): 8102 """ 8103 EnumValueListComma : 8104 """ 8105 p[0] = [] 8106 8107 def p_EnumValueListString(self, p): 8108 """ 8109 EnumValueListString : STRING EnumValueListComma 8110 """ 8111 p[0] = [p[1]] 8112 p[0].extend(p[2]) 8113 8114 def p_EnumValueListStringEmpty(self, p): 8115 """ 8116 EnumValueListString : 8117 """ 8118 p[0] = [] 8119 8120 def p_CallbackRest(self, p): 8121 """ 8122 CallbackRest : IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON 8123 """ 8124 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) 8125 p[0] = IDLCallback( 8126 self.getLocation(p, 1), 8127 self.globalScope(), 8128 identifier, 8129 p[3], 8130 p[5], 8131 isConstructor=False, 8132 ) 8133 8134 def p_CallbackConstructorRest(self, p): 8135 """ 8136 CallbackConstructorRest : CONSTRUCTOR IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON 8137 """ 8138 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) 8139 p[0] = IDLCallback( 8140 self.getLocation(p, 2), 8141 self.globalScope(), 8142 identifier, 8143 p[4], 8144 p[6], 8145 isConstructor=True, 8146 ) 8147 8148 def p_ExceptionMembers(self, p): 8149 """ 8150 ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers 8151 | 8152 """ 8153 pass 8154 8155 def p_Typedef(self, p): 8156 """ 8157 Typedef : TYPEDEF TypeWithExtendedAttributes IDENTIFIER SEMICOLON 8158 """ 8159 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) 8160 typedef = IDLTypedef( 8161 self.getLocation(p, 1), 8162 self.globalScope(), 8163 p[2], 8164 identifier, 8165 ) 8166 p[0] = typedef 8167 8168 def p_IncludesStatement(self, p): 8169 """ 8170 IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON 8171 """ 8172 assert p[2] == "includes" 8173 interface = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1]) 8174 mixin = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3]) 8175 p[0] = IDLIncludesStatement(self.getLocation(p, 1), interface, mixin) 8176 8177 def p_Const(self, p): 8178 """ 8179 Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON 8180 """ 8181 location = self.getLocation(p, 1) 8182 type = p[2] 8183 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) 8184 value = p[5] 8185 p[0] = IDLConst(location, identifier, type, value) 8186 8187 def p_ConstValueBoolean(self, p): 8188 """ 8189 ConstValue : BooleanLiteral 8190 """ 8191 location = self.getLocation(p, 1) 8192 booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean] 8193 p[0] = IDLValue(location, booleanType, p[1]) 8194 8195 def p_ConstValueInteger(self, p): 8196 """ 8197 ConstValue : INTEGER 8198 """ 8199 location = self.getLocation(p, 1) 8200 8201 # We don't know ahead of time what type the integer literal is. 8202 # Determine the smallest type it could possibly fit in and use that. 8203 integerType = matchIntegerValueToType(p[1]) 8204 if integerType is None: 8205 raise WebIDLError("Integer literal out of range", [location]) 8206 8207 p[0] = IDLValue(location, integerType, p[1]) 8208 8209 def p_ConstValueFloat(self, p): 8210 """ 8211 ConstValue : FLOATLITERAL 8212 """ 8213 location = self.getLocation(p, 1) 8214 p[0] = IDLValue( 8215 location, BuiltinTypes[IDLBuiltinType.Types.unrestricted_float], p[1] 8216 ) 8217 8218 def p_ConstValueString(self, p): 8219 """ 8220 ConstValue : STRING 8221 """ 8222 location = self.getLocation(p, 1) 8223 stringType = BuiltinTypes[IDLBuiltinType.Types.domstring] 8224 p[0] = IDLValue(location, stringType, p[1]) 8225 8226 def p_BooleanLiteralTrue(self, p): 8227 """ 8228 BooleanLiteral : TRUE 8229 """ 8230 p[0] = True 8231 8232 def p_BooleanLiteralFalse(self, p): 8233 """ 8234 BooleanLiteral : FALSE 8235 """ 8236 p[0] = False 8237 8238 def p_AttributeOrOperationOrMaplikeOrSetlikeOrIterable(self, p): 8239 """ 8240 AttributeOrOperationOrMaplikeOrSetlikeOrIterable : Attribute 8241 | Maplike 8242 | Setlike 8243 | Iterable 8244 | AsyncIterable 8245 | Operation 8246 """ 8247 p[0] = p[1] 8248 8249 def p_Iterable(self, p): 8250 """ 8251 Iterable : ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON 8252 | ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON 8253 """ 8254 location = self.getLocation(p, 1) 8255 identifier = IDLUnresolvedIdentifier( 8256 location, "__iterable", allowDoubleUnderscore=True 8257 ) 8258 if len(p) > 6: 8259 keyType = p[3] 8260 valueType = p[5] 8261 else: 8262 keyType = None 8263 valueType = p[3] 8264 8265 p[0] = IDLIterable(location, identifier, keyType, valueType, self.globalScope()) 8266 8267 def p_AsyncIterable(self, p): 8268 """ 8269 AsyncIterable : ASYNC_ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON 8270 | ASYNC_ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON 8271 | ASYNC_ITERABLE LT TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON 8272 | ASYNC_ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON 8273 """ 8274 location = self.getLocation(p, 1) 8275 identifier = IDLUnresolvedIdentifier( 8276 location, "__async_iterable", allowDoubleUnderscore=True 8277 ) 8278 if len(p) == 11: 8279 keyType = p[3] 8280 valueType = p[5] 8281 argList = p[8] 8282 elif len(p) == 9: 8283 keyType = None 8284 valueType = p[3] 8285 argList = p[6] 8286 elif len(p) == 8: 8287 keyType = p[3] 8288 valueType = p[5] 8289 argList = [] 8290 else: 8291 keyType = None 8292 valueType = p[3] 8293 argList = [] 8294 8295 p[0] = IDLAsyncIterable( 8296 location, identifier, keyType, valueType, argList, self.globalScope() 8297 ) 8298 8299 def p_Setlike(self, p): 8300 """ 8301 Setlike : ReadOnly SETLIKE LT TypeWithExtendedAttributes GT SEMICOLON 8302 """ 8303 readonly = p[1] 8304 maplikeOrSetlikeType = p[2] 8305 location = self.getLocation(p, 2) 8306 identifier = IDLUnresolvedIdentifier( 8307 location, "__setlike", allowDoubleUnderscore=True 8308 ) 8309 keyType = p[4] 8310 valueType = keyType 8311 p[0] = IDLMaplikeOrSetlike( 8312 location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType 8313 ) 8314 8315 def p_Maplike(self, p): 8316 """ 8317 Maplike : ReadOnly MAPLIKE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON 8318 """ 8319 readonly = p[1] 8320 maplikeOrSetlikeType = p[2] 8321 location = self.getLocation(p, 2) 8322 identifier = IDLUnresolvedIdentifier( 8323 location, "__maplike", allowDoubleUnderscore=True 8324 ) 8325 keyType = p[4] 8326 valueType = p[6] 8327 p[0] = IDLMaplikeOrSetlike( 8328 location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType 8329 ) 8330 8331 def p_AttributeWithQualifier(self, p): 8332 """ 8333 Attribute : Qualifier AttributeRest 8334 """ 8335 static = IDLInterfaceMember.Special.Static in p[1] 8336 stringifier = IDLInterfaceMember.Special.Stringifier in p[1] 8337 (location, identifier, type, readonly) = p[2] 8338 p[0] = IDLAttribute( 8339 location, identifier, type, readonly, static=static, stringifier=stringifier 8340 ) 8341 8342 def p_AttributeInherited(self, p): 8343 """ 8344 Attribute : INHERIT AttributeRest 8345 """ 8346 (location, identifier, type, readonly) = p[2] 8347 p[0] = IDLAttribute(location, identifier, type, readonly, inherit=True) 8348 8349 def p_Attribute(self, p): 8350 """ 8351 Attribute : AttributeRest 8352 """ 8353 (location, identifier, type, readonly) = p[1] 8354 p[0] = IDLAttribute(location, identifier, type, readonly, inherit=False) 8355 8356 def p_AttributeRest(self, p): 8357 """ 8358 AttributeRest : ReadOnly ATTRIBUTE TypeWithExtendedAttributes AttributeName SEMICOLON 8359 """ 8360 location = self.getLocation(p, 2) 8361 readonly = p[1] 8362 t = p[3] 8363 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 4), p[4]) 8364 p[0] = (location, identifier, t, readonly) 8365 8366 def p_ReadOnly(self, p): 8367 """ 8368 ReadOnly : READONLY 8369 """ 8370 p[0] = True 8371 8372 def p_ReadOnlyEmpty(self, p): 8373 """ 8374 ReadOnly : 8375 """ 8376 p[0] = False 8377 8378 def p_Operation(self, p): 8379 """ 8380 Operation : Qualifiers OperationRest 8381 """ 8382 qualifiers = p[1] 8383 8384 # Disallow duplicates in the qualifier set 8385 if not len(set(qualifiers)) == len(qualifiers): 8386 raise WebIDLError( 8387 "Duplicate qualifiers are not allowed", [self.getLocation(p, 1)] 8388 ) 8389 8390 static = IDLInterfaceMember.Special.Static in p[1] 8391 # If static is there that's all that's allowed. This is disallowed 8392 # by the parser, so we can assert here. 8393 assert not static or len(qualifiers) == 1 8394 8395 stringifier = IDLInterfaceMember.Special.Stringifier in p[1] 8396 # If stringifier is there that's all that's allowed. This is disallowed 8397 # by the parser, so we can assert here. 8398 assert not stringifier or len(qualifiers) == 1 8399 8400 getter = True if IDLMethod.Special.Getter in p[1] else False 8401 setter = True if IDLMethod.Special.Setter in p[1] else False 8402 deleter = True if IDLMethod.Special.Deleter in p[1] else False 8403 legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False 8404 8405 if getter or deleter: 8406 if setter: 8407 raise WebIDLError( 8408 "getter and deleter are incompatible with setter", 8409 [self.getLocation(p, 1)], 8410 ) 8411 8412 (returnType, identifier, arguments) = p[2] 8413 8414 assert isinstance(returnType, IDLType) 8415 8416 specialType = IDLMethod.NamedOrIndexed.Neither 8417 8418 if getter or deleter: 8419 if len(arguments) != 1: 8420 raise WebIDLError( 8421 "%s has wrong number of arguments" 8422 % ("getter" if getter else "deleter"), 8423 [self.getLocation(p, 2)], 8424 ) 8425 argType = arguments[0].type 8426 if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: 8427 specialType = IDLMethod.NamedOrIndexed.Named 8428 elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: 8429 specialType = IDLMethod.NamedOrIndexed.Indexed 8430 if deleter: 8431 raise WebIDLError( 8432 "There is no such thing as an indexed deleter.", 8433 [self.getLocation(p, 1)], 8434 ) 8435 else: 8436 raise WebIDLError( 8437 "%s has wrong argument type (must be DOMString or UnsignedLong)" 8438 % ("getter" if getter else "deleter"), 8439 [arguments[0].location], 8440 ) 8441 if arguments[0].optional or arguments[0].variadic: 8442 raise WebIDLError( 8443 "%s cannot have %s argument" 8444 % ( 8445 "getter" if getter else "deleter", 8446 "optional" if arguments[0].optional else "variadic", 8447 ), 8448 [arguments[0].location], 8449 ) 8450 if getter: 8451 if returnType.isUndefined(): 8452 raise WebIDLError( 8453 "getter cannot have undefined return type", [self.getLocation(p, 2)] 8454 ) 8455 if setter: 8456 if len(arguments) != 2: 8457 raise WebIDLError( 8458 "setter has wrong number of arguments", [self.getLocation(p, 2)] 8459 ) 8460 argType = arguments[0].type 8461 if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: 8462 specialType = IDLMethod.NamedOrIndexed.Named 8463 elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: 8464 specialType = IDLMethod.NamedOrIndexed.Indexed 8465 else: 8466 raise WebIDLError( 8467 "settter has wrong argument type (must be DOMString or UnsignedLong)", 8468 [arguments[0].location], 8469 ) 8470 if arguments[0].optional or arguments[0].variadic: 8471 raise WebIDLError( 8472 "setter cannot have %s argument" 8473 % ("optional" if arguments[0].optional else "variadic"), 8474 [arguments[0].location], 8475 ) 8476 if arguments[1].optional or arguments[1].variadic: 8477 raise WebIDLError( 8478 "setter cannot have %s argument" 8479 % ("optional" if arguments[1].optional else "variadic"), 8480 [arguments[1].location], 8481 ) 8482 8483 if stringifier: 8484 if len(arguments) != 0: 8485 raise WebIDLError( 8486 "stringifier has wrong number of arguments", 8487 [self.getLocation(p, 2)], 8488 ) 8489 if not returnType.isDOMString(): 8490 raise WebIDLError( 8491 "stringifier must have DOMString return type", 8492 [self.getLocation(p, 2)], 8493 ) 8494 8495 # identifier might be None. This is only permitted for special methods. 8496 if not identifier: 8497 if ( 8498 not getter 8499 and not setter 8500 and not deleter 8501 and not legacycaller 8502 and not stringifier 8503 ): 8504 raise WebIDLError( 8505 "Identifier required for non-special methods", 8506 [self.getLocation(p, 2)], 8507 ) 8508 8509 location = BuiltinLocation("<auto-generated-identifier>") 8510 identifier = IDLUnresolvedIdentifier( 8511 location, 8512 "__%s%s%s%s%s%s" 8513 % ( 8514 ( 8515 "named" 8516 if specialType == IDLMethod.NamedOrIndexed.Named 8517 else ( 8518 "indexed" 8519 if specialType == IDLMethod.NamedOrIndexed.Indexed 8520 else "" 8521 ) 8522 ), 8523 "getter" if getter else "", 8524 "setter" if setter else "", 8525 "deleter" if deleter else "", 8526 "legacycaller" if legacycaller else "", 8527 "stringifier" if stringifier else "", 8528 ), 8529 allowDoubleUnderscore=True, 8530 ) 8531 8532 method = IDLMethod( 8533 self.getLocation(p, 2), 8534 identifier, 8535 returnType, 8536 arguments, 8537 static=static, 8538 getter=getter, 8539 setter=setter, 8540 deleter=deleter, 8541 specialType=specialType, 8542 legacycaller=legacycaller, 8543 stringifier=stringifier, 8544 ) 8545 p[0] = method 8546 8547 def p_Stringifier(self, p): 8548 """ 8549 Operation : STRINGIFIER SEMICOLON 8550 """ 8551 identifier = IDLUnresolvedIdentifier( 8552 BuiltinLocation("<auto-generated-identifier>"), 8553 "__stringifier", 8554 allowDoubleUnderscore=True, 8555 ) 8556 method = IDLMethod( 8557 self.getLocation(p, 1), 8558 identifier, 8559 returnType=BuiltinTypes[IDLBuiltinType.Types.domstring], 8560 arguments=[], 8561 stringifier=True, 8562 ) 8563 p[0] = method 8564 8565 def p_QualifierStatic(self, p): 8566 """ 8567 Qualifier : STATIC 8568 """ 8569 p[0] = [IDLInterfaceMember.Special.Static] 8570 8571 def p_QualifierStringifier(self, p): 8572 """ 8573 Qualifier : STRINGIFIER 8574 """ 8575 p[0] = [IDLInterfaceMember.Special.Stringifier] 8576 8577 def p_Qualifiers(self, p): 8578 """ 8579 Qualifiers : Qualifier 8580 | Specials 8581 """ 8582 p[0] = p[1] 8583 8584 def p_Specials(self, p): 8585 """ 8586 Specials : Special Specials 8587 """ 8588 p[0] = [p[1]] 8589 p[0].extend(p[2]) 8590 8591 def p_SpecialsEmpty(self, p): 8592 """ 8593 Specials : 8594 """ 8595 p[0] = [] 8596 8597 def p_SpecialGetter(self, p): 8598 """ 8599 Special : GETTER 8600 """ 8601 p[0] = IDLMethod.Special.Getter 8602 8603 def p_SpecialSetter(self, p): 8604 """ 8605 Special : SETTER 8606 """ 8607 p[0] = IDLMethod.Special.Setter 8608 8609 def p_SpecialDeleter(self, p): 8610 """ 8611 Special : DELETER 8612 """ 8613 p[0] = IDLMethod.Special.Deleter 8614 8615 def p_SpecialLegacyCaller(self, p): 8616 """ 8617 Special : LEGACYCALLER 8618 """ 8619 p[0] = IDLMethod.Special.LegacyCaller 8620 8621 def p_OperationRest(self, p): 8622 """ 8623 OperationRest : Type OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON 8624 """ 8625 p[0] = (p[1], p[2], p[4]) 8626 8627 def p_OptionalIdentifier(self, p): 8628 """ 8629 OptionalIdentifier : IDENTIFIER 8630 """ 8631 p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) 8632 8633 def p_OptionalIdentifierEmpty(self, p): 8634 """ 8635 OptionalIdentifier : 8636 """ 8637 pass 8638 8639 def p_ArgumentList(self, p): 8640 """ 8641 ArgumentList : Argument Arguments 8642 """ 8643 p[0] = [p[1]] if p[1] else [] 8644 p[0].extend(p[2]) 8645 8646 def p_ArgumentListEmpty(self, p): 8647 """ 8648 ArgumentList : 8649 """ 8650 p[0] = [] 8651 8652 def p_Arguments(self, p): 8653 """ 8654 Arguments : COMMA Argument Arguments 8655 """ 8656 p[0] = [p[2]] if p[2] else [] 8657 p[0].extend(p[3]) 8658 8659 def p_ArgumentsEmpty(self, p): 8660 """ 8661 Arguments : 8662 """ 8663 p[0] = [] 8664 8665 def p_Argument(self, p): 8666 """ 8667 Argument : ExtendedAttributeList ArgumentRest 8668 """ 8669 p[0] = p[2] 8670 p[0].addExtendedAttributes(p[1]) 8671 8672 def p_ArgumentRestOptional(self, p): 8673 """ 8674 ArgumentRest : OPTIONAL TypeWithExtendedAttributes ArgumentName Default 8675 """ 8676 t = p[2] 8677 assert isinstance(t, IDLType) 8678 # Arg names can be reserved identifiers 8679 identifier = IDLUnresolvedIdentifier( 8680 self.getLocation(p, 3), p[3], allowForbidden=True 8681 ) 8682 8683 defaultValue = p[4] 8684 8685 # We can't test t.isAny() here and give it a default value as needed, 8686 # since at this point t is not a fully resolved type yet (e.g. it might 8687 # be a typedef). We'll handle the 'any' case in IDLArgument.complete. 8688 8689 p[0] = IDLArgument( 8690 self.getLocation(p, 3), identifier, t, True, defaultValue, False 8691 ) 8692 8693 def p_ArgumentRest(self, p): 8694 """ 8695 ArgumentRest : Type Ellipsis ArgumentName 8696 """ 8697 t = p[1] 8698 assert isinstance(t, IDLType) 8699 # Arg names can be reserved identifiers 8700 identifier = IDLUnresolvedIdentifier( 8701 self.getLocation(p, 3), p[3], allowForbidden=True 8702 ) 8703 8704 variadic = p[2] 8705 8706 # We can't test t.isAny() here and give it a default value as needed, 8707 # since at this point t is not a fully resolved type yet (e.g. it might 8708 # be a typedef). We'll handle the 'any' case in IDLArgument.complete. 8709 8710 # variadic implies optional 8711 # Any attributes that precede this may apply to the type, so 8712 # we configure the argument to forward type attributes down instead of producing 8713 # a parse error 8714 p[0] = IDLArgument( 8715 self.getLocation(p, 3), 8716 identifier, 8717 t, 8718 variadic, 8719 None, 8720 variadic, 8721 allowTypeAttributes=True, 8722 ) 8723 8724 def p_ArgumentName(self, p): 8725 """ 8726 ArgumentName : IDENTIFIER 8727 | ArgumentNameKeyword 8728 """ 8729 p[0] = p[1] 8730 8731 def p_ArgumentNameKeyword(self, p): 8732 """ 8733 ArgumentNameKeyword : ATTRIBUTE 8734 | CALLBACK 8735 | CONST 8736 | CONSTRUCTOR 8737 | DELETER 8738 | DICTIONARY 8739 | ENUM 8740 | EXCEPTION 8741 | GETTER 8742 | INCLUDES 8743 | INHERIT 8744 | INTERFACE 8745 | ITERABLE 8746 | LEGACYCALLER 8747 | MAPLIKE 8748 | MIXIN 8749 | NAMESPACE 8750 | PARTIAL 8751 | READONLY 8752 | REQUIRED 8753 | SERIALIZER 8754 | SETLIKE 8755 | SETTER 8756 | STATIC 8757 | STRINGIFIER 8758 | TYPEDEF 8759 | UNRESTRICTED 8760 """ 8761 p[0] = p[1] 8762 8763 def p_AttributeName(self, p): 8764 """ 8765 AttributeName : IDENTIFIER 8766 | AttributeNameKeyword 8767 """ 8768 p[0] = p[1] 8769 8770 def p_AttributeNameKeyword(self, p): 8771 """ 8772 AttributeNameKeyword : REQUIRED 8773 """ 8774 p[0] = p[1] 8775 8776 def p_Ellipsis(self, p): 8777 """ 8778 Ellipsis : ELLIPSIS 8779 """ 8780 p[0] = True 8781 8782 def p_EllipsisEmpty(self, p): 8783 """ 8784 Ellipsis : 8785 """ 8786 p[0] = False 8787 8788 def p_ExceptionMember(self, p): 8789 """ 8790 ExceptionMember : Const 8791 | ExceptionField 8792 """ 8793 pass 8794 8795 def p_ExceptionField(self, p): 8796 """ 8797 ExceptionField : Type IDENTIFIER SEMICOLON 8798 """ 8799 pass 8800 8801 def p_ExtendedAttributeList(self, p): 8802 """ 8803 ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET 8804 """ 8805 p[0] = [p[2]] 8806 if p[3]: 8807 p[0].extend(p[3]) 8808 8809 def p_ExtendedAttributeListEmpty(self, p): 8810 """ 8811 ExtendedAttributeList : 8812 """ 8813 p[0] = [] 8814 8815 def p_ExtendedAttribute(self, p): 8816 """ 8817 ExtendedAttribute : ExtendedAttributeNoArgs 8818 | ExtendedAttributeArgList 8819 | ExtendedAttributeIdent 8820 | ExtendedAttributeWildcard 8821 | ExtendedAttributeNamedArgList 8822 | ExtendedAttributeIdentList 8823 """ 8824 p[0] = IDLExtendedAttribute(self.getLocation(p, 1), p[1]) 8825 8826 def p_ExtendedAttributeEmpty(self, p): 8827 """ 8828 ExtendedAttribute : 8829 """ 8830 pass 8831 8832 def p_ExtendedAttributes(self, p): 8833 """ 8834 ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes 8835 """ 8836 p[0] = [p[2]] if p[2] else [] 8837 p[0].extend(p[3]) 8838 8839 def p_ExtendedAttributesEmpty(self, p): 8840 """ 8841 ExtendedAttributes : 8842 """ 8843 p[0] = [] 8844 8845 def p_Other(self, p): 8846 """ 8847 Other : INTEGER 8848 | FLOATLITERAL 8849 | IDENTIFIER 8850 | STRING 8851 | OTHER 8852 | ELLIPSIS 8853 | COLON 8854 | SCOPE 8855 | SEMICOLON 8856 | LT 8857 | EQUALS 8858 | GT 8859 | QUESTIONMARK 8860 | ASTERISK 8861 | DOMSTRING 8862 | BYTESTRING 8863 | USVSTRING 8864 | UTF8STRING 8865 | JSSTRING 8866 | PROMISE 8867 | ANY 8868 | BOOLEAN 8869 | BYTE 8870 | DOUBLE 8871 | FALSE 8872 | FLOAT 8873 | LONG 8874 | NULL 8875 | OBJECT 8876 | OCTET 8877 | OR 8878 | OPTIONAL 8879 | RECORD 8880 | SEQUENCE 8881 | SHORT 8882 | SYMBOL 8883 | TRUE 8884 | UNSIGNED 8885 | UNDEFINED 8886 | ArgumentNameKeyword 8887 """ 8888 pass 8889 8890 def p_OtherOrComma(self, p): 8891 """ 8892 OtherOrComma : Other 8893 | COMMA 8894 """ 8895 pass 8896 8897 def p_TypeSingleType(self, p): 8898 """ 8899 Type : SingleType 8900 """ 8901 p[0] = p[1] 8902 8903 def p_TypeUnionType(self, p): 8904 """ 8905 Type : UnionType Null 8906 """ 8907 p[0] = self.handleNullable(p[1], p[2]) 8908 8909 def p_TypeWithExtendedAttributes(self, p): 8910 """ 8911 TypeWithExtendedAttributes : ExtendedAttributeList Type 8912 """ 8913 p[0] = p[2].withExtendedAttributes(p[1]) 8914 8915 def p_SingleTypeDistinguishableType(self, p): 8916 """ 8917 SingleType : DistinguishableType 8918 """ 8919 p[0] = p[1] 8920 8921 def p_SingleTypeAnyType(self, p): 8922 """ 8923 SingleType : ANY 8924 """ 8925 p[0] = BuiltinTypes[IDLBuiltinType.Types.any] 8926 8927 def p_SingleTypePromiseType(self, p): 8928 """ 8929 SingleType : PROMISE LT Type GT 8930 """ 8931 p[0] = IDLPromiseType(self.getLocation(p, 1), p[3]) 8932 8933 def p_UnionType(self, p): 8934 """ 8935 UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN 8936 """ 8937 types = [p[2], p[4]] 8938 types.extend(p[5]) 8939 p[0] = IDLUnionType(self.getLocation(p, 1), types) 8940 8941 def p_UnionMemberTypeDistinguishableType(self, p): 8942 """ 8943 UnionMemberType : ExtendedAttributeList DistinguishableType 8944 """ 8945 p[0] = p[2].withExtendedAttributes(p[1]) 8946 8947 def p_UnionMemberType(self, p): 8948 """ 8949 UnionMemberType : UnionType Null 8950 """ 8951 p[0] = self.handleNullable(p[1], p[2]) 8952 8953 def p_UnionMemberTypes(self, p): 8954 """ 8955 UnionMemberTypes : OR UnionMemberType UnionMemberTypes 8956 """ 8957 p[0] = [p[2]] 8958 p[0].extend(p[3]) 8959 8960 def p_UnionMemberTypesEmpty(self, p): 8961 """ 8962 UnionMemberTypes : 8963 """ 8964 p[0] = [] 8965 8966 def p_DistinguishableType(self, p): 8967 """ 8968 DistinguishableType : PrimitiveType Null 8969 | ARRAYBUFFER Null 8970 | OBJECT Null 8971 | UNDEFINED Null 8972 """ 8973 if p[1] == "object": 8974 type = BuiltinTypes[IDLBuiltinType.Types.object] 8975 elif p[1] == "ArrayBuffer": 8976 type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer] 8977 elif p[1] == "undefined": 8978 type = BuiltinTypes[IDLBuiltinType.Types.undefined] 8979 else: 8980 type = BuiltinTypes[p[1]] 8981 8982 p[0] = self.handleNullable(type, p[2]) 8983 8984 def p_DistinguishableTypeStringType(self, p): 8985 """ 8986 DistinguishableType : StringType Null 8987 """ 8988 p[0] = self.handleNullable(p[1], p[2]) 8989 8990 def p_DistinguishableTypeSequenceType(self, p): 8991 """ 8992 DistinguishableType : SEQUENCE LT TypeWithExtendedAttributes GT Null 8993 """ 8994 innerType = p[3] 8995 type = IDLSequenceType(self.getLocation(p, 1), innerType) 8996 p[0] = self.handleNullable(type, p[5]) 8997 8998 def p_DistinguishableTypeRecordType(self, p): 8999 """ 9000 DistinguishableType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null 9001 """ 9002 keyType = p[3] 9003 valueType = p[5] 9004 type = IDLRecordType(self.getLocation(p, 1), keyType, valueType) 9005 p[0] = self.handleNullable(type, p[7]) 9006 9007 def p_DistinguishableTypeObservableArrayType(self, p): 9008 """ 9009 DistinguishableType : OBSERVABLEARRAY LT TypeWithExtendedAttributes GT Null 9010 """ 9011 innerType = p[3] 9012 type = IDLObservableArrayType(self.getLocation(p, 1), innerType) 9013 p[0] = self.handleNullable(type, p[5]) 9014 9015 def p_DistinguishableTypeScopedName(self, p): 9016 """ 9017 DistinguishableType : ScopedName Null 9018 """ 9019 assert isinstance(p[1], IDLUnresolvedIdentifier) 9020 9021 if p[1].name == "Promise": 9022 raise WebIDLError( 9023 "Promise used without saying what it's parametrized over", 9024 [self.getLocation(p, 1)], 9025 ) 9026 9027 type = None 9028 9029 try: 9030 if self.globalScope()._lookupIdentifier(p[1]): 9031 obj = self.globalScope()._lookupIdentifier(p[1]) 9032 assert not obj.isType() 9033 if obj.isTypedef(): 9034 type = IDLTypedefType( 9035 self.getLocation(p, 1), obj.innerType, obj.identifier.name 9036 ) 9037 elif obj.isCallback() and not obj.isInterface(): 9038 type = IDLCallbackType(self.getLocation(p, 1), obj) 9039 else: 9040 type = IDLWrapperType(self.getLocation(p, 1), p[1]) 9041 p[0] = self.handleNullable(type, p[2]) 9042 return 9043 except Exception: 9044 pass 9045 9046 type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) 9047 p[0] = self.handleNullable(type, p[2]) 9048 9049 def p_ConstType(self, p): 9050 """ 9051 ConstType : PrimitiveType 9052 """ 9053 p[0] = BuiltinTypes[p[1]] 9054 9055 def p_ConstTypeIdentifier(self, p): 9056 """ 9057 ConstType : IDENTIFIER 9058 """ 9059 identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) 9060 9061 p[0] = IDLUnresolvedType(self.getLocation(p, 1), identifier) 9062 9063 def p_PrimitiveTypeUint(self, p): 9064 """ 9065 PrimitiveType : UnsignedIntegerType 9066 """ 9067 p[0] = p[1] 9068 9069 def p_PrimitiveTypeBoolean(self, p): 9070 """ 9071 PrimitiveType : BOOLEAN 9072 """ 9073 p[0] = IDLBuiltinType.Types.boolean 9074 9075 def p_PrimitiveTypeByte(self, p): 9076 """ 9077 PrimitiveType : BYTE 9078 """ 9079 p[0] = IDLBuiltinType.Types.byte 9080 9081 def p_PrimitiveTypeOctet(self, p): 9082 """ 9083 PrimitiveType : OCTET 9084 """ 9085 p[0] = IDLBuiltinType.Types.octet 9086 9087 def p_PrimitiveTypeFloat(self, p): 9088 """ 9089 PrimitiveType : FLOAT 9090 """ 9091 p[0] = IDLBuiltinType.Types.float 9092 9093 def p_PrimitiveTypeUnrestictedFloat(self, p): 9094 """ 9095 PrimitiveType : UNRESTRICTED FLOAT 9096 """ 9097 p[0] = IDLBuiltinType.Types.unrestricted_float 9098 9099 def p_PrimitiveTypeDouble(self, p): 9100 """ 9101 PrimitiveType : DOUBLE 9102 """ 9103 p[0] = IDLBuiltinType.Types.double 9104 9105 def p_PrimitiveTypeUnrestictedDouble(self, p): 9106 """ 9107 PrimitiveType : UNRESTRICTED DOUBLE 9108 """ 9109 p[0] = IDLBuiltinType.Types.unrestricted_double 9110 9111 def p_StringType(self, p): 9112 """ 9113 StringType : BuiltinStringType 9114 """ 9115 p[0] = BuiltinTypes[p[1]] 9116 9117 def p_BuiltinStringTypeDOMString(self, p): 9118 """ 9119 BuiltinStringType : DOMSTRING 9120 """ 9121 p[0] = IDLBuiltinType.Types.domstring 9122 9123 def p_BuiltinStringTypeBytestring(self, p): 9124 """ 9125 BuiltinStringType : BYTESTRING 9126 """ 9127 p[0] = IDLBuiltinType.Types.bytestring 9128 9129 def p_BuiltinStringTypeUSVString(self, p): 9130 """ 9131 BuiltinStringType : USVSTRING 9132 """ 9133 p[0] = IDLBuiltinType.Types.usvstring 9134 9135 def p_BuiltinStringTypeUTF8String(self, p): 9136 """ 9137 BuiltinStringType : UTF8STRING 9138 """ 9139 p[0] = IDLBuiltinType.Types.utf8string 9140 9141 def p_BuiltinStringTypeJSString(self, p): 9142 """ 9143 BuiltinStringType : JSSTRING 9144 """ 9145 p[0] = IDLBuiltinType.Types.jsstring 9146 9147 def p_UnsignedIntegerTypeUnsigned(self, p): 9148 """ 9149 UnsignedIntegerType : UNSIGNED IntegerType 9150 """ 9151 # Adding one to a given signed integer type gets you the unsigned type: 9152 p[0] = p[2] + 1 9153 9154 def p_UnsignedIntegerType(self, p): 9155 """ 9156 UnsignedIntegerType : IntegerType 9157 """ 9158 p[0] = p[1] 9159 9160 def p_IntegerTypeShort(self, p): 9161 """ 9162 IntegerType : SHORT 9163 """ 9164 p[0] = IDLBuiltinType.Types.short 9165 9166 def p_IntegerTypeLong(self, p): 9167 """ 9168 IntegerType : LONG OptionalLong 9169 """ 9170 if p[2]: 9171 p[0] = IDLBuiltinType.Types.long_long 9172 else: 9173 p[0] = IDLBuiltinType.Types.long 9174 9175 def p_OptionalLong(self, p): 9176 """ 9177 OptionalLong : LONG 9178 """ 9179 p[0] = True 9180 9181 def p_OptionalLongEmpty(self, p): 9182 """ 9183 OptionalLong : 9184 """ 9185 p[0] = False 9186 9187 def p_Null(self, p): 9188 """ 9189 Null : QUESTIONMARK 9190 | 9191 """ 9192 if len(p) > 1: 9193 p[0] = self.getLocation(p, 1) 9194 else: 9195 p[0] = None 9196 9197 def p_ScopedName(self, p): 9198 """ 9199 ScopedName : AbsoluteScopedName 9200 | RelativeScopedName 9201 """ 9202 p[0] = p[1] 9203 9204 def p_AbsoluteScopedName(self, p): 9205 """ 9206 AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts 9207 """ 9208 assert False 9209 pass 9210 9211 def p_RelativeScopedName(self, p): 9212 """ 9213 RelativeScopedName : IDENTIFIER ScopedNameParts 9214 """ 9215 assert not p[2] # Not implemented! 9216 9217 p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) 9218 9219 def p_ScopedNameParts(self, p): 9220 """ 9221 ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts 9222 """ 9223 assert False 9224 pass 9225 9226 def p_ScopedNamePartsEmpty(self, p): 9227 """ 9228 ScopedNameParts : 9229 """ 9230 p[0] = None 9231 9232 def p_ExtendedAttributeNoArgs(self, p): 9233 """ 9234 ExtendedAttributeNoArgs : IDENTIFIER 9235 """ 9236 p[0] = (p[1],) 9237 9238 def p_ExtendedAttributeArgList(self, p): 9239 """ 9240 ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN 9241 """ 9242 p[0] = (p[1], p[3]) 9243 9244 def p_ExtendedAttributeIdent(self, p): 9245 """ 9246 ExtendedAttributeIdent : IDENTIFIER EQUALS STRING 9247 | IDENTIFIER EQUALS IDENTIFIER 9248 """ 9249 p[0] = (p[1], p[3]) 9250 9251 def p_ExtendedAttributeWildcard(self, p): 9252 """ 9253 ExtendedAttributeWildcard : IDENTIFIER EQUALS ASTERISK 9254 """ 9255 p[0] = (p[1], p[3]) 9256 9257 def p_ExtendedAttributeNamedArgList(self, p): 9258 """ 9259 ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN 9260 """ 9261 p[0] = (p[1], p[3], p[5]) 9262 9263 def p_ExtendedAttributeIdentList(self, p): 9264 """ 9265 ExtendedAttributeIdentList : IDENTIFIER EQUALS LPAREN IdentifierList RPAREN 9266 """ 9267 p[0] = (p[1], p[4]) 9268 9269 def p_IdentifierList(self, p): 9270 """ 9271 IdentifierList : IDENTIFIER Identifiers 9272 """ 9273 idents = list(p[2]) 9274 # This is only used for identifier-list-valued extended attributes, and if 9275 # we're going to restrict to IDENTIFIER here we should at least allow 9276 # escaping with leading '_' as usual for identifiers. 9277 ident = p[1] 9278 if ident[0] == "_": 9279 ident = ident[1:] 9280 idents.insert(0, ident) 9281 p[0] = idents 9282 9283 def p_IdentifiersList(self, p): 9284 """ 9285 Identifiers : COMMA IDENTIFIER Identifiers 9286 """ 9287 idents = list(p[3]) 9288 # This is only used for identifier-list-valued extended attributes, and if 9289 # we're going to restrict to IDENTIFIER here we should at least allow 9290 # escaping with leading '_' as usual for identifiers. 9291 ident = p[2] 9292 if ident[0] == "_": 9293 ident = ident[1:] 9294 idents.insert(0, ident) 9295 p[0] = idents 9296 9297 def p_IdentifiersEmpty(self, p): 9298 """ 9299 Identifiers : 9300 """ 9301 p[0] = [] 9302 9303 def p_error(self, p): 9304 if not p: 9305 raise WebIDLError( 9306 ( 9307 "Syntax Error at end of file. Possibly due to " 9308 "missing semicolon(;), braces(}) or both" 9309 ), 9310 [self._filename], 9311 ) 9312 else: 9313 raise WebIDLError( 9314 "invalid syntax", 9315 [Location(self.lexer, p.lineno, p.lexpos, self._filename)], 9316 ) 9317 9318 def __init__(self, outputdir="", lexer=None): 9319 Tokenizer.__init__(self, outputdir, lexer) 9320 9321 logger = SqueakyCleanLogger() 9322 try: 9323 self.parser = yacc.yacc( 9324 module=self, 9325 outputdir=outputdir, 9326 errorlog=logger, 9327 write_tables=False, 9328 # Pickling the grammar is a speedup in 9329 # some cases (older Python?) but a 9330 # significant slowdown in others. 9331 # We're not pickling for now, until it 9332 # becomes a speedup again. 9333 # , picklefile='WebIDLGrammar.pkl' 9334 ) 9335 finally: 9336 logger.reportGrammarErrors() 9337 9338 self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None) 9339 self._installBuiltins(self._globalScope) 9340 self._productions = [] 9341 9342 def _installBuiltins(self, scope): 9343 assert isinstance(scope, IDLScope) 9344 9345 # range omits the last value. 9346 for x in range( 9347 IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.BigUint64Array + 1 9348 ): 9349 builtin = BuiltinTypes[x] 9350 identifier = IDLUnresolvedIdentifier( 9351 BuiltinLocation("<builtin type>"), builtin.name 9352 ) 9353 IDLTypedef( 9354 BuiltinLocation("<builtin type>"), 9355 scope, 9356 builtin, 9357 identifier, 9358 ) 9359 9360 @staticmethod 9361 def handleNullable(type, questionMarkLocation): 9362 if questionMarkLocation is not None: 9363 type = IDLNullableType(questionMarkLocation, type) 9364 9365 return type 9366 9367 def parse(self, t, filename=None): 9368 self.lexer.input(t) 9369 9370 # for tok in iter(self.lexer.token, None): 9371 # print tok 9372 9373 self._filename = filename 9374 self._productions.extend(self.parser.parse(lexer=self.lexer, tracking=True)) 9375 self._filename = None 9376 9377 def finish(self): 9378 # If we have interfaces that are iterable, create their 9379 # iterator interfaces and add them to the productions array. 9380 interfaceStatements = [] 9381 for p in self._productions: 9382 if isinstance(p, IDLInterface): 9383 interfaceStatements.append(p) 9384 9385 for iface in interfaceStatements: 9386 iterable = None 9387 # We haven't run finish() on the interface yet, so we don't know 9388 # whether our interface is maplike/setlike/iterable or not. This 9389 # means we have to loop through the members to see if we have an 9390 # iterable member. 9391 for m in iface.members: 9392 if isinstance(m, (IDLIterable, IDLAsyncIterable)): 9393 iterable = m 9394 break 9395 if iterable and (iterable.isPairIterator() or iterable.isAsyncIterable()): 9396 9397 def simpleExtendedAttr(str): 9398 return IDLExtendedAttribute(iface.location, (str,)) 9399 9400 if isinstance(iterable, IDLAsyncIterable): 9401 nextReturnType = IDLPromiseType( 9402 iterable.location, BuiltinTypes[IDLBuiltinType.Types.any] 9403 ) 9404 else: 9405 nextReturnType = BuiltinTypes[IDLBuiltinType.Types.object] 9406 nextMethod = IDLMethod( 9407 iterable.location, 9408 IDLUnresolvedIdentifier(iterable.location, "next"), 9409 nextReturnType, 9410 [], 9411 ) 9412 nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) 9413 9414 methods = [nextMethod] 9415 9416 if iterable.getExtendedAttribute("GenerateReturnMethod"): 9417 assert isinstance(iterable, IDLAsyncIterable) 9418 9419 returnMethod = IDLMethod( 9420 iterable.location, 9421 IDLUnresolvedIdentifier(iterable.location, "return"), 9422 IDLPromiseType( 9423 iterable.location, BuiltinTypes[IDLBuiltinType.Types.any] 9424 ), 9425 [ 9426 IDLArgument( 9427 iterable.location, 9428 IDLUnresolvedIdentifier( 9429 BuiltinLocation("<auto-generated-identifier>"), 9430 "value", 9431 ), 9432 BuiltinTypes[IDLBuiltinType.Types.any], 9433 optional=True, 9434 ), 9435 ], 9436 ) 9437 returnMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) 9438 methods.append(returnMethod) 9439 9440 if iterable.isIterable(): 9441 itr_suffix = "Iterator" 9442 else: 9443 itr_suffix = "AsyncIterator" 9444 itr_ident = IDLUnresolvedIdentifier( 9445 iface.location, iface.identifier.name + itr_suffix 9446 ) 9447 if iterable.isIterable(): 9448 classNameOverride = iface.identifier.name + " Iterator" 9449 elif iterable.isAsyncIterable(): 9450 classNameOverride = iface.identifier.name + " AsyncIterator" 9451 itr_iface = IDLInterface( 9452 iface.location, 9453 self.globalScope(), 9454 itr_ident, 9455 None, 9456 methods, 9457 isKnownNonPartial=True, 9458 classNameOverride=classNameOverride, 9459 ) 9460 itr_iface.addExtendedAttributes( 9461 [simpleExtendedAttr("LegacyNoInterfaceObject")] 9462 ) 9463 # Make sure the exposure set for the iterator interface is the 9464 # same as the exposure set for the iterable interface, because 9465 # we're going to generate methods on the iterable that return 9466 # instances of the iterator. 9467 itr_iface._exposureGlobalNames = set(iface._exposureGlobalNames) 9468 # Always append generated iterable interfaces after the 9469 # interface they're a member of, otherwise nativeType generation 9470 # won't work correctly. 9471 if iterable.isIterable(): 9472 itr_iface.iterableInterface = iface 9473 else: 9474 itr_iface.asyncIterableInterface = iface 9475 self._productions.append(itr_iface) 9476 iterable.iteratorType = IDLWrapperType(iface.location, itr_iface) 9477 9478 # Make sure we finish IDLIncludesStatements before we finish the 9479 # IDLInterfaces. 9480 # XXX khuey hates this bit and wants to nuke it from orbit. 9481 includesStatements = [ 9482 p for p in self._productions if isinstance(p, IDLIncludesStatement) 9483 ] 9484 otherStatements = [ 9485 p for p in self._productions if not isinstance(p, IDLIncludesStatement) 9486 ] 9487 for production in includesStatements: 9488 production.finish(self.globalScope()) 9489 for production in otherStatements: 9490 production.finish(self.globalScope()) 9491 9492 # Do any post-finish validation we need to do 9493 for production in self._productions: 9494 production.validate() 9495 9496 # De-duplicate self._productions, without modifying its order. 9497 result = dict.fromkeys(self._productions) 9498 return list(result.keys()) 9499 9500 def reset(self): 9501 return Parser(lexer=self.lexer) 9502 9503 9504 def main(): 9505 # Parse arguments. 9506 from optparse import OptionParser 9507 9508 usageString = "usage: %prog [options] files" 9509 o = OptionParser(usage=usageString) 9510 o.add_option( 9511 "--cachedir", 9512 dest="cachedir", 9513 default=None, 9514 help="Directory in which to cache lex/parse tables.", 9515 ) 9516 o.add_option( 9517 "--verbose-errors", 9518 action="store_true", 9519 default=False, 9520 help="When an error happens, display the Python traceback.", 9521 ) 9522 (options, args) = o.parse_args() 9523 9524 if len(args) < 1: 9525 o.error(usageString) 9526 9527 fileList = args 9528 baseDir = os.getcwd() 9529 9530 # Parse the WebIDL. 9531 parser = Parser(options.cachedir) 9532 try: 9533 for filename in fileList: 9534 fullPath = os.path.normpath(os.path.join(baseDir, filename)) 9535 f = open(fullPath, "rb") 9536 lines = f.readlines() 9537 f.close() 9538 print(fullPath) 9539 parser.parse("".join(lines), fullPath) 9540 parser.finish() 9541 except WebIDLError as e: 9542 if options.verbose_errors: 9543 traceback.print_exc() 9544 else: 9545 print(e) 9546 9547 9548 if __name__ == "__main__": 9549 main()