diff options
Diffstat (limited to 'components/script/dom/bindings/codegen/parser/WebIDL.py')
-rw-r--r-- | components/script/dom/bindings/codegen/parser/WebIDL.py | 5904 |
1 files changed, 3642 insertions, 2262 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index e317087837d..9618ec3531f 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -4,16 +4,17 @@ """ A WebIDL parser. """ - -from ply import lex, yacc -import re -import os -import traceback +import copy import math +import os +import re import string -from collections import defaultdict, OrderedDict +import traceback +from collections import OrderedDict, defaultdict from itertools import chain +from ply import lex, yacc + # Machinery @@ -22,14 +23,14 @@ def parseInt(literal): sign = 0 base = 0 - if string[0] == '-': + if string[0] == "-": sign = -1 string = string[1:] else: sign = 1 - if string[0] == '0' and len(string) > 1: - if string[1] == 'x' or string[1] == 'X': + if string[0] == "0" and len(string) > 1: + if string[1] == "x" or string[1] == "X": base = 16 string = string[2:] else: @@ -45,19 +46,22 @@ def parseInt(literal): def enum(*names, **kw): class Foo(object): attrs = OrderedDict() + def __init__(self, names): for v, k in enumerate(names): self.attrs[k] = v + def __getattr__(self, attr): if attr in self.attrs: return self.attrs[attr] raise AttributeError + def __setattr__(self, name, value): # this makes it read-only raise NotImplementedError if "base" not in kw: return Foo(names) - return Foo(chain(list(kw["base"].attrs.keys()), names)) + return Foo(chain(kw["base"].attrs.keys(), names)) class WebIDLError(Exception): @@ -67,10 +71,12 @@ class WebIDLError(Exception): self.warning = warning def __str__(self): - return "%s: %s%s%s" % (self.warning and 'warning' or 'error', - self.message, - ", " if len(self.locations) != 0 else "", - "\n".join(self.locations)) + return "%s: %s%s%s" % ( + self.warning and "warning" or "error", + self.message, + ", " if len(self.locations) != 0 else "", + "\n".join(self.locations), + ) class Location(object): @@ -82,8 +88,7 @@ class Location(object): self._file = filename if filename else "<unknown>" def __eq__(self, other): - return (self._lexpos == other._lexpos and - self._file == other._file) + return self._lexpos == other._lexpos and self._file == other._file def filename(self): return self._file @@ -92,8 +97,8 @@ class Location(object): if self._line: return - startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1 - endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80) + startofline = self._lexdata.rfind("\n", 0, self._lexpos) + 1 + endofline = self._lexdata.find("\n", self._lexpos, self._lexpos + 80) if endofline != -1: self._line = self._lexdata[startofline:endofline] else: @@ -101,7 +106,7 @@ class Location(object): self._colno = self._lexpos - startofline # Our line number seems to point to the start of self._lexdata - self._lineno += self._lexdata.count('\n', 0, startofline) + self._lineno += self._lexdata.count("\n", 0, startofline) def get(self): self.resolve() @@ -112,8 +117,13 @@ class Location(object): def __str__(self): self.resolve() - return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno, - self._line, self._pointerline()) + return "%s line %s:%s\n%s\n%s" % ( + self._file, + self._lineno, + self._colno, + self._line, + self._pointerline(), + ) class BuiltinLocation(object): @@ -121,14 +131,10 @@ class BuiltinLocation(object): self.msg = text + "\n" def __eq__(self, other): - return (isinstance(other, BuiltinLocation) and - self.msg == other.msg) - - def __hash__(self): - return hash(self.msg) + return isinstance(other, BuiltinLocation) and self.msg == other.msg def filename(self): - return '<builtin>' + return "<builtin>" def resolve(self): pass @@ -194,13 +200,13 @@ class IDLObject(object): assert False # Override me! def getDeps(self, visited=None): - """ Return a set of files that this object depends on. If any of - these files are changed the parser needs to be rerun to regenerate - a new IDLObject. + """Return a set of files that this object depends on. If any of + these files are changed the parser needs to be rerun to regenerate + a new IDLObject. - The visited argument is a set of all the objects already visited. - We must test to see if we are in it, and if so, do nothing. This - prevents infinite recursion.""" + The visited argument is a set of all the objects already visited. + We must test to see if we are in it, and if so, do nothing. This + prevents infinite recursion.""" # NB: We can't use visited=set() above because the default value is # evaluated when the def statement is evaluated, not when the function @@ -256,9 +262,9 @@ class IDLScope(IDLObject): def ensureUnique(self, identifier, object): """ - Ensure that there is at most one 'identifier' in scope ('self'). - Note that object can be None. This occurs if we end up here for an - interface type we haven't seen yet. + Ensure that there is at most one 'identifier' in scope ('self'). + Note that object can be None. This occurs if we end up here for an + interface type we haven't seen yet. """ assert isinstance(identifier, IDLUnresolvedIdentifier) assert not object or isinstance(object, IDLObjectWithIdentifier) @@ -271,9 +277,9 @@ class IDLScope(IDLObject): # ensureUnique twice with the same object is not allowed assert id(object) != id(self._dict[identifier.name]) - replacement = self.resolveIdentifierConflict(self, identifier, - self._dict[identifier.name], - object) + replacement = self.resolveIdentifierConflict( + self, identifier, self._dict[identifier.name], object + ) self._dict[identifier.name] = replacement return @@ -282,44 +288,53 @@ class IDLScope(IDLObject): self._dict[identifier.name] = object def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): - if (isinstance(originalObject, IDLExternalInterface) and - isinstance(newObject, IDLExternalInterface) and - originalObject.identifier.name == newObject.identifier.name): + if ( + isinstance(originalObject, IDLExternalInterface) + and isinstance(newObject, IDLExternalInterface) + and originalObject.identifier.name == newObject.identifier.name + ): return originalObject - if (isinstance(originalObject, IDLExternalInterface) or - isinstance(newObject, IDLExternalInterface)): + if isinstance(originalObject, IDLExternalInterface) or isinstance( + newObject, IDLExternalInterface + ): raise WebIDLError( "Name collision between " "interface declarations for identifier '%s' at '%s' and '%s'" - % (identifier.name, - originalObject.location, newObject.location), []) + % (identifier.name, originalObject.location, newObject.location), + [], + ) - if (isinstance(originalObject, IDLDictionary) or - isinstance(newObject, IDLDictionary)): + if isinstance(originalObject, IDLDictionary) or isinstance( + newObject, IDLDictionary + ): raise WebIDLError( "Name collision between dictionary declarations for " "identifier '%s'.\n%s\n%s" - % (identifier.name, - originalObject.location, newObject.location), []) + % (identifier.name, originalObject.location, newObject.location), + [], + ) # We do the merging of overloads here as opposed to in IDLInterface - # because we need to merge overloads of NamedConstructors and we need to + # because we need to merge overloads of LegacyFactoryFunctions and we need to # detect conflicts in those across interfaces. See also the comment in - # IDLInterface.addExtendedAttributes for "NamedConstructor". - if (isinstance(originalObject, IDLMethod) and - isinstance(newObject, IDLMethod)): + # IDLInterface.addExtendedAttributes for "LegacyFactoryFunction". + if isinstance(originalObject, IDLMethod) and isinstance(newObject, IDLMethod): return originalObject.addOverload(newObject) # Default to throwing, derived classes can override. - conflictdesc = "\n\t%s at %s\n\t%s at %s" % (originalObject, - originalObject.location, - newObject, - newObject.location) + conflictdesc = "\n\t%s at %s\n\t%s at %s" % ( + originalObject, + originalObject.location, + newObject, + newObject.location, + ) raise WebIDLError( "Multiple unresolvable definitions of identifier '%s' in scope '%s'%s" - % (identifier.name, str(self), conflictdesc), []) + % (identifier.name, str(self), conflictdesc), + [], + ) def _lookupIdentifier(self, identifier): return self._dict[identifier.name] @@ -362,8 +377,9 @@ class IDLIdentifier(IDLObject): class IDLUnresolvedIdentifier(IDLObject): - def __init__(self, location, name, allowDoubleUnderscore=False, - allowForbidden=False): + def __init__( + self, location, name, allowDoubleUnderscore=False, allowForbidden=False + ): IDLObject.__init__(self, location) assert len(name) > 0 @@ -371,15 +387,14 @@ class IDLUnresolvedIdentifier(IDLObject): if name == "__noSuchMethod__": raise WebIDLError("__noSuchMethod__ is deprecated", [location]) - if name[:2] == "__" and name != "__content" and not allowDoubleUnderscore: - raise WebIDLError("Identifiers beginning with __ are reserved", - [location]) - if name[0] == '_' and not allowDoubleUnderscore: + if name[:2] == "__" and not allowDoubleUnderscore: + raise WebIDLError("Identifiers beginning with __ are reserved", [location]) + if name[0] == "_" and not allowDoubleUnderscore: name = name[1:] - if (name in ["constructor", "toString"] and - not allowForbidden): - raise WebIDLError("Cannot use reserved identifier '%s'" % (name), - [location]) + if name in ["constructor", "toString"] and not allowForbidden: + raise WebIDLError( + "Cannot use reserved identifier '%s'" % (name), [location] + ) self.name = name @@ -439,14 +454,15 @@ class IDLIdentifierPlaceholder(IDLObjectWithIdentifier): try: scope._lookupIdentifier(self.identifier) except: - raise WebIDLError("Unresolved type '%s'." % self.identifier, - [self.location]) + raise WebIDLError( + "Unresolved type '%s'." % self.identifier, [self.location] + ) obj = self.identifier.resolve(scope, None) return scope.lookupIdentifier(obj) -class IDLExposureMixins(): +class IDLExposureMixins: def __init__(self, location): # _exposureGlobalNames are the global names listed in our [Exposed] # extended attribute. exposureSet is the exposure set as defined in the @@ -460,11 +476,15 @@ class IDLExposureMixins(): assert scope.parentScope is None self._globalScope = scope - # Verify that our [Exposed] value, if any, makes sense. - for globalName in self._exposureGlobalNames: - if globalName not in scope.globalNames: - raise WebIDLError("Unknown [Exposed] value %s" % globalName, - [self._location]) + if "*" in self._exposureGlobalNames: + self._exposureGlobalNames = scope.globalNames + else: + # Verify that our [Exposed] value, if any, makes sense. + for globalName in self._exposureGlobalNames: + if globalName not in scope.globalNames: + raise WebIDLError( + "Unknown [Exposed] value %s" % globalName, [self._location] + ) # Verify that we are exposed _somwhere_ if we have some place to be # exposed. We don't want to assert that we're definitely exposed @@ -473,16 +493,20 @@ class IDLExposureMixins(): # and add global interfaces and [Exposed] annotations to all those # tests. if len(scope.globalNames) != 0: - if (len(self._exposureGlobalNames) == 0): - raise WebIDLError(("'%s' is not exposed anywhere even though we have " - "globals to be exposed to") % self, - [self.location]) + if len(self._exposureGlobalNames) == 0 and not self.isPseudoInterface(): + raise WebIDLError( + ( + "'%s' is not exposed anywhere even though we have " + "globals to be exposed to" + ) + % self, + [self.location], + ) - globalNameSetToExposureSet(scope, self._exposureGlobalNames, - self.exposureSet) + globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposureSet) def isExposedInWindow(self): - return 'Window' in self.exposureSet + return "Window" in self.exposureSet def isExposedInAnyWorker(self): return len(self.getWorkerExposureSet()) > 0 @@ -505,6 +529,9 @@ class IDLExposureMixins(): workerScopes = self.parentScope.globalNameMapping["Worker"] return len(workerScopes.difference(self.exposureSet)) > 0 + def isExposedInShadowRealms(self): + return "ShadowRealmGlobalScope" in self.exposureSet + def getWorkerExposureSet(self): workerScopes = self._globalScope.globalNameMapping["Worker"] return workerScopes.intersection(self.exposureSet) @@ -535,6 +562,9 @@ class IDLExternalInterface(IDLObjectWithIdentifier): def isIteratorInterface(self): return False + def isAsyncIteratorInterface(self): + return False + def isExternal(self): return True @@ -543,9 +573,11 @@ class IDLExternalInterface(IDLObjectWithIdentifier): def addExtendedAttributes(self, attrs): if len(attrs) != 0: - raise WebIDLError("There are no extended attributes that are " - "allowed on external interfaces", - [attrs[0].location, self.location]) + raise WebIDLError( + "There are no extended attributes that are " + "allowed on external interfaces", + [attrs[0].location, self.location], + ) def resolve(self, parentScope): pass @@ -610,49 +642,68 @@ class IDLPartialInterfaceOrNamespace(IDLObject): for attr in attrs: identifier = attr.identifier() - if identifier == "NamedConstructor": + if identifier == "LegacyFactoryFunction": self.propagatedExtendedAttrs.append(attr) elif identifier == "SecureContext": self._haveSecureContextExtendedAttribute = True # This gets propagated to all our members. for member in self.members: if member.getExtendedAttribute("SecureContext"): - raise WebIDLError("[SecureContext] specified on both a " - "partial interface member and on the " - "partial interface itself", - [member.location, attr.location]) + raise WebIDLError( + "[SecureContext] specified on both a " + "partial interface member and on the " + "partial interface itself", + [member.location, attr.location], + ) member.addExtendedAttributes([attr]) elif identifier == "Exposed": # This just gets propagated to all our members. for member in self.members: if len(member._exposureGlobalNames) != 0: - raise WebIDLError("[Exposed] specified on both a " - "partial interface member and on the " - "partial interface itself", - [member.location, attr.location]) + raise WebIDLError( + "[Exposed] specified on both a " + "partial interface member and on the " + "partial interface itself", + [member.location, attr.location], + ) member.addExtendedAttributes([attr]) else: - raise WebIDLError("Unknown extended attribute %s on partial " - "interface" % identifier, - [attr.location]) + raise WebIDLError( + "Unknown extended attribute %s on partial " + "interface" % identifier, + [attr.location], + ) def finish(self, scope): if self._finished: return self._finished = True - if (not self._haveSecureContextExtendedAttribute and - self._nonPartialInterfaceOrNamespace.getExtendedAttribute("SecureContext")): + if ( + not self._haveSecureContextExtendedAttribute + and self._nonPartialInterfaceOrNamespace.getExtendedAttribute( + "SecureContext" + ) + ): # This gets propagated to all our members. for member in self.members: if member.getExtendedAttribute("SecureContext"): - raise WebIDLError("[SecureContext] specified on both a " - "partial interface member and on the " - "non-partial interface", - [member.location, - self._nonPartialInterfaceOrNamespace.location]) + raise WebIDLError( + "[SecureContext] specified on both a " + "partial interface member and on the " + "non-partial interface", + [ + member.location, + self._nonPartialInterfaceOrNamespace.location, + ], + ) member.addExtendedAttributes( - [IDLExtendedAttribute(self._nonPartialInterfaceOrNamespace.location, - ("SecureContext",))]) + [ + IDLExtendedAttribute( + self._nonPartialInterfaceOrNamespace.location, + ("SecureContext",), + ) + ] + ) # Need to make sure our non-partial interface or namespace gets # finished so it can report cases when we only have partial # interfaces/namespaces. @@ -675,6 +726,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): for name in nameSet: exposureSet.update(globalScope.globalNameMapping[name]) + class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins): def __init__(self, location, parentScope, name): assert isinstance(parentScope, IDLScope) @@ -691,8 +743,10 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix def finish(self, scope): if not self._isKnownNonPartial: - raise WebIDLError("%s does not have a non-partial declaration" % - str(self), [self.location]) + raise WebIDLError( + "%s does not have a non-partial declaration" % str(self), + [self.location], + ) IDLExposureMixins.finish(self, scope) @@ -707,8 +761,9 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix assert isinstance(originalObject, IDLInterfaceMember) assert isinstance(newObject, IDLInterfaceMember) - retval = IDLScope.resolveIdentifierConflict(self, scope, identifier, - originalObject, newObject) + retval = IDLScope.resolveIdentifierConflict( + self, scope, identifier, originalObject, newObject + ) # Might be a ctor, which isn't in self.members if newObject in self.members: @@ -728,9 +783,10 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix def setNonPartial(self, location, members): if self._isKnownNonPartial: - raise WebIDLError("Two non-partial definitions for the " - "same %s" % self.typeName(), - [location, self.location]) + raise WebIDLError( + "Two non-partial definitions for the " "same %s" % self.typeName(), + [location, self.location], + ) self._isKnownNonPartial = True # Now make it look like we were parsed at this new location, since # that's the place where the interface is "really" defined @@ -775,9 +831,11 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix # sets, make sure they aren't exposed in places where we are not. for member in self.members: if not member.exposureSet.issubset(self.exposureSet): - raise WebIDLError("Interface or interface mixin member has " - "larger exposure set than its container", - [member.location, self.location]) + raise WebIDLError( + "Interface or interface mixin member has " + "larger exposure set than its container", + [member.location, self.location], + ) def isExternal(self): return False @@ -788,7 +846,9 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): self.actualExposureGlobalNames = set() assert isKnownNonPartial or len(members) == 0 - IDLInterfaceOrInterfaceMixinOrNamespace.__init__(self, location, parentScope, name) + IDLInterfaceOrInterfaceMixinOrNamespace.__init__( + self, location, parentScope, name + ) if isKnownNonPartial: self.setNonPartial(location, members) @@ -824,26 +884,33 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): if member.isAttr(): if member.inherit: - raise WebIDLError("Interface mixin member cannot include " - "an inherited attribute", - [member.location, self.location]) + raise WebIDLError( + "Interface mixin member cannot include " + "an inherited attribute", + [member.location, self.location], + ) if member.isStatic(): - raise WebIDLError("Interface mixin member cannot include " - "a static member", - [member.location, self.location]) + raise WebIDLError( + "Interface mixin member cannot include " "a static member", + [member.location, self.location], + ) if member.isMethod(): if member.isStatic(): - raise WebIDLError("Interface mixin member cannot include " - "a static operation", - [member.location, self.location]) - if (member.isGetter() or - member.isSetter() or - member.isDeleter() or - member.isLegacycaller()): - raise WebIDLError("Interface mixin member cannot include a " - "special operation", - [member.location, self.location]) + raise WebIDLError( + "Interface mixin member cannot include " "a static operation", + [member.location, self.location], + ) + if ( + member.isGetter() + or member.isSetter() + or member.isDeleter() + or member.isLegacycaller() + ): + raise WebIDLError( + "Interface mixin member cannot include a " "special operation", + [member.location, self.location], + ) def addExtendedAttributes(self, attrs): for attr in attrs: @@ -851,22 +918,26 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): if identifier == "SecureContext": if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must take no arguments" % identifier, [attr.location] + ) # This gets propagated to all our members. for member in self.members: if member.getExtendedAttribute("SecureContext"): - raise WebIDLError("[SecureContext] specified on both " - "an interface mixin member and on" - "the interface mixin itself", - [member.location, attr.location]) + raise WebIDLError( + "[SecureContext] specified on both " + "an interface mixin member and on" + "the interface mixin itself", + [member.location, attr.location], + ) member.addExtendedAttributes([attr]) elif identifier == "Exposed": - convertExposedAttrToGlobalNameSet(attr, - self._exposureGlobalNames) + convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) else: - raise WebIDLError("Unknown extended attribute %s on interface" % identifier, - [attr.location]) + raise WebIDLError( + "Unknown extended attribute %s on interface" % identifier, + [attr.location], + ) attrlist = attr.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True @@ -876,8 +947,7 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): - def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial, toStringTag): + def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial): assert isKnownNonPartial or not parent assert isKnownNonPartial or len(members) == 0 @@ -887,7 +957,7 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # namedConstructors needs deterministic ordering because bindings code # outputs the constructs in the order that namedConstructors enumerates # them. - self.namedConstructors = list() + self.legacyFactoryFunctions = list() self.legacyWindowAliases = [] self.includedMixins = set() # self.interfacesBasedOnSelf is the set of interfaces that inherit from @@ -896,6 +966,9 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): self.interfacesBasedOnSelf = set([self]) self._hasChildInterfaces = False self._isOnGlobalProtoChain = False + # Pseudo interfaces aren't exposed anywhere, and so shouldn't issue warnings + self._isPseudo = False + # Tracking of the number of reserved slots we need for our # members and those of ancestor interfaces. self.totalMembersInSlots = 0 @@ -904,33 +977,49 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # If this is an iterator interface, we need to know what iterable # interface we're iterating for in order to get its nativeType. self.iterableInterface = None + self.asyncIterableInterface = None # True if we have cross-origin members. self.hasCrossOriginMembers = False # True if some descendant (including ourselves) has cross-origin members self.hasDescendantWithCrossOriginMembers = False - self.toStringTag = toStringTag - - IDLInterfaceOrInterfaceMixinOrNamespace.__init__(self, location, parentScope, name) + IDLInterfaceOrInterfaceMixinOrNamespace.__init__( + self, location, parentScope, name + ) if isKnownNonPartial: self.setNonPartial(location, parent, members) def ctor(self): - identifier = IDLUnresolvedIdentifier(self.location, "constructor", - allowForbidden=True) + identifier = IDLUnresolvedIdentifier( + self.location, "constructor", allowForbidden=True + ) try: return self._lookupIdentifier(identifier) except: return None def isIterable(self): - return (self.maplikeOrSetlikeOrIterable and - self.maplikeOrSetlikeOrIterable.isIterable()) + return ( + self.maplikeOrSetlikeOrIterable + and self.maplikeOrSetlikeOrIterable.isIterable() + ) + + def isAsyncIterable(self): + return ( + self.maplikeOrSetlikeOrIterable + and self.maplikeOrSetlikeOrIterable.isAsyncIterable() + ) def isIteratorInterface(self): return self.iterableInterface is not None + def isAsyncIteratorInterface(self): + return self.asyncIterableInterface is not None + + def getClassName(self): + return self.identifier.name + def finish(self, scope): if self._finished: return @@ -941,48 +1030,71 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): if len(self.legacyWindowAliases) > 0: if not self.hasInterfaceObject(): - raise WebIDLError("Interface %s unexpectedly has [LegacyWindowAlias] " - "and [NoInterfaceObject] together" % self.identifier.name, - [self.location]) + raise WebIDLError( + "Interface %s unexpectedly has [LegacyWindowAlias] " + "and [LegacyNoInterfaceObject] together" % self.identifier.name, + [self.location], + ) if not self.isExposedInWindow(): - raise WebIDLError("Interface %s has [LegacyWindowAlias] " - "but not exposed in Window" % self.identifier.name, - [self.location]) + raise WebIDLError( + "Interface %s has [LegacyWindowAlias] " + "but not exposed in Window" % self.identifier.name, + [self.location], + ) # Generate maplike/setlike interface members. Since generated members # need to be treated like regular interface members, do this before # things like exposure setting. for member in self.members: if member.isMaplikeOrSetlikeOrIterable(): + if self.isJSImplemented(): + raise WebIDLError( + "%s declaration used on " + "interface that is implemented in JS" + % (member.maplikeOrSetlikeOrIterableType), + [member.location], + ) + if member.valueType.isObservableArray() or ( + member.hasKeyType() and member.keyType.isObservableArray() + ): + raise WebIDLError( + "%s declaration uses ObservableArray as value or key type" + % (member.maplikeOrSetlikeOrIterableType), + [member.location], + ) # Check that we only have one interface declaration (currently # there can only be one maplike/setlike declaration per # interface) if self.maplikeOrSetlikeOrIterable: - raise WebIDLError("%s declaration used on " - "interface that already has %s " - "declaration" % - (member.maplikeOrSetlikeOrIterableType, - self.maplikeOrSetlikeOrIterable.maplikeOrSetlikeOrIterableType), - [self.maplikeOrSetlikeOrIterable.location, - member.location]) + raise WebIDLError( + "%s declaration used on " + "interface that already has %s " + "declaration" + % ( + member.maplikeOrSetlikeOrIterableType, + self.maplikeOrSetlikeOrIterable.maplikeOrSetlikeOrIterableType, + ), + [self.maplikeOrSetlikeOrIterable.location, member.location], + ) self.maplikeOrSetlikeOrIterable = member # If we've got a maplike or setlike declaration, we'll be building all of # our required methods in Codegen. Generate members now. - self.maplikeOrSetlikeOrIterable.expand(self.members, self.isJSImplemented()) + self.maplikeOrSetlikeOrIterable.expand(self.members) assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder) parent = self.parent.finish(scope) if self.parent else None if parent and isinstance(parent, IDLExternalInterface): - raise WebIDLError("%s inherits from %s which does not have " - "a definition" % - (self.identifier.name, - self.parent.identifier.name), - [self.location]) + raise WebIDLError( + "%s inherits from %s which does not have " + "a definition" % (self.identifier.name, self.parent.identifier.name), + [self.location], + ) if parent and not isinstance(parent, IDLInterface): - raise WebIDLError("%s inherits from %s which is not an interface " % - (self.identifier.name, - self.parent.identifier.name), - [self.location, parent.location]) + raise WebIDLError( + "%s inherits from %s which is not an interface " + % (self.identifier.name, self.parent.identifier.name), + [self.location, parent.location], + ) self.parent = parent @@ -993,9 +1105,10 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): for m in self.members: if m.isAttr() or m.isMethod(): if m.isStatic(): - raise WebIDLError("Don't mark things explicitly static " - "in namespaces", - [self.location, m.location]) + raise WebIDLError( + "Don't mark things explicitly static " "in namespaces", + [self.location, m.location], + ) # Just mark all our methods/attributes as static. The other # option is to duplicate the relevant InterfaceMembers # production bits but modified to produce static stuff to @@ -1013,55 +1126,63 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # Note: This is not a self.parent.isOnGlobalProtoChain() check # because ancestors of a [Global] interface can have other # descendants. - raise WebIDLError("[Global] interface has another interface " - "inheriting from it", - [self.location, self.parent.location]) + raise WebIDLError( + "[Global] interface has another interface " "inheriting from it", + [self.location, self.parent.location], + ) # Make sure that we're not exposed in places where our parent is not if not self.exposureSet.issubset(self.parent.exposureSet): - raise WebIDLError("Interface %s is exposed in globals where its " - "parent interface %s is not exposed." % - (self.identifier.name, - self.parent.identifier.name), - [self.location, self.parent.location]) + raise WebIDLError( + "Interface %s is exposed in globals where its " + "parent interface %s is not exposed." + % (self.identifier.name, self.parent.identifier.name), + [self.location, self.parent.location], + ) # Callbacks must not inherit from non-callbacks. # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending. if self.isCallback(): if not self.parent.isCallback(): - raise WebIDLError("Callback interface %s inheriting from " - "non-callback interface %s" % - (self.identifier.name, - self.parent.identifier.name), - [self.location, self.parent.location]) + raise WebIDLError( + "Callback interface %s inheriting from " + "non-callback interface %s" + % (self.identifier.name, self.parent.identifier.name), + [self.location, self.parent.location], + ) elif self.parent.isCallback(): - raise WebIDLError("Non-callback interface %s inheriting from " - "callback interface %s" % - (self.identifier.name, - self.parent.identifier.name), - [self.location, self.parent.location]) + raise WebIDLError( + "Non-callback interface %s inheriting from " + "callback interface %s" + % (self.identifier.name, self.parent.identifier.name), + [self.location, self.parent.location], + ) # Interfaces which have interface objects can't inherit - # from [NoInterfaceObject] interfaces. - if (self.parent.getExtendedAttribute("NoInterfaceObject") and - not self.getExtendedAttribute("NoInterfaceObject")): - raise WebIDLError("Interface %s does not have " - "[NoInterfaceObject] but inherits from " - "interface %s which does" % - (self.identifier.name, - self.parent.identifier.name), - [self.location, self.parent.location]) + # from [LegacyNoInterfaceObject] interfaces. + if self.parent.getExtendedAttribute( + "LegacyNoInterfaceObject" + ) and not self.getExtendedAttribute("LegacyNoInterfaceObject"): + raise WebIDLError( + "Interface %s does not have " + "[LegacyNoInterfaceObject] but inherits from " + "interface %s which does" + % (self.identifier.name, self.parent.identifier.name), + [self.location, self.parent.location], + ) # Interfaces that are not [SecureContext] can't inherit # from [SecureContext] interfaces. - if (self.parent.getExtendedAttribute("SecureContext") and - not self.getExtendedAttribute("SecureContext")): - raise WebIDLError("Interface %s does not have " - "[SecureContext] but inherits from " - "interface %s which does" % - (self.identifier.name, - self.parent.identifier.name), - [self.location, self.parent.location]) + if self.parent.getExtendedAttribute( + "SecureContext" + ) and not self.getExtendedAttribute("SecureContext"): + raise WebIDLError( + "Interface %s does not have " + "[SecureContext] but inherits from " + "interface %s which does" + % (self.identifier.name, self.parent.identifier.name), + [self.location, self.parent.location], + ) for mixin in self.includedMixins: mixin.finish(scope) @@ -1070,7 +1191,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): if cycleInGraph: raise WebIDLError( "Interface %s has itself as ancestor" % self.identifier.name, - [self.location, cycleInGraph.location]) + [self.location, cycleInGraph.location], + ) self.finishMembers(scope) @@ -1078,25 +1200,28 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): if ctor is not None: if not self.hasInterfaceObject(): raise WebIDLError( - "Can't have both a constructor and [NoInterfaceObject]", - [self.location, ctor.location]) + "Can't have both a constructor and [LegacyNoInterfaceObject]", + [self.location, ctor.location], + ) if self.globalNames: raise WebIDLError( "Can't have both a constructor and [Global]", - [self.location, ctor.location]) + [self.location, ctor.location], + ) - assert(ctor._exposureGlobalNames == self._exposureGlobalNames) + assert ctor._exposureGlobalNames == self._exposureGlobalNames ctor._exposureGlobalNames.update(self._exposureGlobalNames) # Remove the constructor operation from our member list so # it doesn't get in the way later. self.members.remove(ctor) - for ctor in self.namedConstructors: + for ctor in self.legacyFactoryFunctions: if self.globalNames: raise WebIDLError( - "Can't have both a named constructor and [Global]", - [self.location, ctor.location]) + "Can't have both a legacy factory function and [Global]", + [self.location, ctor.location], + ) assert len(ctor._exposureGlobalNames) == 0 ctor._exposureGlobalNames.update(self._exposureGlobalNames) ctor.finish(scope) @@ -1106,67 +1231,84 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # admixed. self.originalMembers = list(self.members) - for mixin in sorted(self.includedMixins, - key=lambda x: x.identifier.name): + for mixin in sorted(self.includedMixins, key=lambda x: x.identifier.name): for mixinMember in mixin.members: for member in self.members: if mixinMember.identifier.name == member.identifier.name: raise WebIDLError( - "Multiple definitions of %s on %s coming from 'includes' statements" % - (member.identifier.name, self), - [mixinMember.location, member.location]) + "Multiple definitions of %s on %s coming from 'includes' statements" + % (member.identifier.name, self), + [mixinMember.location, member.location], + ) self.members.extend(mixin.members) for ancestor in self.getInheritedInterfaces(): ancestor.interfacesBasedOnSelf.add(self) - if (ancestor.maplikeOrSetlikeOrIterable is not None and - self.maplikeOrSetlikeOrIterable is not None): - raise WebIDLError("Cannot have maplike/setlike on %s that " - "inherits %s, which is already " - "maplike/setlike" % - (self.identifier.name, - ancestor.identifier.name), - [self.maplikeOrSetlikeOrIterable.location, - ancestor.maplikeOrSetlikeOrIterable.location]) - - # Deal with interfaces marked [Unforgeable], now that we have our full + if ( + ancestor.maplikeOrSetlikeOrIterable is not None + and self.maplikeOrSetlikeOrIterable is not None + ): + raise WebIDLError( + "Cannot have maplike/setlike on %s that " + "inherits %s, which is already " + "maplike/setlike" + % (self.identifier.name, ancestor.identifier.name), + [ + self.maplikeOrSetlikeOrIterable.location, + ancestor.maplikeOrSetlikeOrIterable.location, + ], + ) + + # Deal with interfaces marked [LegacyUnforgeable], now that we have our full # member list, except unforgeables pulled in from parents. We want to # do this before we set "originatingInterface" on our unforgeable # members. - if self.getExtendedAttribute("Unforgeable"): + if self.getExtendedAttribute("LegacyUnforgeable"): # Check that the interface already has all the things the # spec would otherwise require us to synthesize and is # missing the ones we plan to synthesize. if not any(m.isMethod() and m.isStringifier() for m in self.members): - raise WebIDLError("Unforgeable interface %s does not have a " - "stringifier" % self.identifier.name, - [self.location]) + raise WebIDLError( + "LegacyUnforgeable interface %s does not have a " + "stringifier" % self.identifier.name, + [self.location], + ) for m in self.members: if m.identifier.name == "toJSON": - raise WebIDLError("Unforgeable interface %s has a " - "toJSON so we won't be able to add " - "one ourselves" % self.identifier.name, - [self.location, m.location]) + raise WebIDLError( + "LegacyUnforgeable interface %s has a " + "toJSON so we won't be able to add " + "one ourselves" % self.identifier.name, + [self.location, m.location], + ) if m.identifier.name == "valueOf" and not m.isStatic(): - raise WebIDLError("Unforgeable interface %s has a valueOf " - "member so we won't be able to add one " - "ourselves" % self.identifier.name, - [self.location, m.location]) + raise WebIDLError( + "LegacyUnforgeable interface %s has a valueOf " + "member so we won't be able to add one " + "ourselves" % self.identifier.name, + [self.location, m.location], + ) for member in self.members: - if ((member.isAttr() or member.isMethod()) and - member.isUnforgeable() and - not hasattr(member, "originatingInterface")): + if ( + (member.isAttr() or member.isMethod()) + and member.isLegacyUnforgeable() + and not hasattr(member, "originatingInterface") + ): member.originatingInterface = self for member in self.members: - if ((member.isMethod() and - member.getExtendedAttribute("CrossOriginCallable")) or - (member.isAttr() and - (member.getExtendedAttribute("CrossOriginReadable") or - member.getExtendedAttribute("CrossOriginWritable")))): + if ( + member.isMethod() and member.getExtendedAttribute("CrossOriginCallable") + ) or ( + member.isAttr() + and ( + member.getExtendedAttribute("CrossOriginReadable") + or member.getExtendedAttribute("CrossOriginWritable") + ) + ): self.hasCrossOriginMembers = True break @@ -1180,16 +1322,21 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): # members from our parent. Also, maplike/setlike declarations get a # slot to hold their backing object. for member in self.members: - if ((member.isAttr() and - (member.getExtendedAttribute("StoreInSlot") or - member.getExtendedAttribute("Cached"))) or - member.isMaplikeOrSetlike()): + if ( + member.isAttr() + and ( + member.getExtendedAttribute("StoreInSlot") + or member.getExtendedAttribute("Cached") + or member.type.isObservableArray() + ) + ) or member.isMaplikeOrSetlike(): if self.isJSImplemented() and not member.isMaplikeOrSetlike(): - raise WebIDLError("Interface %s is JS-implemented and we " - "don't support [Cached] or [StoreInSlot] " - "on JS-implemented interfaces" % - self.identifier.name, - [self.location, member.location]) + raise WebIDLError( + "Interface %s is JS-implemented and we " + "don't support [Cached] or [StoreInSlot] or ObservableArray " + "on JS-implemented interfaces" % self.identifier.name, + [self.location, member.location], + ) if member.slotIndices is None: member.slotIndices = dict() member.slotIndices[self.identifier.name] = self.totalMembersInSlots @@ -1198,27 +1345,33 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): self._ownMembersInSlots += 1 if self.parent: - # Make sure we don't shadow any of the [Unforgeable] attributes on our + # Make sure we don't shadow any of the [LegacyUnforgeable] attributes on our # ancestor interfaces. We don't have to worry about mixins here, because # those have already been imported into the relevant .members lists. And # we don't have to worry about anything other than our parent, because it # has already imported its ancestors' unforgeable attributes into its # member list. - for unforgeableMember in (member for member in self.parent.members if - (member.isAttr() or member.isMethod()) and - member.isUnforgeable()): - shadows = [m for m in self.members if - (m.isAttr() or m.isMethod()) and - not m.isStatic() and - m.identifier.name == unforgeableMember.identifier.name] + for unforgeableMember in ( + member + for member in self.parent.members + if (member.isAttr() or member.isMethod()) + and member.isLegacyUnforgeable() + ): + shadows = [ + m + for m in self.members + if (m.isAttr() or m.isMethod()) + and not m.isStatic() + and m.identifier.name == unforgeableMember.identifier.name + ] if len(shadows) != 0: - locs = [unforgeableMember.location] + [s.location for s - in shadows] - raise WebIDLError("Interface %s shadows [Unforgeable] " - "members of %s" % - (self.identifier.name, - ancestor.identifier.name), - locs) + locs = [unforgeableMember.location] + [s.location for s in shadows] + raise WebIDLError( + "Interface %s shadows [LegacyUnforgeable] " + "members of %s" + % (self.identifier.name, ancestor.identifier.name), + locs, + ) # And now just stick it in our members, since we won't be # inheriting this down the proto chain. If we really cared we # could try to do something where we set up the unforgeable @@ -1234,8 +1387,9 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): testInterface = self isAncestor = False while testInterface: - self.maplikeOrSetlikeOrIterable.checkCollisions(testInterface.members, - isAncestor) + self.maplikeOrSetlikeOrIterable.checkCollisions( + testInterface.members, isAncestor + ) isAncestor = True testInterface = testInterface.parent @@ -1265,7 +1419,7 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): else: continue - if (memberType != "stringifiers" and memberType != "legacycallers"): + if memberType != "stringifiers" and memberType != "legacycallers": if member.isNamed(): memberType = "named " + memberType else: @@ -1273,10 +1427,14 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): memberType = "indexed " + memberType if memberType in specialMembersSeen: - raise WebIDLError("Multiple " + memberType + " on %s" % (self), - [self.location, - specialMembersSeen[memberType].location, - member.location]) + raise WebIDLError( + "Multiple " + memberType + " on %s" % (self), + [ + self.location, + specialMembersSeen[memberType].location, + member.location, + ], + ) specialMembersSeen[memberType] = member @@ -1286,7 +1444,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): raise WebIDLError( "Interface with [LegacyUnenumerableNamedProperties] does " "not have a named getter", - [self.location]) + [self.location], + ) ancestor = self.parent while ancestor: if ancestor.getExtendedAttribute("LegacyUnenumerableNamedProperties"): @@ -1294,7 +1453,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): "Interface with [LegacyUnenumerableNamedProperties] " "inherits from another interface with " "[LegacyUnenumerableNamedProperties]", - [self.location, ancestor.location]) + [self.location, ancestor.location], + ) ancestor = ancestor.parent if self._isOnGlobalProtoChain: @@ -1302,56 +1462,63 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): for memberType in ["setter", "deleter"]: memberId = "named " + memberType + "s" if memberId in specialMembersSeen: - raise WebIDLError("Interface with [Global] has a named %s" % - memberType, - [self.location, - specialMembersSeen[memberId].location]) - # Make sure we're not [OverrideBuiltins] - if self.getExtendedAttribute("OverrideBuiltins"): - raise WebIDLError("Interface with [Global] also has " - "[OverrideBuiltins]", - [self.location]) + raise WebIDLError( + "Interface with [Global] has a named %s" % memberType, + [self.location, specialMembersSeen[memberId].location], + ) + # Make sure we're not [LegacyOverrideBuiltIns] + if self.getExtendedAttribute("LegacyOverrideBuiltIns"): + raise WebIDLError( + "Interface with [Global] also has " "[LegacyOverrideBuiltIns]", + [self.location], + ) # Mark all of our ancestors as being on the global's proto chain too parent = self.parent while parent: - # Must not inherit from an interface with [OverrideBuiltins] - if parent.getExtendedAttribute("OverrideBuiltins"): - raise WebIDLError("Interface with [Global] inherits from " - "interface with [OverrideBuiltins]", - [self.location, parent.location]) + # Must not inherit from an interface with [LegacyOverrideBuiltIns] + if parent.getExtendedAttribute("LegacyOverrideBuiltIns"): + raise WebIDLError( + "Interface with [Global] inherits from " + "interface with [LegacyOverrideBuiltIns]", + [self.location, parent.location], + ) parent._isOnGlobalProtoChain = True parent = parent.parent def validate(self): - def checkDuplicateNames(member, name, attributeName): for m in self.members: if m.identifier.name == name: - raise WebIDLError("[%s=%s] has same name as interface member" % - (attributeName, name), - [member.location, m.location]) + raise WebIDLError( + "[%s=%s] has same name as interface member" + % (attributeName, name), + [member.location, m.location], + ) if m.isMethod() and m != member and name in m.aliases: - raise WebIDLError("conflicting [%s=%s] definitions" % - (attributeName, name), - [member.location, m.location]) + raise WebIDLError( + "conflicting [%s=%s] definitions" % (attributeName, name), + [member.location, m.location], + ) if m.isAttr() and m != member and name in m.bindingAliases: - raise WebIDLError("conflicting [%s=%s] definitions" % - (attributeName, name), - [member.location, m.location]) + raise WebIDLError( + "conflicting [%s=%s] definitions" % (attributeName, name), + [member.location, m.location], + ) # We also don't support inheriting from unforgeable interfaces. - if self.getExtendedAttribute("Unforgeable") and self.hasChildInterfaces(): - locations = ([self.location] + - list(i.location for i in - self.interfacesBasedOnSelf if i.parent == self)) - raise WebIDLError("%s is an unforgeable ancestor interface" % - self.identifier.name, - locations) + if self.getExtendedAttribute("LegacyUnforgeable") and self.hasChildInterfaces(): + locations = [self.location] + list( + i.location for i in self.interfacesBasedOnSelf if i.parent == self + ) + raise WebIDLError( + "%s is an unforgeable ancestor interface" % self.identifier.name, + locations, + ) ctor = self.ctor() if ctor is not None: ctor.validate() - for namedCtor in self.namedConstructors: + for namedCtor in self.legacyFactoryFunctions: namedCtor.validate() indexedGetter = None @@ -1360,50 +1527,57 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): member.validate() if self.isCallback() and member.getExtendedAttribute("Replaceable"): - raise WebIDLError("[Replaceable] used on an attribute on " - "interface %s which is a callback interface" % - self.identifier.name, - [self.location, member.location]) + raise WebIDLError( + "[Replaceable] used on an attribute on " + "interface %s which is a callback interface" % self.identifier.name, + [self.location, member.location], + ) # Check that PutForwards refers to another attribute and that no # cycles exist in forwarded assignments. Also check for a # integer-typed "length" attribute. if member.isAttr(): - if (member.identifier.name == "length" and - member.type.isInteger()): + if member.identifier.name == "length" and member.type.isInteger(): hasLengthAttribute = True iface = self attr = member putForwards = attr.getExtendedAttribute("PutForwards") if putForwards and self.isCallback(): - raise WebIDLError("[PutForwards] used on an attribute " - "on interface %s which is a callback " - "interface" % self.identifier.name, - [self.location, member.location]) + raise WebIDLError( + "[PutForwards] used on an attribute " + "on interface %s which is a callback " + "interface" % self.identifier.name, + [self.location, member.location], + ) while putForwards is not None: forwardIface = attr.type.unroll().inner fowardAttr = None for forwardedMember in forwardIface.members: - if (not forwardedMember.isAttr() or - forwardedMember.identifier.name != putForwards[0]): + if ( + not forwardedMember.isAttr() + or forwardedMember.identifier.name != putForwards[0] + ): continue if forwardedMember == member: - raise WebIDLError("Cycle detected in forwarded " - "assignments for attribute %s on " - "%s" % - (member.identifier.name, self), - [member.location]) + raise WebIDLError( + "Cycle detected in forwarded " + "assignments for attribute %s on " + "%s" % (member.identifier.name, self), + [member.location], + ) fowardAttr = forwardedMember break if fowardAttr is None: - raise WebIDLError("Attribute %s on %s forwards to " - "missing attribute %s" % - (attr.identifier.name, iface, putForwards), - [attr.location]) + raise WebIDLError( + "Attribute %s on %s forwards to " + "missing attribute %s" + % (attr.identifier.name, iface, putForwards), + [attr.location], + ) iface = forwardIface attr = fowardAttr @@ -1417,29 +1591,41 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): for alias in member.aliases: if self.isOnGlobalProtoChain(): - raise WebIDLError("[Alias] must not be used on a " - "[Global] interface operation", - [member.location]) - if (member.getExtendedAttribute("Exposed") or - member.getExtendedAttribute("ChromeOnly") or - member.getExtendedAttribute("Pref") or - member.getExtendedAttribute("Func") or - member.getExtendedAttribute("SecureContext")): - raise WebIDLError("[Alias] must not be used on a " - "conditionally exposed operation", - [member.location]) + raise WebIDLError( + "[Alias] must not be used on a " + "[Global] interface operation", + [member.location], + ) + if ( + member.getExtendedAttribute("Exposed") + or member.getExtendedAttribute("ChromeOnly") + or member.getExtendedAttribute("Pref") + or member.getExtendedAttribute("Func") + or member.getExtendedAttribute("Trial") + or member.getExtendedAttribute("SecureContext") + ): + raise WebIDLError( + "[Alias] must not be used on a " + "conditionally exposed operation", + [member.location], + ) if member.isStatic(): - raise WebIDLError("[Alias] must not be used on a " - "static operation", - [member.location]) + raise WebIDLError( + "[Alias] must not be used on a " "static operation", + [member.location], + ) if member.isIdentifierLess(): - raise WebIDLError("[Alias] must not be used on an " - "identifierless operation", - [member.location]) - if member.isUnforgeable(): - raise WebIDLError("[Alias] must not be used on an " - "[Unforgeable] operation", - [member.location]) + raise WebIDLError( + "[Alias] must not be used on an " + "identifierless operation", + [member.location], + ) + if member.isLegacyUnforgeable(): + raise WebIDLError( + "[Alias] must not be used on an " + "[LegacyUnforgeable] operation", + [member.location], + ) checkDuplicateNames(member, alias, "Alias") @@ -1449,16 +1635,18 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): for bindingAlias in member.bindingAliases: checkDuplicateNames(member, bindingAlias, "BindingAlias") - # Conditional exposure makes no sense for interfaces with no # interface object. # And SecureContext makes sense for interfaces with no interface object, # since it is also propagated to interface members. - if (self.isExposedConditionally(exclusions=["SecureContext"]) and - not self.hasInterfaceObject()): - raise WebIDLError("Interface with no interface object is " - "exposed conditionally", - [self.location]) + if ( + self.isExposedConditionally(exclusions=["SecureContext"]) + and not self.hasInterfaceObject() + ): + raise WebIDLError( + "Interface with no interface object is " "exposed conditionally", + [self.location], + ) # Value iterators are only allowed on interfaces with indexed getters, # and pair iterators are only allowed on interfaces without indexed @@ -1467,32 +1655,38 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): iterableDecl = self.maplikeOrSetlikeOrIterable if iterableDecl.isValueIterator(): if not indexedGetter: - raise WebIDLError("Interface with value iterator does not " - "support indexed properties", - [self.location, iterableDecl.location]) + raise WebIDLError( + "Interface with value iterator does not " + "support indexed properties", + [self.location, iterableDecl.location], + ) if iterableDecl.valueType != indexedGetter.signatures()[0][0]: - raise WebIDLError("Iterable type does not match indexed " - "getter type", - [iterableDecl.location, - indexedGetter.location]) + raise WebIDLError( + "Iterable type does not match indexed " "getter type", + [iterableDecl.location, indexedGetter.location], + ) if not hasLengthAttribute: - raise WebIDLError('Interface with value iterator does not ' - 'have an integer-typed "length" attribute', - [self.location, iterableDecl.location]) + raise WebIDLError( + "Interface with value iterator does not " + 'have an integer-typed "length" attribute', + [self.location, iterableDecl.location], + ) else: assert iterableDecl.isPairIterator() if indexedGetter: - raise WebIDLError("Interface with pair iterator supports " - "indexed properties", - [self.location, iterableDecl.location, - indexedGetter.location]) + raise WebIDLError( + "Interface with pair iterator supports " "indexed properties", + [self.location, iterableDecl.location, indexedGetter.location], + ) if indexedGetter and not hasLengthAttribute: - raise WebIDLError('Interface with an indexed getter does not have ' - 'an integer-typed "length" attribute', - [self.location, indexedGetter.location]) + raise WebIDLError( + "Interface with an indexed getter does not have " + 'an integer-typed "length" attribute', + [self.location, indexedGetter.location], + ) def setCallback(self, value): self._callback = value @@ -1505,15 +1699,25 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): return ( # JS-implemented things should never need the # this-handling weirdness of single-operation interfaces. - not self.isJSImplemented() and + not self.isJSImplemented() + and # Not inheriting from another interface - not self.parent and + not self.parent + and # No attributes of any kinds - not any(m.isAttr() for m in self.members) and + not any(m.isAttr() for m in self.members) + and # There is at least one regular operation, and all regular # operations have the same identifier - len(set(m.identifier.name for m in self.members if - m.isMethod() and not m.isStatic())) == 1) + len( + set( + m.identifier.name + for m in self.members + if m.isMethod() and not m.isStatic() + ) + ) + == 1 + ) def inheritanceDepth(self): depth = 0 @@ -1529,14 +1733,18 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): def hasInterfaceObject(self): if self.isCallback(): return self.hasConstants() - return not hasattr(self, "_noInterfaceObject") + return not hasattr(self, "_noInterfaceObject") and not self.isPseudoInterface() def hasInterfacePrototypeObject(self): - return (not self.isCallback() and not self.isNamespace() - and self.getUserData('hasConcreteDescendant', False)) + return ( + not self.isCallback() + and not self.isNamespace() + and self.getUserData("hasConcreteDescendant", False) + and not self.isPseudoInterface() + ) def addIncludedMixin(self, includedMixin): - assert(isinstance(includedMixin, IDLInterfaceMixin)) + assert isinstance(includedMixin, IDLInterfaceMixin) self.includedMixins.add(includedMixin) def getInheritedInterfaces(self): @@ -1545,7 +1753,7 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): (not including this interface itself). The list is in order from most derived to least derived. """ - assert(self._finished) + assert self._finished if not self.parent: return [] parentInterfaces = self.parent.getInheritedInterfaces() @@ -1596,6 +1804,9 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): def isOnGlobalProtoChain(self): return self._isOnGlobalProtoChain + def isPseudoInterface(self): + return self._isPseudo + def _getDependentObjects(self): deps = set(self.members) deps.update(self.includedMixins) @@ -1606,18 +1817,35 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): def hasMembersInSlots(self): return self._ownMembersInSlots != 0 - conditionExtendedAttributes = [ "Pref", "ChromeOnly", "Func", - "SecureContext" ] + conditionExtendedAttributes = [ + "Pref", + "ChromeOnly", + "Func", + "Trial", + "SecureContext", + ] + def isExposedConditionally(self, exclusions=[]): - return any(((not a in exclusions) and self.getExtendedAttribute(a)) for a in self.conditionExtendedAttributes) + return any( + ((not a in exclusions) and self.getExtendedAttribute(a)) + for a in self.conditionExtendedAttributes + ) + class IDLInterface(IDLInterfaceOrNamespace): - def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial, classNameOverride=None, - toStringTag=None): - IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, - parent, members, isKnownNonPartial, - toStringTag) + def __init__( + self, + location, + parentScope, + name, + parent, + members, + isKnownNonPartial, + classNameOverride=None, + ): + IDLInterfaceOrNamespace.__init__( + self, location, parentScope, name, parent, members, isKnownNonPartial + ) self.classNameOverride = classNameOverride def __str__(self): @@ -1629,7 +1857,7 @@ class IDLInterface(IDLInterfaceOrNamespace): def getClassName(self): if self.classNameOverride: return self.classNameOverride - return self.identifier.name + return IDLInterfaceOrNamespace.getClassName(self) def addExtendedAttributes(self, attrs): for attr in attrs: @@ -1637,22 +1865,29 @@ class IDLInterface(IDLInterfaceOrNamespace): # Special cased attrs if identifier == "TreatNonCallableAsNull": - raise WebIDLError("TreatNonCallableAsNull cannot be specified on interfaces", - [attr.location, self.location]) - if identifier == "TreatNonObjectAsNull": - raise WebIDLError("TreatNonObjectAsNull cannot be specified on interfaces", - [attr.location, self.location]) - elif identifier == "NoInterfaceObject": + raise WebIDLError( + "TreatNonCallableAsNull cannot be specified on interfaces", + [attr.location, self.location], + ) + if identifier == "LegacyTreatNonObjectAsNull": + raise WebIDLError( + "LegacyTreatNonObjectAsNull cannot be specified on interfaces", + [attr.location, self.location], + ) + elif identifier == "LegacyNoInterfaceObject": if not attr.noArguments(): - raise WebIDLError("[NoInterfaceObject] must take no arguments", - [attr.location]) + raise WebIDLError( + "[LegacyNoInterfaceObject] must take no arguments", + [attr.location], + ) self._noInterfaceObject = True - elif identifier == "NamedConstructor": + elif identifier == "LegacyFactoryFunction": if not attr.hasValue(): - raise WebIDLError("NamedConstructor must either take an identifier or take a named argument list", - [attr.location]) - + raise WebIDLError( + "LegacyFactoryFunction must either take an identifier or take a named argument list", + [attr.location], + ) args = attr.args() if attr.hasArgs() else [] @@ -1664,37 +1899,43 @@ class IDLInterface(IDLInterfaceOrNamespace): # Named constructors are always assumed to be able to # throw (since there's no way to indicate otherwise). method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("Throws",))]) + [IDLExtendedAttribute(self.location, ("Throws",))] + ) - # We need to detect conflicts for NamedConstructors across + # We need to detect conflicts for LegacyFactoryFunctions across # interfaces. We first call resolve on the parentScope, - # which will merge all NamedConstructors with the same + # which will merge all LegacyFactoryFunctions with the same # identifier accross interfaces as overloads. method.resolve(self.parentScope) # Then we look up the identifier on the parentScope. If the # result is the same as the method we're adding then it # hasn't been added as an overload and it's the first time - # we've encountered a NamedConstructor with that identifier. + # we've encountered a LegacyFactoryFunction with that identifier. # If the result is not the same as the method we're adding # then it has been added as an overload and we need to check # whether the result is actually one of our existing - # NamedConstructors. + # LegacyFactoryFunctions. newMethod = self.parentScope.lookupIdentifier(method.identifier) if newMethod == method: - self.namedConstructors.append(method) - elif newMethod not in self.namedConstructors: - raise WebIDLError("NamedConstructor conflicts with a " - "NamedConstructor of a different interface", - [method.location, newMethod.location]) - elif (identifier == "ExceptionClass"): + self.legacyFactoryFunctions.append(method) + elif newMethod not in self.legacyFactoryFunctions: + raise WebIDLError( + "LegacyFactoryFunction conflicts with a " + "LegacyFactoryFunction of a different interface", + [method.location, newMethod.location], + ) + elif identifier == "ExceptionClass": if not attr.noArguments(): - raise WebIDLError("[ExceptionClass] must take no arguments", - [attr.location]) + raise WebIDLError( + "[ExceptionClass] must take no arguments", [attr.location] + ) if self.parent: - raise WebIDLError("[ExceptionClass] must not be specified on " - "an interface with inherited interfaces", - [attr.location, self.location]) + raise WebIDLError( + "[ExceptionClass] must not be specified on " + "an interface with inherited interfaces", + [attr.location, self.location], + ) elif identifier == "Global": if attr.hasValue(): self.globalNames = [attr.value()] @@ -1702,8 +1943,9 @@ class IDLInterface(IDLInterfaceOrNamespace): self.globalNames = attr.args() else: self.globalNames = [self.identifier.name] - self.parentScope.addIfaceGlobalNames(self.identifier.name, - self.globalNames) + self.parentScope.addIfaceGlobalNames( + self.identifier.name, self.globalNames + ) self._isOnGlobalProtoChain = True elif identifier == "LegacyWindowAlias": if attr.hasValue(): @@ -1711,60 +1953,74 @@ class IDLInterface(IDLInterfaceOrNamespace): elif attr.hasArgs(): self.legacyWindowAliases = attr.args() else: - raise WebIDLError("[%s] must either take an identifier " - "or take an identifier list" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must either take an identifier " + "or take an identifier list" % identifier, + [attr.location], + ) for alias in self.legacyWindowAliases: unresolved = IDLUnresolvedIdentifier(attr.location, alias) IDLObjectWithIdentifier(attr.location, self.parentScope, unresolved) elif identifier == "SecureContext": if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must take no arguments" % identifier, [attr.location] + ) # This gets propagated to all our members. for member in self.members: if member.getExtendedAttribute("SecureContext"): - raise WebIDLError("[SecureContext] specified on both " - "an interface member and on the " - "interface itself", - [member.location, attr.location]) + raise WebIDLError( + "[SecureContext] specified on both " + "an interface member and on the " + "interface itself", + [member.location, attr.location], + ) member.addExtendedAttributes([attr]) - elif (identifier == "NeedResolve" or - identifier == "OverrideBuiltins" or - identifier == "ChromeOnly" or - identifier == "Unforgeable" or - identifier == "LegacyEventInit" or - identifier == "ProbablyShortLivingWrapper" or - identifier == "LegacyUnenumerableNamedProperties" or - identifier == "RunConstructorInCallerCompartment" or - identifier == "WantsEventListenerHooks" or - identifier == "Serializable" or - identifier == "Abstract" or - identifier == "Inline"): + elif ( + identifier == "NeedResolve" + or identifier == "LegacyOverrideBuiltIns" + or identifier == "ChromeOnly" + or identifier == "LegacyUnforgeable" + or identifier == "LegacyEventInit" + or identifier == "ProbablyShortLivingWrapper" + or identifier == "LegacyUnenumerableNamedProperties" + or identifier == "RunConstructorInCallerCompartment" + or identifier == "WantsEventListenerHooks" + or identifier == "Serializable" + or identifier == "Abstract" + or identifier == "Inline" + ): # Known extended attributes that do not take values if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must take no arguments" % identifier, [attr.location] + ) elif identifier == "Exposed": - convertExposedAttrToGlobalNameSet(attr, - self._exposureGlobalNames) - elif (identifier == "Pref" or - identifier == "JSImplementation" or - identifier == "HeaderFile" or - identifier == "Func" or - identifier == "Deprecated"): + convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) + elif ( + identifier == "Pref" + or identifier == "JSImplementation" + or identifier == "HeaderFile" + or identifier == "Func" + or identifier == "Trial" + or identifier == "Deprecated" + ): # Known extended attributes that take a string value if not attr.hasValue(): - raise WebIDLError("[%s] must have a value" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must have a value" % identifier, [attr.location] + ) elif identifier == "InstrumentedProps": # Known extended attributes that take a list if not attr.hasArgs(): - raise WebIDLError("[%s] must have arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must have arguments" % identifier, [attr.location] + ) else: - raise WebIDLError("Unknown extended attribute %s on interface" % identifier, - [attr.location]) + raise WebIDLError( + "Unknown extended attribute %s on interface" % identifier, + [attr.location], + ) attrlist = attr.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True @@ -1777,7 +2033,8 @@ class IDLInterface(IDLInterfaceOrNamespace): "interface. Per spec, that means the object should not be " "serializable, so chances are someone made a mistake here " "somewhere.", - [self.location, self.parent.location]) + [self.location, self.parent.location], + ) def isSerializable(self): return self.getExtendedAttribute("Serializable") @@ -1796,9 +2053,9 @@ class IDLInterface(IDLInterfaceOrNamespace): class IDLNamespace(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, members, isKnownNonPartial): - IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, - None, members, isKnownNonPartial, - toStringTag=None) + IDLInterfaceOrNamespace.__init__( + self, location, parentScope, name, None, members, isKnownNonPartial + ) def __str__(self): return "Namespace '%s'" % self.identifier.name @@ -1815,30 +2072,35 @@ class IDLNamespace(IDLInterfaceOrNamespace): identifier = attr.identifier() if identifier == "Exposed": - convertExposedAttrToGlobalNameSet(attr, - self._exposureGlobalNames) + convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) elif identifier == "ClassString": # Takes a string value to override the default "Object" if # desired. if not attr.hasValue(): - raise WebIDLError("[%s] must have a value" % identifier, - [attr.location]) - elif (identifier == "ProtoObjectHack" or - identifier == "ChromeOnly"): + raise WebIDLError( + "[%s] must have a value" % identifier, [attr.location] + ) + elif identifier == "ProtoObjectHack" or identifier == "ChromeOnly": if not attr.noArguments(): - raise WebIDLError("[%s] must not have arguments" % identifier, - [attr.location]) - elif (identifier == "Pref" or - identifier == "HeaderFile" or - identifier == "Func"): + raise WebIDLError( + "[%s] must not have arguments" % identifier, [attr.location] + ) + elif ( + identifier == "Pref" + or identifier == "HeaderFile" + or identifier == "Func" + or identifier == "Trial" + ): # Known extended attributes that take a string value if not attr.hasValue(): - raise WebIDLError("[%s] must have a value" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must have a value" % identifier, [attr.location] + ) else: - raise WebIDLError("Unknown extended attribute %s on namespace" % - identifier, - [attr.location]) + raise WebIDLError( + "Unknown extended attribute %s on namespace" % identifier, + [attr.location], + ) attrlist = attr.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True @@ -1874,8 +2136,9 @@ class IDLDictionary(IDLObjectWithScope): Returns true if this dictionary can be empty (that is, it has no required members and neither do any of its ancestors). """ - return (all(member.optional for member in self.members) and - (not self.parent or self.parent.canBeEmpty())) + return all(member.optional for member in self.members) and ( + not self.parent or self.parent.canBeEmpty() + ) def finish(self, scope): if self._finished: @@ -1888,9 +2151,11 @@ class IDLDictionary(IDLObjectWithScope): oldParent = self.parent self.parent = self.parent.finish(scope) if not isinstance(self.parent, IDLDictionary): - raise WebIDLError("Dictionary %s has parent that is not a dictionary" % - self.identifier.name, - [oldParent.location, self.parent.location]) + raise WebIDLError( + "Dictionary %s has parent that is not a dictionary" + % self.identifier.name, + [oldParent.location, self.parent.location], + ) # Make sure the parent resolves all its members before we start # looking at them. @@ -1907,16 +2172,19 @@ class IDLDictionary(IDLObjectWithScope): member.complete(scope) assert member.type.isComplete() - # Members of a dictionary are sorted in lexicographic order - self.members.sort(key=lambda x: x.identifier.name) + # Members of a dictionary are sorted in lexicographic order, + # unless the dictionary opts out. + if not self.getExtendedAttribute("Unsorted"): + self.members.sort(key=lambda x: x.identifier.name) inheritedMembers = [] ancestor = self.parent while ancestor: if ancestor == self: - raise WebIDLError("Dictionary %s has itself as an ancestor" % - self.identifier.name, - [self.identifier.location]) + raise WebIDLError( + "Dictionary %s has itself as an ancestor" % self.identifier.name, + [self.identifier.location], + ) inheritedMembers.extend(ancestor.members) ancestor = ancestor.parent @@ -1924,9 +2192,11 @@ class IDLDictionary(IDLObjectWithScope): for inheritedMember in inheritedMembers: for member in self.members: if member.identifier.name == inheritedMember.identifier.name: - raise WebIDLError("Dictionary %s has two members with name %s" % - (self.identifier.name, member.identifier.name), - [member.location, inheritedMember.location]) + raise WebIDLError( + "Dictionary %s has two members with name %s" + % (self.identifier.name, member.identifier.name), + [member.location, inheritedMember.location], + ) def validate(self): def typeContainsDictionary(memberType, dictionary): @@ -1944,17 +2214,20 @@ class IDLDictionary(IDLObjectWithScope): None, if the boolean value in the first element is False. """ - if (memberType.nullable() or - memberType.isSequence() or - memberType.isRecord()): + if ( + memberType.nullable() + or memberType.isSequence() + or memberType.isRecord() + ): return typeContainsDictionary(memberType.inner, dictionary) if memberType.isDictionary(): if memberType.inner == dictionary: return (True, [memberType.location]) - (contains, locations) = dictionaryContainsDictionary(memberType.inner, - dictionary) + (contains, locations) = dictionaryContainsDictionary( + memberType.inner, dictionary + ) if contains: return (True, [memberType.location] + locations) @@ -1976,7 +2249,9 @@ class IDLDictionary(IDLObjectWithScope): if dictMember.parent == dictionary: return (True, [dictMember.location]) else: - (contains, locations) = dictionaryContainsDictionary(dictMember.parent, dictionary) + (contains, locations) = dictionaryContainsDictionary( + dictMember.parent, dictionary + ) if contains: return (True, [dictMember.location] + locations) @@ -1984,14 +2259,33 @@ class IDLDictionary(IDLObjectWithScope): for member in self.members: if member.type.isDictionary() and member.type.nullable(): - raise WebIDLError("Dictionary %s has member with nullable " - "dictionary type" % self.identifier.name, - [member.location]) + raise WebIDLError( + "Dictionary %s has member with nullable " + "dictionary type" % self.identifier.name, + [member.location], + ) (contains, locations) = typeContainsDictionary(member.type, self) if contains: - raise WebIDLError("Dictionary %s has member with itself as type." % - self.identifier.name, - [member.location] + locations) + raise WebIDLError( + "Dictionary %s has member with itself as type." + % self.identifier.name, + [member.location] + locations, + ) + + if member.type.isUndefined(): + raise WebIDLError( + "Dictionary %s has member with undefined as its type." + % self.identifier.name, + [member.location], + ) + elif member.type.isUnion(): + for unionMember in member.type.unroll().flatMemberTypes: + if unionMember.isUndefined(): + raise WebIDLError( + "Dictionary %s has member with a union containing " + "undefined as a type." % self.identifier.name, + [unionMember.location], + ) def getExtendedAttribute(self, name): return self._extendedAttrDict.get(name, None) @@ -2000,31 +2294,40 @@ class IDLDictionary(IDLObjectWithScope): for attr in attrs: identifier = attr.identifier() - if (identifier == "GenerateInitFromJSON" or - identifier == "GenerateInit"): + if identifier == "GenerateInitFromJSON" or identifier == "GenerateInit": if not attr.noArguments(): - raise WebIDLError("[%s] must not have arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must not have arguments" % identifier, [attr.location] + ) self.needsConversionFromJS = True - elif (identifier == "GenerateConversionToJS" or - identifier == "GenerateToJSON"): + elif ( + identifier == "GenerateConversionToJS" or identifier == "GenerateToJSON" + ): if not attr.noArguments(): - raise WebIDLError("[%s] must not have arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must not have arguments" % identifier, [attr.location] + ) # ToJSON methods require to-JS conversion, because we # implement ToJSON by converting to a JS object and # then using JSON.stringify. self.needsConversionToJS = True + elif identifier == "Unsorted": + if not attr.noArguments(): + raise WebIDLError( + "[Unsorted] must take no arguments", [attr.location] + ) else: - raise WebIDLError("[%s] extended attribute not allowed on " - "dictionaries" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] extended attribute not allowed on " + "dictionaries" % identifier, + [attr.location], + ) self._extendedAttrDict[identifier] = True def _getDependentObjects(self): deps = set(self.members) - if (self.parent): + if self.parent: deps.add(self.parent) return deps @@ -2039,8 +2342,9 @@ class IDLEnum(IDLObjectWithIdentifier): assert isinstance(name, IDLUnresolvedIdentifier) if len(values) != len(set(values)): - raise WebIDLError("Enum %s has multiple identical strings" % name.name, - [location]) + raise WebIDLError( + "Enum %s has multiple identical strings" % name.name, [location] + ) IDLObjectWithIdentifier.__init__(self, location, parentScope, name) self._values = values @@ -2059,9 +2363,10 @@ class IDLEnum(IDLObjectWithIdentifier): def addExtendedAttributes(self, attrs): if len(attrs) != 0: - raise WebIDLError("There are no extended attributes that are " - "allowed on enums", - [attrs[0].location, self.location]) + raise WebIDLError( + "There are no extended attributes that are " "allowed on enums", + [attrs[0].location, self.location], + ) def _getDependentObjects(self): return set() @@ -2070,56 +2375,72 @@ class IDLEnum(IDLObjectWithIdentifier): class IDLType(IDLObject): Tags = enum( # The integer types - 'int8', - 'uint8', - 'int16', - 'uint16', - 'int32', - 'uint32', - 'int64', - 'uint64', + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", # Additional primitive types - 'bool', - 'unrestricted_float', - 'float', - 'unrestricted_double', + "bool", + "unrestricted_float", + "float", + "unrestricted_double", # "double" last primitive type to match IDLBuiltinType - 'double', + "double", # Other types - 'any', - 'domstring', - 'bytestring', - 'usvstring', - 'utf8string', - 'jsstring', - 'object', - 'undefined', + "any", + "undefined", + "domstring", + "bytestring", + "usvstring", + "utf8string", + "jsstring", + "object", # Funny stuff - 'interface', - 'dictionary', - 'enum', - 'callback', - 'union', - 'sequence', - 'record', - 'promise', - ) + "interface", + "dictionary", + "enum", + "callback", + "union", + "sequence", + "record", + "promise", + "observablearray", + ) def __init__(self, location, name): IDLObject.__init__(self, location) self.name = name self.builtin = False - self.treatNullAsEmpty = False + self.legacyNullToEmptyString = False self._clamp = False self._enforceRange = False self._allowShared = False self._extendedAttrDict = {} + def __hash__(self): + return ( + hash(self.builtin) + + hash(self.name) + + hash(self._clamp) + + hash(self._enforceRange) + + hash(self.legacyNullToEmptyString) + + hash(self._allowShared) + ) + def __eq__(self, other): - return (other and self.builtin == other.builtin and self.name == other.name and - self._clamp == other.hasClamp() and self._enforceRange == other.hasEnforceRange() and - self.treatNullAsEmpty == other.treatNullAsEmpty and - self._allowShared == other.hasAllowShared()) + return ( + other + and self.builtin == other.builtin + and self.name == other.name + and self._clamp == other.hasClamp() + and self._enforceRange == other.hasEnforceRange() + and self.legacyNullToEmptyString == other.legacyNullToEmptyString + and self._allowShared == other.hasAllowShared() + ) def __ne__(self, other): return not self == other @@ -2169,7 +2490,7 @@ class IDLType(IDLObject): return False def isUndefined(self): - return self.name == "Undefined" + return False def isSequence(self): return False @@ -2177,9 +2498,6 @@ class IDLType(IDLObject): def isRecord(self): return False - def isReadableStream(self): - return False - def isArrayBuffer(self): return False @@ -2199,23 +2517,16 @@ class IDLType(IDLObject): return False def isGeckoInterface(self): - """ Returns a boolean indicating whether this type is an 'interface' - type that is implemented in Gecko. At the moment, this returns - true for all interface types that are not types from the TypedArray - spec.""" + """Returns a boolean indicating whether this type is an 'interface' + type that is implemented in Gecko. At the moment, this returns + true for all interface types that are not types from the TypedArray + spec.""" return self.isInterface() and not self.isSpiderMonkeyInterface() def isSpiderMonkeyInterface(self): - """ Returns a boolean indicating whether this type is an 'interface' - type that is implemented in SpiderMonkey. """ - return self.isInterface() and (self.isBufferSource() or - self.isReadableStream()) - - def isDictionary(self): - return False - - def isInterface(self): - return False + """Returns a boolean indicating whether this type is an 'interface' + type that is implemented in SpiderMonkey.""" + return self.isInterface() and self.isBufferSource() def isAny(self): return self.tag() == IDLType.Tags.any @@ -2242,6 +2553,12 @@ class IDLType(IDLObject): def isJSONType(self): return False + def isObservableArray(self): + return False + + def isDictionaryLike(self): + return self.isDictionary() or self.isRecord() or self.isCallbackInterface() + def hasClamp(self): return self._clamp @@ -2264,8 +2581,10 @@ class IDLType(IDLObject): def withExtendedAttributes(self, attrs): if len(attrs) > 0: - raise WebIDLError("Extended attributes on types only supported for builtins", - [attrs[0].location, self.location]) + raise WebIDLError( + "Extended attributes on types only supported for builtins", + [attrs[0].location, self.location], + ) return self def getExtendedAttribute(self, name): @@ -2278,8 +2597,10 @@ class IDLType(IDLObject): return self def isDistinguishableFrom(self, other): - raise TypeError("Can't tell whether a generic type is or is not " - "distinguishable from other things") + raise TypeError( + "Can't tell whether a generic type is or is not " + "distinguishable from other things" + ) def isExposedInAllOf(self, exposureSet): return True @@ -2287,7 +2608,7 @@ class IDLType(IDLObject): class IDLUnresolvedType(IDLType): """ - Unresolved types are interface types + Unresolved types are interface types """ def __init__(self, location, name, attrs=[]): @@ -2302,19 +2623,17 @@ class IDLUnresolvedType(IDLType): try: obj = scope._lookupIdentifier(self.name) except: - raise WebIDLError("Unresolved type '%s'." % self.name, - [self.location]) + raise WebIDLError("Unresolved type '%s'." % self.name, [self.location]) assert obj - if obj.isType(): - print(obj) assert not obj.isType() if obj.isTypedef(): assert self.name.name == obj.identifier.name - typedefType = IDLTypedefType(self.location, obj.innerType, - obj.identifier) + typedefType = IDLTypedefType(self.location, obj.innerType, obj.identifier) assert not typedefType.isComplete() - return typedefType.complete(scope).withExtendedAttributes(self.extraTypeAttributes) + return typedefType.complete(scope).withExtendedAttributes( + self.extraTypeAttributes + ) elif obj.isCallback() and not obj.isInterface(): assert self.name.name == obj.identifier.name return IDLCallbackType(obj.location, obj) @@ -2326,8 +2645,10 @@ class IDLUnresolvedType(IDLType): return IDLUnresolvedType(self.location, self.name, attrs) def isDistinguishableFrom(self, other): - raise TypeError("Can't tell whether an unresolved type is or is not " - "distinguishable from other things") + raise TypeError( + "Can't tell whether an unresolved type is or is not " + "distinguishable from other things" + ) class IDLParametrizedType(IDLType): @@ -2355,17 +2676,16 @@ class IDLParametrizedType(IDLType): class IDLNullableType(IDLParametrizedType): def __init__(self, location, innerType): - assert not innerType.isUndefined() assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] IDLParametrizedType.__init__(self, location, None, innerType) - def __eq__(self, other): - return isinstance(other, IDLNullableType) and self.inner == other.inner - def __hash__(self): return hash(self.inner) + def __eq__(self, other): + return isinstance(other, IDLNullableType) and self.inner == other.inner + def __str__(self): return self.inner.__str__() + "OrNull" @@ -2415,7 +2735,7 @@ class IDLNullableType(IDLParametrizedType): return self.inner.isInteger() def isUndefined(self): - return False + return self.inner.isUndefined() def isSequence(self): return self.inner.isSequence() @@ -2423,9 +2743,6 @@ class IDLNullableType(IDLParametrizedType): def isRecord(self): return self.inner.isRecord() - def isReadableStream(self): - return self.inner.isReadableStream() - def isArrayBuffer(self): return self.inner.isArrayBuffer() @@ -2461,6 +2778,9 @@ class IDLNullableType(IDLParametrizedType): def isJSONType(self): return self.inner.isJSONType() + def isObservableArray(self): + return self.inner.isObservableArray() + def hasClamp(self): return self.inner.hasClamp() @@ -2482,27 +2802,41 @@ class IDLNullableType(IDLParametrizedType): assert self.inner.isComplete() if self.inner.nullable(): - raise WebIDLError("The inner type of a nullable type must not be " - "a nullable type", - [self.location, self.inner.location]) + raise WebIDLError( + "The inner type of a nullable type must not be a nullable type", + [self.location, self.inner.location], + ) if self.inner.isUnion(): if self.inner.hasNullableType: - raise WebIDLError("The inner type of a nullable type must not " - "be a union type that itself has a nullable " - "type as a member type", [self.location]) + raise WebIDLError( + "The inner type of a nullable type must not " + "be a union type that itself has a nullable " + "type as a member type", + [self.location], + ) if self.inner.isDOMString(): - if self.inner.treatNullAsEmpty: - raise WebIDLError("[TreatNullAs] not allowed on a nullable DOMString", - [self.location, self.inner.location]) + if self.inner.legacyNullToEmptyString: + raise WebIDLError( + "[LegacyNullToEmptyString] not allowed on a nullable DOMString", + [self.location, self.inner.location], + ) + if self.inner.isObservableArray(): + raise WebIDLError( + "The inner type of a nullable type must not be an ObservableArray type", + [self.location, self.inner.location], + ) self.name = self.inner.name + "OrNull" return self def isDistinguishableFrom(self, other): - if (other.nullable() or - other.isDictionary() or - (other.isUnion() and - (other.hasNullableType or other.hasDictionaryType()))): + if ( + other.nullable() + or other.isDictionary() + or ( + other.isUnion() and (other.hasNullableType or other.hasDictionaryType()) + ) + ): # Can't tell which type null should become return False return self.inner.isDistinguishableFrom(other) @@ -2525,57 +2859,21 @@ class IDLSequenceType(IDLParametrizedType): if self.inner.isComplete(): self.name = self.inner.name + "Sequence" - def __eq__(self, other): - return isinstance(other, IDLSequenceType) and self.inner == other.inner - def __hash__(self): return hash(self.inner) + def __eq__(self, other): + return isinstance(other, IDLSequenceType) and self.inner == other.inner + def __str__(self): return self.inner.__str__() + "Sequence" def prettyName(self): return "sequence<%s>" % self.inner.prettyName() - def nullable(self): - return False - - def isPrimitive(self): - return False - - def isString(self): - return False - - def isByteString(self): - return False - - def isDOMString(self): - return False - - def isUSVString(self): - return False - - def isUTF8String(self): - return False - - def isJSString(self): - return False - - def isUndefined(self): - return False - def isSequence(self): return True - def isDictionary(self): - return False - - def isInterface(self): - return False - - def isEnum(self): - return False - def isJSONType(self): return self.inner.isJSONType() @@ -2583,6 +2881,12 @@ class IDLSequenceType(IDLParametrizedType): return IDLType.Tags.sequence def complete(self, scope): + if self.inner.isObservableArray(): + raise WebIDLError( + "The inner type of a sequence type must not be an ObservableArray type", + [self.location, self.inner.location], + ) + self.inner = self.inner.complete(scope) self.name = self.inner.name + "Sequence" return self @@ -2593,9 +2897,16 @@ class IDLSequenceType(IDLParametrizedType): if other.isUnion(): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isInterface() or other.isDictionary() or - other.isCallback() or other.isRecord()) + return ( + other.isUndefined() + or other.isPrimitive() + or other.isString() + or other.isEnum() + or other.isInterface() + or other.isDictionary() + or other.isCallback() + or other.isRecord() + ) class IDLRecordType(IDLParametrizedType): @@ -2612,6 +2923,9 @@ class IDLRecordType(IDLParametrizedType): if self.inner.isComplete(): self.name = self.keyType.name + self.inner.name + "Record" + def __hash__(self): + return hash(self.inner) + def __eq__(self, other): return isinstance(other, IDLRecordType) and self.inner == other.inner @@ -2631,6 +2945,12 @@ class IDLRecordType(IDLParametrizedType): return IDLType.Tags.record def complete(self, scope): + if self.inner.isObservableArray(): + raise WebIDLError( + "The value type of a record type must not be an ObservableArray type", + [self.location, self.inner.location], + ) + self.inner = self.inner.complete(scope) self.name = self.keyType.name + self.inner.name + "Record" return self @@ -2647,13 +2967,84 @@ class IDLRecordType(IDLParametrizedType): if other.isUnion(): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isNonCallbackInterface() or other.isSequence()) + return ( + other.isPrimitive() + or other.isString() + or other.isEnum() + or other.isNonCallbackInterface() + or other.isSequence() + ) def isExposedInAllOf(self, exposureSet): return self.inner.unroll().isExposedInAllOf(exposureSet) +class IDLObservableArrayType(IDLParametrizedType): + def __init__(self, location, innerType): + assert not innerType.isUndefined() + IDLParametrizedType.__init__(self, location, None, innerType) + + def __hash__(self): + return hash(self.inner) + + def __eq__(self, other): + return isinstance(other, IDLObservableArrayType) and self.inner == other.inner + + def __str__(self): + return self.inner.__str__() + "ObservableArray" + + def prettyName(self): + return "ObservableArray<%s>" % self.inner.prettyName() + + def isJSONType(self): + return self.inner.isJSONType() + + def isObservableArray(self): + return True + + def isComplete(self): + return self.name is not None + + def tag(self): + return IDLType.Tags.observablearray + + def complete(self, scope): + if not self.inner.isComplete(): + self.inner = self.inner.complete(scope) + assert self.inner.isComplete() + + if self.inner.isDictionary(): + raise WebIDLError( + "The inner type of an ObservableArray type must not " + "be a dictionary type", + [self.location, self.inner.location], + ) + if self.inner.isSequence(): + raise WebIDLError( + "The inner type of an ObservableArray type must not " + "be a sequence type", + [self.location, self.inner.location], + ) + if self.inner.isRecord(): + raise WebIDLError( + "The inner type of an ObservableArray type must not be a record type", + [self.location, self.inner.location], + ) + if self.inner.isObservableArray(): + raise WebIDLError( + "The inner type of an ObservableArray type must not " + "be an ObservableArray type", + [self.location, self.inner.location], + ) + + self.name = self.inner.name + "ObservableArray" + return self + + def isDistinguishableFrom(self, other): + # ObservableArrays are not distinguishable from anything. + return False + + class IDLUnionType(IDLType): def __init__(self, location, memberTypes): IDLType.__init__(self, location, "") @@ -2673,9 +3064,6 @@ class IDLUnionType(IDLType): def prettyName(self): return "(" + " or ".join(m.prettyName() for m in self.memberTypes) + ")" - def isUndefined(self): - return False - def isUnion(self): return True @@ -2727,36 +3115,46 @@ class IDLUnionType(IDLType): while i < len(self.flatMemberTypes): if self.flatMemberTypes[i].nullable(): if self.hasNullableType: - raise WebIDLError("Can't have more than one nullable types in a union", - [nullableType.location, self.flatMemberTypes[i].location]) + raise WebIDLError( + "Can't have more than one nullable types in a union", + [nullableType.location, self.flatMemberTypes[i].location], + ) if self.hasDictionaryType(): - raise WebIDLError("Can't have a nullable type and a " - "dictionary type in a union", - [self._dictionaryType.location, - self.flatMemberTypes[i].location]) + raise WebIDLError( + "Can't have a nullable type and a " + "dictionary type in a union", + [ + self._dictionaryType.location, + self.flatMemberTypes[i].location, + ], + ) self.hasNullableType = True nullableType = self.flatMemberTypes[i] self.flatMemberTypes[i] = self.flatMemberTypes[i].inner continue if self.flatMemberTypes[i].isDictionary(): if self.hasNullableType: - raise WebIDLError("Can't have a nullable type and a " - "dictionary type in a union", - [nullableType.location, - self.flatMemberTypes[i].location]) + raise WebIDLError( + "Can't have a nullable type and a " + "dictionary type in a union", + [nullableType.location, self.flatMemberTypes[i].location], + ) self._dictionaryType = self.flatMemberTypes[i] + self.flatMemberTypes[i].inner.needsConversionFromJS = True elif self.flatMemberTypes[i].isUnion(): - self.flatMemberTypes[i:i + 1] = self.flatMemberTypes[i].memberTypes + self.flatMemberTypes[i : i + 1] = self.flatMemberTypes[i].memberTypes continue i += 1 for (i, t) in enumerate(self.flatMemberTypes[:-1]): - for u in self.flatMemberTypes[i + 1:]: + for u in self.flatMemberTypes[i + 1 :]: if not t.isDistinguishableFrom(u): - raise WebIDLError("Flat member types of a union should be " - "distinguishable, " + str(t) + " is not " - "distinguishable from " + str(u), - [self.location, t.location, u.location]) + raise WebIDLError( + "Flat member types of a union should be " + "distinguishable, " + str(t) + " is not " + "distinguishable from " + str(u), + [self.location, t.location, u.location], + ) return self @@ -2778,8 +3176,10 @@ class IDLUnionType(IDLType): def isExposedInAllOf(self, exposureSet): # We could have different member types in different globals. Just make sure that each thing in exposureSet has one of our member types exposed in it. for globalName in exposureSet: - if not any(t.unroll().isExposedInAllOf(set([globalName])) for t - in self.flatMemberTypes): + if not any( + t.unroll().isExposedInAllOf(set([globalName])) + for t in self.flatMemberTypes + ): return False return True @@ -2787,8 +3187,9 @@ class IDLUnionType(IDLType): return self._dictionaryType is not None def hasPossiblyEmptyDictionaryType(self): - return (self._dictionaryType is not None and - self._dictionaryType.inner.canBeEmpty()) + return ( + self._dictionaryType is not None and self._dictionaryType.inner.canBeEmpty() + ) def _getDependentObjects(self): return set(self.memberTypes) @@ -2800,6 +3201,9 @@ class IDLTypedefType(IDLType): self.inner = innerType self.builtin = False + def __hash__(self): + return hash(self.inner) + def __eq__(self, other): return isinstance(other, IDLTypedefType) and self.inner == other.inner @@ -2848,9 +3252,6 @@ class IDLTypedefType(IDLType): def isRecord(self): return self.inner.isRecord() - def isReadableStream(self): - return self.inner.isReadableStream() - def isDictionary(self): return self.inner.isDictionary() @@ -2896,7 +3297,9 @@ class IDLTypedefType(IDLType): return self.inner._getDependentObjects() def withExtendedAttributes(self, attrs): - return IDLTypedefType(self.location, self.inner.withExtendedAttributes(attrs), self.name) + return IDLTypedefType( + self.location, self.inner.withExtendedAttributes(attrs), self.name + ) class IDLTypedef(IDLObjectWithIdentifier): @@ -2922,9 +3325,10 @@ class IDLTypedef(IDLObjectWithIdentifier): def addExtendedAttributes(self, attrs): if len(attrs) != 0: - raise WebIDLError("There are no extended attributes that are " - "allowed on typedefs", - [attrs[0].location, self.location]) + raise WebIDLError( + "There are no extended attributes that are " "allowed on typedefs", + [attrs[0].location, self.location], + ) def _getDependentObjects(self): return self.innerType._getDependentObjects() @@ -2937,53 +3341,26 @@ class IDLWrapperType(IDLType): self._identifier = inner.identifier self.builtin = False - def __eq__(self, other): - return (isinstance(other, IDLWrapperType) and - self._identifier == other._identifier and - self.builtin == other.builtin) - def __hash__(self): - return hash((self._identifier, self.builtin)) + return hash(self._identifier) + hash(self.builtin) + + def __eq__(self, other): + return ( + isinstance(other, IDLWrapperType) + and self._identifier == other._identifier + and self.builtin == other.builtin + ) def __str__(self): return str(self.name) + " (Wrapper)" - def nullable(self): - return False - - def isPrimitive(self): - return False - - def isString(self): - return False - - def isByteString(self): - return False - - def isDOMString(self): - return False - - def isUSVString(self): - return False - - def isUTF8String(self): - return False - - def isJSString(self): - return False - - def isUndefined(self): - return False - - def isSequence(self): - return False - def isDictionary(self): return isinstance(self.inner, IDLDictionary) def isInterface(self): - return (isinstance(self.inner, IDLInterface) or - isinstance(self.inner, IDLExternalInterface)) + return isinstance(self.inner, IDLInterface) or isinstance( + self.inner, IDLExternalInterface + ) def isCallbackInterface(self): return self.isInterface() and self.inner.isCallback() @@ -3014,8 +3391,11 @@ class IDLWrapperType(IDLType): dictionary = dictionary.parent return True else: - raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " - "is serializable" % type(self.inner), [self.location]) + raise WebIDLError( + "IDLWrapperType wraps type %s that we don't know if " + "is serializable" % type(self.inner), + [self.location], + ) def resolveType(self, parentScope): assert isinstance(parentScope, IDLScope) @@ -3042,13 +3422,24 @@ class IDLWrapperType(IDLType): return other.isDistinguishableFrom(self) assert self.isInterface() or self.isEnum() or self.isDictionary() if self.isEnum(): - return (other.isPrimitive() or other.isInterface() or other.isObject() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord()) - if self.isDictionary() and other.nullable(): + return ( + other.isUndefined() + or other.isPrimitive() + or other.isInterface() + or other.isObject() + or other.isCallback() + or other.isDictionary() + or other.isSequence() + or other.isRecord() + ) + if self.isDictionary() and (other.nullable() or other.isUndefined()): return False - if (other.isPrimitive() or other.isString() or other.isEnum() or - other.isSequence()): + if ( + other.isPrimitive() + or other.isString() + or other.isEnum() + or other.isSequence() + ): return True if self.isDictionary(): return other.isNonCallbackInterface() @@ -3061,12 +3452,16 @@ class IDLWrapperType(IDLType): assert self.isGeckoInterface() and other.isGeckoInterface() if self.inner.isExternal() or other.unroll().inner.isExternal(): return self != other - return (len(self.inner.interfacesBasedOnSelf & - other.unroll().inner.interfacesBasedOnSelf) == 0 and - (self.isNonCallbackInterface() or - other.isNonCallbackInterface())) - if (other.isDictionary() or other.isCallback() or - other.isRecord()): + return len( + self.inner.interfacesBasedOnSelf + & other.unroll().inner.interfacesBasedOnSelf + ) == 0 and (self.isNonCallbackInterface() or other.isNonCallbackInterface()) + if ( + other.isUndefined() + or other.isDictionary() + or other.isCallback() + or other.isRecord() + ): return self.isNonCallbackInterface() # Not much else |other| can be @@ -3113,9 +3508,14 @@ class IDLPromiseType(IDLParametrizedType): def __init__(self, location, innerType): IDLParametrizedType.__init__(self, location, "Promise", innerType) + def __hash__(self): + return hash(self.promiseInnerType()) + def __eq__(self, other): - return (isinstance(other, IDLPromiseType) and - self.promiseInnerType() == other.promiseInnerType()) + return ( + isinstance(other, IDLPromiseType) + and self.promiseInnerType() == other.promiseInnerType() + ) def __str__(self): return self.inner.__str__() + "Promise" @@ -3133,6 +3533,12 @@ class IDLPromiseType(IDLParametrizedType): return IDLType.Tags.promise def complete(self, scope): + if self.inner.isObservableArray(): + raise WebIDLError( + "The inner type of a promise type must not be an ObservableArray type", + [self.location, self.inner.location], + ) + self.inner = self.promiseInnerType().complete(scope) return self @@ -3155,44 +3561,43 @@ class IDLBuiltinType(IDLType): Types = enum( # The integer types - 'byte', - 'octet', - 'short', - 'unsigned_short', - 'long', - 'unsigned_long', - 'long_long', - 'unsigned_long_long', + "byte", + "octet", + "short", + "unsigned_short", + "long", + "unsigned_long", + "long_long", + "unsigned_long_long", # Additional primitive types - 'boolean', - 'unrestricted_float', - 'float', - 'unrestricted_double', + "boolean", + "unrestricted_float", + "float", + "unrestricted_double", # IMPORTANT: "double" must be the last primitive type listed - 'double', + "double", # Other types - 'any', - 'domstring', - 'bytestring', - 'usvstring', - 'utf8string', - 'jsstring', - 'object', - 'undefined', + "any", + "undefined", + "domstring", + "bytestring", + "usvstring", + "utf8string", + "jsstring", + "object", # Funny stuff - 'ArrayBuffer', - 'ArrayBufferView', - 'Int8Array', - 'Uint8Array', - 'Uint8ClampedArray', - 'Int16Array', - 'Uint16Array', - 'Int32Array', - 'Uint32Array', - 'Float32Array', - 'Float64Array', - 'ReadableStream', - ) + "ArrayBuffer", + "ArrayBufferView", + "Int8Array", + "Uint8Array", + "Uint8ClampedArray", + "Int16Array", + "Uint16Array", + "Int32Array", + "Uint32Array", + "Float32Array", + "Float64Array", + ) TagLookup = { Types.byte: IDLType.Tags.int8, @@ -3209,13 +3614,13 @@ class IDLBuiltinType(IDLType): Types.unrestricted_double: IDLType.Tags.unrestricted_double, Types.double: IDLType.Tags.double, Types.any: IDLType.Tags.any, + Types.undefined: IDLType.Tags.undefined, Types.domstring: IDLType.Tags.domstring, Types.bytestring: IDLType.Tags.bytestring, Types.usvstring: IDLType.Tags.usvstring, Types.utf8string: IDLType.Tags.utf8string, Types.jsstring: IDLType.Tags.jsstring, Types.object: IDLType.Tags.object, - Types.undefined: IDLType.Tags.undefined, Types.ArrayBuffer: IDLType.Tags.interface, Types.ArrayBufferView: IDLType.Tags.interface, Types.Int8Array: IDLType.Tags.interface, @@ -3227,7 +3632,6 @@ class IDLBuiltinType(IDLType): Types.Uint32Array: IDLType.Tags.interface, Types.Float32Array: IDLType.Tags.interface, Types.Float64Array: IDLType.Tags.interface, - Types.ReadableStream: IDLType.Tags.interface, } PrettyNames = { @@ -3245,13 +3649,13 @@ class IDLBuiltinType(IDLType): Types.unrestricted_double: "unrestricted double", Types.double: "double", Types.any: "any", + Types.undefined: "undefined", Types.domstring: "DOMString", Types.bytestring: "ByteString", Types.usvstring: "USVString", - Types.utf8string: "USVString", # That's what it is in spec terms - Types.jsstring: "USVString", # Again, that's what it is in spec terms + Types.utf8string: "USVString", # That's what it is in spec terms + Types.jsstring: "USVString", # Again, that's what it is in spec terms Types.object: "object", - Types.undefined: "undefined", Types.ArrayBuffer: "ArrayBuffer", Types.ArrayBufferView: "ArrayBufferView", Types.Int8Array: "Int8Array", @@ -3263,15 +3667,23 @@ class IDLBuiltinType(IDLType): Types.Uint32Array: "Uint32Array", Types.Float32Array: "Float32Array", Types.Float64Array: "Float64Array", - Types.ReadableStream: "ReadableStream", } - def __init__(self, location, name, type, clamp=False, enforceRange=False, treatNullAsEmpty=False, - allowShared=False, attrLocation=[]): - """ - The mutually exclusive clamp/enforceRange/treatNullAsEmpty/allowShared arguments are used + def __init__( + self, + location, + name, + type, + clamp=False, + enforceRange=False, + legacyNullToEmptyString=False, + allowShared=False, + attrLocation=[], + ): + """ + The mutually exclusive clamp/enforceRange/legacyNullToEmptyString/allowShared arguments are used to create instances of this type with the appropriate attributes attached. Use .clamped(), - .rangeEnforced(), .withTreatNullAs() and .withAllowShared(). + .rangeEnforced(), .withLegacyNullToEmptyString() and .withAllowShared(). attrLocation is an array of source locations of these attributes for error reporting. """ @@ -3280,8 +3692,8 @@ class IDLBuiltinType(IDLType): self._typeTag = type self._clamped = None self._rangeEnforced = None - self._withTreatNullAs = None - self._withAllowShared = None; + self._withLegacyNullToEmptyString = None + self._withAllowShared = None if self.isInteger(): if clamp: self._clamp = True @@ -3292,20 +3704,27 @@ class IDLBuiltinType(IDLType): self.name = "RangeEnforced" + self.name self._extendedAttrDict["EnforceRange"] = True elif clamp or enforceRange: - raise WebIDLError("Non-integer types cannot be [Clamp] or [EnforceRange]", attrLocation) + raise WebIDLError( + "Non-integer types cannot be [Clamp] or [EnforceRange]", attrLocation + ) if self.isDOMString() or self.isUTF8String(): - if treatNullAsEmpty: - self.treatNullAsEmpty = True + if legacyNullToEmptyString: + self.legacyNullToEmptyString = True self.name = "NullIsEmpty" + self.name - self._extendedAttrDict["TreatNullAs"] = ["EmptyString"] - elif treatNullAsEmpty: - raise WebIDLError("Non-string types cannot be [TreatNullAs]", attrLocation) + self._extendedAttrDict["LegacyNullToEmptyString"] = True + elif legacyNullToEmptyString: + raise WebIDLError( + "Non-string types cannot be [LegacyNullToEmptyString]", attrLocation + ) if self.isBufferSource(): if allowShared: self._allowShared = True self._extendedAttrDict["AllowShared"] = True elif allowShared: - raise WebIDLError("Types that are not buffer source types cannot be [AllowShared]", attrLocation) + raise WebIDLError( + "Types that are not buffer source types cannot be [AllowShared]", + attrLocation, + ) def __str__(self): if self._allowShared: @@ -3313,41 +3732,51 @@ class IDLBuiltinType(IDLType): return "MaybeShared" + str(self.name) return str(self.name) - def __eq__(self, other): - return other and self.location == other.location and self.name == other.name and self._typeTag == other._typeTag - - def __hash__(self): - return hash((self.location, self.name, self._typeTag)) - def prettyName(self): return IDLBuiltinType.PrettyNames[self._typeTag] def clamped(self, attrLocation): if not self._clamped: - self._clamped = IDLBuiltinType(self.location, self.name, - self._typeTag, clamp=True, - attrLocation=attrLocation) + self._clamped = IDLBuiltinType( + self.location, + self.name, + self._typeTag, + clamp=True, + attrLocation=attrLocation, + ) return self._clamped def rangeEnforced(self, attrLocation): if not self._rangeEnforced: - self._rangeEnforced = IDLBuiltinType(self.location, self.name, - self._typeTag, enforceRange=True, - attrLocation=attrLocation) + self._rangeEnforced = IDLBuiltinType( + self.location, + self.name, + self._typeTag, + enforceRange=True, + attrLocation=attrLocation, + ) return self._rangeEnforced - def withTreatNullAs(self, attrLocation): - if not self._withTreatNullAs: - self._withTreatNullAs = IDLBuiltinType(self.location, self.name, - self._typeTag, treatNullAsEmpty=True, - attrLocation=attrLocation) - return self._withTreatNullAs + def withLegacyNullToEmptyString(self, attrLocation): + if not self._withLegacyNullToEmptyString: + self._withLegacyNullToEmptyString = IDLBuiltinType( + self.location, + self.name, + self._typeTag, + legacyNullToEmptyString=True, + attrLocation=attrLocation, + ) + return self._withLegacyNullToEmptyString def withAllowShared(self, attrLocation): if not self._withAllowShared: - self._withAllowShared = IDLBuiltinType(self.location, self.name, - self._typeTag, allowShared=True, - attrLocation=attrLocation) + self._withAllowShared = IDLBuiltinType( + self.location, + self.name, + self._typeTag, + allowShared=True, + attrLocation=attrLocation, + ) return self._withAllowShared def isPrimitive(self): @@ -3356,15 +3785,20 @@ class IDLBuiltinType(IDLType): def isBoolean(self): return self._typeTag == IDLBuiltinType.Types.boolean + def isUndefined(self): + return self._typeTag == IDLBuiltinType.Types.undefined + def isNumeric(self): return self.isPrimitive() and not self.isBoolean() def isString(self): - return (self._typeTag == IDLBuiltinType.Types.domstring or - self._typeTag == IDLBuiltinType.Types.bytestring or - self._typeTag == IDLBuiltinType.Types.usvstring or - self._typeTag == IDLBuiltinType.Types.utf8string or - self._typeTag == IDLBuiltinType.Types.jsstring) + return ( + self._typeTag == IDLBuiltinType.Types.domstring + or self._typeTag == IDLBuiltinType.Types.bytestring + or self._typeTag == IDLBuiltinType.Types.usvstring + or self._typeTag == IDLBuiltinType.Types.utf8string + or self._typeTag == IDLBuiltinType.Types.jsstring + ) def isByteString(self): return self._typeTag == IDLBuiltinType.Types.bytestring @@ -3391,35 +3825,35 @@ class IDLBuiltinType(IDLType): return self._typeTag == IDLBuiltinType.Types.ArrayBufferView def isTypedArray(self): - return (self._typeTag >= IDLBuiltinType.Types.Int8Array and - self._typeTag <= IDLBuiltinType.Types.Float64Array) - - def isReadableStream(self): - return self._typeTag == IDLBuiltinType.Types.ReadableStream + return ( + self._typeTag >= IDLBuiltinType.Types.Int8Array + and self._typeTag <= IDLBuiltinType.Types.Float64Array + ) def isInterface(self): # TypedArray things are interface types per the TypedArray spec, # but we handle them as builtins because SpiderMonkey implements # all of it internally. - return (self.isArrayBuffer() or - self.isArrayBufferView() or - self.isTypedArray() or - self.isReadableStream()) + return self.isArrayBuffer() or self.isArrayBufferView() or self.isTypedArray() def isNonCallbackInterface(self): # All the interfaces we can be are non-callback return self.isInterface() def isFloat(self): - return (self._typeTag == IDLBuiltinType.Types.float or - self._typeTag == IDLBuiltinType.Types.double or - self._typeTag == IDLBuiltinType.Types.unrestricted_float or - self._typeTag == IDLBuiltinType.Types.unrestricted_double) + return ( + self._typeTag == IDLBuiltinType.Types.float + or self._typeTag == IDLBuiltinType.Types.double + or self._typeTag == IDLBuiltinType.Types.unrestricted_float + or self._typeTag == IDLBuiltinType.Types.unrestricted_double + ) def isUnrestricted(self): assert self.isFloat() - return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or - self._typeTag == IDLBuiltinType.Types.unrestricted_double) + return ( + self._typeTag == IDLBuiltinType.Types.unrestricted_float + or self._typeTag == IDLBuiltinType.Types.unrestricted_double + ) def isJSONType(self): return self.isPrimitive() or self.isString() or self.isObject() @@ -3436,48 +3870,84 @@ class IDLBuiltinType(IDLType): if other.isUnion(): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) - if self.isBoolean(): - return (other.isNumeric() or other.isString() or other.isEnum() or - other.isInterface() or other.isObject() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord()) - if self.isNumeric(): - return (other.isBoolean() or other.isString() or other.isEnum() or - other.isInterface() or other.isObject() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord()) + if self.isUndefined(): + return not (other.isUndefined() or other.isDictionaryLike()) + if self.isPrimitive(): + if ( + other.isUndefined() + or other.isString() + or other.isEnum() + or other.isInterface() + or other.isObject() + or other.isCallback() + or other.isDictionary() + or other.isSequence() + or other.isRecord() + ): + return True + if self.isBoolean(): + return other.isNumeric() + assert self.isNumeric() + return other.isBoolean() if self.isString(): - return (other.isPrimitive() or other.isInterface() or - other.isObject() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord()) + return ( + other.isUndefined() + or other.isPrimitive() + or other.isInterface() + or other.isObject() + or other.isCallback() + or other.isDictionary() + or other.isSequence() + or other.isRecord() + ) if self.isAny(): # Can't tell "any" apart from anything return False if self.isObject(): - return other.isPrimitive() or other.isString() or other.isEnum() - if self.isUndefined(): - return not other.isUndefined() + return ( + other.isUndefined() + or other.isPrimitive() + or other.isString() + or other.isEnum() + ) # Not much else we could be! assert self.isSpiderMonkeyInterface() # Like interfaces, but we know we're not a callback - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isRecord() or - (other.isInterface() and ( - # ArrayBuffer is distinguishable from everything - # that's not an ArrayBuffer or a callback interface - (self.isArrayBuffer() and not other.isArrayBuffer()) or - (self.isReadableStream() and not other.isReadableStream()) or - # ArrayBufferView is distinguishable from everything - # that's not an ArrayBufferView or typed array. - (self.isArrayBufferView() and not other.isArrayBufferView() and - not other.isTypedArray()) or - # Typed arrays are distinguishable from everything - # except ArrayBufferView and the same type of typed - # array - (self.isTypedArray() and not other.isArrayBufferView() and not - (other.isTypedArray() and other.name == self.name))))) + return ( + other.isUndefined() + or other.isPrimitive() + or other.isString() + or other.isEnum() + or other.isCallback() + or other.isDictionary() + or other.isSequence() + or other.isRecord() + or ( + other.isInterface() + and ( + # ArrayBuffer is distinguishable from everything + # that's not an ArrayBuffer or a callback interface + (self.isArrayBuffer() and not other.isArrayBuffer()) + or + # ArrayBufferView is distinguishable from everything + # that's not an ArrayBufferView or typed array. + ( + self.isArrayBufferView() + and not other.isArrayBufferView() + and not other.isTypedArray() + ) + or + # Typed arrays are distinguishable from everything + # except ArrayBufferView and the same type of typed + # array + ( + self.isTypedArray() + and not other.isArrayBufferView() + and not (other.isTypedArray() and other.name == self.name) + ) + ) + ) + ) def _getDependentObjects(self): return set() @@ -3488,177 +3958,213 @@ class IDLBuiltinType(IDLType): identifier = attribute.identifier() if identifier == "Clamp": if not attribute.noArguments(): - raise WebIDLError("[Clamp] must take no arguments", - [attribute.location]) + raise WebIDLError( + "[Clamp] must take no arguments", [attribute.location] + ) if ret.hasEnforceRange() or self._enforceRange: - raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", - [self.location, attribute.location]) + raise WebIDLError( + "[EnforceRange] and [Clamp] are mutually exclusive", + [self.location, attribute.location], + ) ret = self.clamped([self.location, attribute.location]) elif identifier == "EnforceRange": if not attribute.noArguments(): - raise WebIDLError("[EnforceRange] must take no arguments", - [attribute.location]) + raise WebIDLError( + "[EnforceRange] must take no arguments", [attribute.location] + ) if ret.hasClamp() or self._clamp: - raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", - [self.location, attribute.location]) + raise WebIDLError( + "[EnforceRange] and [Clamp] are mutually exclusive", + [self.location, attribute.location], + ) ret = self.rangeEnforced([self.location, attribute.location]) - elif identifier == "TreatNullAs": + elif identifier == "LegacyNullToEmptyString": if not (self.isDOMString() or self.isUTF8String()): - raise WebIDLError("[TreatNullAs] only allowed on DOMStrings and UTF8Strings", - [self.location, attribute.location]) + raise WebIDLError( + "[LegacyNullToEmptyString] only allowed on DOMStrings and UTF8Strings", + [self.location, attribute.location], + ) assert not self.nullable() - if not attribute.hasValue(): - raise WebIDLError("[TreatNullAs] must take an identifier argument", - [attribute.location]) - value = attribute.value() - if value != 'EmptyString': - raise WebIDLError("[TreatNullAs] must take the identifier " - "'EmptyString', not '%s'" % value, - [attribute.location]) - ret = self.withTreatNullAs([self.location, attribute.location]) + if attribute.hasValue(): + raise WebIDLError( + "[LegacyNullToEmptyString] must take no identifier argument", + [attribute.location], + ) + ret = self.withLegacyNullToEmptyString( + [self.location, attribute.location] + ) elif identifier == "AllowShared": if not attribute.noArguments(): - raise WebIDLError("[AllowShared] must take no arguments", - [attribute.location]) + raise WebIDLError( + "[AllowShared] must take no arguments", [attribute.location] + ) if not self.isBufferSource(): - raise WebIDLError("[AllowShared] only allowed on buffer source types", - [self.location, attribute.location]) + raise WebIDLError( + "[AllowShared] only allowed on buffer source types", + [self.location, attribute.location], + ) ret = self.withAllowShared([self.location, attribute.location]) else: - raise WebIDLError("Unhandled extended attribute on type", - [self.location, attribute.location]) + raise WebIDLError( + "Unhandled extended attribute on type", + [self.location, attribute.location], + ) return ret + BuiltinTypes = { - IDLBuiltinType.Types.byte: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte", - IDLBuiltinType.Types.byte), - IDLBuiltinType.Types.octet: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Octet", - IDLBuiltinType.Types.octet), - IDLBuiltinType.Types.short: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Short", - IDLBuiltinType.Types.short), - IDLBuiltinType.Types.unsigned_short: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedShort", - IDLBuiltinType.Types.unsigned_short), - IDLBuiltinType.Types.long: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Long", - IDLBuiltinType.Types.long), - IDLBuiltinType.Types.unsigned_long: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedLong", - IDLBuiltinType.Types.unsigned_long), - IDLBuiltinType.Types.long_long: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "LongLong", - IDLBuiltinType.Types.long_long), - IDLBuiltinType.Types.unsigned_long_long: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedLongLong", - IDLBuiltinType.Types.unsigned_long_long), - IDLBuiltinType.Types.boolean: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Boolean", - IDLBuiltinType.Types.boolean), - IDLBuiltinType.Types.float: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float", - IDLBuiltinType.Types.float), - IDLBuiltinType.Types.unrestricted_float: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnrestrictedFloat", - IDLBuiltinType.Types.unrestricted_float), - IDLBuiltinType.Types.double: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Double", - IDLBuiltinType.Types.double), - IDLBuiltinType.Types.unrestricted_double: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnrestrictedDouble", - IDLBuiltinType.Types.unrestricted_double), - IDLBuiltinType.Types.any: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Any", - IDLBuiltinType.Types.any), - IDLBuiltinType.Types.domstring: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "String", - IDLBuiltinType.Types.domstring), - IDLBuiltinType.Types.bytestring: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "ByteString", - IDLBuiltinType.Types.bytestring), - IDLBuiltinType.Types.usvstring: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "USVString", - IDLBuiltinType.Types.usvstring), - IDLBuiltinType.Types.utf8string: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UTF8String", - IDLBuiltinType.Types.utf8string), - IDLBuiltinType.Types.jsstring: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "JSString", - IDLBuiltinType.Types.jsstring), - IDLBuiltinType.Types.object: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object", - IDLBuiltinType.Types.object), - IDLBuiltinType.Types.undefined: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Undefined", - IDLBuiltinType.Types.undefined), - IDLBuiltinType.Types.ArrayBuffer: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBuffer", - IDLBuiltinType.Types.ArrayBuffer), - IDLBuiltinType.Types.ArrayBufferView: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBufferView", - IDLBuiltinType.Types.ArrayBufferView), - IDLBuiltinType.Types.Int8Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int8Array", - IDLBuiltinType.Types.Int8Array), - IDLBuiltinType.Types.Uint8Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8Array", - IDLBuiltinType.Types.Uint8Array), - IDLBuiltinType.Types.Uint8ClampedArray: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8ClampedArray", - IDLBuiltinType.Types.Uint8ClampedArray), - IDLBuiltinType.Types.Int16Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int16Array", - IDLBuiltinType.Types.Int16Array), - IDLBuiltinType.Types.Uint16Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint16Array", - IDLBuiltinType.Types.Uint16Array), - IDLBuiltinType.Types.Int32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int32Array", - IDLBuiltinType.Types.Int32Array), - IDLBuiltinType.Types.Uint32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint32Array", - IDLBuiltinType.Types.Uint32Array), - IDLBuiltinType.Types.Float32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float32Array", - IDLBuiltinType.Types.Float32Array), - IDLBuiltinType.Types.Float64Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array", - IDLBuiltinType.Types.Float64Array), - IDLBuiltinType.Types.ReadableStream: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "ReadableStream", - IDLBuiltinType.Types.ReadableStream), + IDLBuiltinType.Types.byte: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Byte", IDLBuiltinType.Types.byte + ), + IDLBuiltinType.Types.octet: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Octet", IDLBuiltinType.Types.octet + ), + IDLBuiltinType.Types.short: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Short", IDLBuiltinType.Types.short + ), + IDLBuiltinType.Types.unsigned_short: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "UnsignedShort", + IDLBuiltinType.Types.unsigned_short, + ), + IDLBuiltinType.Types.long: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Long", IDLBuiltinType.Types.long + ), + IDLBuiltinType.Types.unsigned_long: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "UnsignedLong", + IDLBuiltinType.Types.unsigned_long, + ), + IDLBuiltinType.Types.long_long: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "LongLong", IDLBuiltinType.Types.long_long + ), + IDLBuiltinType.Types.unsigned_long_long: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "UnsignedLongLong", + IDLBuiltinType.Types.unsigned_long_long, + ), + IDLBuiltinType.Types.undefined: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Undefined", IDLBuiltinType.Types.undefined + ), + IDLBuiltinType.Types.boolean: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Boolean", IDLBuiltinType.Types.boolean + ), + IDLBuiltinType.Types.float: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Float", IDLBuiltinType.Types.float + ), + IDLBuiltinType.Types.unrestricted_float: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "UnrestrictedFloat", + IDLBuiltinType.Types.unrestricted_float, + ), + IDLBuiltinType.Types.double: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Double", IDLBuiltinType.Types.double + ), + IDLBuiltinType.Types.unrestricted_double: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "UnrestrictedDouble", + IDLBuiltinType.Types.unrestricted_double, + ), + IDLBuiltinType.Types.any: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Any", IDLBuiltinType.Types.any + ), + IDLBuiltinType.Types.domstring: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "String", IDLBuiltinType.Types.domstring + ), + IDLBuiltinType.Types.bytestring: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "ByteString", IDLBuiltinType.Types.bytestring + ), + IDLBuiltinType.Types.usvstring: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "USVString", IDLBuiltinType.Types.usvstring + ), + IDLBuiltinType.Types.utf8string: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "UTF8String", IDLBuiltinType.Types.utf8string + ), + IDLBuiltinType.Types.jsstring: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "JSString", IDLBuiltinType.Types.jsstring + ), + IDLBuiltinType.Types.object: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Object", IDLBuiltinType.Types.object + ), + IDLBuiltinType.Types.ArrayBuffer: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "ArrayBuffer", + IDLBuiltinType.Types.ArrayBuffer, + ), + IDLBuiltinType.Types.ArrayBufferView: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "ArrayBufferView", + IDLBuiltinType.Types.ArrayBufferView, + ), + IDLBuiltinType.Types.Int8Array: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Int8Array", IDLBuiltinType.Types.Int8Array + ), + IDLBuiltinType.Types.Uint8Array: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Uint8Array", IDLBuiltinType.Types.Uint8Array + ), + IDLBuiltinType.Types.Uint8ClampedArray: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "Uint8ClampedArray", + IDLBuiltinType.Types.Uint8ClampedArray, + ), + IDLBuiltinType.Types.Int16Array: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Int16Array", IDLBuiltinType.Types.Int16Array + ), + IDLBuiltinType.Types.Uint16Array: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "Uint16Array", + IDLBuiltinType.Types.Uint16Array, + ), + IDLBuiltinType.Types.Int32Array: IDLBuiltinType( + BuiltinLocation("<builtin type>"), "Int32Array", IDLBuiltinType.Types.Int32Array + ), + IDLBuiltinType.Types.Uint32Array: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "Uint32Array", + IDLBuiltinType.Types.Uint32Array, + ), + IDLBuiltinType.Types.Float32Array: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "Float32Array", + IDLBuiltinType.Types.Float32Array, + ), + IDLBuiltinType.Types.Float64Array: IDLBuiltinType( + BuiltinLocation("<builtin type>"), + "Float64Array", + IDLBuiltinType.Types.Float64Array, + ), } integerTypeSizes = { IDLBuiltinType.Types.byte: (-128, 127), - IDLBuiltinType.Types.octet: (0, 255), + IDLBuiltinType.Types.octet: (0, 255), IDLBuiltinType.Types.short: (-32768, 32767), IDLBuiltinType.Types.unsigned_short: (0, 65535), IDLBuiltinType.Types.long: (-2147483648, 2147483647), IDLBuiltinType.Types.unsigned_long: (0, 4294967295), IDLBuiltinType.Types.long_long: (-9223372036854775808, 9223372036854775807), - IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615) + IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615), } def matchIntegerValueToType(value): - for type, extremes in list(integerTypeSizes.items()): + for type, extremes in integerTypeSizes.items(): (min, max) = extremes if value <= max and value >= min: return BuiltinTypes[type] return None + class NoCoercionFoundError(WebIDLError): """ A class we use to indicate generic coercion failures because none of the types worked out in IDLValue.coerceToType. """ + class IDLValue(IDLObject): def __init__(self, location, type, value): IDLObject.__init__(self, location) @@ -3693,8 +4199,9 @@ class IDLValue(IDLObject): # non-WebIDLErrors here, because those can just happen if # "type" is not something that can have a default value at # all. - if (isinstance(e, WebIDLError) and - not isinstance(e, NoCoercionFoundError)): + if isinstance(e, WebIDLError) and not isinstance( + e, NoCoercionFoundError + ): raise e # If the type allows null, rerun this matching on the inner type, except @@ -3713,29 +4220,41 @@ class IDLValue(IDLObject): # Promote return IDLValue(self.location, type, self.value) else: - raise WebIDLError("Value %s is out of range for type %s." % - (self.value, type), [location]) + raise WebIDLError( + "Value %s is out of range for type %s." % (self.value, type), + [location], + ) elif self.type.isInteger() and type.isFloat(): # Convert an integer literal into float - if -2**24 <= self.value <= 2**24: + if -(2 ** 24) <= self.value <= 2 ** 24: return IDLValue(self.location, type, float(self.value)) else: - raise WebIDLError("Converting value %s to %s will lose precision." % - (self.value, type), [location]) + raise WebIDLError( + "Converting value %s to %s will lose precision." + % (self.value, type), + [location], + ) elif self.type.isString() and type.isEnum(): # Just keep our string, but make sure it's a valid value for this enum enum = type.unroll().inner - if self.value not in list(enum.values()): - raise WebIDLError("'%s' is not a valid default value for enum %s" - % (self.value, enum.identifier.name), - [location, enum.location]) + if self.value not in enum.values(): + raise WebIDLError( + "'%s' is not a valid default value for enum %s" + % (self.value, enum.identifier.name), + [location, enum.location], + ) return self elif self.type.isFloat() and type.isFloat(): - if (not type.isUnrestricted() and - (self.value == float("inf") or self.value == float("-inf") or - math.isnan(self.value))): - raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted" - % self.value, [location]) + if not type.isUnrestricted() and ( + self.value == float("inf") + or self.value == float("-inf") + or math.isnan(self.value) + ): + raise WebIDLError( + "Trying to convert unrestricted value %s to non-unrestricted" + % self.value, + [location], + ) return IDLValue(self.location, type, self.value) elif self.type.isString() and type.isUSVString(): # Allow USVStrings to use default value just like @@ -3744,27 +4263,35 @@ class IDLValue(IDLObject): # extra normalization step. assert self.type.isDOMString() return self - elif self.type.isDOMString() and type.treatNullAsEmpty: - # TreatNullAsEmpty is a different type for resolution reasons, - # however once you have a value it doesn't matter - return self - elif self.type.isString() and (type.isByteString() or type.isJSString() or type.isUTF8String()): + elif self.type.isString() and ( + type.isByteString() or type.isJSString() or type.isUTF8String() + ): # Allow ByteStrings, UTF8String, and JSStrings to use a default # value like DOMString. # No coercion is required as Codegen.py will handle the # extra steps. We want to make sure that our string contains # only valid characters, so we check that here. - valid_ascii_lit = " " + string.ascii_letters + string.digits + string.punctuation + valid_ascii_lit = ( + " " + string.ascii_letters + string.digits + string.punctuation + ) for idx, c in enumerate(self.value): if c not in valid_ascii_lit: - raise WebIDLError("Coercing this string literal %s to a ByteString is not supported yet. " - "Coercion failed due to an unsupported byte %d at index %d." - % (self.value.__repr__(), ord(c), idx), [location]) + raise WebIDLError( + "Coercing this string literal %s to a ByteString is not supported yet. " + "Coercion failed due to an unsupported byte %d at index %d." + % (self.value.__repr__(), ord(c), idx), + [location], + ) return IDLValue(self.location, type, self.value) + elif self.type.isDOMString() and type.legacyNullToEmptyString: + # LegacyNullToEmptyString is a different type for resolution reasons, + # however once you have a value it doesn't matter + return self - raise NoCoercionFoundError("Cannot coerce type %s to type %s." % - (self.type, type), [location]) + raise NoCoercionFoundError( + "Cannot coerce type %s to type %s." % (self.type, type), [location] + ) def _getDependentObjects(self): return set() @@ -3777,11 +4304,12 @@ class IDLNullValue(IDLObject): self.value = None def coerceToType(self, type, location): - if (not isinstance(type, IDLNullableType) and - not (type.isUnion() and type.hasNullableType) and - not type.isAny()): - raise WebIDLError("Cannot coerce null value to type %s." % type, - [location]) + if ( + not isinstance(type, IDLNullableType) + and not (type.isUnion() and type.hasNullableType) + and not type.isAny() + ): + raise WebIDLError("Cannot coerce null value to type %s." % type, [location]) nullValue = IDLNullValue(self.location) if type.isUnion() and not type.nullable() and type.hasDictionaryType(): @@ -3816,8 +4344,9 @@ class IDLEmptySequenceValue(IDLObject): pass if not type.isSequence(): - raise WebIDLError("Cannot coerce empty sequence value to type %s." % type, - [location]) + raise WebIDLError( + "Cannot coerce empty sequence value to type %s." % type, [location] + ) emptySequenceValue = IDLEmptySequenceValue(self.location) emptySequenceValue.type = type @@ -3845,8 +4374,9 @@ class IDLDefaultDictionaryValue(IDLObject): pass if not type.isDictionary(): - raise WebIDLError("Cannot coerce default dictionary value to type %s." % type, - [location]) + raise WebIDLError( + "Cannot coerce default dictionary value to type %s." % type, [location] + ) defaultDictionaryValue = IDLDefaultDictionaryValue(self.location) defaultDictionaryValue.type = type @@ -3864,8 +4394,9 @@ class IDLUndefinedValue(IDLObject): def coerceToType(self, type, location): if not type.isAny(): - raise WebIDLError("Cannot coerce undefined value to type %s." % type, - [location]) + raise WebIDLError( + "Cannot coerce undefined value to type %s." % type, [location] + ) undefinedValue = IDLUndefinedValue(self.location) undefinedValue.type = type @@ -3878,17 +4409,10 @@ class IDLUndefinedValue(IDLObject): class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): Tags = enum( - 'Const', - 'Attr', - 'Method', - 'MaplikeOrSetlike', - 'Iterable' + "Const", "Attr", "Method", "MaplikeOrSetlike", "AsyncIterable", "Iterable" ) - Special = enum( - 'Static', - 'Stringifier' - ) + Special = enum("Static", "Stringifier") AffectsValues = ("Nothing", "Everything") DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything") @@ -3912,8 +4436,11 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): return self.tag == IDLInterfaceMember.Tags.Const def isMaplikeOrSetlikeOrIterable(self): - return (self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike or - self.tag == IDLInterfaceMember.Tags.Iterable) + return ( + self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike + or self.tag == IDLInterfaceMember.Tags.AsyncIterable + or self.tag == IDLInterfaceMember.Tags.Iterable + ) def isMaplikeOrSetlike(self): return self.tag == IDLInterfaceMember.Tags.MaplikeOrSetlike @@ -3922,7 +4449,9 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): for attr in attrs: self.handleExtendedAttribute(attr) attrlist = attr.listValue() - self._extendedAttrDict[attr.identifier()] = attrlist if len(attrlist) else True + self._extendedAttrDict[attr.identifier()] = ( + attrlist if len(attrlist) else True + ) def handleExtendedAttribute(self, attr): pass @@ -3936,66 +4465,84 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): def validate(self): if self.isAttr() or self.isMethod(): if self.affects == "Everything" and self.dependsOn != "Everything": - raise WebIDLError("Interface member is flagged as affecting " - "everything but not depending on everything. " - "That seems rather unlikely.", - [self.location]) + raise WebIDLError( + "Interface member is flagged as affecting " + "everything but not depending on everything. " + "That seems rather unlikely.", + [self.location], + ) if self.getExtendedAttribute("NewObject"): if self.dependsOn == "Nothing" or self.dependsOn == "DOMState": - raise WebIDLError("A [NewObject] method is not idempotent, " - "so it has to depend on something other than DOM state.", - [self.location]) - if (self.getExtendedAttribute("Cached") or - self.getExtendedAttribute("StoreInSlot")): - raise WebIDLError("A [NewObject] attribute shouldnt be " - "[Cached] or [StoreInSlot], since the point " - "of those is to keep returning the same " - "thing across multiple calls, which is not " - "what [NewObject] does.", - [self.location]) + raise WebIDLError( + "A [NewObject] method is not idempotent, " + "so it has to depend on something other than DOM state.", + [self.location], + ) + if self.getExtendedAttribute("Cached") or self.getExtendedAttribute( + "StoreInSlot" + ): + raise WebIDLError( + "A [NewObject] attribute shouldnt be " + "[Cached] or [StoreInSlot], since the point " + "of those is to keep returning the same " + "thing across multiple calls, which is not " + "what [NewObject] does.", + [self.location], + ) def _setDependsOn(self, dependsOn): if self.dependsOn != "Everything": - raise WebIDLError("Trying to specify multiple different DependsOn, " - "Pure, or Constant extended attributes for " - "attribute", [self.location]) + raise WebIDLError( + "Trying to specify multiple different DependsOn, " + "Pure, or Constant extended attributes for " + "attribute", + [self.location], + ) if dependsOn not in IDLInterfaceMember.DependsOnValues: - raise WebIDLError("Invalid [DependsOn=%s] on attribute" % dependsOn, - [self.location]) + raise WebIDLError( + "Invalid [DependsOn=%s] on attribute" % dependsOn, [self.location] + ) self.dependsOn = dependsOn def _setAffects(self, affects): if self.affects != "Everything": - raise WebIDLError("Trying to specify multiple different Affects, " - "Pure, or Constant extended attributes for " - "attribute", [self.location]) + raise WebIDLError( + "Trying to specify multiple different Affects, " + "Pure, or Constant extended attributes for " + "attribute", + [self.location], + ) if affects not in IDLInterfaceMember.AffectsValues: - raise WebIDLError("Invalid [Affects=%s] on attribute" % dependsOn, - [self.location]) + raise WebIDLError( + "Invalid [Affects=%s] on attribute" % dependsOn, [self.location] + ) self.affects = affects def _addAlias(self, alias): if alias in self.aliases: - raise WebIDLError("Duplicate [Alias=%s] on attribute" % alias, - [self.location]) + raise WebIDLError( + "Duplicate [Alias=%s] on attribute" % alias, [self.location] + ) self.aliases.append(alias) def _addBindingAlias(self, bindingAlias): if bindingAlias in self.bindingAliases: - raise WebIDLError("Duplicate [BindingAlias=%s] on attribute" % bindingAlias, - [self.location]) + raise WebIDLError( + "Duplicate [BindingAlias=%s] on attribute" % bindingAlias, + [self.location], + ) self.bindingAliases.append(bindingAlias) -class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): +class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind): IDLInterfaceMember.__init__(self, location, identifier, ifaceKind) if keyType is not None: assert isinstance(keyType, IDLType) else: assert valueType is not None - assert ifaceType in ['maplike', 'setlike', 'iterable'] + assert ifaceType in ["maplike", "setlike", "iterable", "asynciterable"] if valueType is not None: assert isinstance(valueType, IDLType) self.keyType = keyType @@ -4013,6 +4560,9 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): def isIterable(self): return self.maplikeOrSetlikeOrIterableType == "iterable" + def isAsyncIterable(self): + return self.maplikeOrSetlikeOrIterableType == "asynciterable" + def hasKeyType(self): return self.keyType is not None @@ -4022,28 +4572,42 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): def checkCollisions(self, members, isAncestor): for member in members: # Check that there are no disallowed members - if (member.identifier.name in self.disallowedMemberNames and - not ((member.isMethod() and member.isMaplikeOrSetlikeOrIterableMethod()) or - (member.isAttr() and member.isMaplikeOrSetlikeAttr()))): - raise WebIDLError("Member '%s' conflicts " - "with reserved %s name." % - (member.identifier.name, - self.maplikeOrSetlikeOrIterableType), - [self.location, member.location]) + if member.identifier.name in self.disallowedMemberNames and not ( + (member.isMethod() and member.isMaplikeOrSetlikeOrIterableMethod()) + or (member.isAttr() and member.isMaplikeOrSetlikeAttr()) + ): + raise WebIDLError( + "Member '%s' conflicts " + "with reserved %s name." + % (member.identifier.name, self.maplikeOrSetlikeOrIterableType), + [self.location, member.location], + ) # Check that there are no disallowed non-method members. # Ancestor members are always disallowed here; own members # are disallowed only if they're non-methods. - if ((isAncestor or member.isAttr() or member.isConst()) and - member.identifier.name in self.disallowedNonMethodNames): - raise WebIDLError("Member '%s' conflicts " - "with reserved %s method." % - (member.identifier.name, - self.maplikeOrSetlikeOrIterableType), - [self.location, member.location]) - - def addMethod(self, name, members, allowExistingOperations, returnType, args=[], - chromeOnly=False, isPure=False, affectsNothing=False, newObject=False, - isIteratorAlias=False): + if ( + isAncestor or member.isAttr() or member.isConst() + ) and member.identifier.name in self.disallowedNonMethodNames: + raise WebIDLError( + "Member '%s' conflicts " + "with reserved %s method." + % (member.identifier.name, self.maplikeOrSetlikeOrIterableType), + [self.location, member.location], + ) + + def addMethod( + self, + name, + members, + allowExistingOperations, + returnType, + args=[], + chromeOnly=False, + isPure=False, + affectsNothing=False, + newObject=False, + isIteratorAlias=False, + ): """ Create an IDLMethod based on the parameters passed in. @@ -4082,35 +4646,47 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): for m in members: if m.identifier.name == name and m.isMethod() and not m.isStatic(): return - method = IDLMethod(self.location, - IDLUnresolvedIdentifier(self.location, name, allowDoubleUnderscore=chromeOnly), - returnType, args, maplikeOrSetlikeOrIterable=self) + method = IDLMethod( + self.location, + IDLUnresolvedIdentifier( + self.location, name, allowDoubleUnderscore=chromeOnly + ), + returnType, + args, + maplikeOrSetlikeOrIterable=self, + ) # We need to be able to throw from declaration methods - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("Throws",))]) + method.addExtendedAttributes([IDLExtendedAttribute(self.location, ("Throws",))]) if chromeOnly: method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) + [IDLExtendedAttribute(self.location, ("ChromeOnly",))] + ) if isPure: method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("Pure",))]) + [IDLExtendedAttribute(self.location, ("Pure",))] + ) # Following attributes are used for keys/values/entries. Can't mark # them pure, since they return a new object each time they are run. if affectsNothing: method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("DependsOn", "Everything")), - IDLExtendedAttribute(self.location, ("Affects", "Nothing"))]) + [ + IDLExtendedAttribute(self.location, ("DependsOn", "Everything")), + IDLExtendedAttribute(self.location, ("Affects", "Nothing")), + ] + ) if newObject: method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("NewObject",))]) + [IDLExtendedAttribute(self.location, ("NewObject",))] + ) if isIteratorAlias: - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))]) - # Methods generated for iterables should be enumerable, but the ones for - # maplike/setlike should not be. - if not self.isIterable(): - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("NonEnumerable",))]) + if not self.isAsyncIterable(): + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("Alias", "@@iterator"))] + ) + else: + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("Alias", "@@asyncIterator"))] + ) members.append(method) def resolve(self, parentScope): @@ -4151,30 +4727,47 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): return deps def getForEachArguments(self): - return [IDLArgument(self.location, - IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "callback"), - BuiltinTypes[IDLBuiltinType.Types.object]), - IDLArgument(self.location, - IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "thisArg"), - BuiltinTypes[IDLBuiltinType.Types.any], - optional=True)] + return [ + IDLArgument( + self.location, + IDLUnresolvedIdentifier( + BuiltinLocation("<auto-generated-identifier>"), "callback" + ), + BuiltinTypes[IDLBuiltinType.Types.object], + ), + IDLArgument( + self.location, + IDLUnresolvedIdentifier( + BuiltinLocation("<auto-generated-identifier>"), "thisArg" + ), + BuiltinTypes[IDLBuiltinType.Types.any], + optional=True, + ), + ] + # Iterable adds ES6 iterator style functions and traits # (keys/values/entries/@@iterator) to an interface. class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): - - def __init__(self, location, identifier, keyType, valueType=None, scope=None): - IDLMaplikeOrSetlikeOrIterableBase.__init__(self, location, identifier, - "iterable", keyType, valueType, - IDLInterfaceMember.Tags.Iterable) + def __init__(self, location, identifier, keyType, valueType, scope): + IDLMaplikeOrSetlikeOrIterableBase.__init__( + self, + location, + identifier, + "iterable", + keyType, + valueType, + IDLInterfaceMember.Tags.Iterable, + ) self.iteratorType = None def __str__(self): - return "declared iterable with key '%s' and value '%s'" % (self.keyType, self.valueType) + return "declared iterable with key '%s' and value '%s'" % ( + self.keyType, + self.valueType, + ) - def expand(self, members, isJSImplemented): + def expand(self, members): """ In order to take advantage of all of the method machinery in Codegen, we generate our functions as if they were part of the interface @@ -4186,20 +4779,125 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): return # object entries() - self.addMethod("entries", members, False, self.iteratorType, - affectsNothing=True, newObject=True, - isIteratorAlias=True) + self.addMethod( + "entries", + members, + False, + self.iteratorType, + affectsNothing=True, + newObject=True, + isIteratorAlias=True, + ) # object keys() - self.addMethod("keys", members, False, self.iteratorType, - affectsNothing=True, newObject=True) + self.addMethod( + "keys", + members, + False, + self.iteratorType, + affectsNothing=True, + newObject=True, + ) # object values() - self.addMethod("values", members, False, self.iteratorType, - affectsNothing=True, newObject=True) + self.addMethod( + "values", + members, + False, + self.iteratorType, + affectsNothing=True, + newObject=True, + ) # undefined forEach(callback(valueType, keyType), optional any thisArg) - self.addMethod("forEach", members, False, - BuiltinTypes[IDLBuiltinType.Types.undefined], - self.getForEachArguments()) + self.addMethod( + "forEach", + members, + False, + BuiltinTypes[IDLBuiltinType.Types.undefined], + self.getForEachArguments(), + ) + + def isValueIterator(self): + return not self.isPairIterator() + + def isPairIterator(self): + return self.hasKeyType() + + +class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): + def __init__(self, location, identifier, keyType, valueType, argList, scope): + for arg in argList: + if not arg.optional: + raise WebIDLError( + "The arguments of the asynchronously iterable declaration on " + "%s must all be optional arguments." % identifier, + [arg.location], + ) + + IDLMaplikeOrSetlikeOrIterableBase.__init__( + self, + location, + identifier, + "asynciterable", + keyType, + valueType, + IDLInterfaceMember.Tags.AsyncIterable, + ) + self.iteratorType = None + self.argList = argList + + def __str__(self): + return "declared async iterable with key '%s' and value '%s'" % ( + self.keyType, + self.valueType, + ) + + def expand(self, members): + """ + In order to take advantage of all of the method machinery in Codegen, + we generate our functions as if they were part of the interface + specification during parsing. + """ + # object values() + self.addMethod( + "values", + members, + False, + self.iteratorType, + self.argList, + affectsNothing=True, + newObject=True, + isIteratorAlias=(not self.isPairIterator()), + ) + + # We only need to add entries/keys here if we're a pair iterator. + if not self.isPairIterator(): + return + + # Methods can't share their IDLArguments, so we need to make copies here. + def copyArgList(argList): + return map(copy.copy, argList) + + # object entries() + self.addMethod( + "entries", + members, + False, + self.iteratorType, + copyArgList(self.argList), + affectsNothing=True, + newObject=True, + isIteratorAlias=True, + ) + # object keys() + self.addMethod( + "keys", + members, + False, + self.iteratorType, + copyArgList(self.argList), + affectsNothing=True, + newObject=True, + ) def isValueIterator(self): return not self.isPairIterator() @@ -4207,98 +4905,137 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): def isPairIterator(self): return self.hasKeyType() + # MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface. class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): - - def __init__(self, location, identifier, maplikeOrSetlikeType, - readonly, keyType, valueType): - IDLMaplikeOrSetlikeOrIterableBase.__init__(self, location, identifier, maplikeOrSetlikeType, - keyType, valueType, IDLInterfaceMember.Tags.MaplikeOrSetlike) + def __init__( + self, location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType + ): + IDLMaplikeOrSetlikeOrIterableBase.__init__( + self, + location, + identifier, + maplikeOrSetlikeType, + keyType, + valueType, + IDLInterfaceMember.Tags.MaplikeOrSetlike, + ) self.readonly = readonly self.slotIndices = None # When generating JSAPI access code, we need to know the backing object # type prefix to create the correct function. Generate here for reuse. if self.isMaplike(): - self.prefix = 'Map' + self.prefix = "Map" elif self.isSetlike(): - self.prefix = 'Set' + self.prefix = "Set" def __str__(self): - return "declared '%s' with key '%s'" % (self.maplikeOrSetlikeOrIterableType, self.keyType) + return "declared '%s' with key '%s'" % ( + self.maplikeOrSetlikeOrIterableType, + self.keyType, + ) - def expand(self, members, isJSImplemented): + def expand(self, members): """ In order to take advantage of all of the method machinery in Codegen, we generate our functions as if they were part of the interface specification during parsing. """ # Both maplike and setlike have a size attribute - sizeAttr = IDLAttribute(self.location, - IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), "size"), - BuiltinTypes[IDLBuiltinType.Types.unsigned_long], - True, - maplikeOrSetlike=self) - # This should be non-enumerable. - sizeAttr.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("NonEnumerable",))]) - members.append(sizeAttr) + members.append( + IDLAttribute( + self.location, + IDLUnresolvedIdentifier( + BuiltinLocation("<auto-generated-identifier>"), "size" + ), + BuiltinTypes[IDLBuiltinType.Types.unsigned_long], + True, + maplikeOrSetlike=self, + ) + ) self.reserved_ro_names = ["size"] self.disallowedMemberNames.append("size") # object entries() - self.addMethod("entries", members, False, BuiltinTypes[IDLBuiltinType.Types.object], - affectsNothing=True, isIteratorAlias=self.isMaplike()) + self.addMethod( + "entries", + members, + False, + BuiltinTypes[IDLBuiltinType.Types.object], + affectsNothing=True, + isIteratorAlias=self.isMaplike(), + ) # object keys() - self.addMethod("keys", members, False, BuiltinTypes[IDLBuiltinType.Types.object], - affectsNothing=True) + self.addMethod( + "keys", + members, + False, + BuiltinTypes[IDLBuiltinType.Types.object], + affectsNothing=True, + ) # object values() - self.addMethod("values", members, False, BuiltinTypes[IDLBuiltinType.Types.object], - affectsNothing=True, isIteratorAlias=self.isSetlike()) + self.addMethod( + "values", + members, + False, + BuiltinTypes[IDLBuiltinType.Types.object], + affectsNothing=True, + isIteratorAlias=self.isSetlike(), + ) # undefined forEach(callback(valueType, keyType), thisVal) - self.addMethod("forEach", members, False, BuiltinTypes[IDLBuiltinType.Types.undefined], - self.getForEachArguments()) + self.addMethod( + "forEach", + members, + False, + BuiltinTypes[IDLBuiltinType.Types.undefined], + self.getForEachArguments(), + ) def getKeyArg(): - return IDLArgument(self.location, - IDLUnresolvedIdentifier(self.location, "key"), - self.keyType) + return IDLArgument( + self.location, + IDLUnresolvedIdentifier(self.location, "key"), + self.keyType, + ) # boolean has(keyType key) - self.addMethod("has", members, False, BuiltinTypes[IDLBuiltinType.Types.boolean], - [getKeyArg()], isPure=True) + self.addMethod( + "has", + members, + False, + BuiltinTypes[IDLBuiltinType.Types.boolean], + [getKeyArg()], + isPure=True, + ) if not self.readonly: # undefined clear() - self.addMethod("clear", members, True, BuiltinTypes[IDLBuiltinType.Types.undefined], - []) + self.addMethod( + "clear", members, True, BuiltinTypes[IDLBuiltinType.Types.undefined], [] + ) # boolean delete(keyType key) - self.addMethod("delete", members, True, - BuiltinTypes[IDLBuiltinType.Types.boolean], [getKeyArg()]) - - # Always generate underscored functions (e.g. __add, __clear) for js - # implemented interfaces as convenience functions. - if isJSImplemented: - # undefined clear() - self.addMethod("clear", members, True, BuiltinTypes[IDLBuiltinType.Types.undefined], - [], chromeOnly=True) - # boolean delete(keyType key) - self.addMethod("delete", members, True, - BuiltinTypes[IDLBuiltinType.Types.boolean], [getKeyArg()], - chromeOnly=True) + self.addMethod( + "delete", + members, + True, + BuiltinTypes[IDLBuiltinType.Types.boolean], + [getKeyArg()], + ) if self.isSetlike(): if not self.readonly: # Add returns the set object it just added to. # object add(keyType key) - self.addMethod("add", members, True, - BuiltinTypes[IDLBuiltinType.Types.object], [getKeyArg()]) - if isJSImplemented: - self.addMethod("add", members, True, - BuiltinTypes[IDLBuiltinType.Types.object], [getKeyArg()], - chromeOnly=True) + self.addMethod( + "add", + members, + True, + BuiltinTypes[IDLBuiltinType.Types.object], + [getKeyArg()], + ) return # If we get this far, we're a maplike declaration. @@ -4311,39 +5048,52 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): # # TODO: Bug 1155340 may change this to use specific type to provide # more info to JIT. - self.addMethod("get", members, False, BuiltinTypes[IDLBuiltinType.Types.any], - [getKeyArg()], isPure=True) + self.addMethod( + "get", + members, + False, + BuiltinTypes[IDLBuiltinType.Types.any], + [getKeyArg()], + isPure=True, + ) def getValueArg(): - return IDLArgument(self.location, - IDLUnresolvedIdentifier(self.location, "value"), - self.valueType) + return IDLArgument( + self.location, + IDLUnresolvedIdentifier(self.location, "value"), + self.valueType, + ) if not self.readonly: - self.addMethod("set", members, True, BuiltinTypes[IDLBuiltinType.Types.object], - [getKeyArg(), getValueArg()]) - if isJSImplemented: - self.addMethod("set", members, True, BuiltinTypes[IDLBuiltinType.Types.object], - [getKeyArg(), getValueArg()], chromeOnly=True) + self.addMethod( + "set", + members, + True, + BuiltinTypes[IDLBuiltinType.Types.object], + [getKeyArg(), getValueArg()], + ) + class IDLConst(IDLInterfaceMember): def __init__(self, location, identifier, type, value): - IDLInterfaceMember.__init__(self, location, identifier, - IDLInterfaceMember.Tags.Const) + IDLInterfaceMember.__init__( + self, location, identifier, IDLInterfaceMember.Tags.Const + ) assert isinstance(type, IDLType) if type.isDictionary(): - raise WebIDLError("A constant cannot be of a dictionary type", - [self.location]) + raise WebIDLError( + "A constant cannot be of a dictionary type", [self.location] + ) if type.isRecord(): - raise WebIDLError("A constant cannot be of a record type", - [self.location]) + raise WebIDLError("A constant cannot be of a record type", [self.location]) self.type = type self.value = value if identifier.name == "prototype": - raise WebIDLError("The identifier of a constant must not be 'prototype'", - [location]) + raise WebIDLError( + "The identifier of a constant must not be 'prototype'", [location] + ) def __str__(self): return "'%s' const '%s'" % (self.type, self.identifier) @@ -4375,17 +5125,21 @@ class IDLConst(IDLInterfaceMember): identifier = attr.identifier() if identifier == "Exposed": convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) - elif (identifier == "Pref" or - identifier == "ChromeOnly" or - identifier == "Func" or - identifier == "SecureContext" or - identifier == "NonEnumerable" or - identifier == "NeedsWindowsUndef"): + elif ( + identifier == "Pref" + or identifier == "ChromeOnly" + or identifier == "Func" + or identifier == "Trial" + or identifier == "SecureContext" + or identifier == "NonEnumerable" + ): # Known attributes that we don't need to do anything with here pass else: - raise WebIDLError("Unknown extended attribute %s on constant" % identifier, - [attr.location]) + raise WebIDLError( + "Unknown extended attribute %s on constant" % identifier, + [attr.location], + ) IDLInterfaceMember.handleExtendedAttribute(self, attr) def _getDependentObjects(self): @@ -4393,35 +5147,53 @@ class IDLConst(IDLInterfaceMember): class IDLAttribute(IDLInterfaceMember): - def __init__(self, location, identifier, type, readonly, inherit=False, - static=False, stringifier=False, maplikeOrSetlike=None, - extendedAttrDict=None): - IDLInterfaceMember.__init__(self, location, identifier, - IDLInterfaceMember.Tags.Attr, - extendedAttrDict=extendedAttrDict) + def __init__( + self, + location, + identifier, + type, + readonly, + inherit=False, + static=False, + stringifier=False, + maplikeOrSetlike=None, + extendedAttrDict=None, + ): + IDLInterfaceMember.__init__( + self, + location, + identifier, + IDLInterfaceMember.Tags.Attr, + extendedAttrDict=extendedAttrDict, + ) assert isinstance(type, IDLType) self.type = type self.readonly = readonly self.inherit = inherit self._static = static - self.lenientThis = False - self._unforgeable = False + self.legacyLenientThis = False + self._legacyUnforgeable = False self.stringifier = stringifier self.slotIndices = None - assert maplikeOrSetlike is None or isinstance(maplikeOrSetlike, IDLMaplikeOrSetlike) + assert maplikeOrSetlike is None or isinstance( + maplikeOrSetlike, IDLMaplikeOrSetlike + ) self.maplikeOrSetlike = maplikeOrSetlike self.dependsOn = "Everything" self.affects = "Everything" self.bindingAliases = [] if static and identifier.name == "prototype": - raise WebIDLError("The identifier of a static attribute must not be 'prototype'", - [location]) + raise WebIDLError( + "The identifier of a static attribute must not be 'prototype'", + [location], + ) if readonly and inherit: - raise WebIDLError("An attribute cannot be both 'readonly' and 'inherit'", - [self.location]) + raise WebIDLError( + "An attribute cannot be both 'readonly' and 'inherit'", [self.location] + ) def isStatic(self): return self._static @@ -4443,69 +5215,111 @@ class IDLAttribute(IDLInterfaceMember): assert not isinstance(t.name, IDLUnresolvedIdentifier) self.type = t - if self.readonly and (self.type.hasClamp() or self.type.hasEnforceRange() or - self.type.hasAllowShared() or self.type.treatNullAsEmpty): - raise WebIDLError("A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]", - [self.location]) + if self.readonly and ( + self.type.hasClamp() + or self.type.hasEnforceRange() + or self.type.hasAllowShared() + or self.type.legacyNullToEmptyString + ): + raise WebIDLError( + "A readonly attribute cannot be [Clamp] or [EnforceRange] or [AllowShared]", + [self.location], + ) if self.type.isDictionary() and not self.getExtendedAttribute("Cached"): - raise WebIDLError("An attribute cannot be of a dictionary type", - [self.location]) + raise WebIDLError( + "An attribute cannot be of a dictionary type", [self.location] + ) if self.type.isSequence() and not self.getExtendedAttribute("Cached"): - raise WebIDLError("A non-cached attribute cannot be of a sequence " - "type", [self.location]) + raise WebIDLError( + "A non-cached attribute cannot be of a sequence " "type", + [self.location], + ) if self.type.isRecord() and not self.getExtendedAttribute("Cached"): - raise WebIDLError("A non-cached attribute cannot be of a record " - "type", [self.location]) + raise WebIDLError( + "A non-cached attribute cannot be of a record " "type", [self.location] + ) if self.type.isUnion(): for f in self.type.unroll().flatMemberTypes: if f.isDictionary(): - raise WebIDLError("An attribute cannot be of a union " - "type if one of its member types (or " - "one of its member types's member " - "types, and so on) is a dictionary " - "type", [self.location, f.location]) + raise WebIDLError( + "An attribute cannot be of a union " + "type if one of its member types (or " + "one of its member types's member " + "types, and so on) is a dictionary " + "type", + [self.location, f.location], + ) if f.isSequence(): - raise WebIDLError("An attribute cannot be of a union " - "type if one of its member types (or " - "one of its member types's member " - "types, and so on) is a sequence " - "type", [self.location, f.location]) + raise WebIDLError( + "An attribute cannot be of a union " + "type if one of its member types (or " + "one of its member types's member " + "types, and so on) is a sequence " + "type", + [self.location, f.location], + ) if f.isRecord(): - raise WebIDLError("An attribute cannot be of a union " - "type if one of its member types (or " - "one of its member types's member " - "types, and so on) is a record " - "type", [self.location, f.location]) + raise WebIDLError( + "An attribute cannot be of a union " + "type if one of its member types (or " + "one of its member types's member " + "types, and so on) is a record " + "type", + [self.location, f.location], + ) if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"): - raise WebIDLError("An attribute with [PutForwards] must have an " - "interface type as its type", [self.location]) + raise WebIDLError( + "An attribute with [PutForwards] must have an " + "interface type as its type", + [self.location], + ) - if (not self.type.isInterface() and - self.getExtendedAttribute("SameObject")): - raise WebIDLError("An attribute with [SameObject] must have an " - "interface type as its type", [self.location]) + if not self.type.isInterface() and self.getExtendedAttribute("SameObject"): + raise WebIDLError( + "An attribute with [SameObject] must have an " + "interface type as its type", + [self.location], + ) if self.type.isPromise() and not self.readonly: - raise WebIDLError("Promise-returning attributes must be readonly", - [self.location]) + raise WebIDLError( + "Promise-returning attributes must be readonly", [self.location] + ) + + if self.type.isObservableArray(): + if self.isStatic(): + raise WebIDLError( + "A static attribute cannot have an ObservableArray type", + [self.location], + ) + if self.getExtendedAttribute("Cached") or self.getExtendedAttribute( + "StoreInSlot" + ): + raise WebIDLError( + "[Cached] and [StoreInSlot] must not be used " + "on an attribute whose type is ObservableArray", + [self.location], + ) def validate(self): def typeContainsChromeOnlyDictionaryMember(type): - if (type.nullable() or - type.isSequence() or - type.isRecord()): + if type.nullable() or type.isSequence() or type.isRecord(): return typeContainsChromeOnlyDictionaryMember(type.inner) if type.isUnion(): for memberType in type.flatMemberTypes: - (contains, location) = typeContainsChromeOnlyDictionaryMember(memberType) + (contains, location) = typeContainsChromeOnlyDictionaryMember( + memberType + ) if contains: return (True, location) if type.isDictionary(): dictionary = type.inner while dictionary: - (contains, location) = dictionaryContainsChromeOnlyMember(dictionary) + (contains, location) = dictionaryContainsChromeOnlyMember( + dictionary + ) if contains: return (True, location) dictionary = dictionary.parent @@ -4516,254 +5330,345 @@ class IDLAttribute(IDLInterfaceMember): for member in dictionary.members: if member.getExtendedAttribute("ChromeOnly"): return (True, member.location) - (contains, location) = typeContainsChromeOnlyDictionaryMember(member.type) + (contains, location) = typeContainsChromeOnlyDictionaryMember( + member.type + ) if contains: return (True, location) return (False, None) IDLInterfaceMember.validate(self) - if (self.getExtendedAttribute("Cached") or - self.getExtendedAttribute("StoreInSlot")): + if self.getExtendedAttribute("Cached") or self.getExtendedAttribute( + "StoreInSlot" + ): if not self.affects == "Nothing": - raise WebIDLError("Cached attributes and attributes stored in " - "slots must be Constant or Pure or " - "Affects=Nothing, since the getter won't always " - "be called.", - [self.location]) + raise WebIDLError( + "Cached attributes and attributes stored in " + "slots must be Constant or Pure or " + "Affects=Nothing, since the getter won't always " + "be called.", + [self.location], + ) (contains, location) = typeContainsChromeOnlyDictionaryMember(self.type) if contains: - raise WebIDLError("[Cached] and [StoreInSlot] must not be used " - "on an attribute whose type contains a " - "[ChromeOnly] dictionary member", - [self.location, location]) + raise WebIDLError( + "[Cached] and [StoreInSlot] must not be used " + "on an attribute whose type contains a " + "[ChromeOnly] dictionary member", + [self.location, location], + ) if self.getExtendedAttribute("Frozen"): - if (not self.type.isSequence() and not self.type.isDictionary() and - not self.type.isRecord()): - raise WebIDLError("[Frozen] is only allowed on " - "sequence-valued, dictionary-valued, and " - "record-valued attributes", - [self.location]) + if ( + not self.type.isSequence() + and not self.type.isDictionary() + and not self.type.isRecord() + ): + raise WebIDLError( + "[Frozen] is only allowed on " + "sequence-valued, dictionary-valued, and " + "record-valued attributes", + [self.location], + ) if not self.type.unroll().isExposedInAllOf(self.exposureSet): - raise WebIDLError("Attribute returns a type that is not exposed " - "everywhere where the attribute is exposed", - [self.location]) + raise WebIDLError( + "Attribute returns a type that is not exposed " + "everywhere where the attribute is exposed", + [self.location], + ) if self.getExtendedAttribute("CEReactions"): if self.readonly: - raise WebIDLError("[CEReactions] is not allowed on " - "readonly attributes", - [self.location]) + raise WebIDLError( + "[CEReactions] is not allowed on " "readonly attributes", + [self.location], + ) def handleExtendedAttribute(self, attr): identifier = attr.identifier() - if ((identifier == "SetterThrows" or identifier == "SetterCanOOM" or - identifier == "SetterNeedsSubjectPrincipal") - and self.readonly): - raise WebIDLError("Readonly attributes must not be flagged as " - "[%s]" % identifier, - [self.location]) + if ( + identifier == "SetterThrows" + or identifier == "SetterCanOOM" + or identifier == "SetterNeedsSubjectPrincipal" + ) and self.readonly: + raise WebIDLError( + "Readonly attributes must not be flagged as " "[%s]" % identifier, + [self.location], + ) elif identifier == "BindingAlias": if not attr.hasValue(): - raise WebIDLError("[BindingAlias] takes an identifier or string", - [attr.location]) + raise WebIDLError( + "[BindingAlias] takes an identifier or string", [attr.location] + ) self._addBindingAlias(attr.value()) - elif (((identifier == "Throws" or identifier == "GetterThrows" or - identifier == "CanOOM" or identifier == "GetterCanOOM") and - self.getExtendedAttribute("StoreInSlot")) or - (identifier == "StoreInSlot" and - (self.getExtendedAttribute("Throws") or - self.getExtendedAttribute("GetterThrows") or - self.getExtendedAttribute("CanOOM") or - self.getExtendedAttribute("GetterCanOOM")))): - raise WebIDLError("Throwing things can't be [StoreInSlot]", - [attr.location]) - elif identifier == "LenientThis": + elif ( + ( + identifier == "Throws" + or identifier == "GetterThrows" + or identifier == "CanOOM" + or identifier == "GetterCanOOM" + ) + and self.getExtendedAttribute("StoreInSlot") + ) or ( + identifier == "StoreInSlot" + and ( + self.getExtendedAttribute("Throws") + or self.getExtendedAttribute("GetterThrows") + or self.getExtendedAttribute("CanOOM") + or self.getExtendedAttribute("GetterCanOOM") + ) + ): + raise WebIDLError("Throwing things can't be [StoreInSlot]", [attr.location]) + elif identifier == "LegacyLenientThis": if not attr.noArguments(): - raise WebIDLError("[LenientThis] must take no arguments", - [attr.location]) + raise WebIDLError( + "[LegacyLenientThis] must take no arguments", [attr.location] + ) if self.isStatic(): - raise WebIDLError("[LenientThis] is only allowed on non-static " - "attributes", [attr.location, self.location]) + raise WebIDLError( + "[LegacyLenientThis] is only allowed on non-static " "attributes", + [attr.location, self.location], + ) if self.getExtendedAttribute("CrossOriginReadable"): - raise WebIDLError("[LenientThis] is not allowed in combination " - "with [CrossOriginReadable]", - [attr.location, self.location]) + raise WebIDLError( + "[LegacyLenientThis] is not allowed in combination " + "with [CrossOriginReadable]", + [attr.location, self.location], + ) if self.getExtendedAttribute("CrossOriginWritable"): - raise WebIDLError("[LenientThis] is not allowed in combination " - "with [CrossOriginWritable]", - [attr.location, self.location]) - self.lenientThis = True - elif identifier == "Unforgeable": + raise WebIDLError( + "[LegacyLenientThis] is not allowed in combination " + "with [CrossOriginWritable]", + [attr.location, self.location], + ) + self.legacyLenientThis = True + elif identifier == "LegacyUnforgeable": if self.isStatic(): - raise WebIDLError("[Unforgeable] is only allowed on non-static " - "attributes", [attr.location, self.location]) - self._unforgeable = True + raise WebIDLError( + "[LegacyUnforgeable] is only allowed on non-static " "attributes", + [attr.location, self.location], + ) + self._legacyUnforgeable = True elif identifier == "SameObject" and not self.readonly: - raise WebIDLError("[SameObject] only allowed on readonly attributes", - [attr.location, self.location]) + raise WebIDLError( + "[SameObject] only allowed on readonly attributes", + [attr.location, self.location], + ) elif identifier == "Constant" and not self.readonly: - raise WebIDLError("[Constant] only allowed on readonly attributes", - [attr.location, self.location]) + raise WebIDLError( + "[Constant] only allowed on readonly attributes", + [attr.location, self.location], + ) elif identifier == "PutForwards": if not self.readonly: - raise WebIDLError("[PutForwards] is only allowed on readonly " - "attributes", [attr.location, self.location]) + raise WebIDLError( + "[PutForwards] is only allowed on readonly " "attributes", + [attr.location, self.location], + ) if self.type.isPromise(): - raise WebIDLError("[PutForwards] is not allowed on " - "Promise-typed attributes", - [attr.location, self.location]) + raise WebIDLError( + "[PutForwards] is not allowed on " "Promise-typed attributes", + [attr.location, self.location], + ) if self.isStatic(): - raise WebIDLError("[PutForwards] is only allowed on non-static " - "attributes", [attr.location, self.location]) + raise WebIDLError( + "[PutForwards] is only allowed on non-static " "attributes", + [attr.location, self.location], + ) if self.getExtendedAttribute("Replaceable") is not None: - raise WebIDLError("[PutForwards] and [Replaceable] can't both " - "appear on the same attribute", - [attr.location, self.location]) + raise WebIDLError( + "[PutForwards] and [Replaceable] can't both " + "appear on the same attribute", + [attr.location, self.location], + ) if not attr.hasValue(): - raise WebIDLError("[PutForwards] takes an identifier", - [attr.location, self.location]) + raise WebIDLError( + "[PutForwards] takes an identifier", [attr.location, self.location] + ) elif identifier == "Replaceable": if not attr.noArguments(): - raise WebIDLError("[Replaceable] must take no arguments", - [attr.location]) + raise WebIDLError( + "[Replaceable] must take no arguments", [attr.location] + ) if not self.readonly: - raise WebIDLError("[Replaceable] is only allowed on readonly " - "attributes", [attr.location, self.location]) + raise WebIDLError( + "[Replaceable] is only allowed on readonly " "attributes", + [attr.location, self.location], + ) if self.type.isPromise(): - raise WebIDLError("[Replaceable] is not allowed on " - "Promise-typed attributes", - [attr.location, self.location]) + raise WebIDLError( + "[Replaceable] is not allowed on " "Promise-typed attributes", + [attr.location, self.location], + ) if self.isStatic(): - raise WebIDLError("[Replaceable] is only allowed on non-static " - "attributes", [attr.location, self.location]) + raise WebIDLError( + "[Replaceable] is only allowed on non-static " "attributes", + [attr.location, self.location], + ) if self.getExtendedAttribute("PutForwards") is not None: - raise WebIDLError("[PutForwards] and [Replaceable] can't both " - "appear on the same attribute", - [attr.location, self.location]) - elif identifier == "LenientSetter": + raise WebIDLError( + "[PutForwards] and [Replaceable] can't both " + "appear on the same attribute", + [attr.location, self.location], + ) + elif identifier == "LegacyLenientSetter": if not attr.noArguments(): - raise WebIDLError("[LenientSetter] must take no arguments", - [attr.location]) + raise WebIDLError( + "[LegacyLenientSetter] must take no arguments", [attr.location] + ) if not self.readonly: - raise WebIDLError("[LenientSetter] is only allowed on readonly " - "attributes", [attr.location, self.location]) + raise WebIDLError( + "[LegacyLenientSetter] is only allowed on readonly " "attributes", + [attr.location, self.location], + ) if self.type.isPromise(): - raise WebIDLError("[LenientSetter] is not allowed on " - "Promise-typed attributes", - [attr.location, self.location]) + raise WebIDLError( + "[LegacyLenientSetter] is not allowed on " + "Promise-typed attributes", + [attr.location, self.location], + ) if self.isStatic(): - raise WebIDLError("[LenientSetter] is only allowed on non-static " - "attributes", [attr.location, self.location]) + raise WebIDLError( + "[LegacyLenientSetter] is only allowed on non-static " "attributes", + [attr.location, self.location], + ) if self.getExtendedAttribute("PutForwards") is not None: - raise WebIDLError("[LenientSetter] and [PutForwards] can't both " - "appear on the same attribute", - [attr.location, self.location]) + raise WebIDLError( + "[LegacyLenientSetter] and [PutForwards] can't both " + "appear on the same attribute", + [attr.location, self.location], + ) if self.getExtendedAttribute("Replaceable") is not None: - raise WebIDLError("[LenientSetter] and [Replaceable] can't both " - "appear on the same attribute", - [attr.location, self.location]) + raise WebIDLError( + "[LegacyLenientSetter] and [Replaceable] can't both " + "appear on the same attribute", + [attr.location, self.location], + ) elif identifier == "LenientFloat": if self.readonly: - raise WebIDLError("[LenientFloat] used on a readonly attribute", - [attr.location, self.location]) + raise WebIDLError( + "[LenientFloat] used on a readonly attribute", + [attr.location, self.location], + ) if not self.type.includesRestrictedFloat(): - raise WebIDLError("[LenientFloat] used on an attribute with a " - "non-restricted-float type", - [attr.location, self.location]) + raise WebIDLError( + "[LenientFloat] used on an attribute with a " + "non-restricted-float type", + [attr.location, self.location], + ) elif identifier == "StoreInSlot": if self.getExtendedAttribute("Cached"): - raise WebIDLError("[StoreInSlot] and [Cached] must not be " - "specified on the same attribute", - [attr.location, self.location]) + raise WebIDLError( + "[StoreInSlot] and [Cached] must not be " + "specified on the same attribute", + [attr.location, self.location], + ) elif identifier == "Cached": if self.getExtendedAttribute("StoreInSlot"): - raise WebIDLError("[Cached] and [StoreInSlot] must not be " - "specified on the same attribute", - [attr.location, self.location]) - elif (identifier == "CrossOriginReadable" or - identifier == "CrossOriginWritable"): + raise WebIDLError( + "[Cached] and [StoreInSlot] must not be " + "specified on the same attribute", + [attr.location, self.location], + ) + elif identifier == "CrossOriginReadable" or identifier == "CrossOriginWritable": if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must take no arguments" % identifier, [attr.location] + ) if self.isStatic(): - raise WebIDLError("[%s] is only allowed on non-static " - "attributes" % identifier, - [attr.location, self.location]) - if self.getExtendedAttribute("LenientThis"): - raise WebIDLError("[LenientThis] is not allowed in combination " - "with [%s]" % identifier, - [attr.location, self.location]) + raise WebIDLError( + "[%s] is only allowed on non-static " "attributes" % identifier, + [attr.location, self.location], + ) + if self.getExtendedAttribute("LegacyLenientThis"): + raise WebIDLError( + "[LegacyLenientThis] is not allowed in combination " + "with [%s]" % identifier, + [attr.location, self.location], + ) elif identifier == "Exposed": convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) elif identifier == "Pure": if not attr.noArguments(): - raise WebIDLError("[Pure] must take no arguments", - [attr.location]) + raise WebIDLError("[Pure] must take no arguments", [attr.location]) self._setDependsOn("DOMState") self._setAffects("Nothing") elif identifier == "Constant" or identifier == "SameObject": if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must take no arguments" % identifier, [attr.location] + ) self._setDependsOn("Nothing") self._setAffects("Nothing") elif identifier == "Affects": if not attr.hasValue(): - raise WebIDLError("[Affects] takes an identifier", - [attr.location]) + raise WebIDLError("[Affects] takes an identifier", [attr.location]) self._setAffects(attr.value()) elif identifier == "DependsOn": if not attr.hasValue(): - raise WebIDLError("[DependsOn] takes an identifier", - [attr.location]) - if (attr.value() != "Everything" and attr.value() != "DOMState" and - not self.readonly): - raise WebIDLError("[DependsOn=%s] only allowed on " - "readonly attributes" % attr.value(), - [attr.location, self.location]) + raise WebIDLError("[DependsOn] takes an identifier", [attr.location]) + if ( + attr.value() != "Everything" + and attr.value() != "DOMState" + and not self.readonly + ): + raise WebIDLError( + "[DependsOn=%s] only allowed on " + "readonly attributes" % attr.value(), + [attr.location, self.location], + ) self._setDependsOn(attr.value()) elif identifier == "UseCounter": if self.stringifier: - raise WebIDLError("[UseCounter] must not be used on a " - "stringifier attribute", - [attr.location, self.location]) + raise WebIDLError( + "[UseCounter] must not be used on a " "stringifier attribute", + [attr.location, self.location], + ) elif identifier == "Unscopable": if not attr.noArguments(): - raise WebIDLError("[Unscopable] must take no arguments", - [attr.location]) + raise WebIDLError( + "[Unscopable] must take no arguments", [attr.location] + ) if self.isStatic(): - raise WebIDLError("[Unscopable] is only allowed on non-static " - "attributes and operations", - [attr.location, self.location]) + raise WebIDLError( + "[Unscopable] is only allowed on non-static " + "attributes and operations", + [attr.location, self.location], + ) elif identifier == "CEReactions": if not attr.noArguments(): - raise WebIDLError("[CEReactions] must take no arguments", - [attr.location]) - elif (identifier == "Pref" or - identifier == "Deprecated" or - identifier == "SetterThrows" or - identifier == "Throws" or - identifier == "GetterThrows" or - identifier == "SetterCanOOM" or - identifier == "CanOOM" or - identifier == "GetterCanOOM" or - identifier == "ChromeOnly" or - identifier == "Func" or - identifier == "SecureContext" or - identifier == "Frozen" or - identifier == "NewObject" or - identifier == "NeedsSubjectPrincipal" or - identifier == "SetterNeedsSubjectPrincipal" or - identifier == "GetterNeedsSubjectPrincipal" or - identifier == "NeedsCallerType" or - identifier == "ReturnValueNeedsContainsHack" or - identifier == "BinaryName" or - identifier == "NonEnumerable"): + raise WebIDLError( + "[CEReactions] must take no arguments", [attr.location] + ) + elif ( + identifier == "Pref" + or identifier == "Deprecated" + or identifier == "SetterThrows" + or identifier == "Throws" + or identifier == "GetterThrows" + or identifier == "SetterCanOOM" + or identifier == "CanOOM" + or identifier == "GetterCanOOM" + or identifier == "ChromeOnly" + or identifier == "Func" + or identifier == "Trial" + or identifier == "SecureContext" + or identifier == "Frozen" + or identifier == "NewObject" + or identifier == "NeedsSubjectPrincipal" + or identifier == "SetterNeedsSubjectPrincipal" + or identifier == "GetterNeedsSubjectPrincipal" + or identifier == "NeedsCallerType" + or identifier == "ReturnValueNeedsContainsHack" + or identifier == "BinaryName" + or identifier == "NonEnumerable" + ): # Known attributes that we don't need to do anything with here pass else: - raise WebIDLError("Unknown extended attribute %s on attribute" % identifier, - [attr.location]) + raise WebIDLError( + "Unknown extended attribute %s on attribute" % identifier, + [attr.location], + ) IDLInterfaceMember.handleExtendedAttribute(self, attr) def resolve(self, parentScope): @@ -4771,8 +5676,8 @@ class IDLAttribute(IDLInterfaceMember): self.type.resolveType(parentScope) IDLObjectWithIdentifier.resolve(self, parentScope) - def hasLenientThis(self): - return self.lenientThis + def hasLegacyLenientThis(self): + return self.legacyLenientThis def isMaplikeOrSetlikeAttr(self): """ @@ -4782,24 +5687,35 @@ class IDLAttribute(IDLInterfaceMember): """ return self.maplikeOrSetlike is not None - def isUnforgeable(self): - return self._unforgeable + def isLegacyUnforgeable(self): + return self._legacyUnforgeable def _getDependentObjects(self): return set([self.type]) def expand(self, members): assert self.stringifier - if not self.type.isDOMString() and not self.type.isUSVString(): - raise WebIDLError("The type of a stringifer attribute must be " - "either DOMString or USVString", - [self.location]) - identifier = IDLUnresolvedIdentifier(self.location, "__stringifier", - allowDoubleUnderscore=True) - method = IDLMethod(self.location, - identifier, - returnType=self.type, arguments=[], - stringifier=True, underlyingAttr=self) + if ( + not self.type.isDOMString() + and not self.type.isUSVString() + and not self.type.isUTF8String() + ): + raise WebIDLError( + "The type of a stringifer attribute must be " + "either DOMString, USVString or UTF8String", + [self.location], + ) + identifier = IDLUnresolvedIdentifier( + self.location, "__stringifier", allowDoubleUnderscore=True + ) + method = IDLMethod( + self.location, + identifier, + returnType=self.type, + arguments=[], + stringifier=True, + underlyingAttr=self, + ) allowedExtAttrs = ["Throws", "NeedsSubjectPrincipal", "Pure"] # Safe to ignore these as they are only meaningful for attributes attributeOnlyExtAttrs = [ @@ -4807,24 +5723,40 @@ class IDLAttribute(IDLInterfaceMember): "CrossOriginWritable", "SetterThrows", ] - for (key, value) in list(self._extendedAttrDict.items()): + for (key, value) in self._extendedAttrDict.items(): if key in allowedExtAttrs: if value is not True: - raise WebIDLError("[%s] with a value is currently " - "unsupported in stringifier attributes, " - "please file a bug to add support" % key, - [self.location]) - method.addExtendedAttributes([IDLExtendedAttribute(self.location, (key,))]) + raise WebIDLError( + "[%s] with a value is currently " + "unsupported in stringifier attributes, " + "please file a bug to add support" % key, + [self.location], + ) + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, (key,))] + ) elif not key in attributeOnlyExtAttrs: - raise WebIDLError("[%s] is currently unsupported in " - "stringifier attributes, please file a bug " - "to add support" % key, - [self.location]) + raise WebIDLError( + "[%s] is currently unsupported in " + "stringifier attributes, please file a bug " + "to add support" % key, + [self.location], + ) members.append(method) class IDLArgument(IDLObjectWithIdentifier): - def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False, allowTypeAttributes=False): + def __init__( + self, + location, + identifier, + type, + optional=False, + defaultValue=None, + variadic=False, + dictionaryMember=False, + allowTypeAttributes=False, + ): IDLObjectWithIdentifier.__init__(self, location, None, identifier) assert isinstance(type, IDLType) @@ -4845,24 +5777,37 @@ class IDLArgument(IDLObjectWithIdentifier): def addExtendedAttributes(self, attrs): for attribute in attrs: identifier = attribute.identifier() - if self.allowTypeAttributes and (identifier == "EnforceRange" or identifier == "Clamp" or - identifier == "TreatNullAs" or identifier == "AllowShared"): + if self.allowTypeAttributes and ( + identifier == "EnforceRange" + or identifier == "Clamp" + or identifier == "LegacyNullToEmptyString" + or identifier == "AllowShared" + ): self.type = self.type.withExtendedAttributes([attribute]) elif identifier == "TreatNonCallableAsNull": self._allowTreatNonCallableAsNull = True - elif (self.dictionaryMember and - (identifier == "ChromeOnly" or - identifier == "Func" or - identifier == "Pref")): + elif self.dictionaryMember and ( + identifier == "ChromeOnly" + or identifier == "Func" + or identifier == "Trial" + or identifier == "Pref" + ): if not self.optional: - raise WebIDLError("[%s] must not be used on a required " - "dictionary member" % identifier, - [attribute.location]) + raise WebIDLError( + "[%s] must not be used on a required " + "dictionary member" % identifier, + [attribute.location], + ) else: - raise WebIDLError("Unhandled extended attribute on %s" % - ("a dictionary member" if self.dictionaryMember else - "an argument"), - [attribute.location]) + raise WebIDLError( + "Unhandled extended attribute on %s" + % ( + "a dictionary member" + if self.dictionaryMember + else "an argument" + ), + [attribute.location], + ) attrlist = attribute.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True @@ -4885,22 +5830,37 @@ class IDLArgument(IDLObjectWithIdentifier): assert not isinstance(type.name, IDLUnresolvedIdentifier) self.type = type + if self.type.isUndefined(): + raise WebIDLError( + "undefined must not be used as the type of an argument in any circumstance", + [self.location], + ) + if self.type.isAny(): - assert (self.defaultValue is None or - isinstance(self.defaultValue, IDLNullValue)) + assert self.defaultValue is None or isinstance( + self.defaultValue, IDLNullValue + ) # optional 'any' values always have a default value if self.optional and not self.defaultValue and not self.variadic: # Set the default value to undefined, for simplicity, so the # codegen doesn't have to special-case this. self.defaultValue = IDLUndefinedValue(self.location) - if self.dictionaryMember and self.type.treatNullAsEmpty: - raise WebIDLError("Dictionary members cannot be [TreatNullAs]", [self.location]) + if self.dictionaryMember and self.type.legacyNullToEmptyString: + raise WebIDLError( + "Dictionary members cannot be [LegacyNullToEmptyString]", + [self.location], + ) + if self.type.isObservableArray(): + raise WebIDLError( + "%s cannot have an ObservableArray type" + % ("Dictionary members" if self.dictionaryMember else "Arguments"), + [self.location], + ) # Now do the coercing thing; this needs to happen after the # above creation of a default value. if self.defaultValue: - self.defaultValue = self.defaultValue.coerceToType(self.type, - self.location) + self.defaultValue = self.defaultValue.coerceToType(self.type, self.location) assert self.defaultValue def allowTreatNonCallableAsNull(self): @@ -4917,7 +5877,9 @@ class IDLArgument(IDLObjectWithIdentifier): class IDLCallback(IDLObjectWithScope): - def __init__(self, location, parentScope, identifier, returnType, arguments, isConstructor): + def __init__( + self, location, parentScope, identifier, returnType, arguments, isConstructor + ): assert isinstance(returnType, IDLType) self._returnType = returnType @@ -4965,29 +5927,42 @@ class IDLCallback(IDLObjectWithScope): argument.type = type def validate(self): - pass + for argument in self._arguments: + if argument.type.isUndefined(): + raise WebIDLError( + "undefined must not be used as the type of an argument in any circumstance", + [self.location], + ) def addExtendedAttributes(self, attrs): unhandledAttrs = [] for attr in attrs: if attr.identifier() == "TreatNonCallableAsNull": self._treatNonCallableAsNull = True - elif attr.identifier() == "TreatNonObjectAsNull": + elif attr.identifier() == "LegacyTreatNonObjectAsNull": if self._isConstructor: - raise WebIDLError("[TreatNonObjectAsNull] is not supported " - "on constructors", [self.location]) + raise WebIDLError( + "[LegacyTreatNonObjectAsNull] is not supported " + "on constructors", + [self.location], + ) self._treatNonObjectAsNull = True elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY": if self._isConstructor: - raise WebIDLError("[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not " - "permitted on constructors", - [self.location]) + raise WebIDLError( + "[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not " + "permitted on constructors", + [self.location], + ) self._isRunScriptBoundary = True else: unhandledAttrs.append(attr) if self._treatNonCallableAsNull and self._treatNonObjectAsNull: - raise WebIDLError("Cannot specify both [TreatNonCallableAsNull] " - "and [TreatNonObjectAsNull]", [self.location]) + raise WebIDLError( + "Cannot specify both [TreatNonCallableAsNull] " + "and [LegacyTreatNonObjectAsNull]", + [self.location], + ) if len(unhandledAttrs) != 0: IDLType.addExtendedAttributes(self, unhandledAttrs) @@ -4995,7 +5970,7 @@ class IDLCallback(IDLObjectWithScope): return set([self._returnType] + self._arguments) def isRunScriptBoundary(self): - return self._isRunScriptBoundary; + return self._isRunScriptBoundary class IDLCallbackType(IDLType): @@ -5015,8 +5990,14 @@ class IDLCallbackType(IDLType): if other.isUnion(): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isNonCallbackInterface() or other.isSequence()) + return ( + other.isUndefined() + or other.isPrimitive() + or other.isString() + or other.isEnum() + or other.isNonCallbackInterface() + or other.isSequence() + ) def _getDependentObjects(self): return self.callback._getDependentObjects() @@ -5031,6 +6012,7 @@ class IDLMethodOverload: IDLMethodOverload for each one, all hanging off an IDLMethod representing the full set of overloads. """ + def __init__(self, returnType, arguments, location): self.returnType = returnType # Clone the list of arguments, just in case @@ -5049,28 +6031,31 @@ class IDLMethodOverload: class IDLMethod(IDLInterfaceMember, IDLScope): Special = enum( - 'Getter', - 'Setter', - 'Deleter', - 'LegacyCaller', - base=IDLInterfaceMember.Special + "Getter", "Setter", "Deleter", "LegacyCaller", base=IDLInterfaceMember.Special ) - NamedOrIndexed = enum( - 'Neither', - 'Named', - 'Indexed' - ) - - def __init__(self, location, identifier, returnType, arguments, - static=False, getter=False, setter=False, - deleter=False, specialType=NamedOrIndexed.Neither, - legacycaller=False, stringifier=False, - maplikeOrSetlikeOrIterable=None, - underlyingAttr=None): + NamedOrIndexed = enum("Neither", "Named", "Indexed") + + def __init__( + self, + location, + identifier, + returnType, + arguments, + static=False, + getter=False, + setter=False, + deleter=False, + specialType=NamedOrIndexed.Neither, + legacycaller=False, + stringifier=False, + maplikeOrSetlikeOrIterable=None, + underlyingAttr=None, + ): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. - IDLInterfaceMember.__init__(self, location, identifier, - IDLInterfaceMember.Tags.Method) + IDLInterfaceMember.__init__( + self, location, identifier, IDLInterfaceMember.Tags.Method + ) self._hasOverloads = False @@ -5091,19 +6076,23 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._legacycaller = legacycaller assert isinstance(stringifier, bool) self._stringifier = stringifier - assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) + assert maplikeOrSetlikeOrIterable is None or isinstance( + maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase + ) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable self._htmlConstructor = False self.underlyingAttr = underlyingAttr self._specialType = specialType - self._unforgeable = False + self._legacyUnforgeable = False self.dependsOn = "Everything" self.affects = "Everything" self.aliases = [] if static and identifier.name == "prototype": - raise WebIDLError("The identifier of a static operation must not be 'prototype'", - [location]) + raise WebIDLError( + "The identifier of a static operation must not be 'prototype'", + [location], + ) self.assertSignatureConstraints() @@ -5116,8 +6105,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): overload = self._overloads[0] arguments = overload.arguments assert len(arguments) == 1 - assert (arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or - arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]) + assert ( + arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] + or arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] + ) assert not arguments[0].optional and not arguments[0].variadic assert not self._getter or not overload.returnType.isUndefined() @@ -5125,8 +6116,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert len(self._overloads) == 1 arguments = self._overloads[0].arguments assert len(arguments) == 2 - assert (arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or - arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]) + assert ( + arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] + or arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] + ) assert not arguments[0].optional and not arguments[0].variadic assert not arguments[1].optional and not arguments[1].variadic @@ -5135,7 +6128,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope): overload = self._overloads[0] assert len(overload.arguments) == 0 if not self.underlyingAttr: - assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] + assert ( + overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] + ) def isStatic(self): return self._static @@ -5153,13 +6148,17 @@ class IDLMethod(IDLInterfaceMember, IDLScope): return self._deleter def isNamed(self): - assert (self._specialType == IDLMethod.NamedOrIndexed.Named or - self._specialType == IDLMethod.NamedOrIndexed.Indexed) + assert ( + self._specialType == IDLMethod.NamedOrIndexed.Named + or self._specialType == IDLMethod.NamedOrIndexed.Indexed + ) return self._specialType == IDLMethod.NamedOrIndexed.Named def isIndexed(self): - assert (self._specialType == IDLMethod.NamedOrIndexed.Named or - self._specialType == IDLMethod.NamedOrIndexed.Indexed) + assert ( + self._specialType == IDLMethod.NamedOrIndexed.Named + or self._specialType == IDLMethod.NamedOrIndexed.Indexed + ) return self._specialType == IDLMethod.NamedOrIndexed.Indexed def isLegacycaller(self): @@ -5182,11 +6181,13 @@ class IDLMethod(IDLInterfaceMember, IDLScope): return self.maplikeOrSetlikeOrIterable is not None def isSpecial(self): - return (self.isGetter() or - self.isSetter() or - self.isDeleter() or - self.isLegacycaller() or - self.isStringifier()) + return ( + self.isGetter() + or self.isSetter() + or self.isDeleter() + or self.isLegacycaller() + or self.isStringifier() + ) def isHTMLConstructor(self): return self._htmlConstructor @@ -5202,8 +6203,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope): implemented interfaces, so while these functions use what is considered an non-identifier name, they actually DO have an identifier. """ - return (self.identifier.name[:2] == "__" and - not self.isMaplikeOrSetlikeOrIterableMethod()) + return ( + self.identifier.name[:2] == "__" + and not self.isMaplikeOrSetlikeOrIterableMethod() + ) def resolve(self, parentScope): assert isinstance(parentScope, IDLScope) @@ -5217,36 +6220,52 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert len(method._overloads) == 1 if self._extendedAttrDict != method._extendedAttrDict: - extendedAttrDiff = set(self._extendedAttrDict.keys()) ^ set(method._extendedAttrDict.keys()) + extendedAttrDiff = set(self._extendedAttrDict.keys()) ^ set( + method._extendedAttrDict.keys() + ) - if extendedAttrDiff == { "LenientFloat" }: + if extendedAttrDiff == {"LenientFloat"}: if "LenientFloat" not in self._extendedAttrDict: for overload in self._overloads: if overload.includesRestrictedFloatArgument(): - raise WebIDLError("Restricted float behavior differs on different " - "overloads of %s" % method.identifier, - [overload.location, method.location]) - self._extendedAttrDict["LenientFloat"] = method._extendedAttrDict["LenientFloat"] + raise WebIDLError( + "Restricted float behavior differs on different " + "overloads of %s" % method.identifier, + [overload.location, method.location], + ) + self._extendedAttrDict["LenientFloat"] = method._extendedAttrDict[ + "LenientFloat" + ] elif method._overloads[0].includesRestrictedFloatArgument(): - raise WebIDLError("Restricted float behavior differs on different " - "overloads of %s" % method.identifier, - [self.location, method.location]) + raise WebIDLError( + "Restricted float behavior differs on different " + "overloads of %s" % method.identifier, + [self.location, method.location], + ) else: - raise WebIDLError("Extended attributes differ on different " - "overloads of %s" % method.identifier, - [self.location, method.location]) + raise WebIDLError( + "Extended attributes differ on different " + "overloads of %s" % method.identifier, + [self.location, method.location], + ) self._overloads.extend(method._overloads) self._hasOverloads = True if self.isStatic() != method.isStatic(): - raise WebIDLError("Overloaded identifier %s appears with different values of the 'static' attribute" % method.identifier, - [method.location]) + raise WebIDLError( + "Overloaded identifier %s appears with different values of the 'static' attribute" + % method.identifier, + [method.location], + ) if self.isLegacycaller() != method.isLegacycaller(): - raise WebIDLError("Overloaded identifier %s appears with different values of the 'legacycaller' attribute" % method.identifier, - [method.location]) + raise WebIDLError( + "Overloaded identifier %s appears with different values of the 'legacycaller' attribute" + % method.identifier, + [method.location], + ) # Can't overload special things! assert not self.isGetter() @@ -5263,8 +6282,9 @@ class IDLMethod(IDLInterfaceMember, IDLScope): return self def signatures(self): - return [(overload.returnType, overload.arguments) for overload in - self._overloads] + return [ + (overload.returnType, overload.arguments) for overload in self._overloads + ] def finish(self, scope): IDLInterfaceMember.finish(self, scope) @@ -5286,8 +6306,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope): # Now compute various information that will be used by the # WebIDL overload resolution algorithm. self.maxArgCount = max(len(s[1]) for s in self.signatures()) - self.allowedArgCounts = [i for i in range(self.maxArgCount+1) - if len(self.signaturesForArgCount(i)) != 0] + self.allowedArgCounts = [ + i + for i in range(self.maxArgCount + 1) + if len(self.signaturesForArgCount(i)) != 0 + ] def validate(self): IDLInterfaceMember.validate(self) @@ -5306,19 +6329,26 @@ class IDLMethod(IDLInterfaceMember, IDLScope): raise WebIDLError( "Signatures for method '%s' with %d arguments have " "different types of arguments at index %d, which " - "is before distinguishing index %d" % - (self.identifier.name, argCount, idx, - distinguishingIndex), - [self.location, overload.location]) + "is before distinguishing index %d" + % ( + self.identifier.name, + argCount, + idx, + distinguishingIndex, + ), + [self.location, overload.location], + ) overloadWithPromiseReturnType = None overloadWithoutPromiseReturnType = None for overload in self._overloads: returnType = overload.returnType if not returnType.unroll().isExposedInAllOf(self.exposureSet): - raise WebIDLError("Overload returns a type that is not exposed " - "everywhere where the method is exposed", - [overload.location]) + raise WebIDLError( + "Overload returns a type that is not exposed " + "everywhere where the method is exposed", + [overload.location], + ) variadicArgument = None @@ -5326,46 +6356,62 @@ class IDLMethod(IDLInterfaceMember, IDLScope): for (idx, argument) in enumerate(arguments): assert argument.type.isComplete() - if ((argument.type.isDictionary() and - argument.type.unroll().inner.canBeEmpty()) or - (argument.type.isUnion() and - argument.type.unroll().hasPossiblyEmptyDictionaryType())): + if ( + argument.type.isDictionary() + and argument.type.unroll().inner.canBeEmpty() + ) or ( + argument.type.isUnion() + and argument.type.unroll().hasPossiblyEmptyDictionaryType() + ): # Optional dictionaries and unions containing optional # dictionaries at the end of the list or followed by # optional arguments must be optional. - if (not argument.optional and - all(arg.optional for arg in arguments[idx+1:])): - raise WebIDLError("Dictionary argument without any " - "required fields or union argument " - "containing such dictionary not " - "followed by a required argument " - "must be optional", - [argument.location]) - - if (not argument.defaultValue and - all(arg.optional for arg in arguments[idx+1:])): - raise WebIDLError("Dictionary argument without any " - "required fields or union argument " - "containing such dictionary not " - "followed by a required argument " - "must have a default value", - [argument.location]) + if not argument.optional and all( + arg.optional for arg in arguments[idx + 1 :] + ): + raise WebIDLError( + "Dictionary argument without any " + "required fields or union argument " + "containing such dictionary not " + "followed by a required argument " + "must be optional", + [argument.location], + ) + + if not argument.defaultValue and all( + arg.optional for arg in arguments[idx + 1 :] + ): + raise WebIDLError( + "Dictionary argument without any " + "required fields or union argument " + "containing such dictionary not " + "followed by a required argument " + "must have a default value", + [argument.location], + ) # An argument cannot be a nullable dictionary or a # nullable union containing a dictionary. - if (argument.type.nullable() and - (argument.type.isDictionary() or - (argument.type.isUnion() and - argument.type.unroll().hasDictionaryType()))): - raise WebIDLError("An argument cannot be a nullable " - "dictionary or nullable union " - "containing a dictionary", - [argument.location]) + if argument.type.nullable() and ( + argument.type.isDictionary() + or ( + argument.type.isUnion() + and argument.type.unroll().hasDictionaryType() + ) + ): + raise WebIDLError( + "An argument cannot be a nullable " + "dictionary or nullable union " + "containing a dictionary", + [argument.location], + ) # Only the last argument can be variadic if variadicArgument: - raise WebIDLError("Variadic argument is not last argument", - [variadicArgument.location]) + raise WebIDLError( + "Variadic argument is not last argument", + [variadicArgument.location], + ) if argument.variadic: variadicArgument = argument @@ -5376,47 +6422,64 @@ class IDLMethod(IDLInterfaceMember, IDLScope): # Make sure either all our overloads return Promises or none do if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType: - raise WebIDLError("We have overloads with both Promise and " - "non-Promise return types", - [overloadWithPromiseReturnType.location, - overloadWithoutPromiseReturnType.location]) + raise WebIDLError( + "We have overloads with both Promise and " "non-Promise return types", + [ + overloadWithPromiseReturnType.location, + overloadWithoutPromiseReturnType.location, + ], + ) if overloadWithPromiseReturnType and self._legacycaller: - raise WebIDLError("May not have a Promise return type for a " - "legacycaller.", - [overloadWithPromiseReturnType.location]) + raise WebIDLError( + "May not have a Promise return type for a " "legacycaller.", + [overloadWithPromiseReturnType.location], + ) - if self.getExtendedAttribute("StaticClassOverride") and not \ - (self.identifier.scope.isJSImplemented() and self.isStatic()): - raise WebIDLError("StaticClassOverride can be applied to static" - " methods on JS-implemented classes only.", - [self.location]) + if self.getExtendedAttribute("StaticClassOverride") and not ( + self.identifier.scope.isJSImplemented() and self.isStatic() + ): + raise WebIDLError( + "StaticClassOverride can be applied to static" + " methods on JS-implemented classes only.", + [self.location], + ) # Ensure that toJSON methods satisfy the spec constraints on them. if self.identifier.name == "toJSON": if len(self.signatures()) != 1: - raise WebIDLError("toJSON method has multiple overloads", - [self._overloads[0].location, - self._overloads[1].location]) + raise WebIDLError( + "toJSON method has multiple overloads", + [self._overloads[0].location, self._overloads[1].location], + ) if len(self.signatures()[0][1]) != 0: - raise WebIDLError("toJSON method has arguments", - [self.location]) + raise WebIDLError("toJSON method has arguments", [self.location]) if not self.signatures()[0][0].isJSONType(): - raise WebIDLError("toJSON method has non-JSON return type", - [self.location]) + raise WebIDLError( + "toJSON method has non-JSON return type", [self.location] + ) def overloadsForArgCount(self, argc): - return [overload for overload in self._overloads if - len(overload.arguments) == argc or - (len(overload.arguments) > argc and - all(arg.optional for arg in overload.arguments[argc:])) or - (len(overload.arguments) < argc and - len(overload.arguments) > 0 and - overload.arguments[-1].variadic)] + return [ + overload + for overload in self._overloads + if len(overload.arguments) == argc + or ( + len(overload.arguments) > argc + and all(arg.optional for arg in overload.arguments[argc:]) + ) + or ( + len(overload.arguments) < argc + and len(overload.arguments) > 0 + and overload.arguments[-1].variadic + ) + ] def signaturesForArgCount(self, argc): - return [(overload.returnType, overload.arguments) for overload - in self.overloadsForArgCount(argc)] + return [ + (overload.returnType, overload.arguments) + for overload in self.overloadsForArgCount(argc) + ] def locationsForArgCount(self, argc): return [overload.location for overload in self.overloadsForArgCount(argc)] @@ -5424,163 +6487,199 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def distinguishingIndexForArgCount(self, argc): def isValidDistinguishingIndex(idx, signatures): for (firstSigIndex, (firstRetval, firstArgs)) in enumerate(signatures[:-1]): - for (secondRetval, secondArgs) in signatures[firstSigIndex+1:]: + for (secondRetval, secondArgs) in signatures[firstSigIndex + 1 :]: if idx < len(firstArgs): firstType = firstArgs[idx].type else: - assert(firstArgs[-1].variadic) + assert firstArgs[-1].variadic firstType = firstArgs[-1].type if idx < len(secondArgs): secondType = secondArgs[idx].type else: - assert(secondArgs[-1].variadic) + assert secondArgs[-1].variadic secondType = secondArgs[-1].type if not firstType.isDistinguishableFrom(secondType): return False return True + signatures = self.signaturesForArgCount(argc) for idx in range(argc): if isValidDistinguishingIndex(idx, signatures): return idx # No valid distinguishing index. Time to throw locations = self.locationsForArgCount(argc) - raise WebIDLError("Signatures with %d arguments for method '%s' are not " - "distinguishable" % (argc, self.identifier.name), - locations) + raise WebIDLError( + "Signatures with %d arguments for method '%s' are not " + "distinguishable" % (argc, self.identifier.name), + locations, + ) def handleExtendedAttribute(self, attr): identifier = attr.identifier() - if (identifier == "GetterThrows" or - identifier == "SetterThrows" or - identifier == "GetterCanOOM" or - identifier == "SetterCanOOM" or - identifier == "SetterNeedsSubjectPrincipal" or - identifier == "GetterNeedsSubjectPrincipal"): - raise WebIDLError("Methods must not be flagged as " - "[%s]" % identifier, - [attr.location, self.location]) - elif identifier == "Unforgeable": + if ( + identifier == "GetterThrows" + or identifier == "SetterThrows" + or identifier == "GetterCanOOM" + or identifier == "SetterCanOOM" + or identifier == "SetterNeedsSubjectPrincipal" + or identifier == "GetterNeedsSubjectPrincipal" + ): + raise WebIDLError( + "Methods must not be flagged as " "[%s]" % identifier, + [attr.location, self.location], + ) + elif identifier == "LegacyUnforgeable": if self.isStatic(): - raise WebIDLError("[Unforgeable] is only allowed on non-static " - "methods", [attr.location, self.location]) - self._unforgeable = True + raise WebIDLError( + "[LegacyUnforgeable] is only allowed on non-static " "methods", + [attr.location, self.location], + ) + self._legacyUnforgeable = True elif identifier == "SameObject": - raise WebIDLError("Methods must not be flagged as [SameObject]", - [attr.location, self.location]) + raise WebIDLError( + "Methods must not be flagged as [SameObject]", + [attr.location, self.location], + ) elif identifier == "Constant": - raise WebIDLError("Methods must not be flagged as [Constant]", - [attr.location, self.location]) + raise WebIDLError( + "Methods must not be flagged as [Constant]", + [attr.location, self.location], + ) elif identifier == "PutForwards": - raise WebIDLError("Only attributes support [PutForwards]", - [attr.location, self.location]) - elif identifier == "LenientSetter": - raise WebIDLError("Only attributes support [LenientSetter]", - [attr.location, self.location]) + raise WebIDLError( + "Only attributes support [PutForwards]", [attr.location, self.location] + ) + elif identifier == "LegacyLenientSetter": + raise WebIDLError( + "Only attributes support [LegacyLenientSetter]", + [attr.location, self.location], + ) elif identifier == "LenientFloat": # This is called before we've done overload resolution overloads = self._overloads assert len(overloads) == 1 if not overloads[0].returnType.isUndefined(): - raise WebIDLError("[LenientFloat] used on a non-undefined returning method", - [attr.location, self.location]) + raise WebIDLError( + "[LenientFloat] used on a non-undefined method", + [attr.location, self.location], + ) if not overloads[0].includesRestrictedFloatArgument(): - raise WebIDLError("[LenientFloat] used on an operation with no " - "restricted float type arguments", - [attr.location, self.location]) + raise WebIDLError( + "[LenientFloat] used on an operation with no " + "restricted float type arguments", + [attr.location, self.location], + ) elif identifier == "Exposed": convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) - elif (identifier == "CrossOriginCallable" or - identifier == "WebGLHandlesContextLoss"): + elif ( + identifier == "CrossOriginCallable" + or identifier == "WebGLHandlesContextLoss" + ): # Known no-argument attributes. if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) + raise WebIDLError( + "[%s] must take no arguments" % identifier, [attr.location] + ) if identifier == "CrossOriginCallable" and self.isStatic(): - raise WebIDLError("[CrossOriginCallable] is only allowed on non-static " - "attributes", - [attr.location, self.location]) + raise WebIDLError( + "[CrossOriginCallable] is only allowed on non-static " "attributes", + [attr.location, self.location], + ) elif identifier == "Pure": if not attr.noArguments(): - raise WebIDLError("[Pure] must take no arguments", - [attr.location]) + raise WebIDLError("[Pure] must take no arguments", [attr.location]) self._setDependsOn("DOMState") self._setAffects("Nothing") elif identifier == "Affects": if not attr.hasValue(): - raise WebIDLError("[Affects] takes an identifier", - [attr.location]) + raise WebIDLError("[Affects] takes an identifier", [attr.location]) self._setAffects(attr.value()) elif identifier == "DependsOn": if not attr.hasValue(): - raise WebIDLError("[DependsOn] takes an identifier", - [attr.location]) + raise WebIDLError("[DependsOn] takes an identifier", [attr.location]) self._setDependsOn(attr.value()) elif identifier == "Alias": if not attr.hasValue(): - raise WebIDLError("[Alias] takes an identifier or string", - [attr.location]) + raise WebIDLError( + "[Alias] takes an identifier or string", [attr.location] + ) self._addAlias(attr.value()) elif identifier == "UseCounter": if self.isSpecial(): - raise WebIDLError("[UseCounter] must not be used on a special " - "operation", - [attr.location, self.location]) + raise WebIDLError( + "[UseCounter] must not be used on a special " "operation", + [attr.location, self.location], + ) elif identifier == "Unscopable": if not attr.noArguments(): - raise WebIDLError("[Unscopable] must take no arguments", - [attr.location]) + raise WebIDLError( + "[Unscopable] must take no arguments", [attr.location] + ) if self.isStatic(): - raise WebIDLError("[Unscopable] is only allowed on non-static " - "attributes and operations", - [attr.location, self.location]) + raise WebIDLError( + "[Unscopable] is only allowed on non-static " + "attributes and operations", + [attr.location, self.location], + ) elif identifier == "CEReactions": if not attr.noArguments(): - raise WebIDLError("[CEReactions] must take no arguments", - [attr.location]) + raise WebIDLError( + "[CEReactions] must take no arguments", [attr.location] + ) if self.isSpecial() and not self.isSetter() and not self.isDeleter(): - raise WebIDLError("[CEReactions] is only allowed on operation, " - "attribute, setter, and deleter", - [attr.location, self.location]) + raise WebIDLError( + "[CEReactions] is only allowed on operation, " + "attribute, setter, and deleter", + [attr.location, self.location], + ) elif identifier == "Default": if not attr.noArguments(): - raise WebIDLError("[Default] must take no arguments", - [attr.location]) + raise WebIDLError("[Default] must take no arguments", [attr.location]) if not self.isToJSON(): - raise WebIDLError("[Default] is only allowed on toJSON operations", - [attr.location, self.location]) + raise WebIDLError( + "[Default] is only allowed on toJSON operations", + [attr.location, self.location], + ) if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]: - raise WebIDLError("The return type of the default toJSON " - "operation must be 'object'", - [attr.location, self.location]) - elif (identifier == "Throws" or - identifier == "CanOOM" or - identifier == "NewObject" or - identifier == "ChromeOnly" or - identifier == "Pref" or - identifier == "Deprecated" or - identifier == "Func" or - identifier == "SecureContext" or - identifier == "BinaryName" or - identifier == "NeedsSubjectPrincipal" or - identifier == "NeedsCallerType" or - identifier == "StaticClassOverride" or - identifier == "NonEnumerable" or - identifier == "Unexposed"): + raise WebIDLError( + "The return type of the default toJSON " + "operation must be 'object'", + [attr.location, self.location], + ) + elif ( + identifier == "Throws" + or identifier == "CanOOM" + or identifier == "NewObject" + or identifier == "ChromeOnly" + or identifier == "Pref" + or identifier == "Deprecated" + or identifier == "Func" + or identifier == "Trial" + or identifier == "SecureContext" + or identifier == "BinaryName" + or identifier == "NeedsSubjectPrincipal" + or identifier == "NeedsCallerType" + or identifier == "StaticClassOverride" + or identifier == "NonEnumerable" + or identifier == "Unexposed" + or identifier == "WebExtensionStub" + ): # Known attributes that we don't need to do anything with here pass else: - raise WebIDLError("Unknown extended attribute %s on method" % identifier, - [attr.location]) + raise WebIDLError( + "Unknown extended attribute %s on method" % identifier, [attr.location] + ) IDLInterfaceMember.handleExtendedAttribute(self, attr) def returnsPromise(self): return self._overloads[0].returnType.isPromise() - def isUnforgeable(self): - return self._unforgeable + def isLegacyUnforgeable(self): + return self._legacyUnforgeable def _getDependentObjects(self): deps = set() @@ -5607,45 +6706,55 @@ class IDLConstructor(IDLMethod): def handleExtendedAttribute(self, attr): identifier = attr.identifier() - if (identifier == "BinaryName" or - identifier == "ChromeOnly" or - identifier == "NewObject" or - identifier == "SecureContext" or - identifier == "Throws" or - identifier == "Func" or - identifier == "Pref"): + if ( + identifier == "BinaryName" + or identifier == "ChromeOnly" + or identifier == "NewObject" + or identifier == "SecureContext" + or identifier == "Throws" + or identifier == "Func" + or identifier == "Trial" + or identifier == "Pref" + or identifier == "UseCounter" + ): IDLMethod.handleExtendedAttribute(self, attr) elif identifier == "HTMLConstructor": if not attr.noArguments(): - raise WebIDLError("[HTMLConstructor] must take no arguments", - [attr.location]) - # We shouldn't end up here for named constructors. - assert(self.identifier.name == "constructor") + raise WebIDLError( + "[HTMLConstructor] must take no arguments", [attr.location] + ) + # We shouldn't end up here for legacy factory functions. + assert self.identifier.name == "constructor" if any(len(sig[1]) != 0 for sig in self.signatures()): - raise WebIDLError("[HTMLConstructor] must not be applied to a " - "constructor operation that has arguments.", - [attr.location]) + raise WebIDLError( + "[HTMLConstructor] must not be applied to a " + "constructor operation that has arguments.", + [attr.location], + ) self._htmlConstructor = True else: - raise WebIDLError("Unknown extended attribute %s on method" % identifier, - [attr.location]) + raise WebIDLError( + "Unknown extended attribute %s on method" % identifier, [attr.location] + ) def reallyInit(self, parentInterface): name = self._initName location = self._initLocation identifier = IDLUnresolvedIdentifier(location, name, allowForbidden=True) retType = IDLWrapperType(parentInterface.location, parentInterface) - IDLMethod.__init__(self, location, identifier, retType, self._initArgs, - static=True) - self._inited = True; + IDLMethod.__init__( + self, location, identifier, retType, self._initArgs, static=True + ) + self._inited = True # Propagate through whatever extended attributes we already had self.addExtendedAttributes(self._initExtendedAttrs) self._initExtendedAttrs = [] # Constructors are always NewObject. Whether they throw or not is # indicated by [Throws] annotations in the usual way. self.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("NewObject",))]) + [IDLExtendedAttribute(self.location, ("NewObject",))] + ) class IDLIncludesStatement(IDLObject): @@ -5659,25 +6768,28 @@ class IDLIncludesStatement(IDLObject): if self._finished: return self._finished = True - assert(isinstance(self.interface, IDLIdentifierPlaceholder)) - assert(isinstance(self.mixin, IDLIdentifierPlaceholder)) + assert isinstance(self.interface, IDLIdentifierPlaceholder) + assert isinstance(self.mixin, IDLIdentifierPlaceholder) interface = self.interface.finish(scope) mixin = self.mixin.finish(scope) # NOTE: we depend on not setting self.interface and # self.mixin here to keep track of the original # locations. if not isinstance(interface, IDLInterface): - raise WebIDLError("Left-hand side of 'includes' is not an " - "interface", - [self.interface.location, interface.location]) + raise WebIDLError( + "Left-hand side of 'includes' is not an " "interface", + [self.interface.location, interface.location], + ) if interface.isCallback(): - raise WebIDLError("Left-hand side of 'includes' is a callback " - "interface", - [self.interface.location, interface.location]) + raise WebIDLError( + "Left-hand side of 'includes' is a callback " "interface", + [self.interface.location, interface.location], + ) if not isinstance(mixin, IDLInterfaceMixin): - raise WebIDLError("Right-hand side of 'includes' is not an " - "interface mixin", - [self.mixin.location, mixin.location]) + raise WebIDLError( + "Right-hand side of 'includes' is not an " "interface mixin", + [self.mixin.location, mixin.location], + ) mixin.actualExposureGlobalNames.update(interface._exposureGlobalNames) @@ -5690,14 +6802,18 @@ class IDLIncludesStatement(IDLObject): def addExtendedAttributes(self, attrs): if len(attrs) != 0: - raise WebIDLError("There are no extended attributes that are " - "allowed on includes statements", - [attrs[0].location, self.location]) + raise WebIDLError( + "There are no extended attributes that are " + "allowed on includes statements", + [attrs[0].location, self.location], + ) + class IDLExtendedAttribute(IDLObject): """ A class to represent IDL extended attributes so we can give them locations """ + def __init__(self, location, tuple): IDLObject.__init__(self, location) self._tuple = tuple @@ -5712,15 +6828,18 @@ class IDLExtendedAttribute(IDLObject): return len(self._tuple) >= 2 and isinstance(self._tuple[1], str) def value(self): - assert(self.hasValue()) + assert self.hasValue() return self._tuple[1] def hasArgs(self): - return (len(self._tuple) == 2 and isinstance(self._tuple[1], list) or - len(self._tuple) == 3) + return ( + len(self._tuple) == 2 + and isinstance(self._tuple[1], list) + or len(self._tuple) == 3 + ) def args(self): - assert(self.hasArgs()) + assert self.hasArgs() # Our args are our last element return self._tuple[-1] @@ -5730,41 +6849,40 @@ class IDLExtendedAttribute(IDLObject): """ return list(self._tuple)[1:] + # Parser class Tokenizer(object): - tokens = [ - "INTEGER", - "FLOATLITERAL", - "IDENTIFIER", - "STRING", - "COMMENTS", - "WHITESPACE", - "OTHER" - ] + tokens = ["INTEGER", "FLOATLITERAL", "IDENTIFIER", "STRING", "WHITESPACE", "OTHER"] def t_FLOATLITERAL(self, t): - r'(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN' + r"(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN" t.value = float(t.value) return t def t_INTEGER(self, t): - r'-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)' + r"-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)" try: # Can't use int(), because that doesn't handle octal properly. t.value = parseInt(t.value) except: - raise WebIDLError("Invalid integer literal", - [Location(lexer=self.lexer, - lineno=self.lexer.lineno, - lexpos=self.lexer.lexpos, - filename=self._filename)]) + raise WebIDLError( + "Invalid integer literal", + [ + Location( + lexer=self.lexer, + lineno=self.lexer.lineno, + lexpos=self.lexer.lexpos, + filename=self._filename, + ) + ], + ) return t def t_IDENTIFIER(self, t): - r'[_-]?[A-Za-z][0-9A-Z_a-z-]*' - t.type = self.keywords.get(t.value, 'IDENTIFIER') + r"[_-]?[A-Za-z][0-9A-Z_a-z-]*" + t.type = self.keywords.get(t.value, "IDENTIFIER") return t def t_STRING(self, t): @@ -5772,22 +6890,18 @@ class Tokenizer(object): t.value = t.value[1:-1] return t - def t_COMMENTS(self, t): - r'(\/\*(.|\n)*?\*\/)|(\/\/.*)' - pass - def t_WHITESPACE(self, t): - r'[\t\n\r ]+' + r"[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+" pass def t_ELLIPSIS(self, t): - r'\.\.\.' + r"\.\.\." t.type = self.keywords.get(t.value) return t def t_OTHER(self, t): - r'[^\t\n\r 0-9A-Z_a-z]' - t.type = self.keywords.get(t.value, 'OTHER') + r"[^\t\n\r 0-9A-Z_a-z]" + t.type = self.keywords.get(t.value, "OTHER") return t keywords = { @@ -5830,6 +6944,7 @@ class Tokenizer(object): "float": "FLOAT", "long": "LONG", "object": "OBJECT", + "ObservableArray": "OBSERVABLEARRAY", "octet": "OCTET", "Promise": "PROMISE", "required": "REQUIRED", @@ -5847,6 +6962,7 @@ class Tokenizer(object): "[": "LBRACKET", "]": "RBRACKET", "?": "QUESTIONMARK", + "*": "ASTERISK", ",": "COMMA", "=": "EQUALS", "<": "LT", @@ -5857,36 +6973,40 @@ class Tokenizer(object): "setlike": "SETLIKE", "iterable": "ITERABLE", "namespace": "NAMESPACE", - "ReadableStream": "READABLESTREAM", "constructor": "CONSTRUCTOR", "symbol": "SYMBOL", "async": "ASYNC", - } + } - tokens.extend(list(keywords.values())) + tokens.extend(keywords.values()) def t_error(self, t): - raise WebIDLError("Unrecognized Input", - [Location(lexer=self.lexer, - lineno=self.lexer.lineno, - lexpos=self.lexer.lexpos, - filename=self.filename)]) + raise WebIDLError( + "Unrecognized Input", + [ + Location( + lexer=self.lexer, + lineno=self.lexer.lineno, + lexpos=self.lexer.lexpos, + filename=self.filename, + ) + ], + ) - def __init__(self, lexer=None): + def __init__(self, outputdir, lexer=None): if lexer: self.lexer = lexer else: - self.lexer = lex.lex(object=self) + self.lexer = lex.lex(object=self, reflags=re.DOTALL) class SqueakyCleanLogger(object): errorWhitelist = [ - # Web IDL defines the WHITESPACE and COMMENTS token, but doesn't actually + # Web IDL defines the WHITESPACE token, but doesn't actually # use it ... so far. "Token 'WHITESPACE' defined, but not used", - "Token 'COMMENTS' defined, but not used", - # And that means we have unused tokens - "There are 2 unused tokens", + # And that means we have an unused token + "There is 1 unused token", # Web IDL defines a OtherOrComma rule that's only used in # ExtendedAttributeInner, which we don't use yet. "Rule 'OtherOrComma' defined, but not used", @@ -5896,18 +7016,21 @@ class SqueakyCleanLogger(object): "Symbol 'OtherOrComma' is unreachable", # Which means the Other symbol is unreachable. "Symbol 'Other' is unreachable", - ] + ] def __init__(self): self.errors = [] def debug(self, msg, *args, **kwargs): pass + info = debug def warning(self, msg, *args, **kwargs): - if msg == "%s:%d: Rule %r defined, but not used" or \ - msg == "%s:%d: Rule '%s' defined, but not used": + if ( + msg == "%s:%d: Rule %r defined, but not used" + or msg == "%s:%d: Rule '%s' defined, but not used" + ): # Munge things so we don't have to hardcode filenames and # line numbers in our whitelist. whitelistmsg = "Rule %r defined, but not used" @@ -5917,6 +7040,7 @@ class SqueakyCleanLogger(object): whitelistargs = args if (whitelistmsg % whitelistargs) not in SqueakyCleanLogger.errorWhitelist: self.errors.append(msg % args) + error = warning def reportGrammarErrors(self): @@ -5935,7 +7059,7 @@ class Parser(Tokenizer): # It's acceptable to split things at '|' boundaries. def p_Definitions(self, p): """ - Definitions : ExtendedAttributeList Definition Definitions + Definitions : ExtendedAttributeList Definition Definitions """ if p[2]: p[0] = [p[2]] @@ -5948,27 +7072,27 @@ class Parser(Tokenizer): def p_DefinitionsEmpty(self, p): """ - Definitions : + Definitions : """ p[0] = [] def p_Definition(self, p): """ - Definition : CallbackOrInterfaceOrMixin - | Namespace - | Partial - | Dictionary - | Exception - | Enum - | Typedef - | IncludesStatement + Definition : CallbackOrInterfaceOrMixin + | Namespace + | Partial + | Dictionary + | Exception + | Enum + | Typedef + | IncludesStatement """ p[0] = p[1] assert p[1] # We might not have implemented something ... def p_CallbackOrInterfaceOrMixinCallback(self, p): """ - CallbackOrInterfaceOrMixin : CALLBACK CallbackRestOrInterface + CallbackOrInterfaceOrMixin : CALLBACK CallbackRestOrInterface """ if p[2].isInterface(): assert isinstance(p[2], IDLInterface) @@ -5978,21 +7102,22 @@ class Parser(Tokenizer): def p_CallbackOrInterfaceOrMixinInterfaceOrMixin(self, p): """ - CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin + CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin """ p[0] = p[2] def p_CallbackRestOrInterface(self, p): """ - CallbackRestOrInterface : CallbackRest - | CallbackConstructorRest - | CallbackInterface + CallbackRestOrInterface : CallbackRest + | CallbackConstructorRest + | CallbackInterface """ assert p[1] p[0] = p[1] - def handleNonPartialObject(self, location, identifier, constructor, - constructorArgs, nonPartialArgs): + def handleNonPartialObject( + self, location, identifier, constructor, constructorArgs, nonPartialArgs + ): """ This handles non-partial objects (interfaces, namespaces and dictionaries) by checking for an existing partial object, and promoting @@ -6013,10 +7138,11 @@ class Parser(Tokenizer): existingObj = self.globalScope()._lookupIdentifier(identifier) if existingObj: if not isinstance(existingObj, constructor): - raise WebIDLError("%s has the same name as " - "non-%s object" % - (prettyname.capitalize(), prettyname), - [location, existingObj.location]) + raise WebIDLError( + "%s has the same name as " + "non-%s object" % (prettyname.capitalize(), prettyname), + [location, existingObj.location], + ) existingObj.setNonPartial(*nonPartialArgs) return existingObj except Exception as ex: @@ -6029,20 +7155,20 @@ class Parser(Tokenizer): def p_InterfaceOrMixin(self, p): """ - InterfaceOrMixin : InterfaceRest - | MixinRest + InterfaceOrMixin : InterfaceRest + | MixinRest """ p[0] = p[1] def p_CallbackInterface(self, p): """ - CallbackInterface : INTERFACE InterfaceRest + CallbackInterface : INTERFACE InterfaceRest """ p[0] = p[2] def p_InterfaceRest(self, p): """ - InterfaceRest : IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON + InterfaceRest : IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(location, p[1]) @@ -6050,13 +7176,16 @@ class Parser(Tokenizer): parent = p[2] p[0] = self.handleNonPartialObject( - location, identifier, IDLInterface, + location, + identifier, + IDLInterface, [location, self.globalScope(), identifier, parent, members], - [location, parent, members]) + [location, parent, members], + ) def p_InterfaceForwardDecl(self, p): """ - InterfaceRest : IDENTIFIER SEMICOLON + InterfaceRest : IDENTIFIER SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(location, p[1]) @@ -6065,10 +7194,12 @@ class Parser(Tokenizer): if self.globalScope()._lookupIdentifier(identifier): p[0] = self.globalScope()._lookupIdentifier(identifier) if not isinstance(p[0], IDLExternalInterface): - raise WebIDLError("Name collision between external " - "interface declaration for identifier " - "%s and %s" % (identifier.name, p[0]), - [location, p[0].location]) + raise WebIDLError( + "Name collision between external " + "interface declaration for identifier " + "%s and %s" % (identifier.name, p[0]), + [location, p[0].location], + ) return except Exception as ex: if isinstance(ex, WebIDLError): @@ -6079,52 +7210,63 @@ class Parser(Tokenizer): def p_MixinRest(self, p): """ - MixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON + MixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) members = p[4] p[0] = self.handleNonPartialObject( - location, identifier, IDLInterfaceMixin, + location, + identifier, + IDLInterfaceMixin, [location, self.globalScope(), identifier, members], - [location, members]) + [location, members], + ) def p_Namespace(self, p): """ - Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) members = p[4] p[0] = self.handleNonPartialObject( - location, identifier, IDLNamespace, + location, + identifier, + IDLNamespace, [location, self.globalScope(), identifier, members], - [location, None, members]) + [location, None, members], + ) def p_Partial(self, p): """ - Partial : PARTIAL PartialDefinition + Partial : PARTIAL PartialDefinition """ p[0] = p[2] def p_PartialDefinitionInterface(self, p): """ - PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin + PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin """ p[0] = p[2] def p_PartialDefinition(self, p): """ - PartialDefinition : PartialNamespace - | PartialDictionary + PartialDefinition : PartialNamespace + | PartialDictionary """ p[0] = p[1] - def handlePartialObject(self, location, identifier, nonPartialConstructor, - nonPartialConstructorArgs, - partialConstructorArgs): + def handlePartialObject( + self, + location, + identifier, + nonPartialConstructor, + nonPartialConstructorArgs, + partialConstructorArgs, + ): """ This handles partial objects (interfaces, namespaces and dictionaries) by checking for an existing non-partial object, and adding ourselves to @@ -6148,10 +7290,11 @@ class Parser(Tokenizer): nonPartialObject = self.globalScope()._lookupIdentifier(identifier) if nonPartialObject: if not isinstance(nonPartialObject, nonPartialConstructor): - raise WebIDLError("Partial %s has the same name as " - "non-%s object" % - (prettyname, prettyname), - [location, nonPartialObject.location]) + raise WebIDLError( + "Partial %s has the same name as " + "non-%s object" % (prettyname, prettyname), + [location, nonPartialObject.location], + ) except Exception as ex: if isinstance(ex, WebIDLError): raise ex @@ -6160,96 +7303,115 @@ class Parser(Tokenizer): if not nonPartialObject: nonPartialObject = nonPartialConstructor( # No members, False for isKnownNonPartial - *(nonPartialConstructorArgs), members=[], isKnownNonPartial=False) + *(nonPartialConstructorArgs), + members=[], + isKnownNonPartial=False + ) partialObject = None if isinstance(nonPartialObject, IDLDictionary): partialObject = IDLPartialDictionary( - *(partialConstructorArgs + [nonPartialObject])) - elif isinstance(nonPartialObject, (IDLInterface, IDLInterfaceMixin, IDLNamespace)): + *(partialConstructorArgs + [nonPartialObject]) + ) + elif isinstance( + nonPartialObject, (IDLInterface, IDLInterfaceMixin, IDLNamespace) + ): partialObject = IDLPartialInterfaceOrNamespace( - *(partialConstructorArgs + [nonPartialObject])) + *(partialConstructorArgs + [nonPartialObject]) + ) else: - raise WebIDLError("Unknown partial object type %s" % - type(partialObject), - [location]) + raise WebIDLError( + "Unknown partial object type %s" % type(partialObject), [location] + ) return partialObject def p_PartialInterfaceOrPartialMixin(self, p): """ - PartialInterfaceOrPartialMixin : PartialInterfaceRest - | PartialMixinRest + PartialInterfaceOrPartialMixin : PartialInterfaceRest + | PartialMixinRest """ p[0] = p[1] def p_PartialInterfaceRest(self, p): """ - PartialInterfaceRest : IDENTIFIER LBRACE PartialInterfaceMembers RBRACE SEMICOLON + PartialInterfaceRest : IDENTIFIER LBRACE PartialInterfaceMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(location, p[1]) members = p[3] p[0] = self.handlePartialObject( - location, identifier, IDLInterface, + location, + identifier, + IDLInterface, [location, self.globalScope(), identifier, None], - [location, identifier, members]) + [location, identifier, members], + ) def p_PartialMixinRest(self, p): """ - PartialMixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON + PartialMixinRest : MIXIN IDENTIFIER LBRACE MixinMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) members = p[4] p[0] = self.handlePartialObject( - location, identifier, IDLInterfaceMixin, + location, + identifier, + IDLInterfaceMixin, [location, self.globalScope(), identifier], - [location, identifier, members]) + [location, identifier, members], + ) def p_PartialNamespace(self, p): """ - PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) members = p[4] p[0] = self.handlePartialObject( - location, identifier, IDLNamespace, + location, + identifier, + IDLNamespace, [location, self.globalScope(), identifier], - [location, identifier, members]) + [location, identifier, members], + ) def p_PartialDictionary(self, p): """ - PartialDictionary : DICTIONARY IDENTIFIER LBRACE DictionaryMembers RBRACE SEMICOLON + PartialDictionary : DICTIONARY IDENTIFIER LBRACE DictionaryMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) members = p[4] p[0] = self.handlePartialObject( - location, identifier, IDLDictionary, + location, + identifier, + IDLDictionary, [location, self.globalScope(), identifier], - [location, identifier, members]) + [location, identifier, members], + ) def p_Inheritance(self, p): """ - Inheritance : COLON ScopedName + Inheritance : COLON ScopedName """ p[0] = IDLIdentifierPlaceholder(self.getLocation(p, 2), p[2]) def p_InheritanceEmpty(self, p): """ - Inheritance : + Inheritance : """ pass def p_InterfaceMembers(self, p): """ - InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers + InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers """ p[0] = [p[2]] @@ -6260,26 +7422,26 @@ class Parser(Tokenizer): def p_InterfaceMembersEmpty(self, p): """ - InterfaceMembers : + InterfaceMembers : """ p[0] = [] def p_InterfaceMember(self, p): """ - InterfaceMember : PartialInterfaceMember - | Constructor + InterfaceMember : PartialInterfaceMember + | Constructor """ p[0] = p[1] def p_Constructor(self, p): """ - Constructor : CONSTRUCTOR LPAREN ArgumentList RPAREN SEMICOLON + Constructor : CONSTRUCTOR LPAREN ArgumentList RPAREN SEMICOLON """ p[0] = IDLConstructor(self.getLocation(p, 1), p[3], "constructor") def p_PartialInterfaceMembers(self, p): """ - PartialInterfaceMembers : ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers + PartialInterfaceMembers : ExtendedAttributeList PartialInterfaceMember PartialInterfaceMembers """ p[0] = [p[2]] @@ -6290,27 +7452,26 @@ class Parser(Tokenizer): def p_PartialInterfaceMembersEmpty(self, p): """ - PartialInterfaceMembers : + PartialInterfaceMembers : """ p[0] = [] def p_PartialInterfaceMember(self, p): """ - PartialInterfaceMember : Const - | AttributeOrOperationOrMaplikeOrSetlikeOrIterable + PartialInterfaceMember : Const + | AttributeOrOperationOrMaplikeOrSetlikeOrIterable """ p[0] = p[1] - def p_MixinMembersEmpty(self, p): """ - MixinMembers : + MixinMembers : """ p[0] = [] def p_MixinMembers(self, p): """ - MixinMembers : ExtendedAttributeList MixinMember MixinMembers + MixinMembers : ExtendedAttributeList MixinMember MixinMembers """ p[0] = [p[2]] @@ -6321,15 +7482,15 @@ class Parser(Tokenizer): def p_MixinMember(self, p): """ - MixinMember : Const - | Attribute - | Operation + MixinMember : Const + | Attribute + | Operation """ p[0] = p[1] def p_Dictionary(self, p): """ - Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON + Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) @@ -6338,8 +7499,8 @@ class Parser(Tokenizer): def p_DictionaryMembers(self, p): """ - DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers - | + DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers + | """ if len(p) == 1: # We're at the end of the list @@ -6351,21 +7512,26 @@ class Parser(Tokenizer): def p_DictionaryMemberRequired(self, p): """ - DictionaryMember : REQUIRED TypeWithExtendedAttributes IDENTIFIER SEMICOLON + DictionaryMember : REQUIRED TypeWithExtendedAttributes IDENTIFIER SEMICOLON """ # These quack a lot like required arguments, so just treat them that way. t = p[2] assert isinstance(t, IDLType) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) - p[0] = IDLArgument(self.getLocation(p, 3), identifier, t, - optional=False, - defaultValue=None, variadic=False, - dictionaryMember=True) + p[0] = IDLArgument( + self.getLocation(p, 3), + identifier, + t, + optional=False, + defaultValue=None, + variadic=False, + dictionaryMember=True, + ) def p_DictionaryMember(self, p): """ - DictionaryMember : Type IDENTIFIER Default SEMICOLON + DictionaryMember : Type IDENTIFIER Default SEMICOLON """ # These quack a lot like optional arguments, so just treat them that way. t = p[1] @@ -6376,15 +7542,21 @@ class Parser(Tokenizer): # Any attributes that precede this may apply to the type, so # we configure the argument to forward type attributes down instead of producing # a parse error - p[0] = IDLArgument(self.getLocation(p, 2), identifier, t, - optional=True, - defaultValue=defaultValue, variadic=False, - dictionaryMember=True, allowTypeAttributes=True) + p[0] = IDLArgument( + self.getLocation(p, 2), + identifier, + t, + optional=True, + defaultValue=defaultValue, + variadic=False, + dictionaryMember=True, + allowTypeAttributes=True, + ) def p_Default(self, p): """ - Default : EQUALS DefaultValue - | + Default : EQUALS DefaultValue + | """ if len(p) > 1: p[0] = p[2] @@ -6393,9 +7565,9 @@ class Parser(Tokenizer): def p_DefaultValue(self, p): """ - DefaultValue : ConstValue - | LBRACKET RBRACKET - | LBRACE RBRACE + DefaultValue : ConstValue + | LBRACKET RBRACKET + | LBRACE RBRACE """ if len(p) == 2: p[0] = p[1] @@ -6409,19 +7581,25 @@ class Parser(Tokenizer): def p_DefaultValueNull(self, p): """ - DefaultValue : NULL + DefaultValue : NULL """ p[0] = IDLNullValue(self.getLocation(p, 1)) + def p_DefaultValueUndefined(self, p): + """ + DefaultValue : UNDEFINED + """ + p[0] = IDLUndefinedValue(self.getLocation(p, 1)) + def p_Exception(self, p): """ - Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON + Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON """ pass def p_Enum(self, p): """ - Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON + Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON """ location = self.getLocation(p, 1) identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) @@ -6432,79 +7610,90 @@ class Parser(Tokenizer): def p_EnumValueList(self, p): """ - EnumValueList : STRING EnumValueListComma + EnumValueList : STRING EnumValueListComma """ p[0] = [p[1]] p[0].extend(p[2]) def p_EnumValueListComma(self, p): """ - EnumValueListComma : COMMA EnumValueListString + EnumValueListComma : COMMA EnumValueListString """ p[0] = p[2] def p_EnumValueListCommaEmpty(self, p): """ - EnumValueListComma : + EnumValueListComma : """ p[0] = [] def p_EnumValueListString(self, p): """ - EnumValueListString : STRING EnumValueListComma + EnumValueListString : STRING EnumValueListComma """ p[0] = [p[1]] p[0].extend(p[2]) def p_EnumValueListStringEmpty(self, p): """ - EnumValueListString : + EnumValueListString : """ p[0] = [] def p_CallbackRest(self, p): """ - CallbackRest : IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON + CallbackRest : IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON """ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) - p[0] = IDLCallback(self.getLocation(p, 1), self.globalScope(), - identifier, p[3], p[5], isConstructor=False) + p[0] = IDLCallback( + self.getLocation(p, 1), + self.globalScope(), + identifier, + p[3], + p[5], + isConstructor=False, + ) def p_CallbackConstructorRest(self, p): """ - CallbackConstructorRest : CONSTRUCTOR IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON + CallbackConstructorRest : CONSTRUCTOR IDENTIFIER EQUALS Type LPAREN ArgumentList RPAREN SEMICOLON """ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - p[0] = IDLCallback(self.getLocation(p, 2), self.globalScope(), - identifier, p[4], p[6], isConstructor=True) + p[0] = IDLCallback( + self.getLocation(p, 2), + self.globalScope(), + identifier, + p[4], + p[6], + isConstructor=True, + ) def p_ExceptionMembers(self, p): """ - ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers - | + ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers + | """ pass def p_Typedef(self, p): """ - Typedef : TYPEDEF TypeWithExtendedAttributes IDENTIFIER SEMICOLON + Typedef : TYPEDEF TypeWithExtendedAttributes IDENTIFIER SEMICOLON """ - typedef = IDLTypedef(self.getLocation(p, 1), self.globalScope(), - p[2], p[3]) + typedef = IDLTypedef(self.getLocation(p, 1), self.globalScope(), p[2], p[3]) p[0] = typedef def p_IncludesStatement(self, p): """ - IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON + IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON """ - assert(p[2] == "includes") + assert p[2] == "includes" interface = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1]) mixin = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3]) p[0] = IDLIncludesStatement(self.getLocation(p, 1), interface, mixin) def p_Const(self, p): """ - Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON + Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON """ location = self.getLocation(p, 1) type = p[2] @@ -6514,7 +7703,7 @@ class Parser(Tokenizer): def p_ConstValueBoolean(self, p): """ - ConstValue : BooleanLiteral + ConstValue : BooleanLiteral """ location = self.getLocation(p, 1) booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean] @@ -6522,7 +7711,7 @@ class Parser(Tokenizer): def p_ConstValueInteger(self, p): """ - ConstValue : INTEGER + ConstValue : INTEGER """ location = self.getLocation(p, 1) @@ -6536,14 +7725,16 @@ class Parser(Tokenizer): def p_ConstValueFloat(self, p): """ - ConstValue : FLOATLITERAL + ConstValue : FLOATLITERAL """ location = self.getLocation(p, 1) - p[0] = IDLValue(location, BuiltinTypes[IDLBuiltinType.Types.unrestricted_float], p[1]) + p[0] = IDLValue( + location, BuiltinTypes[IDLBuiltinType.Types.unrestricted_float], p[1] + ) def p_ConstValueString(self, p): """ - ConstValue : STRING + ConstValue : STRING """ location = self.getLocation(p, 1) stringType = BuiltinTypes[IDLBuiltinType.Types.domstring] @@ -6551,35 +7742,37 @@ class Parser(Tokenizer): def p_BooleanLiteralTrue(self, p): """ - BooleanLiteral : TRUE + BooleanLiteral : TRUE """ p[0] = True def p_BooleanLiteralFalse(self, p): """ - BooleanLiteral : FALSE + BooleanLiteral : FALSE """ p[0] = False def p_AttributeOrOperationOrMaplikeOrSetlikeOrIterable(self, p): """ - AttributeOrOperationOrMaplikeOrSetlikeOrIterable : Attribute - | Maplike - | Setlike - | Iterable - | Operation + AttributeOrOperationOrMaplikeOrSetlikeOrIterable : Attribute + | Maplike + | Setlike + | Iterable + | AsyncIterable + | Operation """ p[0] = p[1] def p_Iterable(self, p): """ - Iterable : ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON - | ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON + Iterable : ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON + | ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON """ location = self.getLocation(p, 2) - identifier = IDLUnresolvedIdentifier(location, "__iterable", - allowDoubleUnderscore=True) - if (len(p) > 6): + identifier = IDLUnresolvedIdentifier( + location, "__iterable", allowDoubleUnderscore=True + ) + if len(p) > 6: keyType = p[3] valueType = p[5] else: @@ -6588,61 +7781,98 @@ class Parser(Tokenizer): p[0] = IDLIterable(location, identifier, keyType, valueType, self.globalScope()) + def p_AsyncIterable(self, p): + """ + AsyncIterable : ASYNC ITERABLE LT TypeWithExtendedAttributes GT SEMICOLON + | ASYNC ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON + | ASYNC ITERABLE LT TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON + | ASYNC ITERABLE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT LPAREN ArgumentList RPAREN SEMICOLON + """ + location = self.getLocation(p, 2) + identifier = IDLUnresolvedIdentifier( + location, "__iterable", allowDoubleUnderscore=True + ) + if len(p) == 12: + keyType = p[4] + valueType = p[6] + argList = p[9] + elif len(p) == 10: + keyType = None + valueType = p[4] + argList = p[7] + elif len(p) == 9: + keyType = p[4] + valueType = p[6] + argList = [] + else: + keyType = None + valueType = p[4] + argList = [] + + p[0] = IDLAsyncIterable( + location, identifier, keyType, valueType, argList, self.globalScope() + ) + def p_Setlike(self, p): """ - Setlike : ReadOnly SETLIKE LT TypeWithExtendedAttributes GT SEMICOLON + Setlike : ReadOnly SETLIKE LT TypeWithExtendedAttributes GT SEMICOLON """ readonly = p[1] maplikeOrSetlikeType = p[2] location = self.getLocation(p, 2) - identifier = IDLUnresolvedIdentifier(location, "__setlike", - allowDoubleUnderscore=True) + identifier = IDLUnresolvedIdentifier( + location, "__setlike", allowDoubleUnderscore=True + ) keyType = p[4] valueType = keyType - p[0] = IDLMaplikeOrSetlike(location, identifier, maplikeOrSetlikeType, - readonly, keyType, valueType) + p[0] = IDLMaplikeOrSetlike( + location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType + ) def p_Maplike(self, p): """ - Maplike : ReadOnly MAPLIKE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON + Maplike : ReadOnly MAPLIKE LT TypeWithExtendedAttributes COMMA TypeWithExtendedAttributes GT SEMICOLON """ readonly = p[1] maplikeOrSetlikeType = p[2] location = self.getLocation(p, 2) - identifier = IDLUnresolvedIdentifier(location, "__maplike", - allowDoubleUnderscore=True) + identifier = IDLUnresolvedIdentifier( + location, "__maplike", allowDoubleUnderscore=True + ) keyType = p[4] valueType = p[6] - p[0] = IDLMaplikeOrSetlike(location, identifier, maplikeOrSetlikeType, - readonly, keyType, valueType) + p[0] = IDLMaplikeOrSetlike( + location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType + ) def p_AttributeWithQualifier(self, p): """ - Attribute : Qualifier AttributeRest + Attribute : Qualifier AttributeRest """ static = IDLInterfaceMember.Special.Static in p[1] stringifier = IDLInterfaceMember.Special.Stringifier in p[1] (location, identifier, type, readonly) = p[2] - p[0] = IDLAttribute(location, identifier, type, readonly, - static=static, stringifier=stringifier) + p[0] = IDLAttribute( + location, identifier, type, readonly, static=static, stringifier=stringifier + ) def p_AttributeInherited(self, p): """ - Attribute : INHERIT AttributeRest + Attribute : INHERIT AttributeRest """ (location, identifier, type, readonly) = p[2] p[0] = IDLAttribute(location, identifier, type, readonly, inherit=True) def p_Attribute(self, p): """ - Attribute : AttributeRest + Attribute : AttributeRest """ (location, identifier, type, readonly) = p[1] p[0] = IDLAttribute(location, identifier, type, readonly, inherit=False) def p_AttributeRest(self, p): """ - AttributeRest : ReadOnly ATTRIBUTE TypeWithExtendedAttributes AttributeName SEMICOLON + AttributeRest : ReadOnly ATTRIBUTE TypeWithExtendedAttributes AttributeName SEMICOLON """ location = self.getLocation(p, 2) readonly = p[1] @@ -6652,26 +7882,27 @@ class Parser(Tokenizer): def p_ReadOnly(self, p): """ - ReadOnly : READONLY + ReadOnly : READONLY """ p[0] = True def p_ReadOnlyEmpty(self, p): """ - ReadOnly : + ReadOnly : """ p[0] = False def p_Operation(self, p): """ - Operation : Qualifiers OperationRest + Operation : Qualifiers OperationRest """ qualifiers = p[1] # Disallow duplicates in the qualifier set if not len(set(qualifiers)) == len(qualifiers): - raise WebIDLError("Duplicate qualifiers are not allowed", - [self.getLocation(p, 1)]) + raise WebIDLError( + "Duplicate qualifiers are not allowed", [self.getLocation(p, 1)] + ) static = IDLInterfaceMember.Special.Static in p[1] # If static is there that's all that's allowed. This is disallowed @@ -6690,8 +7921,10 @@ class Parser(Tokenizer): if getter or deleter: if setter: - raise WebIDLError("getter and deleter are incompatible with setter", - [self.getLocation(p, 1)]) + raise WebIDLError( + "getter and deleter are incompatible with setter", + [self.getLocation(p, 1)], + ) (returnType, identifier, arguments) = p[2] @@ -6701,234 +7934,285 @@ class Parser(Tokenizer): if getter or deleter: if len(arguments) != 1: - raise WebIDLError("%s has wrong number of arguments" % - ("getter" if getter else "deleter"), - [self.getLocation(p, 2)]) + raise WebIDLError( + "%s has wrong number of arguments" + % ("getter" if getter else "deleter"), + [self.getLocation(p, 2)], + ) argType = arguments[0].type if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: specialType = IDLMethod.NamedOrIndexed.Named elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: specialType = IDLMethod.NamedOrIndexed.Indexed if deleter: - raise WebIDLError("There is no such thing as an indexed deleter.", - [self.getLocation(p, 1)]) + raise WebIDLError( + "There is no such thing as an indexed deleter.", + [self.getLocation(p, 1)], + ) else: - raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % - ("getter" if getter else "deleter"), - [arguments[0].location]) + raise WebIDLError( + "%s has wrong argument type (must be DOMString or UnsignedLong)" + % ("getter" if getter else "deleter"), + [arguments[0].location], + ) if arguments[0].optional or arguments[0].variadic: - raise WebIDLError("%s cannot have %s argument" % - ("getter" if getter else "deleter", - "optional" if arguments[0].optional else "variadic"), - [arguments[0].location]) + raise WebIDLError( + "%s cannot have %s argument" + % ( + "getter" if getter else "deleter", + "optional" if arguments[0].optional else "variadic", + ), + [arguments[0].location], + ) if getter: if returnType.isUndefined(): - raise WebIDLError("getter cannot have undefined return type", - [self.getLocation(p, 2)]) + raise WebIDLError( + "getter cannot have undefined return type", [self.getLocation(p, 2)] + ) if setter: if len(arguments) != 2: - raise WebIDLError("setter has wrong number of arguments", - [self.getLocation(p, 2)]) + raise WebIDLError( + "setter has wrong number of arguments", [self.getLocation(p, 2)] + ) argType = arguments[0].type if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: specialType = IDLMethod.NamedOrIndexed.Named elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: specialType = IDLMethod.NamedOrIndexed.Indexed else: - raise WebIDLError("settter has wrong argument type (must be DOMString or UnsignedLong)", - [arguments[0].location]) + raise WebIDLError( + "settter has wrong argument type (must be DOMString or UnsignedLong)", + [arguments[0].location], + ) if arguments[0].optional or arguments[0].variadic: - raise WebIDLError("setter cannot have %s argument" % - ("optional" if arguments[0].optional else "variadic"), - [arguments[0].location]) + raise WebIDLError( + "setter cannot have %s argument" + % ("optional" if arguments[0].optional else "variadic"), + [arguments[0].location], + ) if arguments[1].optional or arguments[1].variadic: - raise WebIDLError("setter cannot have %s argument" % - ("optional" if arguments[1].optional else "variadic"), - [arguments[1].location]) + raise WebIDLError( + "setter cannot have %s argument" + % ("optional" if arguments[1].optional else "variadic"), + [arguments[1].location], + ) if stringifier: if len(arguments) != 0: - raise WebIDLError("stringifier has wrong number of arguments", - [self.getLocation(p, 2)]) + raise WebIDLError( + "stringifier has wrong number of arguments", + [self.getLocation(p, 2)], + ) if not returnType.isDOMString(): - raise WebIDLError("stringifier must have DOMString return type", - [self.getLocation(p, 2)]) + raise WebIDLError( + "stringifier must have DOMString return type", + [self.getLocation(p, 2)], + ) # identifier might be None. This is only permitted for special methods. if not identifier: - if (not getter and not setter and - not deleter and not legacycaller and not stringifier): - raise WebIDLError("Identifier required for non-special methods", - [self.getLocation(p, 2)]) + if ( + not getter + and not setter + and not deleter + and not legacycaller + and not stringifier + ): + raise WebIDLError( + "Identifier required for non-special methods", + [self.getLocation(p, 2)], + ) location = BuiltinLocation("<auto-generated-identifier>") identifier = IDLUnresolvedIdentifier( location, - "__%s%s%s%s%s%s" % - ("named" if specialType == IDLMethod.NamedOrIndexed.Named else - "indexed" if specialType == IDLMethod.NamedOrIndexed.Indexed else "", - "getter" if getter else "", - "setter" if setter else "", - "deleter" if deleter else "", - "legacycaller" if legacycaller else "", - "stringifier" if stringifier else ""), - allowDoubleUnderscore=True) - - method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments, - static=static, getter=getter, setter=setter, - deleter=deleter, specialType=specialType, - legacycaller=legacycaller, stringifier=stringifier) + "__%s%s%s%s%s%s" + % ( + "named" + if specialType == IDLMethod.NamedOrIndexed.Named + else "indexed" + if specialType == IDLMethod.NamedOrIndexed.Indexed + else "", + "getter" if getter else "", + "setter" if setter else "", + "deleter" if deleter else "", + "legacycaller" if legacycaller else "", + "stringifier" if stringifier else "", + ), + allowDoubleUnderscore=True, + ) + + method = IDLMethod( + self.getLocation(p, 2), + identifier, + returnType, + arguments, + static=static, + getter=getter, + setter=setter, + deleter=deleter, + specialType=specialType, + legacycaller=legacycaller, + stringifier=stringifier, + ) p[0] = method def p_Stringifier(self, p): """ - Operation : STRINGIFIER SEMICOLON + Operation : STRINGIFIER SEMICOLON """ - identifier = IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "__stringifier", - allowDoubleUnderscore=True) - method = IDLMethod(self.getLocation(p, 1), - identifier, - returnType=BuiltinTypes[IDLBuiltinType.Types.domstring], - arguments=[], - stringifier=True) + identifier = IDLUnresolvedIdentifier( + BuiltinLocation("<auto-generated-identifier>"), + "__stringifier", + allowDoubleUnderscore=True, + ) + method = IDLMethod( + self.getLocation(p, 1), + identifier, + returnType=BuiltinTypes[IDLBuiltinType.Types.domstring], + arguments=[], + stringifier=True, + ) p[0] = method def p_QualifierStatic(self, p): """ - Qualifier : STATIC + Qualifier : STATIC """ p[0] = [IDLInterfaceMember.Special.Static] def p_QualifierStringifier(self, p): """ - Qualifier : STRINGIFIER + Qualifier : STRINGIFIER """ p[0] = [IDLInterfaceMember.Special.Stringifier] def p_Qualifiers(self, p): """ - Qualifiers : Qualifier - | Specials + Qualifiers : Qualifier + | Specials """ p[0] = p[1] def p_Specials(self, p): """ - Specials : Special Specials + Specials : Special Specials """ p[0] = [p[1]] p[0].extend(p[2]) def p_SpecialsEmpty(self, p): """ - Specials : + Specials : """ p[0] = [] def p_SpecialGetter(self, p): """ - Special : GETTER + Special : GETTER """ p[0] = IDLMethod.Special.Getter def p_SpecialSetter(self, p): """ - Special : SETTER + Special : SETTER """ p[0] = IDLMethod.Special.Setter def p_SpecialDeleter(self, p): """ - Special : DELETER + Special : DELETER """ p[0] = IDLMethod.Special.Deleter def p_SpecialLegacyCaller(self, p): """ - Special : LEGACYCALLER + Special : LEGACYCALLER """ p[0] = IDLMethod.Special.LegacyCaller def p_OperationRest(self, p): """ - OperationRest : ReturnType OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON + OperationRest : Type OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON """ p[0] = (p[1], p[2], p[4]) def p_OptionalIdentifier(self, p): """ - OptionalIdentifier : IDENTIFIER + OptionalIdentifier : IDENTIFIER """ p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) def p_OptionalIdentifierEmpty(self, p): """ - OptionalIdentifier : + OptionalIdentifier : """ pass def p_ArgumentList(self, p): """ - ArgumentList : Argument Arguments + ArgumentList : Argument Arguments """ p[0] = [p[1]] if p[1] else [] p[0].extend(p[2]) def p_ArgumentListEmpty(self, p): """ - ArgumentList : + ArgumentList : """ p[0] = [] def p_Arguments(self, p): """ - Arguments : COMMA Argument Arguments + Arguments : COMMA Argument Arguments """ p[0] = [p[2]] if p[2] else [] p[0].extend(p[3]) def p_ArgumentsEmpty(self, p): """ - Arguments : + Arguments : """ p[0] = [] def p_Argument(self, p): """ - Argument : ExtendedAttributeList ArgumentRest + Argument : ExtendedAttributeList ArgumentRest """ p[0] = p[2] p[0].addExtendedAttributes(p[1]) def p_ArgumentRestOptional(self, p): """ - ArgumentRest : OPTIONAL TypeWithExtendedAttributes ArgumentName Default + ArgumentRest : OPTIONAL TypeWithExtendedAttributes ArgumentName Default """ t = p[2] assert isinstance(t, IDLType) # Arg names can be reserved identifiers - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3], - allowForbidden=True) + identifier = IDLUnresolvedIdentifier( + self.getLocation(p, 3), p[3], allowForbidden=True + ) defaultValue = p[4] - # We can't test t.isAny() here and give it a default value as needed, # since at this point t is not a fully resolved type yet (e.g. it might # be a typedef). We'll handle the 'any' case in IDLArgument.complete. - p[0] = IDLArgument(self.getLocation(p, 3), identifier, t, True, defaultValue, False) + p[0] = IDLArgument( + self.getLocation(p, 3), identifier, t, True, defaultValue, False + ) def p_ArgumentRest(self, p): """ - ArgumentRest : Type Ellipsis ArgumentName + ArgumentRest : Type Ellipsis ArgumentName """ t = p[1] assert isinstance(t, IDLType) # Arg names can be reserved identifiers - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3], - allowForbidden=True) + identifier = IDLUnresolvedIdentifier( + self.getLocation(p, 3), p[3], allowForbidden=True + ) variadic = p[2] @@ -6940,90 +8224,98 @@ class Parser(Tokenizer): # Any attributes that precede this may apply to the type, so # we configure the argument to forward type attributes down instead of producing # a parse error - p[0] = IDLArgument(self.getLocation(p, 3), identifier, t, variadic, None, variadic, allowTypeAttributes=True) + p[0] = IDLArgument( + self.getLocation(p, 3), + identifier, + t, + variadic, + None, + variadic, + allowTypeAttributes=True, + ) def p_ArgumentName(self, p): """ - ArgumentName : IDENTIFIER - | ArgumentNameKeyword + ArgumentName : IDENTIFIER + | ArgumentNameKeyword """ p[0] = p[1] def p_ArgumentNameKeyword(self, p): """ - ArgumentNameKeyword : ASYNC - | ATTRIBUTE - | CALLBACK - | CONST - | CONSTRUCTOR - | DELETER - | DICTIONARY - | ENUM - | EXCEPTION - | GETTER - | INCLUDES - | INHERIT - | INTERFACE - | ITERABLE - | LEGACYCALLER - | MAPLIKE - | MIXIN - | NAMESPACE - | PARTIAL - | READONLY - | REQUIRED - | SERIALIZER - | SETLIKE - | SETTER - | STATIC - | STRINGIFIER - | TYPEDEF - | UNRESTRICTED + ArgumentNameKeyword : ASYNC + | ATTRIBUTE + | CALLBACK + | CONST + | CONSTRUCTOR + | DELETER + | DICTIONARY + | ENUM + | EXCEPTION + | GETTER + | INCLUDES + | INHERIT + | INTERFACE + | ITERABLE + | LEGACYCALLER + | MAPLIKE + | MIXIN + | NAMESPACE + | PARTIAL + | READONLY + | REQUIRED + | SERIALIZER + | SETLIKE + | SETTER + | STATIC + | STRINGIFIER + | TYPEDEF + | UNRESTRICTED """ p[0] = p[1] def p_AttributeName(self, p): """ - AttributeName : IDENTIFIER - | AttributeNameKeyword + AttributeName : IDENTIFIER + | AttributeNameKeyword """ p[0] = p[1] def p_AttributeNameKeyword(self, p): """ - AttributeNameKeyword : ASYNC - | REQUIRED + AttributeNameKeyword : ASYNC + | REQUIRED """ p[0] = p[1] def p_Ellipsis(self, p): """ - Ellipsis : ELLIPSIS + Ellipsis : ELLIPSIS """ p[0] = True def p_EllipsisEmpty(self, p): """ - Ellipsis : + Ellipsis : """ p[0] = False def p_ExceptionMember(self, p): """ - ExceptionMember : Const - | ExceptionField + ExceptionMember : Const + | ExceptionField """ pass def p_ExceptionField(self, p): """ - ExceptionField : Type IDENTIFIER SEMICOLON + ExceptionField : Type IDENTIFIER SEMICOLON """ pass def p_ExtendedAttributeList(self, p): """ - ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET + ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET """ p[0] = [p[2]] if p[3]: @@ -7031,131 +8323,131 @@ class Parser(Tokenizer): def p_ExtendedAttributeListEmpty(self, p): """ - ExtendedAttributeList : + ExtendedAttributeList : """ p[0] = [] def p_ExtendedAttribute(self, p): """ - ExtendedAttribute : ExtendedAttributeNoArgs - | ExtendedAttributeArgList - | ExtendedAttributeIdent - | ExtendedAttributeNamedArgList - | ExtendedAttributeIdentList + ExtendedAttribute : ExtendedAttributeNoArgs + | ExtendedAttributeArgList + | ExtendedAttributeIdent + | ExtendedAttributeWildcard + | ExtendedAttributeNamedArgList + | ExtendedAttributeIdentList """ p[0] = IDLExtendedAttribute(self.getLocation(p, 1), p[1]) def p_ExtendedAttributeEmpty(self, p): """ - ExtendedAttribute : + ExtendedAttribute : """ pass def p_ExtendedAttributes(self, p): """ - ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes + ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes """ p[0] = [p[2]] if p[2] else [] p[0].extend(p[3]) def p_ExtendedAttributesEmpty(self, p): """ - ExtendedAttributes : + ExtendedAttributes : """ p[0] = [] def p_Other(self, p): """ - Other : INTEGER - | FLOATLITERAL - | IDENTIFIER - | STRING - | OTHER - | ELLIPSIS - | COLON - | SCOPE - | SEMICOLON - | LT - | EQUALS - | GT - | QUESTIONMARK - | DOMSTRING - | BYTESTRING - | USVSTRING - | UTF8STRING - | JSSTRING - | PROMISE - | ANY - | BOOLEAN - | BYTE - | DOUBLE - | FALSE - | FLOAT - | LONG - | NULL - | OBJECT - | OCTET - | OR - | OPTIONAL - | RECORD - | SEQUENCE - | SHORT - | SYMBOL - | TRUE - | UNSIGNED - | UNDEFINED - | ArgumentNameKeyword + Other : INTEGER + | FLOATLITERAL + | IDENTIFIER + | STRING + | OTHER + | ELLIPSIS + | COLON + | SCOPE + | SEMICOLON + | LT + | EQUALS + | GT + | QUESTIONMARK + | ASTERISK + | DOMSTRING + | BYTESTRING + | USVSTRING + | UTF8STRING + | JSSTRING + | PROMISE + | ANY + | BOOLEAN + | BYTE + | DOUBLE + | FALSE + | FLOAT + | LONG + | NULL + | OBJECT + | OCTET + | OR + | OPTIONAL + | RECORD + | SEQUENCE + | SHORT + | SYMBOL + | TRUE + | UNSIGNED + | UNDEFINED + | ArgumentNameKeyword """ pass def p_OtherOrComma(self, p): """ - OtherOrComma : Other - | COMMA + OtherOrComma : Other + | COMMA """ pass def p_TypeSingleType(self, p): """ - Type : SingleType + Type : SingleType """ p[0] = p[1] def p_TypeUnionType(self, p): """ - Type : UnionType Null + Type : UnionType Null """ p[0] = self.handleNullable(p[1], p[2]) def p_TypeWithExtendedAttributes(self, p): """ - TypeWithExtendedAttributes : ExtendedAttributeList Type + TypeWithExtendedAttributes : ExtendedAttributeList Type """ p[0] = p[2].withExtendedAttributes(p[1]) def p_SingleTypeDistinguishableType(self, p): """ - SingleType : DistinguishableType + SingleType : DistinguishableType """ p[0] = p[1] def p_SingleTypeAnyType(self, p): """ - SingleType : ANY + SingleType : ANY """ p[0] = BuiltinTypes[IDLBuiltinType.Types.any] - # Note: Promise<undefined> is allowed, so we want to parametrize on ReturnType, - # not Type. Promise types can't be null, hence no "Null" in there. def p_SingleTypePromiseType(self, p): """ - SingleType : PROMISE LT ReturnType GT + SingleType : PROMISE LT Type GT """ p[0] = IDLPromiseType(self.getLocation(p, 1), p[3]) def p_UnionType(self, p): """ - UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN + UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN """ types = [p[2], p[4]] types.extend(p[5]) @@ -7163,42 +8455,42 @@ class Parser(Tokenizer): def p_UnionMemberTypeDistinguishableType(self, p): """ - UnionMemberType : ExtendedAttributeList DistinguishableType + UnionMemberType : ExtendedAttributeList DistinguishableType """ p[0] = p[2].withExtendedAttributes(p[1]) def p_UnionMemberType(self, p): """ - UnionMemberType : UnionType Null + UnionMemberType : UnionType Null """ p[0] = self.handleNullable(p[1], p[2]) def p_UnionMemberTypes(self, p): """ - UnionMemberTypes : OR UnionMemberType UnionMemberTypes + UnionMemberTypes : OR UnionMemberType UnionMemberTypes """ p[0] = [p[2]] p[0].extend(p[3]) def p_UnionMemberTypesEmpty(self, p): """ - UnionMemberTypes : + UnionMemberTypes : """ p[0] = [] def p_DistinguishableType(self, p): """ - DistinguishableType : PrimitiveType Null - | ARRAYBUFFER Null - | READABLESTREAM Null - | OBJECT Null + DistinguishableType : PrimitiveType Null + | ARRAYBUFFER Null + | OBJECT Null + | UNDEFINED Null """ if p[1] == "object": type = BuiltinTypes[IDLBuiltinType.Types.object] elif p[1] == "ArrayBuffer": type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer] - elif p[1] == "ReadableStream": - type = BuiltinTypes[IDLBuiltinType.Types.ReadableStream] + elif p[1] == "undefined": + type = BuiltinTypes[IDLBuiltinType.Types.undefined] else: type = BuiltinTypes[p[1]] @@ -7206,13 +8498,13 @@ class Parser(Tokenizer): def p_DistinguishableTypeStringType(self, p): """ - DistinguishableType : StringType Null + DistinguishableType : StringType Null """ p[0] = self.handleNullable(p[1], p[2]) def p_DistinguishableTypeSequenceType(self, p): """ - DistinguishableType : SEQUENCE LT TypeWithExtendedAttributes GT Null + DistinguishableType : SEQUENCE LT TypeWithExtendedAttributes GT Null """ innerType = p[3] type = IDLSequenceType(self.getLocation(p, 1), innerType) @@ -7220,23 +8512,32 @@ class Parser(Tokenizer): def p_DistinguishableTypeRecordType(self, p): """ - DistinguishableType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null + DistinguishableType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null """ keyType = p[3] valueType = p[5] type = IDLRecordType(self.getLocation(p, 1), keyType, valueType) p[0] = self.handleNullable(type, p[7]) + def p_DistinguishableTypeObservableArrayType(self, p): + """ + DistinguishableType : OBSERVABLEARRAY LT TypeWithExtendedAttributes GT Null + """ + innerType = p[3] + type = IDLObservableArrayType(self.getLocation(p, 1), innerType) + p[0] = self.handleNullable(type, p[5]) + def p_DistinguishableTypeScopedName(self, p): """ - DistinguishableType : ScopedName Null + DistinguishableType : ScopedName Null """ assert isinstance(p[1], IDLUnresolvedIdentifier) if p[1].name == "Promise": - raise WebIDLError("Promise used without saying what it's " - "parametrized over", - [self.getLocation(p, 1)]) + raise WebIDLError( + "Promise used without saying what it's " "parametrized over", + [self.getLocation(p, 1)], + ) type = None @@ -7245,8 +8546,9 @@ class Parser(Tokenizer): obj = self.globalScope()._lookupIdentifier(p[1]) assert not obj.isType() if obj.isTypedef(): - type = IDLTypedefType(self.getLocation(p, 1), obj.innerType, - obj.identifier.name) + type = IDLTypedefType( + self.getLocation(p, 1), obj.innerType, obj.identifier.name + ) elif obj.isCallback() and not obj.isInterface(): type = IDLCallbackType(obj.location, obj) else: @@ -7261,13 +8563,13 @@ class Parser(Tokenizer): def p_ConstType(self, p): """ - ConstType : PrimitiveType + ConstType : PrimitiveType """ p[0] = BuiltinTypes[p[1]] def p_ConstTypeIdentifier(self, p): """ - ConstType : IDENTIFIER + ConstType : IDENTIFIER """ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) @@ -7275,110 +8577,110 @@ class Parser(Tokenizer): def p_PrimitiveTypeUint(self, p): """ - PrimitiveType : UnsignedIntegerType + PrimitiveType : UnsignedIntegerType """ p[0] = p[1] def p_PrimitiveTypeBoolean(self, p): """ - PrimitiveType : BOOLEAN + PrimitiveType : BOOLEAN """ p[0] = IDLBuiltinType.Types.boolean def p_PrimitiveTypeByte(self, p): """ - PrimitiveType : BYTE + PrimitiveType : BYTE """ p[0] = IDLBuiltinType.Types.byte def p_PrimitiveTypeOctet(self, p): """ - PrimitiveType : OCTET + PrimitiveType : OCTET """ p[0] = IDLBuiltinType.Types.octet def p_PrimitiveTypeFloat(self, p): """ - PrimitiveType : FLOAT + PrimitiveType : FLOAT """ p[0] = IDLBuiltinType.Types.float def p_PrimitiveTypeUnrestictedFloat(self, p): """ - PrimitiveType : UNRESTRICTED FLOAT + PrimitiveType : UNRESTRICTED FLOAT """ p[0] = IDLBuiltinType.Types.unrestricted_float def p_PrimitiveTypeDouble(self, p): """ - PrimitiveType : DOUBLE + PrimitiveType : DOUBLE """ p[0] = IDLBuiltinType.Types.double def p_PrimitiveTypeUnrestictedDouble(self, p): """ - PrimitiveType : UNRESTRICTED DOUBLE + PrimitiveType : UNRESTRICTED DOUBLE """ p[0] = IDLBuiltinType.Types.unrestricted_double def p_StringType(self, p): """ - StringType : BuiltinStringType + StringType : BuiltinStringType """ p[0] = BuiltinTypes[p[1]] def p_BuiltinStringTypeDOMString(self, p): """ - BuiltinStringType : DOMSTRING + BuiltinStringType : DOMSTRING """ p[0] = IDLBuiltinType.Types.domstring def p_BuiltinStringTypeBytestring(self, p): """ - BuiltinStringType : BYTESTRING + BuiltinStringType : BYTESTRING """ p[0] = IDLBuiltinType.Types.bytestring def p_BuiltinStringTypeUSVString(self, p): """ - BuiltinStringType : USVSTRING + BuiltinStringType : USVSTRING """ p[0] = IDLBuiltinType.Types.usvstring def p_BuiltinStringTypeUTF8String(self, p): """ - BuiltinStringType : UTF8STRING + BuiltinStringType : UTF8STRING """ p[0] = IDLBuiltinType.Types.utf8string def p_BuiltinStringTypeJSString(self, p): """ - BuiltinStringType : JSSTRING + BuiltinStringType : JSSTRING """ p[0] = IDLBuiltinType.Types.jsstring def p_UnsignedIntegerTypeUnsigned(self, p): """ - UnsignedIntegerType : UNSIGNED IntegerType + UnsignedIntegerType : UNSIGNED IntegerType """ # Adding one to a given signed integer type gets you the unsigned type: p[0] = p[2] + 1 def p_UnsignedIntegerType(self, p): """ - UnsignedIntegerType : IntegerType + UnsignedIntegerType : IntegerType """ p[0] = p[1] def p_IntegerTypeShort(self, p): """ - IntegerType : SHORT + IntegerType : SHORT """ p[0] = IDLBuiltinType.Types.short def p_IntegerTypeLong(self, p): """ - IntegerType : LONG OptionalLong + IntegerType : LONG OptionalLong """ if p[2]: p[0] = IDLBuiltinType.Types.long_long @@ -7387,55 +8689,43 @@ class Parser(Tokenizer): def p_OptionalLong(self, p): """ - OptionalLong : LONG + OptionalLong : LONG """ p[0] = True def p_OptionalLongEmpty(self, p): """ - OptionalLong : + OptionalLong : """ p[0] = False def p_Null(self, p): """ - Null : QUESTIONMARK - | + Null : QUESTIONMARK + | """ if len(p) > 1: p[0] = self.getLocation(p, 1) else: p[0] = None - def p_ReturnTypeType(self, p): - """ - ReturnType : Type - """ - p[0] = p[1] - - def p_ReturnTypeUndefined(self, p): - """ - ReturnType : UNDEFINED - """ - p[0] = BuiltinTypes[IDLBuiltinType.Types.undefined] - def p_ScopedName(self, p): """ - ScopedName : AbsoluteScopedName - | RelativeScopedName + ScopedName : AbsoluteScopedName + | RelativeScopedName """ p[0] = p[1] def p_AbsoluteScopedName(self, p): """ - AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts + AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts """ assert False pass def p_RelativeScopedName(self, p): """ - RelativeScopedName : IDENTIFIER ScopedNameParts + RelativeScopedName : IDENTIFIER ScopedNameParts """ assert not p[2] # Not implemented! @@ -7443,100 +8733,122 @@ class Parser(Tokenizer): def p_ScopedNameParts(self, p): """ - ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts + ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts """ assert False pass def p_ScopedNamePartsEmpty(self, p): """ - ScopedNameParts : + ScopedNameParts : """ p[0] = None def p_ExtendedAttributeNoArgs(self, p): """ - ExtendedAttributeNoArgs : IDENTIFIER + ExtendedAttributeNoArgs : IDENTIFIER """ p[0] = (p[1],) def p_ExtendedAttributeArgList(self, p): """ - ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN + ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN """ p[0] = (p[1], p[3]) def p_ExtendedAttributeIdent(self, p): """ - ExtendedAttributeIdent : IDENTIFIER EQUALS STRING - | IDENTIFIER EQUALS IDENTIFIER + ExtendedAttributeIdent : IDENTIFIER EQUALS STRING + | IDENTIFIER EQUALS IDENTIFIER + """ + p[0] = (p[1], p[3]) + + def p_ExtendedAttributeWildcard(self, p): + """ + ExtendedAttributeWildcard : IDENTIFIER EQUALS ASTERISK """ p[0] = (p[1], p[3]) def p_ExtendedAttributeNamedArgList(self, p): """ - ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN + ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN """ p[0] = (p[1], p[3], p[5]) def p_ExtendedAttributeIdentList(self, p): """ - ExtendedAttributeIdentList : IDENTIFIER EQUALS LPAREN IdentifierList RPAREN + ExtendedAttributeIdentList : IDENTIFIER EQUALS LPAREN IdentifierList RPAREN """ p[0] = (p[1], p[4]) def p_IdentifierList(self, p): """ - IdentifierList : IDENTIFIER Identifiers + IdentifierList : IDENTIFIER Identifiers """ idents = list(p[2]) # This is only used for identifier-list-valued extended attributes, and if # we're going to restrict to IDENTIFIER here we should at least allow # escaping with leading '_' as usual for identifiers. ident = p[1] - if ident[0] == '_': + if ident[0] == "_": ident = ident[1:] idents.insert(0, ident) p[0] = idents def p_IdentifiersList(self, p): """ - Identifiers : COMMA IDENTIFIER Identifiers + Identifiers : COMMA IDENTIFIER Identifiers """ idents = list(p[3]) # This is only used for identifier-list-valued extended attributes, and if # we're going to restrict to IDENTIFIER here we should at least allow # escaping with leading '_' as usual for identifiers. ident = p[2] - if ident[0] == '_': + if ident[0] == "_": ident = ident[1:] idents.insert(0, ident) p[0] = idents def p_IdentifiersEmpty(self, p): """ - Identifiers : + Identifiers : """ p[0] = [] def p_error(self, p): if not p: - raise WebIDLError("Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both", - [self._filename]) + raise WebIDLError( + "Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both", + [self._filename], + ) else: - raise WebIDLError("invalid syntax", [Location(self.lexer, p.lineno, p.lexpos, self._filename)]) + raise WebIDLError( + "invalid syntax", + [Location(self.lexer, p.lineno, p.lexpos, self._filename)], + ) - def __init__(self, outputdir='', lexer=None): - Tokenizer.__init__(self, lexer) + def __init__(self, outputdir="", lexer=None): + Tokenizer.__init__(self, outputdir, lexer) logger = SqueakyCleanLogger() try: - self.parser = yacc.yacc(module=self, errorlog=logger, debug=False) + self.parser = yacc.yacc( + module=self, + outputdir=outputdir, + errorlog=logger, + debug=False, + write_tables=False, + # Pickling the grammar is a speedup in + # some cases (older Python?) but a + # significant slowdown in others. + # We're not pickling for now, until it + # becomes a speedup again. + # , picklefile='WebIDLGrammar.pkl' + ) finally: logger.reportGrammarErrors() self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None) - self._installBuiltins(self._globalScope) self._productions = [] @@ -7550,12 +8862,16 @@ class Parser(Tokenizer): assert isinstance(scope, IDLScope) # range omits the last value. - for x in range(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): + for x in range( + IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1 + ): builtin = BuiltinTypes[x] name = builtin.name - typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name) + typedef = IDLTypedef( + BuiltinLocation("<builtin type>"), scope, builtin, name + ) - @ staticmethod + @staticmethod def handleNullable(type, questionMarkLocation): if questionMarkLocation is not None: type = IDLNullableType(questionMarkLocation, type) @@ -7563,12 +8879,12 @@ class Parser(Tokenizer): return type def parse(self, t, filename=None): - self._filename = filename - self.lexer.input(t.decode(encoding = 'utf-8')) + self.lexer.input(t) # for tok in iter(self.lexer.token, None): # print tok + self._filename = filename self._productions.extend(self.parser.parse(lexer=self.lexer, tracking=True)) self._filename = None @@ -7580,7 +8896,6 @@ class Parser(Tokenizer): if isinstance(p, IDLInterface): interfaceStatements.append(p) - iterableIteratorIface = None for iface in interfaceStatements: iterable = None # We haven't run finish() on the interface yet, so we don't know @@ -7588,26 +8903,77 @@ class Parser(Tokenizer): # means we have to loop through the members to see if we have an # iterable member. for m in iface.members: - if isinstance(m, IDLIterable): + if isinstance(m, (IDLIterable, IDLAsyncIterable)): iterable = m break - if iterable and iterable.isPairIterator(): + if iterable and (iterable.isPairIterator() or iterable.isAsyncIterable()): + def simpleExtendedAttr(str): - return IDLExtendedAttribute(iface.location, (str, )) + return IDLExtendedAttribute(iface.location, (str,)) + + if isinstance(iterable, IDLAsyncIterable): + nextReturnType = IDLPromiseType( + iterable.location, BuiltinTypes[IDLBuiltinType.Types.any] + ) + else: + nextReturnType = BuiltinTypes[IDLBuiltinType.Types.object] nextMethod = IDLMethod( - iface.location, - IDLUnresolvedIdentifier(iface.location, "next"), - BuiltinTypes[IDLBuiltinType.Types.object], []) + iterable.location, + IDLUnresolvedIdentifier(iterable.location, "next"), + nextReturnType, + [], + ) nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) - itr_ident = IDLUnresolvedIdentifier(iface.location, - iface.identifier.name + "Iterator") - toStringTag = iface.identifier.name + " Iterator" - itr_iface = IDLInterface(iface.location, self.globalScope(), - itr_ident, None, [nextMethod], - isKnownNonPartial=True, - classNameOverride=toStringTag, - toStringTag=toStringTag) - itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")]) + + methods = [nextMethod] + + if iterable.getExtendedAttribute("GenerateReturnMethod"): + assert isinstance(iterable, IDLAsyncIterable) + + returnMethod = IDLMethod( + iterable.location, + IDLUnresolvedIdentifier(iterable.location, "return"), + IDLPromiseType( + iterable.location, BuiltinTypes[IDLBuiltinType.Types.any] + ), + [ + IDLArgument( + iterable.location, + IDLUnresolvedIdentifier( + BuiltinLocation("<auto-generated-identifier>"), + "value", + ), + BuiltinTypes[IDLBuiltinType.Types.any], + optional=True, + ), + ], + ) + returnMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) + methods.append(returnMethod) + + if iterable.isIterable(): + itr_suffix = "Iterator" + else: + itr_suffix = "AsyncIterator" + itr_ident = IDLUnresolvedIdentifier( + iface.location, iface.identifier.name + itr_suffix + ) + if iterable.isIterable(): + classNameOverride = iface.identifier.name + " Iterator" + elif iterable.isAsyncIterable(): + classNameOverride = iface.identifier.name + " AsyncIterator" + itr_iface = IDLInterface( + iface.location, + self.globalScope(), + itr_ident, + None, + methods, + isKnownNonPartial=True, + classNameOverride=classNameOverride, + ) + itr_iface.addExtendedAttributes( + [simpleExtendedAttr("LegacyNoInterfaceObject")] + ) # Make sure the exposure set for the iterator interface is the # same as the exposure set for the iterable interface, because # we're going to generate methods on the iterable that return @@ -7616,17 +8982,22 @@ class Parser(Tokenizer): # Always append generated iterable interfaces after the # interface they're a member of, otherwise nativeType generation # won't work correctly. - itr_iface.iterableInterface = iface + if iterable.isIterable(): + itr_iface.iterableInterface = iface + else: + itr_iface.asyncIterableInterface = iface self._productions.append(itr_iface) iterable.iteratorType = IDLWrapperType(iface.location, itr_iface) # Make sure we finish IDLIncludesStatements before we finish the # IDLInterfaces. # XXX khuey hates this bit and wants to nuke it from orbit. - includesStatements = [p for p in self._productions if - isinstance(p, IDLIncludesStatement)] - otherStatements = [p for p in self._productions if - not isinstance(p, IDLIncludesStatement)] + includesStatements = [ + p for p in self._productions if isinstance(p, IDLIncludesStatement) + ] + otherStatements = [ + p for p in self._productions if not isinstance(p, IDLIncludesStatement) + ] for production in includesStatements: production.finish(self.globalScope()) for production in otherStatements: @@ -7650,7 +9021,6 @@ class Parser(Tokenizer): # Builtin IDL defined by WebIDL _builtins = """ - typedef unsigned long long DOMTimeStamp; typedef (ArrayBufferView or ArrayBuffer) BufferSource; """ @@ -7658,12 +9028,21 @@ class Parser(Tokenizer): def main(): # Parse arguments. from optparse import OptionParser + usageString = "usage: %prog [options] files" o = OptionParser(usage=usageString) - o.add_option("--cachedir", dest='cachedir', default=None, - help="Directory in which to cache lex/parse tables.") - o.add_option("--verbose-errors", action='store_true', default=False, - help="When an error happens, display the Python traceback.") + o.add_option( + "--cachedir", + dest="cachedir", + default=None, + help="Directory in which to cache lex/parse tables.", + ) + o.add_option( + "--verbose-errors", + action="store_true", + default=False, + help="When an error happens, display the Python traceback.", + ) (options, args) = o.parse_args() if len(args) < 1: @@ -7677,11 +9056,11 @@ def main(): try: for filename in fileList: fullPath = os.path.normpath(os.path.join(baseDir, filename)) - f = open(fullPath, 'rb') + f = open(fullPath, "rb") lines = f.readlines() f.close() print(fullPath) - parser.parse(''.join(lines), fullPath) + parser.parse("".join(lines), fullPath) parser.finish() except WebIDLError as e: if options.verbose_errors: @@ -7689,5 +9068,6 @@ def main(): else: print(e) -if __name__ == '__main__': + +if __name__ == "__main__": main() |