mirror of
https://github.com/servo/servo.git
synced 2025-08-02 20:20:14 +01:00
Auto merge of #23987 - saschanaz:update-webidl, r=jdm
Update WebIDL parser <!-- Please describe your changes on the following line: --> This includes IDL mixin support. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes does not fix but helps #22539 / fixes #16244 <!-- Either: --> - [x] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23987) <!-- Reviewable:end -->
This commit is contained in:
commit
2be3c2a1af
10 changed files with 759 additions and 164 deletions
|
@ -1576,7 +1576,7 @@ class PropertyDefiner:
|
|||
"Pref"),
|
||||
PropertyDefiner.getStringAttr(interfaceMember,
|
||||
"Func"),
|
||||
interfaceMember.exposedSet())
|
||||
interfaceMember.exposureSet)
|
||||
|
||||
def generateGuardedArray(self, array, name, specTemplate, specTerminator,
|
||||
specType, getCondition, getDataTuple):
|
||||
|
|
|
@ -314,7 +314,7 @@ class IDLScope(IDLObject):
|
|||
newObject.location)
|
||||
|
||||
raise WebIDLError(
|
||||
"Multiple unresolvable definitions of identifier '%s' in scope '%s%s"
|
||||
"Multiple unresolvable definitions of identifier '%s' in scope '%s'%s"
|
||||
% (identifier.name, str(self), conflictdesc), [])
|
||||
|
||||
def _lookupIdentifier(self, identifier):
|
||||
|
@ -605,7 +605,7 @@ class IDLPartialInterfaceOrNamespace(IDLObject):
|
|||
self._haveSecureContextExtendedAttribute = False
|
||||
self._nonPartialInterfaceOrNamespace = nonPartialInterfaceOrNamespace
|
||||
self._finished = False
|
||||
nonPartialInterfaceOrNamespace.addPartialInterface(self)
|
||||
nonPartialInterfaceOrNamespace.addPartial(self)
|
||||
|
||||
def addExtendedAttributes(self, attrs):
|
||||
for attr in attrs:
|
||||
|
@ -676,30 +676,212 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
|
|||
for name in nameSet:
|
||||
exposureSet.update(globalScope.globalNameMapping[name])
|
||||
|
||||
|
||||
class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
||||
def __init__(self, location, parentScope, name, parent, members,
|
||||
isKnownNonPartial, toStringTag):
|
||||
class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
||||
def __init__(self, location, parentScope, name):
|
||||
assert isinstance(parentScope, IDLScope)
|
||||
assert isinstance(name, IDLUnresolvedIdentifier)
|
||||
|
||||
self._finished = False
|
||||
self.members = []
|
||||
self._partials = []
|
||||
self._extendedAttrDict = {}
|
||||
self._isKnownNonPartial = False
|
||||
|
||||
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
||||
IDLExposureMixins.__init__(self, location)
|
||||
|
||||
def finish(self, scope):
|
||||
if not self._isKnownNonPartial:
|
||||
raise WebIDLError("%s does not have a non-partial declaration" %
|
||||
str(self), [self.location])
|
||||
|
||||
IDLExposureMixins.finish(self, scope)
|
||||
|
||||
# Now go ahead and merge in our partials.
|
||||
for partial in self._partials:
|
||||
partial.finish(scope)
|
||||
self.addExtendedAttributes(partial.propagatedExtendedAttrs)
|
||||
self.members.extend(partial.members)
|
||||
|
||||
def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
|
||||
assert isinstance(scope, IDLScope)
|
||||
assert isinstance(originalObject, IDLInterfaceMember)
|
||||
assert isinstance(newObject, IDLInterfaceMember)
|
||||
|
||||
retval = IDLScope.resolveIdentifierConflict(self, scope, identifier,
|
||||
originalObject, newObject)
|
||||
|
||||
# Might be a ctor, which isn't in self.members
|
||||
if newObject in self.members:
|
||||
self.members.remove(newObject)
|
||||
return retval
|
||||
|
||||
def typeName(self):
|
||||
if self.isInterface():
|
||||
return "interface"
|
||||
if self.isNamespace():
|
||||
return "namespace"
|
||||
return "interface mixin"
|
||||
|
||||
def getExtendedAttribute(self, name):
|
||||
return self._extendedAttrDict.get(name, None)
|
||||
|
||||
def setNonPartial(self, location, members):
|
||||
if self._isKnownNonPartial:
|
||||
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
|
||||
self.location = location
|
||||
# Put the new members at the beginning
|
||||
self.members = members + self.members
|
||||
|
||||
def addPartial(self, partial):
|
||||
assert self.identifier.name == partial.identifier.name
|
||||
self._partials.append(partial)
|
||||
|
||||
def getPartials(self):
|
||||
# Don't let people mutate our guts.
|
||||
return list(self._partials)
|
||||
|
||||
def finishMembers(self, scope):
|
||||
# Assuming we've merged in our partials, set the _exposureGlobalNames on
|
||||
# any members that don't have it set yet. Note that any partial
|
||||
# interfaces that had [Exposed] set have already set up
|
||||
# _exposureGlobalNames on all the members coming from them, so this is
|
||||
# just implementing the "members default to interface or interface mixin
|
||||
# that defined them" and "partial interfaces or interface mixins default
|
||||
# to interface or interface mixin they're a partial for" rules from the
|
||||
# spec.
|
||||
for m in self.members:
|
||||
# If m, or the partial m came from, had [Exposed]
|
||||
# specified, it already has a nonempty exposure global names set.
|
||||
if len(m._exposureGlobalNames) == 0:
|
||||
m._exposureGlobalNames.update(self._exposureGlobalNames)
|
||||
|
||||
# resolve() will modify self.members, so we need to iterate
|
||||
# over a copy of the member list here.
|
||||
for member in list(self.members):
|
||||
member.resolve(self)
|
||||
|
||||
for member in self.members:
|
||||
member.finish(scope)
|
||||
|
||||
# Now that we've finished our members, which has updated their exposure
|
||||
# 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])
|
||||
|
||||
|
||||
class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
|
||||
def __init__(self, location, parentScope, name, members, isKnownNonPartial):
|
||||
self.actualExposureGlobalNames = set()
|
||||
|
||||
assert isKnownNonPartial or len(members) == 0
|
||||
IDLInterfaceOrInterfaceMixinOrNamespace.__init__(self, location, parentScope, name)
|
||||
|
||||
if isKnownNonPartial:
|
||||
self.setNonPartial(location, members)
|
||||
|
||||
def __str__(self):
|
||||
return "Interface mixin '%s'" % self.identifier.name
|
||||
|
||||
def finish(self, scope):
|
||||
if self._finished:
|
||||
return
|
||||
self._finished = True
|
||||
|
||||
# Expose to the globals of interfaces that includes this mixin if this
|
||||
# mixin has no explicit [Exposed] so that its members can be exposed
|
||||
# based on the base interface exposure set.
|
||||
# Make sure this is done before IDLExposureMixins.finish call to
|
||||
# prevent exposing to PrimaryGlobal by default.
|
||||
hasImplicitExposure = len(self._exposureGlobalNames) == 0
|
||||
if hasImplicitExposure:
|
||||
self._exposureGlobalNames.update(self.actualExposureGlobalNames)
|
||||
|
||||
IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope)
|
||||
|
||||
self.finishMembers(scope)
|
||||
|
||||
def validate(self):
|
||||
for member in self.members:
|
||||
|
||||
if member.isAttr():
|
||||
if member.inherit:
|
||||
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])
|
||||
|
||||
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])
|
||||
|
||||
def addExtendedAttributes(self, attrs):
|
||||
for attr in attrs:
|
||||
identifier = attr.identifier()
|
||||
|
||||
if identifier == "SecureContext":
|
||||
if not attr.noArguments():
|
||||
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])
|
||||
member.addExtendedAttributes([attr])
|
||||
elif identifier == "Exposed":
|
||||
convertExposedAttrToGlobalNameSet(attr,
|
||||
self._exposureGlobalNames)
|
||||
else:
|
||||
raise WebIDLError("Unknown extended attribute %s on interface" % identifier,
|
||||
[attr.location])
|
||||
|
||||
attrlist = attr.listValue()
|
||||
self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True
|
||||
|
||||
def _getDependentObjects(self):
|
||||
return set(self.members)
|
||||
|
||||
|
||||
class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
|
||||
def __init__(self, location, parentScope, name, parent, members,
|
||||
isKnownNonPartial, toStringTag):
|
||||
assert isKnownNonPartial or not parent
|
||||
assert isKnownNonPartial or len(members) == 0
|
||||
|
||||
self.parent = None
|
||||
self._callback = False
|
||||
self._finished = False
|
||||
self.members = []
|
||||
self.maplikeOrSetlikeOrIterable = None
|
||||
self._partialInterfaces = []
|
||||
self._extendedAttrDict = {}
|
||||
# namedConstructors needs deterministic ordering because bindings code
|
||||
# outputs the constructs in the order that namedConstructors enumerates
|
||||
# them.
|
||||
self.namedConstructors = list()
|
||||
self.legacyWindowAliases = []
|
||||
self.implementedInterfaces = set()
|
||||
self.includedMixins = set()
|
||||
self._consequential = False
|
||||
self._isKnownNonPartial = False
|
||||
# self.interfacesBasedOnSelf is the set of interfaces that inherit from
|
||||
# self or have self as a consequential interface, including self itself.
|
||||
# Used for distinguishability checking.
|
||||
|
@ -720,8 +902,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
|
||||
self.toStringTag = toStringTag
|
||||
|
||||
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
||||
IDLExposureMixins.__init__(self, location)
|
||||
IDLInterfaceOrInterfaceMixinOrNamespace.__init__(self, location, parentScope, name)
|
||||
|
||||
if isKnownNonPartial:
|
||||
self.setNonPartial(location, parent, members)
|
||||
|
@ -741,31 +922,13 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
def isIteratorInterface(self):
|
||||
return self.iterableInterface is not None
|
||||
|
||||
def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject):
|
||||
assert isinstance(scope, IDLScope)
|
||||
assert isinstance(originalObject, IDLInterfaceMember)
|
||||
assert isinstance(newObject, IDLInterfaceMember)
|
||||
|
||||
retval = IDLScope.resolveIdentifierConflict(self, scope, identifier,
|
||||
originalObject, newObject)
|
||||
|
||||
# Might be a ctor, which isn't in self.members
|
||||
if newObject in self.members:
|
||||
self.members.remove(newObject)
|
||||
return retval
|
||||
|
||||
def finish(self, scope):
|
||||
if self._finished:
|
||||
return
|
||||
|
||||
self._finished = True
|
||||
|
||||
if not self._isKnownNonPartial:
|
||||
raise WebIDLError("Interface %s does not have a non-partial "
|
||||
"declaration" % self.identifier.name,
|
||||
[self.location])
|
||||
|
||||
IDLExposureMixins.finish(self, scope)
|
||||
IDLInterfaceOrInterfaceMixinOrNamespace.finish(self, scope)
|
||||
|
||||
if len(self.legacyWindowAliases) > 0:
|
||||
if not self.hasInterfaceObject():
|
||||
|
@ -777,12 +940,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
"but not exposed in Window" % self.identifier.name,
|
||||
[self.location])
|
||||
|
||||
# Now go ahead and merge in our partial interfaces.
|
||||
for partial in self._partialInterfaces:
|
||||
partial.finish(scope)
|
||||
self.addExtendedAttributes(partial.propagatedExtendedAttrs)
|
||||
self.members.extend(partial.members)
|
||||
|
||||
# Generate maplike/setlike interface members. Since generated members
|
||||
# need to be treated like regular interface members, do this before
|
||||
# things like exposure setting.
|
||||
|
@ -804,19 +961,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
# our required methods in Codegen. Generate members now.
|
||||
self.maplikeOrSetlikeOrIterable.expand(self.members, self.isJSImplemented())
|
||||
|
||||
# Now that we've merged in our partial interfaces, set the
|
||||
# _exposureGlobalNames on any members that don't have it set yet. Note
|
||||
# that any partial interfaces that had [Exposed] set have already set up
|
||||
# _exposureGlobalNames on all the members coming from them, so this is
|
||||
# just implementing the "members default to interface that defined them"
|
||||
# and "partial interfaces default to interface they're a partial for"
|
||||
# rules from the spec.
|
||||
for m in self.members:
|
||||
# If m, or the partial interface m came from, had [Exposed]
|
||||
# specified, it already has a nonempty exposure global names set.
|
||||
if len(m._exposureGlobalNames) == 0:
|
||||
m._exposureGlobalNames.update(self._exposureGlobalNames)
|
||||
|
||||
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):
|
||||
|
@ -912,6 +1056,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
|
||||
for iface in self.implementedInterfaces:
|
||||
iface.finish(scope)
|
||||
for mixin in self.includedMixins:
|
||||
mixin.finish(scope)
|
||||
|
||||
cycleInGraph = self.findInterfaceLoopPoint(self)
|
||||
if cycleInGraph:
|
||||
|
@ -926,24 +1072,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
# And that we're not consequential.
|
||||
assert not self.isConsequential()
|
||||
|
||||
# Now resolve() and finish() our members before importing the
|
||||
# ones from our implemented interfaces.
|
||||
|
||||
# resolve() will modify self.members, so we need to iterate
|
||||
# over a copy of the member list here.
|
||||
for member in list(self.members):
|
||||
member.resolve(self)
|
||||
|
||||
for member in self.members:
|
||||
member.finish(scope)
|
||||
|
||||
# Now that we've finished our members, which has updated their exposure
|
||||
# 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 member has larger exposure set "
|
||||
"than the interface itself",
|
||||
[member.location, self.location])
|
||||
self.finishMembers(scope)
|
||||
|
||||
ctor = self.ctor()
|
||||
if ctor is not None:
|
||||
|
@ -996,6 +1125,10 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
self.members.extend(additionalMembers)
|
||||
iface.interfacesImplementingSelf.add(self)
|
||||
|
||||
for mixin in sorted(self.includedMixins,
|
||||
key=lambda x: x.identifier.name):
|
||||
self.members.extend(mixin.members)
|
||||
|
||||
for ancestor in self.getInheritedInterfaces():
|
||||
ancestor.interfacesBasedOnSelf.add(self)
|
||||
if (ancestor.maplikeOrSetlikeOrIterable is not None and
|
||||
|
@ -1430,6 +1563,10 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
assert(isinstance(implementedInterface, IDLInterface))
|
||||
self.implementedInterfaces.add(implementedInterface)
|
||||
|
||||
def addIncludedMixin(self, includedMixin):
|
||||
assert(isinstance(includedMixin, IDLInterfaceMixin))
|
||||
self.includedMixins.add(includedMixin)
|
||||
|
||||
def getInheritedInterfaces(self):
|
||||
"""
|
||||
Returns a list of the interfaces this interface inherits from
|
||||
|
@ -1478,34 +1615,11 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
if loopPoint:
|
||||
return loopPoint
|
||||
return None
|
||||
|
||||
def getExtendedAttribute(self, name):
|
||||
return self._extendedAttrDict.get(name, None)
|
||||
|
||||
def setNonPartial(self, location, parent, members):
|
||||
assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
|
||||
if self._isKnownNonPartial:
|
||||
raise WebIDLError("Two non-partial definitions for the "
|
||||
"same %s" %
|
||||
("interface" if self.isInterface()
|
||||
else "namespace"),
|
||||
[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
|
||||
self.location = location
|
||||
IDLInterfaceOrInterfaceMixinOrNamespace.setNonPartial(self, location, members)
|
||||
assert not self.parent
|
||||
self.parent = parent
|
||||
# Put the new members at the beginning
|
||||
self.members = members + self.members
|
||||
|
||||
def addPartialInterface(self, partial):
|
||||
assert self.identifier.name == partial.identifier.name
|
||||
self._partialInterfaces.append(partial)
|
||||
|
||||
def getPartialInterfaces(self):
|
||||
# Don't let people mutate our guts.
|
||||
return list(self._partialInterfaces)
|
||||
|
||||
def getJSImplementation(self):
|
||||
classId = self.getExtendedAttribute("JSImplementation")
|
||||
|
@ -1568,6 +1682,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
|
|||
def _getDependentObjects(self):
|
||||
deps = set(self.members)
|
||||
deps.update(self.implementedInterfaces)
|
||||
deps.update(self.includedMixins)
|
||||
if self.parent:
|
||||
deps.add(self.parent)
|
||||
return deps
|
||||
|
@ -3344,7 +3459,7 @@ class IDLBuiltinType(IDLType):
|
|||
[self.location, attribute.location])
|
||||
assert not self.nullable()
|
||||
if not attribute.hasValue():
|
||||
raise WebIDLError("[TreatNullAs] must take an identifier argument",
|
||||
raise WebIDLError("[TreatNullAs] must take an identifier argument"
|
||||
[attribute.location])
|
||||
value = attribute.value()
|
||||
if value != 'EmptyString':
|
||||
|
@ -3723,7 +3838,6 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
|||
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
|
||||
IDLExposureMixins.__init__(self, location)
|
||||
self.tag = tag
|
||||
self.exposed = set()
|
||||
if extendedAttrDict is None:
|
||||
self._extendedAttrDict = {}
|
||||
else:
|
||||
|
@ -3757,16 +3871,12 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
|||
def getExtendedAttribute(self, name):
|
||||
return self._extendedAttrDict.get(name, None)
|
||||
|
||||
def exposedSet(self):
|
||||
return self.exposed
|
||||
|
||||
def finish(self, scope):
|
||||
# We better be exposed _somewhere_.
|
||||
if (len(self._exposureGlobalNames) == 0):
|
||||
print(self.identifier.name)
|
||||
assert len(self._exposureGlobalNames) != 0
|
||||
IDLExposureMixins.finish(self, scope)
|
||||
globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposed)
|
||||
|
||||
def validate(self):
|
||||
if self.isAttr() or self.isMethod():
|
||||
|
@ -5433,6 +5543,49 @@ class IDLImplementsStatement(IDLObject):
|
|||
"allowed on implements statements",
|
||||
[attrs[0].location, self.location])
|
||||
|
||||
class IDLIncludesStatement(IDLObject):
|
||||
def __init__(self, location, interface, mixin):
|
||||
IDLObject.__init__(self, location)
|
||||
self.interface = interface
|
||||
self.mixin = mixin
|
||||
self._finished = False
|
||||
|
||||
def finish(self, scope):
|
||||
if self._finished:
|
||||
return
|
||||
self._finished = True
|
||||
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])
|
||||
if interface.isCallback():
|
||||
raise WebIDLError("Left-hand side of 'includes' is a callback "
|
||||
"interface",
|
||||
[self.interface.location])
|
||||
if not isinstance(mixin, IDLInterfaceMixin):
|
||||
raise WebIDLError("Right-hand side of 'includes' is not an "
|
||||
"interface mixin",
|
||||
[self.mixin.location])
|
||||
mixin.actualExposureGlobalNames.update(interface._exposureGlobalNames)
|
||||
interface.addIncludedMixin(mixin)
|
||||
self.interface = interface
|
||||
self.mixin = mixin
|
||||
|
||||
def validate(self):
|
||||
pass
|
||||
|
||||
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])
|
||||
|
||||
class IDLExtendedAttribute(IDLObject):
|
||||
"""
|
||||
|
@ -5529,12 +5682,14 @@ class Tokenizer(object):
|
|||
"module": "MODULE",
|
||||
"interface": "INTERFACE",
|
||||
"partial": "PARTIAL",
|
||||
"mixin": "MIXIN",
|
||||
"dictionary": "DICTIONARY",
|
||||
"exception": "EXCEPTION",
|
||||
"enum": "ENUM",
|
||||
"callback": "CALLBACK",
|
||||
"typedef": "TYPEDEF",
|
||||
"implements": "IMPLEMENTS",
|
||||
"includes": "INCLUDES",
|
||||
"const": "CONST",
|
||||
"null": "NULL",
|
||||
"true": "TRUE",
|
||||
|
@ -5689,7 +5844,7 @@ class Parser(Tokenizer):
|
|||
|
||||
def p_Definition(self, p):
|
||||
"""
|
||||
Definition : CallbackOrInterface
|
||||
Definition : CallbackOrInterfaceOrMixin
|
||||
| Namespace
|
||||
| Partial
|
||||
| Dictionary
|
||||
|
@ -5697,13 +5852,14 @@ class Parser(Tokenizer):
|
|||
| Enum
|
||||
| Typedef
|
||||
| ImplementsStatement
|
||||
| IncludesStatement
|
||||
"""
|
||||
p[0] = p[1]
|
||||
assert p[1] # We might not have implemented something ...
|
||||
|
||||
def p_CallbackOrInterfaceCallback(self, p):
|
||||
def p_CallbackOrInterfaceOrMixinCallback(self, p):
|
||||
"""
|
||||
CallbackOrInterface : CALLBACK CallbackRestOrInterface
|
||||
CallbackOrInterfaceOrMixin : CALLBACK CallbackRestOrInterface
|
||||
"""
|
||||
if p[2].isInterface():
|
||||
assert isinstance(p[2], IDLInterface)
|
||||
|
@ -5711,17 +5867,17 @@ class Parser(Tokenizer):
|
|||
|
||||
p[0] = p[2]
|
||||
|
||||
def p_CallbackOrInterfaceInterface(self, p):
|
||||
def p_CallbackOrInterfaceOrMixinInterfaceOrMixin(self, p):
|
||||
"""
|
||||
CallbackOrInterface : Interface
|
||||
CallbackOrInterfaceOrMixin : INTERFACE InterfaceOrMixin
|
||||
"""
|
||||
p[0] = p[1]
|
||||
p[0] = p[2]
|
||||
|
||||
def p_CallbackRestOrInterface(self, p):
|
||||
"""
|
||||
CallbackRestOrInterface : CallbackRest
|
||||
| CallbackConstructorRest
|
||||
| Interface
|
||||
| CallbackInterface
|
||||
"""
|
||||
assert p[1]
|
||||
p[0] = p[1]
|
||||
|
@ -5762,14 +5918,27 @@ class Parser(Tokenizer):
|
|||
# True for isKnownNonPartial
|
||||
return constructor(*(constructorArgs + [True]))
|
||||
|
||||
def p_Interface(self, p):
|
||||
def p_InterfaceOrMixin(self, p):
|
||||
"""
|
||||
Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
|
||||
InterfaceOrMixin : InterfaceRest
|
||||
| MixinRest
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_CallbackInterface(self, p):
|
||||
"""
|
||||
CallbackInterface : INTERFACE InterfaceRest
|
||||
"""
|
||||
p[0] = p[2]
|
||||
|
||||
def p_InterfaceRest(self, p):
|
||||
"""
|
||||
InterfaceRest : IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON
|
||||
"""
|
||||
location = self.getLocation(p, 1)
|
||||
identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
|
||||
members = p[5]
|
||||
parent = p[3]
|
||||
identifier = IDLUnresolvedIdentifier(location, p[1])
|
||||
members = p[4]
|
||||
parent = p[2]
|
||||
|
||||
p[0] = self.handleNonPartialObject(
|
||||
location, identifier, IDLInterface,
|
||||
|
@ -5778,10 +5947,10 @@ class Parser(Tokenizer):
|
|||
|
||||
def p_InterfaceForwardDecl(self, p):
|
||||
"""
|
||||
Interface : INTERFACE IDENTIFIER SEMICOLON
|
||||
InterfaceRest : IDENTIFIER SEMICOLON
|
||||
"""
|
||||
location = self.getLocation(p, 1)
|
||||
identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2])
|
||||
identifier = IDLUnresolvedIdentifier(location, p[1])
|
||||
|
||||
try:
|
||||
if self.globalScope()._lookupIdentifier(identifier):
|
||||
|
@ -5799,6 +5968,19 @@ class Parser(Tokenizer):
|
|||
|
||||
p[0] = IDLExternalInterface(location, self.globalScope(), identifier)
|
||||
|
||||
def p_MixinRest(self, p):
|
||||
"""
|
||||
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, self.globalScope(), identifier, members],
|
||||
[location, members])
|
||||
|
||||
def p_Namespace(self, p):
|
||||
"""
|
||||
Namespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
|
||||
|
@ -5818,10 +6000,15 @@ class Parser(Tokenizer):
|
|||
"""
|
||||
p[0] = p[2]
|
||||
|
||||
def p_PartialDefinitionInterface(self, p):
|
||||
"""
|
||||
PartialDefinition : INTERFACE PartialInterfaceOrPartialMixin
|
||||
"""
|
||||
p[0] = p[2]
|
||||
|
||||
def p_PartialDefinition(self, p):
|
||||
"""
|
||||
PartialDefinition : PartialInterface
|
||||
| PartialNamespace
|
||||
PartialDefinition : PartialNamespace
|
||||
| PartialDictionary
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
@ -5864,32 +6051,53 @@ class Parser(Tokenizer):
|
|||
if not nonPartialObject:
|
||||
nonPartialObject = nonPartialConstructor(
|
||||
# No members, False for isKnownNonPartial
|
||||
*(nonPartialConstructorArgs + [[], False]))
|
||||
*(nonPartialConstructorArgs), members=[], isKnownNonPartial=False)
|
||||
|
||||
partialObject = None
|
||||
if isinstance(nonPartialObject, IDLDictionary):
|
||||
partialObject = IDLPartialDictionary(
|
||||
*(partialConstructorArgs + [nonPartialObject]))
|
||||
elif isinstance(nonPartialObject, (IDLInterface, IDLNamespace)):
|
||||
elif isinstance(nonPartialObject, (IDLInterface, IDLInterfaceMixin, IDLNamespace)):
|
||||
partialObject = IDLPartialInterfaceOrNamespace(
|
||||
*(partialConstructorArgs + [nonPartialObject]))
|
||||
else:
|
||||
raise WebIDLError("Unknown partial object type %s" %
|
||||
type(partialObject))
|
||||
type(partialObject),
|
||||
[location])
|
||||
|
||||
return partialObject
|
||||
|
||||
def p_PartialInterface(self, p):
|
||||
def p_PartialInterfaceOrPartialMixin(self, p):
|
||||
"""
|
||||
PartialInterface : INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
|
||||
PartialInterfaceOrPartialMixin : PartialInterfaceRest
|
||||
| PartialMixinRest
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_PartialInterfaceRest(self, p):
|
||||
"""
|
||||
PartialInterfaceRest : IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON
|
||||
"""
|
||||
location = self.getLocation(p, 1)
|
||||
identifier = IDLUnresolvedIdentifier(location, p[1])
|
||||
members = p[3]
|
||||
|
||||
p[0] = self.handlePartialObject(
|
||||
location, identifier, IDLInterface,
|
||||
[location, self.globalScope(), identifier, None],
|
||||
[location, identifier, members])
|
||||
|
||||
def p_PartialMixinRest(self, p):
|
||||
"""
|
||||
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, IDLInterface,
|
||||
[location, self.globalScope(), identifier, None],
|
||||
location, identifier, IDLInterfaceMixin,
|
||||
[location, self.globalScope(), identifier],
|
||||
[location, identifier, members])
|
||||
|
||||
def p_PartialNamespace(self, p):
|
||||
|
@ -5934,7 +6142,7 @@ class Parser(Tokenizer):
|
|||
"""
|
||||
InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers
|
||||
"""
|
||||
p[0] = [p[2]] if p[2] else []
|
||||
p[0] = [p[2]]
|
||||
|
||||
assert not p[1] or p[2]
|
||||
p[2].addExtendedAttributes(p[1])
|
||||
|
@ -5954,6 +6162,32 @@ class Parser(Tokenizer):
|
|||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
|
||||
def p_MixinMembersEmpty(self, p):
|
||||
"""
|
||||
MixinMembers :
|
||||
"""
|
||||
p[0] = []
|
||||
|
||||
def p_MixinMembers(self, p):
|
||||
"""
|
||||
MixinMembers : ExtendedAttributeList MixinMember MixinMembers
|
||||
"""
|
||||
p[0] = [p[2]]
|
||||
|
||||
assert not p[1] or p[2]
|
||||
p[2].addExtendedAttributes(p[1])
|
||||
|
||||
p[0].extend(p[3])
|
||||
|
||||
def p_MixinMember(self, p):
|
||||
"""
|
||||
MixinMember : Const
|
||||
| Attribute
|
||||
| Operation
|
||||
"""
|
||||
p[0] = p[1]
|
||||
|
||||
def p_Dictionary(self, p):
|
||||
"""
|
||||
Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON
|
||||
|
@ -6130,6 +6364,15 @@ class Parser(Tokenizer):
|
|||
p[0] = IDLImplementsStatement(self.getLocation(p, 1), implementor,
|
||||
implementee)
|
||||
|
||||
def p_IncludesStatement(self, p):
|
||||
"""
|
||||
IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON
|
||||
"""
|
||||
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
|
||||
|
@ -7260,10 +7503,17 @@ class Parser(Tokenizer):
|
|||
# XXX khuey hates this bit and wants to nuke it from orbit.
|
||||
implementsStatements = [p for p in self._productions if
|
||||
isinstance(p, IDLImplementsStatement)]
|
||||
# Make sure we finish IDLIncludesStatements before we finish the
|
||||
# IDLInterfaces.
|
||||
includesStatements = [p for p in self._productions if
|
||||
isinstance(p, IDLIncludesStatement)]
|
||||
otherStatements = [p for p in self._productions if
|
||||
not isinstance(p, IDLImplementsStatement)]
|
||||
not isinstance(p, (IDLImplementsStatement,
|
||||
IDLIncludesStatement))]
|
||||
for production in implementsStatements:
|
||||
production.finish(self.globalScope())
|
||||
for production in includesStatements:
|
||||
production.finish(self.globalScope())
|
||||
for production in otherStatements:
|
||||
production.finish(self.globalScope())
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- WebIDL.py
|
||||
+++ WebIDL.py
|
||||
@@ -1768,7 +1768,8 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
||||
@@ -1883,7 +1883,8 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
||||
identifier == "LegacyUnenumerableNamedProperties" or
|
||||
identifier == "RunConstructorInCallerCompartment" or
|
||||
identifier == "WantsEventListenerHooks" or
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- WebIDL.py
|
||||
+++ WebIDL.py
|
||||
@@ -7123,7 +7123,8 @@ class Parser(Tokenizer):
|
||||
@@ -7382,7 +7382,8 @@ class Parser(Tokenizer):
|
||||
self.parser = yacc.yacc(module=self,
|
||||
outputdir=outputdir,
|
||||
tabmodule='webidlyacc',
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
--- WebIDL.py
|
||||
+++ WebIDL.py
|
||||
@@ -3653,6 +3653,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
|
||||
IDLExposureMixins.__init__(self, location)
|
||||
self.tag = tag
|
||||
+ self.exposed = set()
|
||||
if extendedAttrDict is None:
|
||||
self._extendedAttrDict = {}
|
||||
else:
|
||||
@@ -3686,12 +3687,16 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
def getExtendedAttribute(self, name):
|
||||
return self._extendedAttrDict.get(name, None)
|
||||
|
||||
+ def exposedSet(self):
|
||||
+ return self.exposed
|
||||
+
|
||||
def finish(self, scope):
|
||||
# We better be exposed _somewhere_.
|
||||
if (len(self._exposureGlobalNames) == 0):
|
||||
print self.identifier.name
|
||||
assert len(self._exposureGlobalNames) != 0
|
||||
IDLExposureMixins.finish(self, scope)
|
||||
+ globalNameSetToExposureSet(scope, self._exposureGlobalNames, self.exposed)
|
||||
|
||||
def validate(self):
|
||||
if self.isAttr() or self.isMethod():
|
|
@ -1,6 +1,6 @@
|
|||
--- WebIDL.py
|
||||
+++ WebIDL.py
|
||||
@@ -1769,7 +1769,8 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
||||
@@ -1884,7 +1884,8 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
||||
identifier == "RunConstructorInCallerCompartment" or
|
||||
identifier == "WantsEventListenerHooks" or
|
||||
identifier == "Serializable" or
|
||||
|
|
|
@ -44,8 +44,8 @@ def WebIDLTest(parser, harness):
|
|||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except Exception as exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
exception = e
|
||||
|
||||
harness.ok(exception, "Should have thrown.")
|
||||
harness.check(exception.message,
|
||||
|
@ -70,8 +70,8 @@ def WebIDLTest(parser, harness):
|
|||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except Exception as exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
exception = e
|
||||
|
||||
harness.ok(exception, "Should have thrown (2).")
|
||||
harness.check(exception.message,
|
||||
|
@ -100,8 +100,8 @@ def WebIDLTest(parser, harness):
|
|||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except Exception as exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
exception = e
|
||||
|
||||
harness.ok(exception, "Should have thrown (3).")
|
||||
harness.check(exception.message,
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
import WebIDL
|
||||
|
||||
def WebIDLTest(parser, harness):
|
||||
parser.parse("interface mixin Foo { };")
|
||||
results = parser.finish()
|
||||
harness.ok(True, "Empty interface mixin parsed without error.")
|
||||
harness.check(len(results), 1, "Should be one production")
|
||||
harness.ok(isinstance(results[0], WebIDL.IDLInterfaceMixin),
|
||||
"Should be an IDLInterfaceMixin")
|
||||
mixin = results[0]
|
||||
harness.check(mixin.identifier.QName(), "::Foo", "Interface mixin has the right QName")
|
||||
harness.check(mixin.identifier.name, "Foo", "Interface mixin has the right name")
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
interface mixin QNameBase {
|
||||
const long foo = 3;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
harness.check(len(results), 1, "Should be one productions")
|
||||
harness.ok(isinstance(results[0], WebIDL.IDLInterfaceMixin),
|
||||
"Should be an IDLInterfaceMixin")
|
||||
harness.check(len(results[0].members), 1, "Expect 1 productions")
|
||||
mixin = results[0]
|
||||
harness.check(mixin.members[0].identifier.QName(), "::QNameBase::foo",
|
||||
"Member has the right QName")
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
interface mixin A {
|
||||
readonly attribute boolean x;
|
||||
void foo();
|
||||
};
|
||||
partial interface mixin A {
|
||||
readonly attribute boolean y;
|
||||
void foo(long arg);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
harness.check(len(results), 2,
|
||||
"Should have two results with partial interface mixin")
|
||||
mixin = results[0]
|
||||
harness.check(len(mixin.members), 3,
|
||||
"Should have three members with partial interface mixin")
|
||||
harness.check(mixin.members[0].identifier.name, "x",
|
||||
"First member should be x with partial interface mixin")
|
||||
harness.check(mixin.members[1].identifier.name, "foo",
|
||||
"Second member should be foo with partial interface mixin")
|
||||
harness.check(len(mixin.members[1].signatures()), 2,
|
||||
"Should have two foo signatures with partial interface mixin")
|
||||
harness.check(mixin.members[2].identifier.name, "y",
|
||||
"Third member should be y with partial interface mixin")
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
partial interface mixin A {
|
||||
readonly attribute boolean y;
|
||||
void foo(long arg);
|
||||
};
|
||||
interface mixin A {
|
||||
readonly attribute boolean x;
|
||||
void foo();
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
harness.check(len(results), 2,
|
||||
"Should have two results with reversed partial interface mixin")
|
||||
mixin = results[1]
|
||||
harness.check(len(mixin.members), 3,
|
||||
"Should have three members with reversed partial interface mixin")
|
||||
harness.check(mixin.members[0].identifier.name, "x",
|
||||
"First member should be x with reversed partial interface mixin")
|
||||
harness.check(mixin.members[1].identifier.name, "foo",
|
||||
"Second member should be foo with reversed partial interface mixin")
|
||||
harness.check(len(mixin.members[1].signatures()), 2,
|
||||
"Should have two foo signatures with reversed partial interface mixin")
|
||||
harness.check(mixin.members[2].identifier.name, "y",
|
||||
"Third member should be y with reversed partial interface mixin")
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
interface Interface {};
|
||||
interface mixin Mixin {
|
||||
attribute short x;
|
||||
};
|
||||
Interface includes Mixin;
|
||||
""")
|
||||
results = parser.finish()
|
||||
iface = results[0]
|
||||
harness.check(len(iface.members), 1, "Should merge members from mixins")
|
||||
harness.check(iface.members[0].identifier.name, "x",
|
||||
"Should merge members from mixins")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin A {
|
||||
readonly attribute boolean x;
|
||||
};
|
||||
interface mixin A {
|
||||
readonly attribute boolean y;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow two non-partial interface mixins with the same name")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
partial interface mixin A {
|
||||
readonly attribute boolean x;
|
||||
};
|
||||
partial interface mixin A {
|
||||
readonly attribute boolean y;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Must have a non-partial interface mixin for a given name")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
dictionary A {
|
||||
boolean x;
|
||||
};
|
||||
partial interface mixin A {
|
||||
readonly attribute boolean y;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow a name collision between partial interface "
|
||||
"mixin and other object")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
dictionary A {
|
||||
boolean x;
|
||||
};
|
||||
interface mixin A {
|
||||
readonly attribute boolean y;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow a name collision between interface mixin "
|
||||
"and other object")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin A {
|
||||
readonly attribute boolean x;
|
||||
};
|
||||
interface A;
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow a name collision between external interface "
|
||||
"and interface mixin")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[SomeRandomAnnotation]
|
||||
interface mixin A {
|
||||
readonly attribute boolean y;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow unknown extended attributes on interface mixins")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin A {
|
||||
getter double (DOMString propertyName);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow getters on interface mixins")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin A {
|
||||
setter void (DOMString propertyName, double propertyValue);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow setters on interface mixins")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin A {
|
||||
deleter void (DOMString propertyName);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow deleters on interface mixins")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin A {
|
||||
legacycaller double compute(double x);
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow legacycallers on interface mixins")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin A {
|
||||
inherit attribute x;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow inherited attribute on interface mixins")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface Interface {};
|
||||
interface NotMixin {
|
||||
attribute short x;
|
||||
};
|
||||
Interface includes NotMixin;
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should fail if the right side does not point an interface mixin")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin NotInterface {};
|
||||
interface mixin Mixin {
|
||||
attribute short x;
|
||||
};
|
||||
NotInterface includes Mixin;
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should fail if the left side does not point an interface")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin Mixin {
|
||||
iterable<DOMString>;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should fail if an interface mixin includes iterable")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin Mixin {
|
||||
setlike<DOMString>;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should fail if an interface mixin includes setlike")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface mixin Mixin {
|
||||
maplike<DOMString, DOMString>;
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should fail if an interface mixin includes maplike")
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
[Global] interface Window {};
|
||||
[Global] interface Worker {};
|
||||
[Exposed=Window]
|
||||
interface Base {};
|
||||
interface mixin Mixin {
|
||||
Base returnSelf();
|
||||
};
|
||||
Base includes Mixin;
|
||||
""")
|
||||
results = parser.finish()
|
||||
base = results[2]
|
||||
attr = base.members[0]
|
||||
harness.check(attr.exposureSet, set(["Window"]),
|
||||
"Should expose on globals where the base interfaces are exposed")
|
||||
|
||||
parser = parser.reset()
|
||||
parser.parse("""
|
||||
[Global] interface Window {};
|
||||
[Global] interface Worker {};
|
||||
[Exposed=Window]
|
||||
interface Base {};
|
||||
[Exposed=Window]
|
||||
interface mixin Mixin {
|
||||
attribute short a;
|
||||
};
|
||||
Base includes Mixin;
|
||||
""")
|
||||
results = parser.finish()
|
||||
base = results[2]
|
||||
attr = base.members[0]
|
||||
harness.check(attr.exposureSet, set(["Window"]),
|
||||
"Should follow [Exposed] on interface mixin")
|
|
@ -1,8 +1,8 @@
|
|||
--- WebIDL.py
|
||||
+++ WebIDL.py
|
||||
@@ -2613,10 +2613,18 @@ class IDLUnionType(IDLType):
|
||||
@@ -2624,10 +2624,18 @@ class IDLUnionType(IDLType):
|
||||
return type.name
|
||||
|
||||
|
||||
for (i, type) in enumerate(self.memberTypes):
|
||||
- if not type.isComplete():
|
||||
+ # Exclude typedefs because if given "typedef (B or C) test",
|
||||
|
|
|
@ -4,7 +4,6 @@ patch < debug.patch
|
|||
patch < callback-location.patch
|
||||
patch < union-typedef.patch
|
||||
patch < inline.patch
|
||||
patch < exposed-globals.patch
|
||||
|
||||
wget https://hg.mozilla.org/mozilla-central/archive/tip.tar.gz/dom/bindings/parser/tests/ -O tests.tar.gz
|
||||
rm -r tests
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue