diff options
Diffstat (limited to 'components/script/dom/bindings/codegen/parser/WebIDL.py')
-rw-r--r-- | components/script/dom/bindings/codegen/parser/WebIDL.py | 824 |
1 files changed, 602 insertions, 222 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index df88cf120dd..b934c21db5b 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -1,16 +1,18 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# file, You can obtain one at http://mozilla.org/MPL/2.0/. """ A WebIDL parser. """ +from __future__ import print_function from ply import lex, yacc import re import os import traceback import math import string -from collections import defaultdict +from collections import defaultdict, OrderedDict +from itertools import chain # Machinery @@ -40,32 +42,22 @@ def parseInt(literal): return value * sign -# Magic for creating enums -def M_add_class_attribs(attribs, start): - def foo(name, bases, dict_): - for v, k in enumerate(attribs): - dict_[k] = start + v - assert 'length' not in dict_ - dict_['length'] = start + len(attribs) - return type(name, bases, dict_) - return foo - - def enum(*names, **kw): - if len(kw) == 1: - base = kw['base'].__class__ - start = base.length - else: - assert len(kw) == 0 - base = object - start = 0 - - class Foo(base): - __metaclass__ = M_add_class_attribs(names, start) - + class Foo(object): + attrs = OrderedDict() + def __init__(self, names): + for v, k in enumerate(names): + self.attrs[k] = v + def __getattr__(self, attr): + if attr in self.attrs: + return self.attrs[attr] + raise AttributeError def __setattr__(self, name, value): # this makes it read-only raise NotImplementedError - return Foo() + + if "base" not in kw: + return Foo(names) + return Foo(chain(kw["base"].attrs.keys(), names)) class WebIDLError(Exception): @@ -322,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): @@ -482,9 +474,6 @@ class IDLExposureMixins(): def isExposedOnMainThread(self): return self.isExposedInWindow() - def isExposedOffMainThread(self): - return len(self.exposureSet - {'Window', 'FakeTestPrimaryGlobal'}) > 0 - def isExposedInAnyWorker(self): return len(self.getWorkerExposureSet()) > 0 @@ -568,6 +557,9 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def isNavigatorProperty(self): return False + def isSerializable(self): + return False + def _getDependentObjects(self): return set() @@ -613,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: @@ -684,29 +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" + + 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 -class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): + 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. @@ -727,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) @@ -748,37 +922,23 @@ 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) - # 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) + if len(self.legacyWindowAliases) > 0: + if not self.hasInterfaceObject(): + raise WebIDLError("Interface %s unexpectedly has [LegacyWindowAlias] " + "and [NoInterfaceObject] together" % self.identifier.name, + [self.location]) + if not self.isExposedInWindow(): + raise WebIDLError("Interface %s has [LegacyWindowAlias] " + "but not exposed in Window" % self.identifier.name, + [self.location]) # Generate maplike/setlike interface members. Since generated members # need to be treated like regular interface members, do this before @@ -801,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): @@ -909,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: @@ -923,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: @@ -962,7 +1094,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # self.members. Sort our consequential interfaces by name # just so we have a consistent order. for iface in sorted(self.getConsequentialInterfaces(), - cmp=cmp, key=lambda x: x.identifier.name): # Flag the interface as being someone's consequential interface iface.setIsConsequentialInterfaceOf(self) @@ -994,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 @@ -1325,6 +1460,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): for bindingAlias in member.bindingAliases: checkDuplicateNames(member, bindingAlias, "BindingAlias") + # Conditional exposure makes no sense for interfaces with no # interface object, unless they're navigator properties. # And SecureContext makes sense for interfaces with no interface object, @@ -1427,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 @@ -1475,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") @@ -1565,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 @@ -1640,6 +1758,11 @@ class IDLInterface(IDLInterfaceOrNamespace): raise WebIDLError(str(identifier) + " must take no arguments", [attr.location]) + if self.globalNames: + raise WebIDLError("[%s] must not be specified together with " + "[Global]" % identifier, + [self.location, attr.location]) + args = attr.args() if attr.hasArgs() else [] retType = IDLWrapperType(self.location, self) @@ -1700,6 +1823,10 @@ class IDLInterface(IDLInterfaceOrNamespace): "an interface with inherited interfaces", [attr.location, self.location]) elif identifier == "Global": + if self.ctor() or self.namedConstructors: + raise WebIDLError("[Global] cannot be specified on an " + "interface with a constructor", + [attr.location, self.location]); if attr.hasValue(): self.globalNames = [attr.value()] elif attr.hasArgs(): @@ -1723,6 +1850,18 @@ class IDLInterface(IDLInterfaceOrNamespace): self.parentScope.addIfaceGlobalNames(self.identifier.name, [self.identifier.name]) self._isOnGlobalProtoChain = True + elif identifier == "LegacyWindowAlias": + if attr.hasValue(): + self.legacyWindowAliases = [attr.value()] + elif attr.hasArgs(): + self.legacyWindowAliases = attr.args() + else: + raise WebIDLError("[%s] must either take an identifier " + "or take an identifier list" % identifier, + [attr.location]) + for alias in self.legacyWindowAliases: + unresolved = IDLUnresolvedIdentifier(attr.location, alias) + IDLObjectWithIdentifier(attr.location, self.parentScope, unresolved) elif identifier == "SecureContext": if not attr.noArguments(): raise WebIDLError("[%s] must take no arguments" % identifier, @@ -1744,6 +1883,7 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or identifier == "WantsEventListenerHooks" or + identifier == "Serializable" or identifier == "Abstract" or identifier == "Inline"): # Known extended attributes that do not take values @@ -1770,6 +1910,19 @@ class IDLInterface(IDLInterfaceOrNamespace): attrlist = attr.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True + def validate(self): + IDLInterfaceOrNamespace.validate(self) + if self.parent and self.isSerializable() and not self.parent.isSerializable(): + raise WebIDLError( + "Serializable interface inherits from non-serializable " + "interface. Per spec, that means the object should not be " + "serializable, so chances are someone made a mistake here " + "somewhere.", + [self.location, self.parent.location]) + + def isSerializable(self): + return self.getExtendedAttribute("Serializable") + class IDLNamespace(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, members, isKnownNonPartial): @@ -1805,7 +1958,9 @@ class IDLNamespace(IDLInterfaceOrNamespace): if not attr.noArguments(): raise WebIDLError("[%s] must not have arguments" % identifier, [attr.location]) - elif identifier == "Pref" or identifier == "Func": + elif (identifier == "Pref" or + identifier == "HeaderFile" or + identifier == "Func"): # Known extended attributes that take a string value if not attr.hasValue(): raise WebIDLError("[%s] must have a value" % identifier, @@ -1818,6 +1973,9 @@ class IDLNamespace(IDLInterfaceOrNamespace): attrlist = attr.listValue() self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True + def isSerializable(self): + return False + class IDLDictionary(IDLObjectWithScope): def __init__(self, location, parentScope, name, parent, members): @@ -1877,7 +2035,7 @@ class IDLDictionary(IDLObjectWithScope): assert member.type.isComplete() # Members of a dictionary are sorted in lexicographic order - self.members.sort(cmp=cmp, key=lambda x: x.identifier.name) + self.members.sort(key=lambda x: x.identifier.name) inheritedMembers = [] ancestor = self.parent @@ -2232,7 +2390,7 @@ class IDLUnresolvedType(IDLType): assert obj if obj.isType(): - print obj + print(obj) assert not obj.isType() if obj.isTypedef(): assert self.name.name == obj.identifier.name @@ -3562,8 +3720,6 @@ class IDLNullValue(IDLObject): def coerceToType(self, type, location): if (not isinstance(type, IDLNullableType) and not (type.isUnion() and type.hasNullableType) and - not (type.isUnion() and type.hasDictionaryType()) and - not type.isDictionary() and not type.isAny()): raise WebIDLError("Cannot coerce null value to type %s." % type, [location]) @@ -3612,6 +3768,35 @@ class IDLEmptySequenceValue(IDLObject): return set() +class IDLDefaultDictionaryValue(IDLObject): + def __init__(self, location): + IDLObject.__init__(self, location) + self.type = None + self.value = None + + def coerceToType(self, type, location): + if type.isUnion(): + # We use the flat member types here, because if we have a nullable + # member type, or a nested union, we want the type the value + # actually coerces to, not the nullable or nested union type. + for subtype in type.unroll().flatMemberTypes: + try: + return self.coerceToType(subtype, location) + except: + pass + + if not type.isDictionary(): + raise WebIDLError("Cannot coerce default dictionary value to type %s." % type, + [location]) + + defaultDictionaryValue = IDLDefaultDictionaryValue(self.location) + defaultDictionaryValue.type = type + return defaultDictionaryValue + + def _getDependentObjects(self): + return set() + + class IDLUndefinedValue(IDLObject): def __init__(self, location): IDLObject.__init__(self, location) @@ -3689,7 +3874,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins): def finish(self, scope): # We better be exposed _somewhere_. if (len(self._exposureGlobalNames) == 0): - print self.identifier.name + print(self.identifier.name) assert len(self._exposureGlobalNames) != 0 IDLExposureMixins.finish(self, scope) @@ -4577,7 +4762,9 @@ class IDLArgument(IDLObjectWithIdentifier): elif identifier == "TreatNonCallableAsNull": self._allowTreatNonCallableAsNull = True elif (self.dictionaryMember and - (identifier == "ChromeOnly" or identifier == "Func")): + (identifier == "ChromeOnly" or + identifier == "Func" or + identifier == "Pref")): if not self.optional: raise WebIDLError("[%s] must not be used on a required " "dictionary member" % identifier, @@ -4609,14 +4796,7 @@ class IDLArgument(IDLObjectWithIdentifier): assert not isinstance(type.name, IDLUnresolvedIdentifier) self.type = type - if ((self.type.isDictionary() or - self.type.isUnion() and self.type.unroll().hasDictionaryType()) and - self.optional and not self.defaultValue and not self.variadic and - not self.dictionaryMember): - # Default optional non-variadic dictionary arguments to null, - # for simplicity, so the codegen doesn't have to special-case this. - self.defaultValue = IDLNullValue(self.location) - elif self.type.isAny(): + if self.type.isAny(): assert (self.defaultValue is None or isinstance(self.defaultValue, IDLNullValue)) # optional 'any' values always have a default value @@ -4648,7 +4828,7 @@ class IDLArgument(IDLObjectWithIdentifier): class IDLCallback(IDLObjectWithScope): - def __init__(self, location, parentScope, identifier, returnType, arguments): + def __init__(self, location, parentScope, identifier, returnType, arguments, isConstructor): assert isinstance(returnType, IDLType) self._returnType = returnType @@ -4663,10 +4843,15 @@ class IDLCallback(IDLObjectWithScope): self._treatNonCallableAsNull = False self._treatNonObjectAsNull = False + self._isRunScriptBoundary = False + self._isConstructor = isConstructor def isCallback(self): return True + def isConstructor(self): + return self._isConstructor + def signatures(self): return [(self._returnType, self._arguments)] @@ -4699,7 +4884,16 @@ class IDLCallback(IDLObjectWithScope): if attr.identifier() == "TreatNonCallableAsNull": self._treatNonCallableAsNull = True elif attr.identifier() == "TreatNonObjectAsNull": + if self._isConstructor: + raise WebIDLError("[TreatNonObjectAsNull] is not supported " + "on constructors", [self.location]) self._treatNonObjectAsNull = True + elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY": + if self._isConstructor: + raise WebIDLError("[MOZ_CAN_RUN_SCRIPT_BOUNDARY] is not " + "permitted on constructors", + [self.location]) + self._isRunScriptBoundary = True else: unhandledAttrs.append(attr) if self._treatNonCallableAsNull and self._treatNonObjectAsNull: @@ -4711,6 +4905,9 @@ class IDLCallback(IDLObjectWithScope): def _getDependentObjects(self): return set([self._returnType] + self._arguments) + def isRunScriptBoundary(self): + return self._isRunScriptBoundary; + class IDLCallbackType(IDLType): def __init__(self, location, callback): @@ -4757,6 +4954,9 @@ class IDLMethodOverload: deps.add(self.returnType) return deps + def includesRestrictedFloatArgument(self): + return any(arg.type.includesRestrictedFloat() for arg in self.arguments) + class IDLMethod(IDLInterfaceMember, IDLScope): @@ -4928,10 +5128,25 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def addOverload(self, method): assert len(method._overloads) == 1 - if self._extendedAttrDict != method ._extendedAttrDict: - raise WebIDLError("Extended attributes differ on different " - "overloads of %s" % method.identifier, - [self.location, method.location]) + if self._extendedAttrDict != method._extendedAttrDict: + extendedAttrDiff = set(self._extendedAttrDict.keys()) ^ set(method._extendedAttrDict.keys()) + + if extendedAttrDiff == { "LenientFloat" }: + if "LenientFloat" not in self._extendedAttrDict: + for overload in self._overloads: + if overload.includesRestrictedFloatArgument(): + raise WebIDLError("Restricted float behavior differs on different " + "overloads of %s" % method.identifier, + [overload.location, method.location]) + self._extendedAttrDict["LenientFloat"] = method._extendedAttrDict["LenientFloat"] + elif method._overloads[0].includesRestrictedFloatArgument(): + raise WebIDLError("Restricted float behavior differs on different " + "overloads of %s" % method.identifier, + [self.location, method.location]) + else: + raise WebIDLError("Extended attributes differ on different " + "overloads of %s" % method.identifier, + [self.location, method.location]) self._overloads.extend(method._overloads) @@ -5039,6 +5254,15 @@ class IDLMethod(IDLInterfaceMember, IDLScope): "must be optional", [argument.location]) + if (not argument.defaultValue and + all(arg.optional for arg in arguments[idx+1:])): + raise WebIDLError("Dictionary argument without any " + "required fields or union argument " + "containing such dictionary not " + "followed by a required argument " + "must have a default value", + [argument.location]) + # An argument cannot be a Nullable Dictionary if argument.type.nullable(): raise WebIDLError("An argument cannot be a nullable " @@ -5162,12 +5386,12 @@ class IDLMethod(IDLInterfaceMember, IDLScope): [attr.location, self.location]) elif identifier == "LenientFloat": # This is called before we've done overload resolution - assert len(self.signatures()) == 1 - sig = self.signatures()[0] - if not sig[0].isVoid(): + overloads = self._overloads + assert len(overloads) == 1 + if not overloads[0].returnType.isVoid(): raise WebIDLError("[LenientFloat] used on a non-void method", [attr.location, self.location]) - if not any(arg.type.includesRestrictedFloat() for arg in sig[1]): + if not overloads[0].includesRestrictedFloatArgument(): raise WebIDLError("[LenientFloat] used on an operation with no " "restricted float type arguments", [attr.location, self.location]) @@ -5238,7 +5462,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]: raise WebIDLError("The return type of the default toJSON " "operation must be 'object'", - [attr.location, self.location]); + [attr.location, self.location]) elif (identifier == "Throws" or identifier == "CanOOM" or identifier == "NewObject" or @@ -5251,7 +5475,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope): identifier == "NeedsSubjectPrincipal" or identifier == "NeedsCallerType" or identifier == "StaticClassOverride" or - identifier == "NonEnumerable"): + identifier == "NonEnumerable" or + identifier == "Unexposed"): # Known attributes that we don't need to do anything with here pass else: @@ -5318,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): """ @@ -5414,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", @@ -5478,6 +5748,7 @@ class Tokenizer(object): "iterable": "ITERABLE", "namespace": "NAMESPACE", "ReadableStream": "READABLESTREAM", + "constructor": "CONSTRUCTOR", } tokens.extend(keywords.values()) @@ -5573,7 +5844,7 @@ class Parser(Tokenizer): def p_Definition(self, p): """ - Definition : CallbackOrInterface + Definition : CallbackOrInterfaceOrMixin | Namespace | Partial | Dictionary @@ -5581,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) @@ -5595,16 +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 - | Interface + | CallbackConstructorRest + | CallbackInterface """ assert p[1] p[0] = p[1] @@ -5637,7 +5910,7 @@ class Parser(Tokenizer): [location, existingObj.location]) existingObj.setNonPartial(*nonPartialArgs) return existingObj - except Exception, ex: + except Exception as ex: if isinstance(ex, WebIDLError): raise ex pass @@ -5645,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, @@ -5661,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): @@ -5675,13 +5961,26 @@ class Parser(Tokenizer): "%s and %s" % (identifier.name, p[0]), [location, p[0].location]) return - except Exception, ex: + except Exception as ex: if isinstance(ex, WebIDLError): raise ex pass 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 @@ -5701,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] @@ -5739,7 +6043,7 @@ class Parser(Tokenizer): "non-%s object" % (prettyname, prettyname), [location, nonPartialObject.location]) - except Exception, ex: + except Exception as ex: if isinstance(ex, WebIDLError): raise ex pass @@ -5747,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): """ - 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(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 @@ -5817,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]) @@ -5837,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 @@ -5905,12 +6256,23 @@ class Parser(Tokenizer): """ DefaultValue : ConstValue | LBRACKET RBRACKET + | LBRACE RBRACE """ if len(p) == 2: p[0] = p[1] else: - assert len(p) == 3 # Must be [] - p[0] = IDLEmptySequenceValue(self.getLocation(p, 1)) + assert len(p) == 3 # Must be [] or {} + if p[1] == "[": + p[0] = IDLEmptySequenceValue(self.getLocation(p, 1)) + else: + assert p[1] == "{" + p[0] = IDLDefaultDictionaryValue(self.getLocation(p, 1)) + + def p_DefaultValueNull(self, p): + """ + DefaultValue : NULL + """ + p[0] = IDLNullValue(self.getLocation(p, 1)) def p_Exception(self, p): """ @@ -5967,7 +6329,15 @@ class Parser(Tokenizer): """ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) p[0] = IDLCallback(self.getLocation(p, 1), self.globalScope(), - identifier, p[3], p[5]) + identifier, p[3], p[5], isConstructor=False) + + def p_CallbackConstructorRest(self, p): + """ + CallbackConstructorRest : CONSTRUCTOR IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON + """ + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + p[0] = IDLCallback(self.getLocation(p, 2), self.globalScope(), + identifier, p[4], p[6], isConstructor=True) def p_ExceptionMembers(self, p): """ @@ -5994,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 @@ -6041,12 +6420,6 @@ class Parser(Tokenizer): stringType = BuiltinTypes[IDLBuiltinType.Types.domstring] p[0] = IDLValue(location, stringType, p[1]) - def p_ConstValueNull(self, p): - """ - ConstValue : NULL - """ - p[0] = IDLNullValue(self.getLocation(p, 1)) - def p_BooleanLiteralTrue(self, p): """ BooleanLiteral : TRUE @@ -6442,6 +6815,7 @@ class Parser(Tokenizer): | ATTRIBUTE | CALLBACK | CONST + | CONSTRUCTOR | DELETER | DICTIONARY | ENUM @@ -6566,6 +6940,7 @@ class Parser(Tokenizer): | BYTE | LEGACYCALLER | CONST + | CONSTRUCTOR | DELETER | DOUBLE | EXCEPTION @@ -6619,9 +6994,9 @@ class Parser(Tokenizer): """ p[0] = p[2].withExtendedAttributes(p[1]) - def p_SingleTypeNonAnyType(self, p): + def p_SingleTypeDistinguishableType(self, p): """ - SingleType : NonAnyType + SingleType : DistinguishableType """ p[0] = p[1] @@ -6631,6 +7006,14 @@ class Parser(Tokenizer): """ p[0] = BuiltinTypes[IDLBuiltinType.Types.any] + # Note: Promise<void> is allowed, so we want to parametrize on ReturnType, + # not Type. Promise types can't be null, hence no "Null" in there. + def p_SingleTypePromiseType(self, p): + """ + SingleType : PROMISE LT ReturnType GT + """ + p[0] = IDLPromiseType(self.getLocation(p, 1), p[3]) + def p_UnionType(self, p): """ UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN @@ -6639,9 +7022,9 @@ class Parser(Tokenizer): types.extend(p[5]) p[0] = IDLUnionType(self.getLocation(p, 1), types) - def p_UnionMemberTypeNonAnyType(self, p): + def p_UnionMemberTypeDistinguishableType(self, p): """ - UnionMemberType : ExtendedAttributeList NonAnyType + UnionMemberType : ExtendedAttributeList DistinguishableType """ p[0] = p[2].withExtendedAttributes(p[1]) @@ -6664,13 +7047,13 @@ class Parser(Tokenizer): """ p[0] = [] - def p_NonAnyType(self, p): + def p_DistinguishableType(self, p): """ - NonAnyType : PrimitiveType Null - | ARRAYBUFFER Null - | SHAREDARRAYBUFFER Null - | READABLESTREAM Null - | OBJECT Null + DistinguishableType : PrimitiveType Null + | ARRAYBUFFER Null + | SHAREDARRAYBUFFER Null + | READABLESTREAM Null + | OBJECT Null """ if p[1] == "object": type = BuiltinTypes[IDLBuiltinType.Types.object] @@ -6685,40 +7068,32 @@ class Parser(Tokenizer): p[0] = self.handleNullable(type, p[2]) - def p_NonAnyTypeStringType(self, p): + def p_DistinguishableTypeStringType(self, p): """ - NonAnyType : StringType Null + DistinguishableType : StringType Null """ p[0] = self.handleNullable(p[1], p[2]) - def p_NonAnyTypeSequenceType(self, p): + def p_DistinguishableTypeSequenceType(self, p): """ - NonAnyType : SEQUENCE LT TypeWithExtendedAttributes GT Null + DistinguishableType : SEQUENCE LT TypeWithExtendedAttributes GT Null """ innerType = p[3] type = IDLSequenceType(self.getLocation(p, 1), innerType) p[0] = self.handleNullable(type, p[5]) - # Note: Promise<void> is allowed, so we want to parametrize on ReturnType, - # not Type. Promise types can't be null, hence no "Null" in there. - def p_NonAnyTypePromiseType(self, p): + def p_DistinguishableTypeRecordType(self, p): """ - NonAnyType : PROMISE LT ReturnType GT - """ - p[0] = IDLPromiseType(self.getLocation(p, 1), p[3]) - - def p_NonAnyTypeRecordType(self, p): - """ - NonAnyType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null + DistinguishableType : RECORD LT StringType COMMA TypeWithExtendedAttributes GT Null """ keyType = p[3] valueType = p[5] type = IDLRecordType(self.getLocation(p, 1), keyType, valueType) p[0] = self.handleNullable(type, p[7]) - def p_NonAnyTypeScopedName(self, p): + def p_DistinguishableTypeScopedName(self, p): """ - NonAnyType : ScopedName Null + DistinguishableType : ScopedName Null """ assert isinstance(p[1], IDLUnresolvedIdentifier) @@ -6748,28 +7123,26 @@ class Parser(Tokenizer): type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) p[0] = self.handleNullable(type, p[2]) - def p_NonAnyTypeDate(self, p): + def p_DistinguishableTypeDate(self, p): """ - NonAnyType : DATE Null + DistinguishableType : DATE Null """ p[0] = self.handleNullable(BuiltinTypes[IDLBuiltinType.Types.date], p[2]) def p_ConstType(self, p): """ - ConstType : PrimitiveType Null + ConstType : PrimitiveType """ - type = BuiltinTypes[p[1]] - p[0] = self.handleNullable(type, p[2]) + p[0] = BuiltinTypes[p[1]] def p_ConstTypeIdentifier(self, p): """ - ConstType : IDENTIFIER Null + ConstType : IDENTIFIER """ identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) - type = IDLUnresolvedType(self.getLocation(p, 1), identifier) - p[0] = self.handleNullable(type, p[2]) + p[0] = IDLUnresolvedType(self.getLocation(p, 1), identifier) def p_PrimitiveTypeUint(self, p): """ @@ -7040,8 +7413,8 @@ class Parser(Tokenizer): def _installBuiltins(self, scope): assert isinstance(scope, IDLScope) - # xrange omits the last value. - for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): + # range omits the last value. + for x in range(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): builtin = BuiltinTypes[x] name = builtin.name typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name) @@ -7130,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()) @@ -7185,14 +7565,14 @@ def main(): f = open(fullPath, 'rb') lines = f.readlines() f.close() - print fullPath + print(fullPath) parser.parse(''.join(lines), fullPath) parser.finish() - except WebIDLError, e: + except WebIDLError as e: if options.verbose_errors: traceback.print_exc() else: - print e + print(e) if __name__ == '__main__': main() |