diff options
Diffstat (limited to 'components/script/dom/bindings/codegen/parser/WebIDL.py')
-rw-r--r-- | components/script/dom/bindings/codegen/parser/WebIDL.py | 496 |
1 files changed, 373 insertions, 123 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index edfdcf9d745..b934c21db5b 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -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 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" -class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): + 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 isinstance(parentScope, IDLScope) - assert isinstance(name, IDLUnresolvedIdentifier) 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,34 +6051,55 @@ 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): + """ + PartialInterfaceOrPartialMixin : PartialInterfaceRest + | PartialMixinRest + """ + p[0] = p[1] + + def p_PartialInterfaceRest(self, p): """ - PartialInterface : INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + PartialInterfaceRest : IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON """ location = self.getLocation(p, 1) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - members = p[4] + 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, IDLInterfaceMixin, + [location, self.globalScope(), identifier], + [location, identifier, members]) + def p_PartialNamespace(self, p): """ PartialNamespace : NAMESPACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON @@ -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()) |