diff options
Diffstat (limited to 'components/script/dom/bindings/codegen/parser/WebIDL.py')
-rw-r--r-- | components/script/dom/bindings/codegen/parser/WebIDL.py | 315 |
1 files changed, 78 insertions, 237 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index 5e8b958e3de..a36b1b3ecfe 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -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(), + for mixin in sorted(self.includedMixins, 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 mixinMember in mixin.members: for member in self.members: - if additionalMember.identifier.name == member.identifier.name: + if mixinMember.identifier.name == member.identifier.name: raise WebIDLError( - "Multiple definitions of %s on %s coming from 'implements' statements" % + "Multiple definitions of %s on %s coming from 'includes' 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): + [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: |