Remove [PrimaryGlobal]

This commit is contained in:
Kagami Sascha Rosylight 2019-10-02 18:21:34 +09:00
parent 84693d8117
commit 2660f35925
167 changed files with 417 additions and 829 deletions

View file

@ -154,6 +154,9 @@ class IDLObject(object):
def isNamespace(self):
return False
def isInterfaceMixin(self):
return False
def isEnum(self):
return False
@ -233,8 +236,6 @@ class IDLScope(IDLObject):
# A mapping from global name to the set of global interfaces
# that have that global name.
self.globalNameMapping = defaultdict(set)
self.primaryGlobalAttr = None
self.primaryGlobalName = None
def __str__(self):
return self.QName()
@ -462,8 +463,17 @@ class IDLExposureMixins():
raise WebIDLError("Unknown [Exposed] value %s" % globalName,
[self._location])
if len(self._exposureGlobalNames) == 0:
self._exposureGlobalNames.add(scope.primaryGlobalName)
# Verify that we are exposed _somwhere_ if we have some place to be
# exposed. We don't want to assert that we're definitely exposed
# because a lot of our parser tests have small-enough IDL snippets that
# 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):
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)
@ -508,17 +518,15 @@ class IDLExposureMixins():
return workerDebuggerScopes.intersection(self.exposureSet)
class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
class IDLExternalInterface(IDLObjectWithIdentifier):
def __init__(self, location, parentScope, identifier):
assert isinstance(identifier, IDLUnresolvedIdentifier)
assert isinstance(parentScope, IDLScope)
self.parent = None
IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
IDLExposureMixins.__init__(self, location)
IDLObjectWithIdentifier.resolve(self, parentScope)
def finish(self, scope):
IDLExposureMixins.finish(self, scope)
pass
def validate(self):
@ -533,9 +541,6 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
def isInterface(self):
return True
def isConsequential(self):
return False
def addExtendedAttributes(self, attrs):
if len(attrs) != 0:
raise WebIDLError("There are no extended attributes that are "
@ -554,9 +559,6 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
def hasProbablyShortLivingWrapper(self):
return False
def isSerializable(self):
return False
def _getDependentObjects(self):
return set()
@ -718,6 +720,7 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix
return "interface"
if self.isNamespace():
return "namespace"
assert self.isInterfaceMixin()
return "interface mixin"
def getExtendedAttribute(self, name):
@ -770,10 +773,13 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix
# sets, make sure they aren't exposed in places where we are not.
for member in self.members:
if not member.exposureSet.issubset(self.exposureSet):
raise WebIDLError("Interface or interface mixin member has"
raise WebIDLError("Interface or interface mixin member has "
"larger exposure set than its container",
[member.location, self.location])
def isExternal(self):
return False
class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
def __init__(self, location, parentScope, name, members, isKnownNonPartial):
@ -788,6 +794,9 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
def __str__(self):
return "Interface mixin '%s'" % self.identifier.name
def isInterfaceMixin(self):
return True
def finish(self, scope):
if self._finished:
return
@ -796,8 +805,10 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
# 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.
#
# Make sure this is done before IDLExposureMixins.finish call, since
# that converts our set of exposure global names to an actual exposure
# set.
hasImplicitExposure = len(self._exposureGlobalNames) == 0
if hasImplicitExposure:
self._exposureGlobalNames.update(self.actualExposureGlobalNames)
@ -876,16 +887,11 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
# them.
self.namedConstructors = list()
self.legacyWindowAliases = []
self.implementedInterfaces = set()
self.includedMixins = set()
self._consequential = False
# self.interfacesBasedOnSelf is the set of interfaces that inherit from
# self or have self as a consequential interface, including self itself.
# self, including self itself.
# Used for distinguishability checking.
self.interfacesBasedOnSelf = set([self])
# self.interfacesImplementingSelf is the set of interfaces that directly
# have self as a consequential interface
self.interfacesImplementingSelf = set()
self._hasChildInterfaces = False
self._isOnGlobalProtoChain = False
# Tracking of the number of reserved slots we need for our
@ -896,6 +902,10 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
# If this is an iterator interface, we need to know what iterable
# interface we're iterating for in order to get its nativeType.
self.iterableInterface = None
# True if we have cross-origin members.
self.hasCrossOriginMembers = False
# True if some descendant (including ourselves) has cross-origin members
self.hasDescendantWithCrossOriginMembers = False
self.toStringTag = toStringTag
@ -996,10 +1006,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
self.totalMembersInSlots = self.parent.totalMembersInSlots
# Interfaces with [Global] or [PrimaryGlobal] must not
# have anything inherit from them
if (self.parent.getExtendedAttribute("Global") or
self.parent.getExtendedAttribute("PrimaryGlobal")):
# Interfaces with [Global] must not have anything inherit from them
if self.parent.getExtendedAttribute("Global"):
# Note: This is not a self.parent.isOnGlobalProtoChain() check
# because ancestors of a [Global] interface can have other
# descendants.
@ -1015,10 +1023,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
self.parent.identifier.name),
[self.location, self.parent.location])
# Callbacks must not inherit from non-callbacks or inherit from
# anything that has consequential interfaces.
# Callbacks must not inherit from non-callbacks.
# XXXbz Can non-callbacks inherit from callbacks? Spec issue pending.
# XXXbz Can callbacks have consequential interfaces? Spec issue pending
if self.isCallback():
if not self.parent.isCallback():
raise WebIDLError("Callback interface %s inheriting from "
@ -1055,23 +1061,14 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
self.parent.identifier.name),
[self.location, self.parent.location])
for iface in self.implementedInterfaces:
iface.finish(scope)
for mixin in self.includedMixins:
mixin.finish(scope)
cycleInGraph = self.findInterfaceLoopPoint(self)
if cycleInGraph:
raise WebIDLError("Interface %s has itself as ancestor or "
"implemented interface" % self.identifier.name,
[self.location, cycleInGraph.location])
if self.isCallback():
# "implements" should have made sure we have no
# consequential interfaces.
assert len(self.getConsequentialInterfaces()) == 0
# And that we're not consequential.
assert not self.isConsequential()
raise WebIDLError(
"Interface %s has itself as ancestor" % self.identifier.name,
[self.location, cycleInGraph.location])
self.finishMembers(scope)
@ -1104,7 +1101,7 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
if self.globalNames:
raise WebIDLError(
"Can't have both a named constructor and [Global]",
[self.location, self.namedConstructors.location])
[self.location, ctor.location])
assert len(ctor._exposureGlobalNames) == 0
ctor._exposureGlobalNames.update(self._exposureGlobalNames)
ctor.finish(scope)
@ -1114,43 +1111,15 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
# admixed.
self.originalMembers = list(self.members)
# Import everything from our consequential interfaces into
# self.members. Sort our consequential interfaces by name
# just so we have a consistent order.
for iface in sorted(self.getConsequentialInterfaces(),
key=lambda x: x.identifier.name):
# Flag the interface as being someone's consequential interface
iface.setIsConsequentialInterfaceOf(self)
# Verify that we're not exposed somewhere where iface is not exposed
if not self.exposureSet.issubset(iface.exposureSet):
raise WebIDLError("Interface %s is exposed in globals where its "
"consequential interface %s is not exposed." %
(self.identifier.name, iface.identifier.name),
[self.location, iface.location])
# If we have a maplike or setlike, and the consequential interface
# also does, throw an error.
if iface.maplikeOrSetlikeOrIterable and self.maplikeOrSetlikeOrIterable:
raise WebIDLError("Maplike/setlike/iterable interface %s cannot have "
"maplike/setlike/iterable interface %s as a "
"consequential interface" %
(self.identifier.name,
iface.identifier.name),
[self.maplikeOrSetlikeOrIterable.location,
iface.maplikeOrSetlikeOrIterable.location])
additionalMembers = iface.originalMembers
for additionalMember in additionalMembers:
for member in self.members:
if additionalMember.identifier.name == member.identifier.name:
raise WebIDLError(
"Multiple definitions of %s on %s coming from 'implements' statements" %
(member.identifier.name, self),
[additionalMember.location, member.location])
self.members.extend(additionalMembers)
iface.interfacesImplementingSelf.add(self)
for mixin in sorted(self.includedMixins,
key=lambda x: x.identifier.name):
for mixinMember in mixin.members:
for member in self.members:
if mixinMember.identifier.name == member.identifier.name:
raise WebIDLError(
"Multiple definitions of %s on %s coming from 'includes' statements" %
(member.identifier.name, self),
[mixinMember.location, member.location])
self.members.extend(mixin.members)
for ancestor in self.getInheritedInterfaces():
@ -1164,8 +1133,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
ancestor.identifier.name),
[self.maplikeOrSetlikeOrIterable.location,
ancestor.maplikeOrSetlikeOrIterable.location])
for ancestorConsequential in ancestor.getConsequentialInterfaces():
ancestorConsequential.interfacesBasedOnSelf.add(self)
# Deal with interfaces marked [Unforgeable], now that we have our full
# member list, except unforgeables pulled in from parents. We want to
@ -1199,6 +1166,21 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
not hasattr(member, "originatingInterface")):
member.originatingInterface = self
for member in self.members:
if ((member.isMethod() and
member.getExtendedAttribute("CrossOriginCallable")) or
(member.isAttr() and
(member.getExtendedAttribute("CrossOriginReadable") or
member.getExtendedAttribute("CrossOriginWritable")))):
self.hasCrossOriginMembers = True
break
if self.hasCrossOriginMembers:
parent = self
while parent:
parent.hasDescendantWithCrossOriginMembers = True
parent = parent.parent
# Compute slot indices for our members before we pull in unforgeable
# members from our parent. Also, maplike/setlike declarations get a
# slot to hold their backing object.
@ -1221,13 +1203,12 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
self._ownMembersInSlots += 1
if self.parent:
# Make sure we don't shadow any of the [Unforgeable] attributes on
# our ancestor interfaces. We don't have to worry about
# consequential interfaces here, because those have already been
# imported into the relevant .members lists. And we don't have to
# worry about anything other than our parent, because it has already
# imported its ancestors unforgeable attributes into its member
# list.
# Make sure we don't shadow any of the [Unforgeable] attributes on our
# ancestor interfaces. We don't have to worry about mixins here, because
# those have already been imported into the relevant .members lists. And
# we don't have to worry about anything other than our parent, because it
# has already imported its ancestors' unforgeable attributes into its
# member list.
for unforgeableMember in (member for member in self.parent.members if
(member.isAttr() or member.isMethod()) and
member.isUnforgeable()):
@ -1363,17 +1344,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
(attributeName, name),
[member.location, m.location])
# We don't support consequential unforgeable interfaces. Need to check
# this here, because in finish() an interface might not know yet that
# it's consequential.
if self.getExtendedAttribute("Unforgeable") and self.isConsequential():
raise WebIDLError(
"%s is an unforgeable consequential interface" %
self.identifier.name,
[self.location] +
list(i.location for i in
(self.interfacesBasedOnSelf - {self})))
# We also don't support inheriting from unforgeable interfaces.
if self.getExtendedAttribute("Unforgeable") and self.hasChildInterfaces():
locations = ([self.location] +
@ -1529,16 +1499,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
'an integer-typed "length" attribute',
[self.location, indexedGetter.location])
def isExternal(self):
return False
def setIsConsequentialInterfaceOf(self, other):
self._consequential = True
self.interfacesBasedOnSelf.add(other)
def isConsequential(self):
return self._consequential
def setCallback(self, value):
self._callback = value
@ -1553,8 +1513,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
not self.isJSImplemented() and
# Not inheriting from another interface
not self.parent and
# No consequential interfaces
len(self.getConsequentialInterfaces()) == 0 and
# No attributes of any kinds
not any(m.isAttr() for m in self.members) and
# There is at least one regular operation, and all regular
@ -1582,10 +1540,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
return (not self.isCallback() and not self.isNamespace()
and self.getUserData('hasConcreteDescendant', False))
def addImplementedInterface(self, implementedInterface):
assert(isinstance(implementedInterface, IDLInterface))
self.implementedInterfaces.add(implementedInterface)
def addIncludedMixin(self, includedMixin):
assert(isinstance(includedMixin, IDLInterfaceMixin))
self.includedMixins.add(includedMixin)
@ -1603,27 +1557,10 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
parentInterfaces.insert(0, self.parent)
return parentInterfaces
def getConsequentialInterfaces(self):
assert(self._finished)
# The interfaces we implement directly
consequentialInterfaces = set(self.implementedInterfaces)
# And their inherited interfaces
for iface in self.implementedInterfaces:
consequentialInterfaces |= set(iface.getInheritedInterfaces())
# And now collect up the consequential interfaces of all of those
temp = set()
for iface in consequentialInterfaces:
temp |= iface.getConsequentialInterfaces()
return consequentialInterfaces | temp
def findInterfaceLoopPoint(self, otherInterface):
"""
Finds an interface, amongst our ancestors and consequential interfaces,
that inherits from otherInterface or implements otherInterface
directly. If there is no such interface, returns None.
Finds an interface amongst our ancestors that inherits from otherInterface.
If there is no such interface, returns None.
"""
if self.parent:
if self.parent == otherInterface:
@ -1631,13 +1568,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
loopPoint = self.parent.findInterfaceLoopPoint(otherInterface)
if loopPoint:
return loopPoint
if otherInterface in self.implementedInterfaces:
return self
for iface in self.implementedInterfaces:
loopPoint = iface.findInterfaceLoopPoint(otherInterface)
if loopPoint:
return loopPoint
return None
def setNonPartial(self, location, parent, members):
assert not parent or isinstance(parent, IDLIdentifierPlaceholder)
IDLInterfaceOrInterfaceMixinOrNamespace.setNonPartial(self, location, members)
@ -1671,7 +1603,6 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
def _getDependentObjects(self):
deps = set(self.members)
deps.update(self.implementedInterfaces)
deps.update(self.includedMixins)
if self.parent:
deps.add(self.parent)
@ -1794,20 +1725,6 @@ class IDLInterface(IDLInterfaceOrNamespace):
self.parentScope.addIfaceGlobalNames(self.identifier.name,
self.globalNames)
self._isOnGlobalProtoChain = True
elif identifier == "PrimaryGlobal":
if not attr.noArguments():
raise WebIDLError("[PrimaryGlobal] must take no arguments",
[attr.location])
if self.parentScope.primaryGlobalAttr is not None:
raise WebIDLError(
"[PrimaryGlobal] specified twice",
[attr.location,
self.parentScope.primaryGlobalAttr.location])
self.parentScope.primaryGlobalAttr = attr
self.parentScope.primaryGlobalName = self.identifier.name
self.parentScope.addIfaceGlobalNames(self.identifier.name,
[self.identifier.name])
self._isOnGlobalProtoChain = True
elif identifier == "LegacyWindowAlias":
if attr.hasValue():
self.legacyWindowAliases = [attr.value()]
@ -3081,8 +2998,9 @@ class IDLWrapperType(IDLType):
return True
iface = self.inner
if iface.isExternal():
# Let's say true, though ideally we'd only do this when
# exposureSet contains the primary global's name.
# Let's say true, so we don't have to implement exposure mixins on
# external interfaces and sprinkle [Exposed=Window] on every single
# external interface declaration.
return True
return iface.exposureSet.issuperset(exposureSet)
@ -3865,10 +3783,6 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
return self._extendedAttrDict.get(name, None)
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)
def validate(self):
@ -5539,52 +5453,6 @@ class IDLConstructor(IDLMethod):
[IDLExtendedAttribute(self.location, ("NewObject",))])
class IDLImplementsStatement(IDLObject):
def __init__(self, location, implementor, implementee):
IDLObject.__init__(self, location)
self.implementor = implementor
self.implementee = implementee
self._finished = False
def finish(self, scope):
if self._finished:
return
assert(isinstance(self.implementor, IDLIdentifierPlaceholder))
assert(isinstance(self.implementee, IDLIdentifierPlaceholder))
implementor = self.implementor.finish(scope)
implementee = self.implementee.finish(scope)
# NOTE: we depend on not setting self.implementor and
# self.implementee here to keep track of the original
# locations.
if not isinstance(implementor, IDLInterface):
raise WebIDLError("Left-hand side of 'implements' is not an "
"interface",
[self.implementor.location])
if implementor.isCallback():
raise WebIDLError("Left-hand side of 'implements' is a callback "
"interface",
[self.implementor.location])
if not isinstance(implementee, IDLInterface):
raise WebIDLError("Right-hand side of 'implements' is not an "
"interface",
[self.implementee.location])
if implementee.isCallback():
raise WebIDLError("Right-hand side of 'implements' is a callback "
"interface",
[self.implementee.location])
implementor.addImplementedInterface(implementee)
self.implementor = implementor
self.implementee = implementee
def validate(self):
pass
def addExtendedAttributes(self, attrs):
if len(attrs) != 0:
raise WebIDLError("There are no extended attributes that are "
"allowed on implements statements",
[attrs[0].location, self.location])
class IDLIncludesStatement(IDLObject):
def __init__(self, location, interface, mixin):
IDLObject.__init__(self, location)
@ -5606,16 +5474,18 @@ class IDLIncludesStatement(IDLObject):
if not isinstance(interface, IDLInterface):
raise WebIDLError("Left-hand side of 'includes' is not an "
"interface",
[self.interface.location])
[self.interface.location, interface.location])
if interface.isCallback():
raise WebIDLError("Left-hand side of 'includes' is a callback "
"interface",
[self.interface.location])
[self.interface.location, interface.location])
if not isinstance(mixin, IDLInterfaceMixin):
raise WebIDLError("Right-hand side of 'includes' is not an "
"interface mixin",
[self.mixin.location])
[self.mixin.location, mixin.location])
mixin.actualExposureGlobalNames.update(interface._exposureGlobalNames)
interface.addIncludedMixin(mixin)
self.interface = interface
self.mixin = mixin
@ -5721,7 +5591,6 @@ class Tokenizer(object):
return t
keywords = {
"module": "MODULE",
"interface": "INTERFACE",
"partial": "PARTIAL",
"mixin": "MIXIN",
@ -5730,7 +5599,6 @@ class Tokenizer(object):
"enum": "ENUM",
"callback": "CALLBACK",
"typedef": "TYPEDEF",
"implements": "IMPLEMENTS",
"includes": "INCLUDES",
"const": "CONST",
"null": "NULL",
@ -5894,7 +5762,6 @@ class Parser(Tokenizer):
| Exception
| Enum
| Typedef
| ImplementsStatement
| IncludesStatement
"""
p[0] = p[1]
@ -6427,16 +6294,6 @@ class Parser(Tokenizer):
p[2], p[3])
p[0] = typedef
def p_ImplementsStatement(self, p):
"""
ImplementsStatement : ScopedName IMPLEMENTS ScopedName SEMICOLON
"""
assert(p[2] == "implements")
implementor = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1])
implementee = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3])
p[0] = IDLImplementsStatement(self.getLocation(p, 1), implementor,
implementee)
def p_IncludesStatement(self, p):
"""
IncludesStatement : ScopedName INCLUDES ScopedName SEMICOLON
@ -6898,7 +6755,6 @@ class Parser(Tokenizer):
| ENUM
| EXCEPTION
| GETTER
| IMPLEMENTS
| INHERIT
| INTERFACE
| ITERABLE
@ -7025,11 +6881,9 @@ class Parser(Tokenizer):
| FALSE
| FLOAT
| GETTER
| IMPLEMENTS
| INHERIT
| INTERFACE
| LONG
| MODULE
| NULL
| OBJECT
| OCTET
@ -7479,12 +7333,6 @@ class Parser(Tokenizer):
self._globalScope = IDLScope(BuiltinLocation("<Global Scope>"), None, None)
# To make our test harness work, pretend like we have a primary global already.
# Note that we _don't_ set _globalScope.primaryGlobalAttr,
# so we'll still be able to detect multiple PrimaryGlobal extended attributes.
self._globalScope.primaryGlobalName = "FakeTestPrimaryGlobal"
self._globalScope.addIfaceGlobalNames("FakeTestPrimaryGlobal", ["FakeTestPrimaryGlobal"])
self._installBuiltins(self._globalScope)
self._productions = []
@ -7568,20 +7416,13 @@ class Parser(Tokenizer):
self._productions.append(itr_iface)
iterable.iteratorType = IDLWrapperType(iface.location, itr_iface)
# Then, finish all the IDLImplementsStatements. In particular, we
# have to make sure we do those before we do the IDLInterfaces.
# 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.
# XXX khuey hates this bit and wants to nuke it from orbit.
includesStatements = [p for p in self._productions if
isinstance(p, IDLIncludesStatement)]
otherStatements = [p for p in self._productions if
not isinstance(p, (IDLImplementsStatement,
IDLIncludesStatement))]
for production in implementsStatements:
production.finish(self.globalScope())
not isinstance(p, IDLIncludesStatement)]
for production in includesStatements:
production.finish(self.globalScope())
for production in otherStatements: