diff options
author | Ngo Iok Ui (Wu Yu Wei) <yuweiwu@pm.me> | 2024-06-15 13:22:42 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-15 04:22:42 +0000 |
commit | 8eed3b442b214f678b80dbcc7dca07eeaa1e26ff (patch) | |
tree | f8a232e86616e8e5fd234e7bbb32bed4ff7077f2 /third_party/WebIDL/WebIDL.py | |
parent | 19067366df28c9131dcbc436bc96a27e64e0a194 (diff) | |
download | servo-8eed3b442b214f678b80dbcc7dca07eeaa1e26ff.tar.gz servo-8eed3b442b214f678b80dbcc7dca07eeaa1e26ff.zip |
Update WebIDL.py (#32495)
* Update WebIDL.py
* Update WebIDL.py
* Add builtin-array.patch
* Fix CodegenRust.py and Configuration.py
* Fix missing downcasts
* mach fmt
* Update check and comment to explain why we need this check
* Update Global of DissimilarOriginWindow.webidl
Diffstat (limited to 'third_party/WebIDL/WebIDL.py')
-rw-r--r-- | third_party/WebIDL/WebIDL.py | 660 |
1 files changed, 505 insertions, 155 deletions
diff --git a/third_party/WebIDL/WebIDL.py b/third_party/WebIDL/WebIDL.py index 2d5c56f1086..482aa13bc2f 100644 --- a/third_party/WebIDL/WebIDL.py +++ b/third_party/WebIDL/WebIDL.py @@ -43,25 +43,22 @@ def parseInt(literal): return value * sign -def enum(*names, **kw): - class Foo(object): - attrs = OrderedDict() +# This is surprisingly faster than using the enum.IntEnum type (which doesn't +# support 'base' anyway) +def enum(*names, base=None): + if base is not None: + names = base.attrs + names - 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 + class CustomEnumType(object): + attrs = names def __setattr__(self, name, value): # this makes it read-only raise NotImplementedError - if "base" not in kw: - return Foo(names) - return Foo(chain(kw["base"].attrs.keys(), names)) + for v, k in enumerate(names): + setattr(CustomEnumType, k, v) + + return CustomEnumType() class WebIDLError(Exception): @@ -85,13 +82,10 @@ class Location(object): self._lineno = lineno self._lexpos = lexpos self._lexdata = lexer.lexdata - self._file = filename if filename else "<unknown>" + self.filename = filename if filename else "<unknown>" def __eq__(self, other): - return self._lexpos == other._lexpos and self._file == other._file - - def filename(self): - return self._file + return self._lexpos == other._lexpos and self.filename == other.filename def resolve(self): if self._line: @@ -110,7 +104,7 @@ class Location(object): def get(self): self.resolve() - return "%s line %s:%s" % (self._file, self._lineno, self._colno) + return "%s line %s:%s" % (self.filename, self._lineno, self._colno) def _pointerline(self): return " " * self._colno + "^" @@ -118,7 +112,7 @@ class Location(object): def __str__(self): self.resolve() return "%s line %s:%s\n%s\n%s" % ( - self._file, + self.filename, self._lineno, self._colno, self._line, @@ -127,15 +121,15 @@ class Location(object): class BuiltinLocation(object): + __slots__ = "msg", "filename" + def __init__(self, text): self.msg = text + "\n" + self.filename = "<builtin>" def __eq__(self, other): return isinstance(other, BuiltinLocation) and self.msg == other.msg - def filename(self): - return "<builtin>" - def resolve(self): pass @@ -150,12 +144,12 @@ class BuiltinLocation(object): class IDLObject(object): + __slots__ = "location", "userData", "filename" + def __init__(self, location): self.location = location - self.userData = dict() - - def filename(self): - return self.location.filename() + self.userData = {} + self.filename = location and location.filename def isInterface(self): return False @@ -220,8 +214,8 @@ class IDLObject(object): visited.add(self) deps = set() - if self.filename() != "<builtin>": - deps.add(self.filename()) + if self.filename != "<builtin>": + deps.add(self.filename) for d in self._getDependentObjects(): deps.update(d.getDeps(visited)) @@ -230,6 +224,8 @@ class IDLObject(object): class IDLScope(IDLObject): + __slots__ = "parentScope", "_name", "_dict", "globalNames", "globalNameMapping" + def __init__(self, location, parentScope, identifier): IDLObject.__init__(self, location) @@ -283,6 +279,9 @@ class IDLScope(IDLObject): self._dict[identifier.name] = replacement return + self.addNewIdentifier(identifier, object) + + def addNewIdentifier(self, identifier, object): assert object self._dict[identifier.name] = object @@ -323,6 +322,9 @@ class IDLScope(IDLObject): return originalObject.addOverload(newObject) # Default to throwing, derived classes can override. + raise self.createIdentifierConflictError(identifier, originalObject, newObject) + + def createIdentifierConflictError(self, identifier, originalObject, newObject): conflictdesc = "\n\t%s at %s\n\t%s at %s" % ( originalObject, originalObject.location, @@ -330,7 +332,7 @@ class IDLScope(IDLObject): newObject.location, ) - raise WebIDLError( + return WebIDLError( "Multiple unresolvable definitions of identifier '%s' in scope '%s'%s" % (identifier.name, str(self), conflictdesc), [], @@ -353,6 +355,8 @@ class IDLScope(IDLObject): class IDLIdentifier(IDLObject): + __slots__ = "name", "scope" + def __init__(self, location, scope, name): IDLObject.__init__(self, location) @@ -377,12 +381,14 @@ class IDLIdentifier(IDLObject): class IDLUnresolvedIdentifier(IDLObject): + __slots__ = ("name",) + def __init__( self, location, name, allowDoubleUnderscore=False, allowForbidden=False ): IDLObject.__init__(self, location) - assert len(name) > 0 + assert name if name == "__noSuchMethod__": raise WebIDLError("__noSuchMethod__ is deprecated", [location]) @@ -421,6 +427,7 @@ class IDLUnresolvedIdentifier(IDLObject): class IDLObjectWithIdentifier(IDLObject): + # no slots, incompatible with multiple inheritance def __init__(self, location, parentScope, identifier): IDLObject.__init__(self, location) @@ -438,6 +445,8 @@ class IDLObjectWithIdentifier(IDLObject): class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope): + __slots__ = () + def __init__(self, location, parentScope, identifier): assert isinstance(identifier, IDLUnresolvedIdentifier) @@ -446,6 +455,8 @@ class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope): class IDLIdentifierPlaceholder(IDLObjectWithIdentifier): + __slots__ = () + def __init__(self, location, identifier): assert isinstance(identifier, IDLUnresolvedIdentifier) IDLObjectWithIdentifier.__init__(self, location, None, identifier) @@ -453,7 +464,7 @@ class IDLIdentifierPlaceholder(IDLObjectWithIdentifier): def finish(self, scope): try: scope._lookupIdentifier(self.identifier) - except: + except Exception: raise WebIDLError( "Unresolved type '%s'." % self.identifier, [self.location] ) @@ -463,6 +474,7 @@ class IDLIdentifierPlaceholder(IDLObjectWithIdentifier): class IDLExposureMixins: + # no slots, incompatible with multiple inheritance def __init__(self, location): # _exposureGlobalNames are the global names listed in our [Exposed] # extended attribute. exposureSet is the exposure set as defined in the @@ -492,16 +504,15 @@ class IDLExposureMixins: # they don't include any globals, and we don't really want to go through # and add global interfaces and [Exposed] annotations to all those # tests. - if len(scope.globalNames) != 0: - 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], + if len(scope.globalNames) != 0 and len(self._exposureGlobalNames) == 0: + 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) @@ -546,6 +557,8 @@ class IDLExposureMixins: class IDLExternalInterface(IDLObjectWithIdentifier): + __slots__ = ("parent",) + def __init__(self, location, parentScope, identifier): assert isinstance(identifier, IDLUnresolvedIdentifier) assert isinstance(parentScope, IDLScope) @@ -596,6 +609,8 @@ class IDLExternalInterface(IDLObjectWithIdentifier): class IDLPartialDictionary(IDLObject): + __slots__ = "identifier", "members", "_nonPartialDictionary", "_finished" + def __init__(self, location, name, members, nonPartialDictionary): assert isinstance(name, IDLUnresolvedIdentifier) @@ -624,6 +639,15 @@ class IDLPartialDictionary(IDLObject): class IDLPartialInterfaceOrNamespace(IDLObject): + __slots__ = ( + "identifier", + "members", + "propagatedExtendedAttrs", + "_haveSecureContextExtendedAttribute", + "_nonPartialInterfaceOrNamespace", + "_finished", + ) + def __init__(self, location, name, members, nonPartialInterfaceOrNamespace): assert isinstance(name, IDLUnresolvedIdentifier) @@ -727,7 +751,26 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): exposureSet.update(globalScope.globalNameMapping[name]) +# Because WebIDL allows static and regular operations with the same identifier +# we use a special class to be able to store them both in the scope for the +# same identifier. +class IDLOperations: + __slots__ = "static", "regular" + + def __init__(self, static=None, regular=None): + self.static = static + self.regular = regular + + class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins): + __slots__ = ( + "_finished", + "members", + "_partials", + "_extendedAttrDict", + "_isKnownNonPartial", + ) + def __init__(self, location, parentScope, name): assert isinstance(parentScope, IDLScope) assert isinstance(name, IDLUnresolvedIdentifier) @@ -756,15 +799,66 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix self.addExtendedAttributes(partial.propagatedExtendedAttrs) self.members.extend(partial.members) + def addNewIdentifier(self, identifier, object): + if isinstance(object, IDLMethod): + if object.isStatic(): + object = IDLOperations(static=object) + else: + object = IDLOperations(regular=object) + + IDLScope.addNewIdentifier(self, identifier, object) + def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): assert isinstance(scope, IDLScope) - assert isinstance(originalObject, IDLInterfaceMember) assert isinstance(newObject, IDLInterfaceMember) + # The identifier of a regular operation or static operation must not be + # the same as the identifier of a constant or attribute. + if isinstance(newObject, IDLMethod) != isinstance( + originalObject, IDLOperations + ): + if isinstance(originalObject, IDLOperations): + if originalObject.regular is not None: + originalObject = originalObject.regular + else: + assert originalObject.static is not None + originalObject = originalObject.static + + raise self.createIdentifierConflictError( + identifier, originalObject, newObject + ) + + if isinstance(newObject, IDLMethod): + originalOperations = originalObject + if newObject.isStatic(): + if originalOperations.static is None: + originalOperations.static = newObject + return originalOperations + + originalObject = originalOperations.static + else: + if originalOperations.regular is None: + originalOperations.regular = newObject + return originalOperations + + originalObject = originalOperations.regular + + assert isinstance(originalObject, IDLMethod) + else: + assert isinstance(originalObject, IDLInterfaceMember) + retval = IDLScope.resolveIdentifierConflict( self, scope, identifier, originalObject, newObject ) + if isinstance(newObject, IDLMethod): + if newObject.isStatic(): + originalOperations.static = retval + else: + originalOperations.regular = retval + + retval = originalOperations + # Might be a ctor, which isn't in self.members if newObject in self.members: self.members.remove(newObject) @@ -842,10 +936,12 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): + __slots__ = ("actualExposureGlobalNames",) + def __init__(self, location, parentScope, name, members, isKnownNonPartial): self.actualExposureGlobalNames = set() - assert isKnownNonPartial or len(members) == 0 + assert isKnownNonPartial or not members IDLInterfaceOrInterfaceMixinOrNamespace.__init__( self, location, parentScope, name ) @@ -881,7 +977,6 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): def validate(self): for member in self.members: - if member.isAttr(): if member.inherit: raise WebIDLError( @@ -947,27 +1042,43 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace): class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): + __slots__ = ( + "parent", + "_callback", + "maplikeOrSetlikeOrIterable", + "legacyFactoryFunctions", + "legacyWindowAliases", + "includedMixins", + "interfacesBasedOnSelf", + "_hasChildInterfaces", + "_isOnGlobalProtoChain", + "totalMembersInSlots", + "_ownMembersInSlots", + "iterableInterface", + "asyncIterableInterface", + "hasCrossOriginMembers", + "hasDescendantWithCrossOriginMembers", + ) + def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial): assert isKnownNonPartial or not parent - assert isKnownNonPartial or len(members) == 0 + assert isKnownNonPartial or not members self.parent = None self._callback = False self.maplikeOrSetlikeOrIterable = None - # namedConstructors needs deterministic ordering because bindings code - # outputs the constructs in the order that namedConstructors enumerates + # legacyFactoryFunctions needs deterministic ordering because bindings code + # outputs the constructs in the order that legacyFactoryFunctions enumerates # them. - self.legacyFactoryFunctions = list() + self.legacyFactoryFunctions = [] self.legacyWindowAliases = [] self.includedMixins = set() # self.interfacesBasedOnSelf is the set of interfaces that inherit from # self, including self itself. # Used for distinguishability checking. - self.interfacesBasedOnSelf = set([self]) + self.interfacesBasedOnSelf = {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. @@ -995,8 +1106,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): self.location, "constructor", allowForbidden=True ) try: - return self._lookupIdentifier(identifier) - except: + return self._lookupIdentifier(identifier).static + except Exception: return None def isIterable(self): @@ -1234,7 +1345,11 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): 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: + if mixinMember.identifier.name == member.identifier.name and ( + not mixinMember.isMethod() + or not member.isMethod() + or mixinMember.isStatic() == member.isStatic() + ): raise WebIDLError( "Multiple definitions of %s on %s coming from 'includes' statements" % (member.identifier.name, self), @@ -1733,14 +1848,13 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): def hasInterfaceObject(self): if self.isCallback(): return self.hasConstants() - return not hasattr(self, "_noInterfaceObject") and not self.isPseudoInterface() + return not hasattr(self, "_noInterfaceObject") def hasInterfacePrototypeObject(self): return ( not self.isCallback() and not self.isNamespace() and self.getUserData("hasConcreteDescendant", False) - and not self.isPseudoInterface() ) def addIncludedMixin(self, includedMixin): @@ -1804,9 +1918,6 @@ 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) @@ -1827,12 +1938,14 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace): def isExposedConditionally(self, exclusions=[]): return any( - ((not a in exclusions) and self.getExtendedAttribute(a)) + ((a not in exclusions) and self.getExtendedAttribute(a)) for a in self.conditionExtendedAttributes ) class IDLInterface(IDLInterfaceOrNamespace): + __slots__ = ("classNameOverride",) + def __init__( self, location, @@ -1885,18 +1998,19 @@ class IDLInterface(IDLInterfaceOrNamespace): elif identifier == "LegacyFactoryFunction": if not attr.hasValue(): raise WebIDLError( - "LegacyFactoryFunction must either take an identifier or take a named argument list", + ( + "LegacyFactoryFunction must either take an " + "identifier or take a named argument list" + ), [attr.location], ) args = attr.args() if attr.hasArgs() else [] - retType = IDLWrapperType(self.location, self) - method = IDLConstructor(attr.location, args, attr.value()) method.reallyInit(self) - # Named constructors are always assumed to be able to + # Legacy factory functions are always assumed to be able to # throw (since there's no way to indicate otherwise). method.addExtendedAttributes( [IDLExtendedAttribute(self.location, ("Throws",))] @@ -1942,7 +2056,10 @@ class IDLInterface(IDLInterfaceOrNamespace): elif attr.hasArgs(): self.globalNames = attr.args() else: - self.globalNames = [self.identifier.name] + raise WebIDLError( + "[Global] must either take an identifier or take an identifier list", + [attr.location, self.location], + ) self.parentScope.addIfaceGlobalNames( self.identifier.name, self.globalNames ) @@ -2052,6 +2169,8 @@ class IDLInterface(IDLInterfaceOrNamespace): class IDLNamespace(IDLInterfaceOrNamespace): + __slots__ = () + def __init__(self, location, parentScope, name, members, isKnownNonPartial): IDLInterfaceOrNamespace.__init__( self, location, parentScope, name, None, members, isKnownNonPartial @@ -2110,6 +2229,17 @@ class IDLNamespace(IDLInterfaceOrNamespace): class IDLDictionary(IDLObjectWithScope): + __slots__ = ( + "parent", + "_finished", + "members", + "_partialDictionaries", + "_extendedAttrDict", + "needsConversionToJS", + "needsConversionFromJS", + "needsEqualityOperator", + ) + def __init__(self, location, parentScope, name, parent, members): assert isinstance(parentScope, IDLScope) assert isinstance(name, IDLUnresolvedIdentifier) @@ -2122,6 +2252,7 @@ class IDLDictionary(IDLObjectWithScope): self._extendedAttrDict = {} self.needsConversionToJS = False self.needsConversionFromJS = False + self.needsEqualityOperator = None IDLObjectWithScope.__init__(self, location, parentScope, name) @@ -2186,6 +2317,14 @@ class IDLDictionary(IDLObjectWithScope): [self.identifier.location], ) inheritedMembers.extend(ancestor.members) + if ( + self.getExtendedAttribute("GenerateEqualityOperator") + and ancestor.needsEqualityOperator is None + ): + # Store the dictionary that has the [GenerateEqualityOperator] + # extended attribute, so we can use it when generating error + # messages. + ancestor.needsEqualityOperator = self ancestor = ancestor.parent # Catch name duplication @@ -2311,6 +2450,13 @@ class IDLDictionary(IDLObjectWithScope): # implement ToJSON by converting to a JS object and # then using JSON.stringify. self.needsConversionToJS = True + elif identifier == "GenerateEqualityOperator": + if not attr.noArguments(): + raise WebIDLError( + "[GenerateEqualityOperator] must take no arguments", + [attr.location], + ) + self.needsEqualityOperator = self elif identifier == "Unsorted": if not attr.noArguments(): raise WebIDLError( @@ -2337,6 +2483,8 @@ class IDLDictionary(IDLObjectWithScope): class IDLEnum(IDLObjectWithIdentifier): + __slots__ = ("_values",) + def __init__(self, location, parentScope, name, values): assert isinstance(parentScope, IDLScope) assert isinstance(name, IDLUnresolvedIdentifier) @@ -2422,6 +2570,16 @@ class IDLType(IDLObject): "observablearray", ) + __slots__ = ( + "name", + "builtin", + "legacyNullToEmptyString", + "_clamp", + "_enforceRange", + "_allowShared", + "_extendedAttrDict", + ) + def __init__(self, location, name): IDLObject.__init__(self, location) self.name = name @@ -2625,6 +2783,8 @@ class IDLUnresolvedType(IDLType): Unresolved types are interface types """ + __slots__ = ("extraTypeAttributes",) + def __init__(self, location, name, attrs=[]): IDLType.__init__(self, location, name) self.extraTypeAttributes = attrs @@ -2636,7 +2796,7 @@ class IDLUnresolvedType(IDLType): obj = None try: obj = scope._lookupIdentifier(self.name) - except: + except Exception: raise WebIDLError("Unresolved type '%s'." % self.name, [self.location]) assert obj @@ -2652,7 +2812,6 @@ class IDLUnresolvedType(IDLType): assert self.name.name == obj.identifier.name return IDLCallbackType(obj.location, obj) - name = self.name.resolve(scope, None) return IDLWrapperType(self.location, obj) def withExtendedAttributes(self, attrs): @@ -2666,6 +2825,8 @@ class IDLUnresolvedType(IDLType): class IDLParametrizedType(IDLType): + __slots__ = "builtin", "inner" + def __init__(self, location, name, innerType): IDLType.__init__(self, location, name) self.builtin = False @@ -2689,6 +2850,8 @@ class IDLParametrizedType(IDLType): class IDLNullableType(IDLParametrizedType): + __slots__ = () + def __init__(self, location, innerType): assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] @@ -2867,6 +3030,8 @@ class IDLNullableType(IDLParametrizedType): class IDLSequenceType(IDLParametrizedType): + __slots__ = ("name",) + def __init__(self, location, parameterType): assert not parameterType.isUndefined() @@ -2927,10 +3092,17 @@ class IDLSequenceType(IDLParametrizedType): class IDLRecordType(IDLParametrizedType): + __slots__ = "keyType", "name" + def __init__(self, location, keyType, valueType): assert keyType.isString() assert keyType.isComplete() - assert not valueType.isUndefined() + + if valueType.isUndefined(): + raise WebIDLError( + "We don't support undefined as a Record's values' type", + [location, valueType.location], + ) IDLParametrizedType.__init__(self, location, valueType.name, valueType) self.keyType = keyType @@ -2984,6 +3156,9 @@ class IDLRecordType(IDLParametrizedType): if other.isUnion(): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) + if other.isCallback(): + # Let other determine if it's a LegacyTreatNonObjectAsNull callback + return other.isDistinguishableFrom(self) return ( other.isPrimitive() or other.isString() @@ -2997,6 +3172,8 @@ class IDLRecordType(IDLParametrizedType): class IDLObservableArrayType(IDLParametrizedType): + __slots__ = () + def __init__(self, location, innerType): assert not innerType.isUndefined() IDLParametrizedType.__init__(self, location, None, innerType) @@ -3063,6 +3240,14 @@ class IDLObservableArrayType(IDLParametrizedType): class IDLUnionType(IDLType): + __slots__ = ( + "memberTypes", + "hasNullableType", + "_dictionaryType", + "flatMemberTypes", + "builtin", + ) + def __init__(self, location, memberTypes): IDLType.__init__(self, location, "") self.memberTypes = memberTypes @@ -3114,19 +3299,11 @@ class IDLUnionType(IDLType): return "MaybeShared" + type.name return type.name - for (i, type) in enumerate(self.memberTypes): - # Exclude typedefs because if given "typedef (B or C) test", - # we want AOrTest, not AOrBOrC - if not type.isComplete() and not isinstance(type, IDLTypedefType): - self.memberTypes[i] = type.complete(scope) - - self.name = "Or".join(typeName(type) for type in self.memberTypes) - - # We do this again to complete the typedef types - for (i, type) in enumerate(self.memberTypes): + for i, type in enumerate(self.memberTypes): if not type.isComplete(): self.memberTypes[i] = type.complete(scope) + self.name = "Or".join(typeName(type) for type in self.memberTypes) self.flatMemberTypes = list(self.memberTypes) i = 0 while i < len(self.flatMemberTypes): @@ -3163,7 +3340,7 @@ class IDLUnionType(IDLType): continue i += 1 - for (i, t) in enumerate(self.flatMemberTypes[:-1]): + for i, t in enumerate(self.flatMemberTypes[:-1]): for u in self.flatMemberTypes[i + 1 :]: if not t.isDistinguishableFrom(u): raise WebIDLError( @@ -3191,7 +3368,8 @@ class IDLUnionType(IDLType): return True 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. + # 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])) @@ -3213,6 +3391,8 @@ class IDLUnionType(IDLType): class IDLTypedefType(IDLType): + __slots__ = "inner", "builtin" + def __init__(self, location, innerType, name): IDLType.__init__(self, location, name) self.inner = innerType @@ -3323,6 +3503,8 @@ class IDLTypedefType(IDLType): class IDLTypedef(IDLObjectWithIdentifier): + __slots__ = ("innerType",) + def __init__(self, location, parentScope, innerType, name): # Set self.innerType first, because IDLObjectWithIdentifier.__init__ # will call our __str__, which wants to use it. @@ -3355,6 +3537,8 @@ class IDLTypedef(IDLObjectWithIdentifier): class IDLWrapperType(IDLType): + __slots__ = "inner", "_identifier", "builtin" + def __init__(self, location, inner): IDLType.__init__(self, location, inner.identifier.name) self.inner = inner @@ -3452,7 +3636,7 @@ class IDLWrapperType(IDLType): or other.isSequence() or other.isRecord() ) - if self.isDictionary() and (other.nullable() or other.isUndefined()): + if self.isDictionary() and other.nullable(): return False if ( other.isPrimitive() @@ -3461,31 +3645,57 @@ class IDLWrapperType(IDLType): or other.isSequence() ): return True - if self.isDictionary(): + + # If this needs to handle other dictionary-like types we probably need + # some additional checks first. + assert self.isDictionaryLike() == ( + self.isDictionary() or self.isCallbackInterface() + ) + if self.isDictionaryLike(): + if other.isCallback(): + # Let other determine if it's a LegacyTreatNonObjectAsNull callback + return other.isDistinguishableFrom(self) + + assert ( + other.isNonCallbackInterface() + or other.isAny() + or other.isUndefined() + or other.isObject() + or other.isDictionaryLike() + ) + # At this point, dictionary-like (for 'self') and interface-like + # (for 'other') are the only two that are distinguishable. + # any is the union of all non-union types, so it's not distinguishable + # from other unions (because it is a union itself), or from all + # non-union types (because it has all of them as its members). return other.isNonCallbackInterface() - assert self.isInterface() - if other.isInterface(): + assert self.isNonCallbackInterface() + + if other.isUndefined() or other.isDictionaryLike() or other.isCallback(): + return True + + if other.isNonCallbackInterface(): if other.isSpiderMonkeyInterface(): # Just let |other| handle things return other.isDistinguishableFrom(self) + 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.isUndefined() - or other.isDictionary() - or other.isCallback() - or other.isRecord() - ): - return self.isNonCallbackInterface() + return ( + len( + self.inner.interfacesBasedOnSelf + & other.unroll().inner.interfacesBasedOnSelf + ) + == 0 + ) - # Not much else |other| can be - assert other.isObject() + # Not much else |other| can be. + # any is the union of all non-union types, so it's not distinguishable + # from other unions (because it is a union itself), or from all + # non-union types (because it has all of them as its members). + assert other.isAny() or other.isObject() return False def isExposedInAllOf(self, exposureSet): @@ -3525,6 +3735,8 @@ class IDLWrapperType(IDLType): class IDLPromiseType(IDLParametrizedType): + __slots__ = () + def __init__(self, location, innerType): IDLParametrizedType.__init__(self, location, "Promise", innerType) @@ -3578,7 +3790,6 @@ class IDLPromiseType(IDLParametrizedType): class IDLBuiltinType(IDLType): - Types = enum( # The integer types "byte", @@ -3692,6 +3903,14 @@ class IDLBuiltinType(IDLType): Types.ReadableStream: "ReadableStream", } + __slots__ = ( + "_typeTag", + "_clamped", + "_rangeEnforced", + "_withLegacyNullToEmptyString", + "_withAllowShared", + ) + def __init__( self, location, @@ -3704,9 +3923,9 @@ class IDLBuiltinType(IDLType): 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(), .withLegacyNullToEmptyString() and .withAllowShared(). + The mutually exclusive clamp/enforceRange/legacyNullToEmptyString/allowShared arguments + are used to create instances of this type with the appropriate attributes attached. Use + .clamped(), .rangeEnforced(), .withLegacyNullToEmptyString() and .withAllowShared(). attrLocation is an array of source locations of these attributes for error reporting. """ @@ -4203,6 +4422,11 @@ class NoCoercionFoundError(WebIDLError): class IDLValue(IDLObject): + __slots__ = ( + "type", + "value", + ) + def __init__(self, location, type, value): IDLObject.__init__(self, location) self.type = type @@ -4263,7 +4487,7 @@ class IDLValue(IDLObject): ) 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( @@ -4335,6 +4559,8 @@ class IDLValue(IDLObject): class IDLNullValue(IDLObject): + __slots__ = "type", "value" + def __init__(self, location): IDLObject.__init__(self, location) self.type = None @@ -4364,6 +4590,8 @@ class IDLNullValue(IDLObject): class IDLEmptySequenceValue(IDLObject): + __slots__ = "type", "value" + def __init__(self, location): IDLObject.__init__(self, location) self.type = None @@ -4377,7 +4605,7 @@ class IDLEmptySequenceValue(IDLObject): for subtype in type.unroll().flatMemberTypes: try: return self.coerceToType(subtype, location) - except: + except Exception: pass if not type.isSequence(): @@ -4394,6 +4622,8 @@ class IDLEmptySequenceValue(IDLObject): class IDLDefaultDictionaryValue(IDLObject): + __slots__ = "type", "value" + def __init__(self, location): IDLObject.__init__(self, location) self.type = None @@ -4407,7 +4637,7 @@ class IDLDefaultDictionaryValue(IDLObject): for subtype in type.unroll().flatMemberTypes: try: return self.coerceToType(subtype, location) - except: + except Exception: pass if not type.isDictionary(): @@ -4424,6 +4654,8 @@ class IDLDefaultDictionaryValue(IDLObject): class IDLUndefinedValue(IDLObject): + __slots__ = "type", "value" + def __init__(self, location): IDLObject.__init__(self, location) self.type = None @@ -4444,7 +4676,6 @@ class IDLUndefinedValue(IDLObject): class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): - Tags = enum( "Const", "Attr", "Method", "MaplikeOrSetlike", "AsyncIterable", "Iterable" ) @@ -4454,6 +4685,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): AffectsValues = ("Nothing", "Everything") DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything") + # no slots : multiple inheritance def __init__(self, location, identifier, tag, extendedAttrDict=None): IDLObjectWithIdentifier.__init__(self, location, None, identifier) IDLExposureMixins.__init__(self, location) @@ -4552,7 +4784,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): ) if affects not in IDLInterfaceMember.AffectsValues: raise WebIDLError( - "Invalid [Affects=%s] on attribute" % dependsOn, [self.location] + "Invalid [Affects=%s] on attribute" % affects, [self.location] ) self.affects = affects @@ -4573,6 +4805,14 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): + __slots__ = ( + "keyType", + "valueType", + "maplikeOrSetlikeOrIterableType", + "disallowedMemberNames", + "disallowedNonMethodNames", + ) + def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind): IDLInterfaceMember.__init__(self, location, identifier, ifaceKind) if keyType is not None: @@ -4610,7 +4850,12 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): 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()) + ( + member.isMethod() + and ( + member.isStatic() or member.isMaplikeOrSetlikeOrIterableMethod() + ) + ) or (member.isAttr() and member.isMaplikeOrSetlikeAttr()) ): raise WebIDLError( @@ -4676,9 +4921,7 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): self.disallowedNonMethodNames.append(name) # If allowExistingOperations is True, and another operation exists # with the same name as the one we're trying to add, don't add the - # maplike/setlike operation. However, if the operation is static, - # then fail by way of creating the function, which will cause a - # naming conflict, per the spec. + # maplike/setlike operation. if allowExistingOperations: for m in members: if m.identifier.name == name and m.isMethod() and not m.isStatic(): @@ -4786,6 +5029,8 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember): # Iterable adds ES6 iterator style functions and traits # (keys/values/entries/@@iterator) to an interface. class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): + __slots__ = ("iteratorType",) + def __init__(self, location, identifier, keyType, valueType, scope): IDLMaplikeOrSetlikeOrIterableBase.__init__( self, @@ -4861,6 +5106,8 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase): class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): + __slots__ = "iteratorType", "argList" + def __init__(self, location, identifier, keyType, valueType, argList, scope): for arg in argList: if not arg.optional: @@ -4945,6 +5192,8 @@ class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase): # MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface. class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): + __slots__ = "readonly", "slotIndices", "prefix" + def __init__( self, location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType ): @@ -5112,6 +5361,8 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase): class IDLConst(IDLInterfaceMember): + __slots__ = "type", "value" + def __init__(self, location, identifier, type, value): IDLInterfaceMember.__init__( self, location, identifier, IDLInterfaceMember.Tags.Const @@ -5144,7 +5395,7 @@ class IDLConst(IDLInterfaceMember): locations = [self.type.location, type.location] try: locations.append(type.inner.location) - except: + except Exception: pass raise WebIDLError("Incorrect type for constant", locations) self.type = type @@ -5184,6 +5435,21 @@ class IDLConst(IDLInterfaceMember): class IDLAttribute(IDLInterfaceMember): + __slots__ = ( + "type", + "readonly", + "inherit", + "_static", + "legacyLenientThis", + "_legacyUnforgeable", + "stringifier", + "slotIndices", + "maplikeOrSetlike", + "dependsOn", + "affects", + "bindingAliases", + ) + def __init__( self, location, @@ -5695,9 +5961,9 @@ class IDLAttribute(IDLInterfaceMember): or identifier == "SetterNeedsSubjectPrincipal" or identifier == "GetterNeedsSubjectPrincipal" or identifier == "NeedsCallerType" - or identifier == "ReturnValueNeedsContainsHack" or identifier == "BinaryName" or identifier == "NonEnumerable" + or identifier == "BindingTemplate" ): # Known attributes that we don't need to do anything with here pass @@ -5708,6 +5974,9 @@ class IDLAttribute(IDLInterfaceMember): ) IDLInterfaceMember.handleExtendedAttribute(self, attr) + def getExtendedAttributes(self): + return self._extendedAttrDict + def resolve(self, parentScope): assert isinstance(parentScope, IDLScope) self.type.resolveType(parentScope) @@ -5760,7 +6029,7 @@ class IDLAttribute(IDLInterfaceMember): "CrossOriginWritable", "SetterThrows", ] - for (key, value) in self._extendedAttrDict.items(): + for key, value in self._extendedAttrDict.items(): if key in allowedExtAttrs: if value is not True: raise WebIDLError( @@ -5772,7 +6041,7 @@ class IDLAttribute(IDLInterfaceMember): method.addExtendedAttributes( [IDLExtendedAttribute(self.location, (key,))] ) - elif not key in attributeOnlyExtAttrs: + elif key not in attributeOnlyExtAttrs: raise WebIDLError( "[%s] is currently unsupported in " "stringifier attributes, please file a bug " @@ -5783,6 +6052,18 @@ class IDLAttribute(IDLInterfaceMember): class IDLArgument(IDLObjectWithIdentifier): + __slots__ = ( + "type", + "optional", + "defaultValue", + "variadic", + "dictionaryMember", + "_isComplete", + "_allowTreatNonCallableAsNull", + "_extendedAttrDict", + "allowTypeAttributes", + ) + def __init__( self, location, @@ -5835,6 +6116,18 @@ class IDLArgument(IDLObjectWithIdentifier): "dictionary member" % identifier, [attribute.location], ) + elif self.dictionaryMember and identifier == "BinaryType": + if not len(attribute.listValue()) == 1: + raise WebIDLError( + "[%s] BinaryType must take one argument" % identifier, + [attribute.location], + ) + if not self.defaultValue: + raise WebIDLError( + "[%s] BinaryType can't be used without default value" + % identifier, + [attribute.location], + ) else: raise WebIDLError( "Unhandled extended attribute on %s" @@ -5914,6 +6207,15 @@ class IDLArgument(IDLObjectWithIdentifier): class IDLCallback(IDLObjectWithScope): + __slots__ = ( + "_returnType", + "_arguments", + "_treatNonCallableAsNull", + "_treatNonObjectAsNull", + "_isRunScriptBoundary", + "_isConstructor", + ) + def __init__( self, location, parentScope, identifier, returnType, arguments, isConstructor ): @@ -5925,7 +6227,7 @@ class IDLCallback(IDLObjectWithScope): IDLObjectWithScope.__init__(self, location, parentScope, identifier) - for (returnType, arguments) in self.signatures(): + for returnType, arguments in self.signatures(): for argument in arguments: argument.resolve(self) @@ -6011,6 +6313,8 @@ class IDLCallback(IDLObjectWithScope): class IDLCallbackType(IDLType): + __slots__ = ("callback",) + def __init__(self, location, callback): IDLType.__init__(self, location, callback.identifier.name) self.callback = callback @@ -6027,6 +6331,9 @@ class IDLCallbackType(IDLType): if other.isUnion(): # Just forward to the union; it'll deal return other.isDistinguishableFrom(self) + # Callbacks without `LegacyTreatNonObjectAsNull` are distinguishable from Dictionary likes + if other.isDictionaryLike(): + return not self.callback._treatNonObjectAsNull return ( other.isUndefined() or other.isPrimitive() @@ -6050,6 +6357,8 @@ class IDLMethodOverload: the full set of overloads. """ + __slots__ = "returnType", "arguments", "location" + def __init__(self, returnType, arguments, location): self.returnType = returnType # Clone the list of arguments, just in case @@ -6066,13 +6375,31 @@ class IDLMethodOverload: class IDLMethod(IDLInterfaceMember, IDLScope): - Special = enum( "Getter", "Setter", "Deleter", "LegacyCaller", base=IDLInterfaceMember.Special ) NamedOrIndexed = enum("Neither", "Named", "Indexed") + __slots__ = ( + "_hasOverloads", + "_overloads", + "_static", + "_getter", + "_setter", + "_deleter", + "_legacycaller", + "_stringifier", + "maplikeOrSetlikeOrIterable", + "_htmlConstructor", + "underlyingAttr", + "_specialType", + "_legacyUnforgeable", + "dependsOn", + "affects", + "aliases", + ) + def __init__( self, location, @@ -6249,7 +6576,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert isinstance(parentScope, IDLScope) IDLObjectWithIdentifier.resolve(self, parentScope) IDLScope.__init__(self, self.location, parentScope, self.identifier) - for (returnType, arguments) in self.signatures(): + for returnType, arguments in self.signatures(): for argument in arguments: argument.resolve(self) @@ -6299,22 +6626,35 @@ class IDLMethod(IDLInterfaceMember, IDLScope): if self.isLegacycaller() != method.isLegacycaller(): raise WebIDLError( - "Overloaded identifier %s appears with different values of the 'legacycaller' attribute" - % method.identifier, + ( + "Overloaded identifier %s appears with different " + "values of the 'legacycaller' attribute" % method.identifier + ), [method.location], ) # Can't overload special things! - assert not self.isGetter() - assert not method.isGetter() - assert not self.isSetter() - assert not method.isSetter() - assert not self.isDeleter() - assert not method.isDeleter() - assert not self.isStringifier() - assert not method.isStringifier() - assert not self.isHTMLConstructor() - assert not method.isHTMLConstructor() + if ( + self.isGetter() + or method.isGetter() + or self.isSetter() + or method.isSetter() + or self.isDeleter() + or method.isDeleter() + or self.isStringifier() + or method.isStringifier() + ): + raise WebIDLError( + ("Can't overload a special operation"), + [self.location, method.location], + ) + if self.isHTMLConstructor() or method.isHTMLConstructor(): + raise WebIDLError( + ( + "An interface must contain only a single operation annotated with HTMLConstructor, and no others" + ), + [self.location, method.location], + ) return self @@ -6390,7 +6730,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): variadicArgument = None arguments = overload.arguments - for (idx, argument) in enumerate(arguments): + for idx, argument in enumerate(arguments): assert argument.type.isComplete() if ( @@ -6523,8 +6863,8 @@ 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 firstSigIndex, (firstRetval, firstArgs) in enumerate(signatures[:-1]): + for secondRetval, secondArgs in signatures[firstSigIndex + 1 :]: if idx < len(firstArgs): firstType = firstArgs[idx].type else: @@ -6726,6 +7066,14 @@ class IDLMethod(IDLInterfaceMember, IDLScope): class IDLConstructor(IDLMethod): + __slots__ = ( + "_initLocation", + "_initArgs", + "_initName", + "_inited", + "_initExtendedAttrs", + ) + def __init__(self, location, args, name): # We can't actually init our IDLMethod yet, because we do not know the # return type yet. Just save the info we have for now and we will init @@ -6795,6 +7143,8 @@ class IDLConstructor(IDLMethod): class IDLIncludesStatement(IDLObject): + __slots__ = ("interface", "mixin", "_finished") + def __init__(self, location, interface, mixin): IDLObject.__init__(self, location) self.interface = interface @@ -6851,6 +7201,8 @@ class IDLExtendedAttribute(IDLObject): A class to represent IDL extended attributes so we can give them locations """ + __slots__ = ("_tuple",) + def __init__(self, location, tuple): IDLObject.__init__(self, location) self._tuple = tuple @@ -6891,7 +7243,7 @@ class IDLExtendedAttribute(IDLObject): class Tokenizer(object): - tokens = ["INTEGER", "FLOATLITERAL", "IDENTIFIER", "STRING", "WHITESPACE", "OTHER"] + tokens = ["INTEGER", "FLOATLITERAL", "IDENTIFIER", "STRING", "COMMENTS", "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" @@ -6903,7 +7255,7 @@ class Tokenizer(object): try: # Can't use int(), because that doesn't handle octal properly. t.value = parseInt(t.value) - except: + except Exception: raise WebIDLError( "Invalid integer literal", [ @@ -6930,17 +7282,19 @@ class Tokenizer(object): t.value = t.value[1:-1] return t - def t_WHITESPACE(self, t): - r"[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+" + t_ignore = "\t\n\r " + + def t_COMMENTS(self, t): + r"//[^\n]*|/\*(?s:.)*?\*/" pass def t_ELLIPSIS(self, t): r"\.\.\." - t.type = self.keywords.get(t.value) + t.type = "ELLIPSIS" return t def t_OTHER(self, t): - r"[^\t\n\r 0-9A-Z_a-z]" + r"[^0-9A-Z_a-z]" t.type = self.keywords.get(t.value, "OTHER") return t @@ -7029,7 +7383,7 @@ class Tokenizer(object): lexer=self.lexer, lineno=self.lexer.lineno, lexpos=self.lexer.lexpos, - filename=self.filename, + filename=self._filename, ) ], ) @@ -7039,14 +7393,14 @@ class Tokenizer(object): if lexer: self.lexer = lexer else: - self.lexer = lex.lex(object=self, reflags=re.DOTALL) + self.lexer = lex.lex(object=self) class SqueakyCleanLogger(object): errorWhitelist = [ - # Web IDL defines the WHITESPACE token, but doesn't actually + # Web IDL defines the COMMENTS 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 an unused token "There is 1 unused token", # Web IDL defines a OtherOrComma rule that's only used in @@ -8600,7 +8954,7 @@ class Parser(Tokenizer): type = IDLWrapperType(self.getLocation(p, 1), p[1]) p[0] = self.handleNullable(type, p[2]) return - except: + except Exception: pass type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) @@ -8863,7 +9217,10 @@ class Parser(Tokenizer): def p_error(self, p): if not p: raise WebIDLError( - "Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both", + ( + "Syntax Error at end of file. Possibly due to " + "missing semicolon(;), braces(}) or both" + ), [self._filename], ) else: @@ -8912,9 +9269,7 @@ class Parser(Tokenizer): ): builtin = BuiltinTypes[x] name = builtin.name - typedef = IDLTypedef( - BuiltinLocation("<builtin type>"), scope, builtin, name - ) + IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name) @staticmethod def handleNullable(type, questionMarkLocation): @@ -9114,13 +9469,8 @@ class Parser(Tokenizer): production.validate() # De-duplicate self._productions, without modifying its order. - seen = set() - result = [] - for p in self._productions: - if p not in seen: - seen.add(p) - result.append(p) - return result + result = dict.fromkeys(self._productions) + return list(result.keys()) def reset(self): return Parser(lexer=self.lexer) |