diff options
author | Jack Moffitt <jack@metajack.im> | 2014-08-28 09:34:23 -0600 |
---|---|---|
committer | Jack Moffitt <jack@metajack.im> | 2014-09-08 20:21:42 -0600 |
commit | c6ab60dbfc6da7b4f800c9e40893c8b58413960c (patch) | |
tree | d1d74076cf7fa20e4f77ec7cb82cae98b67362cb /src/components/script/dom/bindings/codegen/parser/WebIDL.py | |
parent | db2f642c32fc5bed445bb6f2e45b0f6f0b4342cf (diff) | |
download | servo-c6ab60dbfc6da7b4f800c9e40893c8b58413960c.tar.gz servo-c6ab60dbfc6da7b4f800c9e40893c8b58413960c.zip |
Cargoify servo
Diffstat (limited to 'src/components/script/dom/bindings/codegen/parser/WebIDL.py')
-rw-r--r-- | src/components/script/dom/bindings/codegen/parser/WebIDL.py | 5583 |
1 files changed, 0 insertions, 5583 deletions
diff --git a/src/components/script/dom/bindings/codegen/parser/WebIDL.py b/src/components/script/dom/bindings/codegen/parser/WebIDL.py deleted file mode 100644 index 32f80e82c56..00000000000 --- a/src/components/script/dom/bindings/codegen/parser/WebIDL.py +++ /dev/null @@ -1,5583 +0,0 @@ -# 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 http://mozilla.org/MPL/2.0/. - -""" A WebIDL parser. """ - -from ply import lex, yacc -import re -import os -import traceback -import math -from collections import defaultdict - -# Machinery - -def parseInt(literal): - string = literal - sign = 0 - base = 0 - - if string[0] == '-': - sign = -1 - string = string[1:] - else: - sign = 1 - - if string[0] == '0' and len(string) > 1: - if string[1] == 'x' or string[1] == 'X': - base = 16 - string = string[2:] - else: - base = 8 - string = string[1:] - else: - base = 10 - - value = int(string, base) - 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) - def __setattr__(self, name, value): # this makes it read-only - raise NotImplementedError - return Foo() - -class WebIDLError(Exception): - def __init__(self, message, locations, warning=False): - self.message = message - self.locations = [str(loc) for loc in locations] - self.warning = warning - - def __str__(self): - return "%s: %s%s%s" % (self.warning and 'warning' or 'error', - self.message, - ", " if len(self.locations) != 0 else "", - "\n".join(self.locations)) - -class Location(object): - def __init__(self, lexer, lineno, lexpos, filename): - self._line = None - self._lineno = lineno - self._lexpos = lexpos - self._lexdata = lexer.lexdata - self._file = filename if filename else "<unknown>" - - def __eq__(self, other): - return self._lexpos == other._lexpos and \ - self._file == other._file - - def filename(self): - return self._file - - def resolve(self): - if self._line: - return - - startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1 - endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80) - if endofline != -1: - self._line = self._lexdata[startofline:endofline] - else: - self._line = self._lexdata[startofline:] - self._colno = self._lexpos - startofline - - # Our line number seems to point to the start of self._lexdata - self._lineno += self._lexdata.count('\n', 0, startofline) - - def get(self): - self.resolve() - return "%s line %s:%s" % (self._file, self._lineno, self._colno) - - def _pointerline(self): - return " " * self._colno + "^" - - def __str__(self): - self.resolve() - return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno, - self._line, self._pointerline()) - -class BuiltinLocation(object): - def __init__(self, text): - self.msg = text + "\n" - - def __eq__(self, other): - return isinstance(other, BuiltinLocation) and \ - self.msg == other.msg - - def filename(self): - return '<builtin>' - - def resolve(self): - pass - - def get(self): - return self.msg - - def __str__(self): - return self.get() - - -# Data Model - -class IDLObject(object): - def __init__(self, location): - self.location = location - self.userData = dict() - - def filename(self): - return self.location.filename() - - def isInterface(self): - return False - - def isEnum(self): - return False - - def isCallback(self): - return False - - def isType(self): - return False - - def isDictionary(self): - return False; - - def isUnion(self): - return False - - def getUserData(self, key, default): - return self.userData.get(key, default) - - def setUserData(self, key, value): - self.userData[key] = value - - def addExtendedAttributes(self, attrs): - assert False # Override me! - - def handleExtendedAttribute(self, attr): - assert False # Override me! - - def _getDependentObjects(self): - assert False # Override me! - - def getDeps(self, visited=None): - """ Return a set of files that this object depends on. If any of - these files are changed the parser needs to be rerun to regenerate - a new IDLObject. - - The visited argument is a set of all the objects already visited. - We must test to see if we are in it, and if so, do nothing. This - prevents infinite recursion.""" - - # NB: We can't use visited=set() above because the default value is - # evaluated when the def statement is evaluated, not when the function - # is executed, so there would be one set for all invocations. - if visited == None: - visited = set() - - if self in visited: - return set() - - visited.add(self) - - deps = set() - if self.filename() != "<builtin>": - deps.add(self.filename()) - - for d in self._getDependentObjects(): - deps = deps.union(d.getDeps(visited)) - - return deps - -class IDLScope(IDLObject): - def __init__(self, location, parentScope, identifier): - IDLObject.__init__(self, location) - - self.parentScope = parentScope - if identifier: - assert isinstance(identifier, IDLIdentifier) - self._name = identifier - else: - self._name = None - - self._dict = {} - self.globalNames = set() - # 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() - - def QName(self): - if self._name: - return self._name.QName() + "::" - return "::" - - def ensureUnique(self, identifier, object): - """ - Ensure that there is at most one 'identifier' in scope ('self'). - Note that object can be None. This occurs if we end up here for an - interface type we haven't seen yet. - """ - assert isinstance(identifier, IDLUnresolvedIdentifier) - assert not object or isinstance(object, IDLObjectWithIdentifier) - assert not object or object.identifier == identifier - - if identifier.name in self._dict: - if not object: - return - - # ensureUnique twice with the same object is not allowed - assert id(object) != id(self._dict[identifier.name]) - - replacement = self.resolveIdentifierConflict(self, identifier, - self._dict[identifier.name], - object) - self._dict[identifier.name] = replacement - return - - assert object - - self._dict[identifier.name] = object - - def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): - if isinstance(originalObject, IDLExternalInterface) and \ - isinstance(newObject, IDLExternalInterface) and \ - originalObject.identifier.name == newObject.identifier.name: - return originalObject - - if (isinstance(originalObject, IDLExternalInterface) or - isinstance(newObject, IDLExternalInterface)): - raise WebIDLError( - "Name collision between " - "interface declarations for identifier '%s' at '%s' and '%s'" - % (identifier.name, - originalObject.location, newObject.location), []) - - if (isinstance(originalObject, IDLDictionary) or - isinstance(newObject, IDLDictionary)): - raise WebIDLError( - "Name collision between dictionary declarations for " - "identifier '%s'.\n%s\n%s" - % (identifier.name, - originalObject.location, newObject.location), []) - - # We do the merging of overloads here as opposed to in IDLInterface - # because we need to merge overloads of NamedConstructors and we need to - # detect conflicts in those across interfaces. See also the comment in - # IDLInterface.addExtendedAttributes for "NamedConstructor". - if originalObject.tag == IDLInterfaceMember.Tags.Method and \ - newObject.tag == IDLInterfaceMember.Tags.Method: - return originalObject.addOverload(newObject) - - # Default to throwing, derived classes can override. - conflictdesc = "\n\t%s at %s\n\t%s at %s" % \ - (originalObject, originalObject.location, newObject, newObject.location) - - raise WebIDLError( - "Multiple unresolvable definitions of identifier '%s' in scope '%s%s" - % (identifier.name, str(self), conflictdesc), []) - - def _lookupIdentifier(self, identifier): - return self._dict[identifier.name] - - def lookupIdentifier(self, identifier): - assert isinstance(identifier, IDLIdentifier) - assert identifier.scope == self - return self._lookupIdentifier(identifier) - -class IDLIdentifier(IDLObject): - def __init__(self, location, scope, name): - IDLObject.__init__(self, location) - - self.name = name - assert isinstance(scope, IDLScope) - self.scope = scope - - def __str__(self): - return self.QName() - - def QName(self): - return self.scope.QName() + self.name - - def __hash__(self): - return self.QName().__hash__() - - def __eq__(self, other): - return self.QName() == other.QName() - - def object(self): - return self.scope.lookupIdentifier(self) - -class IDLUnresolvedIdentifier(IDLObject): - def __init__(self, location, name, allowDoubleUnderscore = False, - allowForbidden = False): - IDLObject.__init__(self, location) - - assert len(name) > 0 - - if name[:2] == "__" and name != "__content" and name != "___noSuchMethod__" and not allowDoubleUnderscore: - raise WebIDLError("Identifiers beginning with __ are reserved", - [location]) - if name[0] == '_' and not allowDoubleUnderscore: - name = name[1:] - # TODO: Bug 872377, Restore "toJSON" to below list. - # We sometimes need custom serialization, so allow toJSON for now. - if (name in ["constructor", "toString"] and - not allowForbidden): - raise WebIDLError("Cannot use reserved identifier '%s'" % (name), - [location]) - - self.name = name - - def __str__(self): - return self.QName() - - def QName(self): - return "<unresolved scope>::" + self.name - - def resolve(self, scope, object): - assert isinstance(scope, IDLScope) - assert not object or isinstance(object, IDLObjectWithIdentifier) - assert not object or object.identifier == self - - scope.ensureUnique(self, object) - - identifier = IDLIdentifier(self.location, scope, self.name) - if object: - object.identifier = identifier - return identifier - - def finish(self): - assert False # Should replace with a resolved identifier first. - -class IDLObjectWithIdentifier(IDLObject): - def __init__(self, location, parentScope, identifier): - IDLObject.__init__(self, location) - - assert isinstance(identifier, IDLUnresolvedIdentifier) - - self.identifier = identifier - - if parentScope: - self.resolve(parentScope) - - self.treatNullAs = "Default" - - def resolve(self, parentScope): - assert isinstance(parentScope, IDLScope) - assert isinstance(self.identifier, IDLUnresolvedIdentifier) - self.identifier.resolve(parentScope, self) - - def checkForStringHandlingExtendedAttributes(self, attrs, - isDictionaryMember=False, - isOptional=False): - """ - A helper function to deal with TreatNullAs. Returns the list - of attrs it didn't handle itself. - """ - assert isinstance(self, IDLArgument) or isinstance(self, IDLAttribute) - unhandledAttrs = list() - for attr in attrs: - if not attr.hasValue(): - unhandledAttrs.append(attr) - continue - - identifier = attr.identifier() - value = attr.value() - if identifier == "TreatNullAs": - if not self.type.isDOMString() or self.type.nullable(): - raise WebIDLError("[TreatNullAs] is only allowed on " - "arguments or attributes whose type is " - "DOMString", - [self.location]) - if isDictionaryMember: - raise WebIDLError("[TreatNullAs] is not allowed for " - "dictionary members", [self.location]) - if value != 'EmptyString': - raise WebIDLError("[TreatNullAs] must take the identifier " - "'EmptyString', not '%s'" % value, - [self.location]) - self.treatNullAs = value - else: - unhandledAttrs.append(attr) - - return unhandledAttrs - -class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope): - def __init__(self, location, parentScope, identifier): - assert isinstance(identifier, IDLUnresolvedIdentifier) - - IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) - IDLScope.__init__(self, location, parentScope, self.identifier) - -class IDLIdentifierPlaceholder(IDLObjectWithIdentifier): - def __init__(self, location, identifier): - assert isinstance(identifier, IDLUnresolvedIdentifier) - IDLObjectWithIdentifier.__init__(self, location, None, identifier) - - def finish(self, scope): - try: - scope._lookupIdentifier(self.identifier) - except: - raise WebIDLError("Unresolved type '%s'." % self.identifier, - [self.location]) - - obj = self.identifier.resolve(scope, None) - return scope.lookupIdentifier(obj) - -class IDLExternalInterface(IDLObjectWithIdentifier): - def __init__(self, location, parentScope, identifier): - raise WebIDLError("Servo does not support external interfaces.", - [self.location]) - -class IDLPartialInterface(IDLObject): - def __init__(self, location, name, members, nonPartialInterface): - assert isinstance(name, IDLUnresolvedIdentifier) - - IDLObject.__init__(self, location) - self.identifier = name - self.members = members - # propagatedExtendedAttrs are the ones that should get - # propagated to our non-partial interface. - self.propagatedExtendedAttrs = [] - self._nonPartialInterface = nonPartialInterface - self._finished = False - nonPartialInterface.addPartialInterface(self) - - def addExtendedAttributes(self, attrs): - for attr in attrs: - identifier = attr.identifier() - - if identifier in ["Constructor", "NamedConstructor"]: - self.propagatedExtendedAttrs.append(attr) - elif identifier == "Exposed": - # This just gets propagated to all our members. - for member in self.members: - if len(member._exposureGlobalNames) != 0: - raise WebIDLError("[Exposed] specified on both a " - "partial interface member and on the " - "partial interface itself", - [member.location, attr.location]) - member.addExtendedAttributes([attr]) - else: - raise WebIDLError("Unknown extended attribute %s on partial " - "interface" % identifier, - [attr.location]) - - def finish(self, scope): - if self._finished: - return - self._finished = True - # Need to make sure our non-partial interface gets finished so it can - # report cases when we only have partial interfaces. - self._nonPartialInterface.finish(scope) - - def validate(self): - pass - - -def convertExposedAttrToGlobalNameSet(exposedAttr, targetSet): - assert len(targetSet) == 0 - if exposedAttr.hasValue(): - targetSet.add(exposedAttr.value()) - else: - assert exposedAttr.hasArgs() - targetSet.update(exposedAttr.args()) - -def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): - for name in nameSet: - exposureSet.update(globalScope.globalNameMapping[name]) - -class IDLInterface(IDLObjectWithScope): - def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial): - 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._partialInterfaces = [] - self._extendedAttrDict = {} - # namedConstructors needs deterministic ordering because bindings code - # outputs the constructs in the order that namedConstructors enumerates - # them. - self.namedConstructors = list() - self.implementedInterfaces = 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. - 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 - # members and those of ancestor interfaces. - self.totalMembersInSlots = 0 - # Tracking of the number of own own members we have in slots - self._ownMembersInSlots = 0 - # _exposureGlobalNames are the global names listed in our [Exposed] - # extended attribute. exposureSet is the exposure set as defined in the - # Web IDL spec: it contains interface names. - self._exposureGlobalNames = set() - self.exposureSet = set() - - IDLObjectWithScope.__init__(self, location, parentScope, name) - - if isKnownNonPartial: - self.setNonPartial(location, parent, members) - - def __str__(self): - return "Interface '%s'" % self.identifier.name - - def ctor(self): - identifier = IDLUnresolvedIdentifier(self.location, "constructor", - allowForbidden=True) - try: - return self._lookupIdentifier(identifier) - except: - return 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]) - - # Verify that our [Exposed] value, if any, makes sense. - for globalName in self._exposureGlobalNames: - if globalName not in scope.globalNames: - raise WebIDLError("Unknown [Exposed] value %s" % globalName, - [self.location]) - - if len(self._exposureGlobalNames) == 0: - self._exposureGlobalNames.add(scope.primaryGlobalName) - - globalNameSetToExposureSet(scope, self._exposureGlobalNames, - self.exposureSet) - - # 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) - - # 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): - raise WebIDLError("%s inherits from %s which does not have " - "a definition" % - (self.identifier.name, - self.parent.identifier.name), - [self.location]) - assert not parent or isinstance(parent, IDLInterface) - - self.parent = parent - - assert iter(self.members) - - if self.parent: - self.parent.finish(scope) - - self.parent._hasChildInterfaces = True - - 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")): - # Note: This is not a self.parent.isOnGlobalProtoChain() check - # because ancestors of a [Global] interface can have other - # descendants. - raise WebIDLError("[Global] interface has another interface " - "inheriting from it", - [self.location, self.parent.location]) - - # Make sure that we're not exposed in places where our parent is not - if not self.exposureSet.issubset(self.parent.exposureSet): - raise WebIDLError("Interface %s is exposed in globals where its " - "parent interface %s is not exposed." % - (self.identifier.name, - self.parent.identifier.name), - [self.location, self.parent.location]) - - # Callbacks must not inherit from non-callbacks or inherit from - # anything that has consequential interfaces. - # 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 " - "non-callback interface %s" % - (self.identifier.name, - self.parent.identifier.name), - [self.location, self.parent.location]) - elif self.parent.isCallback(): - raise WebIDLError("Non-callback interface %s inheriting from " - "callback interface %s" % - (self.identifier.name, - self.parent.identifier.name), - [self.location, self.parent.location]) - - for iface in self.implementedInterfaces: - iface.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() - - # 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]) - - ctor = self.ctor() - if ctor is not None: - ctor.finish(scope) - - for ctor in self.namedConstructors: - ctor.finish(scope) - - # Make a copy of our member list, so things that implement us - # can get those without all the stuff we implement ourselves - # 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(), - cmp=cmp, - 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]) - additionalMembers = iface.originalMembers; - for additionalMember in additionalMembers: - for member in self.members: - if additionalMember.identifier.name == member.identifier.name: - raise WebIDLError( - "Multiple definitions of %s on %s coming from 'implements' statements" % - (member.identifier.name, self), - [additionalMember.location, member.location]) - self.members.extend(additionalMembers) - iface.interfacesImplementingSelf.add(self) - - for ancestor in self.getInheritedInterfaces(): - ancestor.interfacesBasedOnSelf.add(self) - 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 - # do this before we set "originatingInterface" on our unforgeable - # members. - if self.getExtendedAttribute("Unforgeable"): - # Check that the interface already has all the things the - # spec would otherwise require us to synthesize and is - # missing the ones we plan to synthesize. - if not any(m.isMethod() and m.isStringifier() for m in self.members): - raise WebIDLError("Unforgeable interface %s does not have a " - "stringifier" % self.identifier.name, - [self.location]) - - for m in self.members: - if ((m.isMethod() and m.isJsonifier()) or - m.identifier.name == "toJSON"): - raise WebIDLError("Unforgeable interface %s has a " - "jsonifier so we won't be able to add " - "one ourselves" % self.identifier.name, - [self.location, m.location]) - - if m.identifier.name == "valueOf" and not m.isStatic(): - raise WebIDLError("Unforgeable interface %s has a valueOf " - "member so we won't be able to add one " - "ourselves" % self.identifier.name, - [self.location, m.location]) - - for member in self.members: - if ((member.isAttr() or member.isMethod()) and - member.isUnforgeable() and - not hasattr(member, "originatingInterface")): - member.originatingInterface = self - - # Compute slot indices for our members before we pull in - # unforgeable members from our parent. - for member in self.members: - if (member.isAttr() and - (member.getExtendedAttribute("StoreInSlot") or - member.getExtendedAttribute("Cached"))): - member.slotIndex = self.totalMembersInSlots - self.totalMembersInSlots += 1 - if member.getExtendedAttribute("StoreInSlot"): - 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. - for unforgeableMember in (member for member in self.parent.members if - (member.isAttr() or member.isMethod()) and - member.isUnforgeable()): - shadows = [ m for m in self.members if - (m.isAttr() or m.isMethod()) and - not m.isStatic() and - m.identifier.name == unforgeableMember.identifier.name ] - if len(shadows) != 0: - locs = [unforgeableMember.location] + [ s.location for s - in shadows ] - raise WebIDLError("Interface %s shadows [Unforgeable] " - "members of %s" % - (self.identifier.name, - ancestor.identifier.name), - locs) - # And now just stick it in our members, since we won't be - # inheriting this down the proto chain. If we really cared we - # could try to do something where we set up the unforgeable - # attributes/methods of ancestor interfaces, with their - # corresponding getters, on our interface, but that gets pretty - # complicated and seems unnecessary. - self.members.append(unforgeableMember) - - # Ensure that there's at most one of each {named,indexed} - # {getter,setter,creator,deleter}, at most one stringifier, - # and at most one legacycaller. Note that this last is not - # quite per spec, but in practice no one overloads - # legacycallers. - specialMembersSeen = {} - for member in self.members: - if not member.isMethod(): - continue - - if member.isGetter(): - memberType = "getters" - elif member.isSetter(): - memberType = "setters" - elif member.isCreator(): - memberType = "creators" - elif member.isDeleter(): - memberType = "deleters" - elif member.isStringifier(): - memberType = "stringifiers" - elif member.isJsonifier(): - memberType = "jsonifiers" - elif member.isLegacycaller(): - memberType = "legacycallers" - else: - continue - - if (memberType != "stringifiers" and memberType != "legacycallers" and - memberType != "jsonifiers"): - if member.isNamed(): - memberType = "named " + memberType - else: - assert member.isIndexed() - memberType = "indexed " + memberType - - if memberType in specialMembersSeen: - raise WebIDLError("Multiple " + memberType + " on %s" % (self), - [self.location, - specialMembersSeen[memberType].location, - member.location]) - - specialMembersSeen[memberType] = member - - if self._isOnGlobalProtoChain: - # Make sure we have no named setters, creators, or deleters - for memberType in ["setter", "creator", "deleter"]: - memberId = "named " + memberType + "s" - if memberId in specialMembersSeen: - raise WebIDLError("Interface with [Global] has a named %s" % - memberType, - [self.location, - specialMembersSeen[memberId].location]) - # Make sure we're not [OverrideBuiltins] - if self.getExtendedAttribute("OverrideBuiltins"): - raise WebIDLError("Interface with [Global] also has " - "[OverrideBuiltins]", - [self.location]) - # Mark all of our ancestors as being on the global's proto chain too - parent = self.parent - while parent: - # Must not inherit from an interface with [OverrideBuiltins] - if parent.getExtendedAttribute("OverrideBuiltins"): - raise WebIDLError("Interface with [Global] inherits from " - "interface with [OverrideBuiltins]", - [self.location, parent.location]) - parent._isOnGlobalProtoChain = True - parent = parent.parent - - def validate(self): - # We don't support consequential unforgeable interfaces. Need to check - # this here, becaue 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(): - raise WebIDLError("%s is an unforgeable ancestor interface" % - self.identifier.name, - [self.location] + - list(i.location for i in - self.interfacesBasedOnSelf if i.parent == self)) - - - for member in self.members: - member.validate() - - # Check that PutForwards refers to another attribute and that no - # cycles exist in forwarded assignments. - if member.isAttr(): - iface = self - attr = member - putForwards = attr.getExtendedAttribute("PutForwards") - if putForwards and self.isCallback(): - raise WebIDLError("[PutForwards] used on an attribute " - "on interface %s which is a callback " - "interface" % self.identifier.name, - [self.location, member.location]) - - while putForwards is not None: - forwardIface = attr.type.unroll().inner - fowardAttr = None - - for forwardedMember in forwardIface.members: - if (not forwardedMember.isAttr() or - forwardedMember.identifier.name != putForwards[0]): - continue - if forwardedMember == member: - raise WebIDLError("Cycle detected in forwarded " - "assignments for attribute %s on " - "%s" % - (member.identifier.name, self), - [member.location]) - fowardAttr = forwardedMember - break - - if fowardAttr is None: - raise WebIDLError("Attribute %s on %s forwards to " - "missing attribute %s" % - (attr.identifier.name, iface, putForwards), - [attr.location]) - - iface = forwardIface - attr = fowardAttr - putForwards = attr.getExtendedAttribute("PutForwards") - - if (self.getExtendedAttribute("Pref") and - self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])): - raise WebIDLError("[Pref] used on an member that is not %s-only" % - self.parentScope.primaryGlobalName, - [self.location]) - - - def isInterface(self): - return True - - 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 - - def isCallback(self): - return self._callback - - def isSingleOperationInterface(self): - assert self.isCallback() or self.isJSImplemented() - return ( - # JS-implemented things should never need the - # this-handling weirdness of single-operation interfaces. - 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 - # operations have the same identifier - len(set(m.identifier.name for m in self.members if - m.isMethod() and not m.isStatic())) == 1) - - def inheritanceDepth(self): - depth = 0 - parent = self.parent - while parent: - depth = depth + 1 - parent = parent.parent - return depth - - def hasConstants(self): - return any(m.isConst() for m in self.members) - - def hasInterfaceObject(self): - if self.isCallback(): - return self.hasConstants() - return not hasattr(self, "_noInterfaceObject") - - def hasInterfacePrototypeObject(self): - return not self.isCallback() and self.getUserData('hasConcreteDescendant', False) - - def addExtendedAttributes(self, attrs): - for attr in attrs: - identifier = attr.identifier() - - # Special cased attrs - if identifier == "TreatNonCallableAsNull": - raise WebIDLError("TreatNonCallableAsNull cannot be specified on interfaces", - [attr.location, self.location]) - if identifier == "TreatNonObjectAsNull": - raise WebIDLError("TreatNonObjectAsNull cannot be specified on interfaces", - [attr.location, self.location]) - elif identifier == "NoInterfaceObject": - if not attr.noArguments(): - raise WebIDLError("[NoInterfaceObject] must take no arguments", - [attr.location]) - - if self.ctor(): - raise WebIDLError("Constructor and NoInterfaceObject are incompatible", - [self.location]) - - self._noInterfaceObject = True - elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor": - if identifier == "Constructor" and not self.hasInterfaceObject(): - raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", - [self.location]) - - if identifier == "NamedConstructor" and not attr.hasValue(): - raise WebIDLError("NamedConstructor must either take an identifier or take a named argument list", - [attr.location]) - - if identifier == "ChromeConstructor" and not self.hasInterfaceObject(): - raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", - [self.location]) - - args = attr.args() if attr.hasArgs() else [] - - retType = IDLWrapperType(self.location, self) - - if identifier == "Constructor" or identifier == "ChromeConstructor": - name = "constructor" - allowForbidden = True - else: - name = attr.value() - allowForbidden = False - - methodIdentifier = IDLUnresolvedIdentifier(self.location, name, - allowForbidden=allowForbidden) - - method = IDLMethod(self.location, methodIdentifier, retType, - args, static=True) - # Constructors are always NewObject and are always - # assumed to be able to throw (since there's no way to - # indicate otherwise) and never have any other - # extended attributes. - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("NewObject",)), - IDLExtendedAttribute(self.location, ("Throws",))]) - if identifier == "ChromeConstructor": - method.addExtendedAttributes( - [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) - - if identifier == "Constructor" or identifier == "ChromeConstructor": - method.resolve(self) - else: - # We need to detect conflicts for NamedConstructors across - # interfaces. We first call resolve on the parentScope, - # which will merge all NamedConstructors with the same - # identifier accross interfaces as overloads. - method.resolve(self.parentScope) - - # Then we look up the identifier on the parentScope. If the - # result is the same as the method we're adding then it - # hasn't been added as an overload and it's the first time - # we've encountered a NamedConstructor with that identifier. - # If the result is not the same as the method we're adding - # then it has been added as an overload and we need to check - # whether the result is actually one of our existing - # NamedConstructors. - newMethod = self.parentScope.lookupIdentifier(method.identifier) - if newMethod == method: - self.namedConstructors.append(method) - elif not newMethod in self.namedConstructors: - raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", - [method.location, newMethod.location]) - elif (identifier == "ArrayClass"): - if not attr.noArguments(): - raise WebIDLError("[ArrayClass] must take no arguments", - [attr.location]) - if self.parent: - raise WebIDLError("[ArrayClass] must not be specified on " - "an interface with inherited interfaces", - [attr.location, self.location]) - elif (identifier == "ExceptionClass"): - if not attr.noArguments(): - raise WebIDLError("[ExceptionClass] must take no arguments", - [attr.location]) - if self.parent: - raise WebIDLError("[ExceptionClass] must not be specified on " - "an interface with inherited interfaces", - [attr.location, self.location]) - elif identifier == "Global": - if attr.hasValue(): - self.globalNames = [ attr.value() ] - elif attr.hasArgs(): - self.globalNames = attr.args() - else: - self.globalNames = [ self.identifier.name ] - self.parentScope.globalNames.update(self.globalNames) - for globalName in self.globalNames: - self.parentScope.globalNameMapping[globalName].add(self.identifier.name) - 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.globalNames.add(self.identifier.name) - self.parentScope.globalNameMapping[self.identifier.name].add(self.identifier.name) - self._isOnGlobalProtoChain = True - elif (identifier == "NeedNewResolve" or - identifier == "OverrideBuiltins" or - identifier == "ChromeOnly" or - identifier == "Unforgeable" or - identifier == "LegacyEventInit"): - # Known extended attributes that do not take values - if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) - elif identifier == "Exposed": - convertExposedAttrToGlobalNameSet(attr, - self._exposureGlobalNames) - elif (identifier == "Pref" or - identifier == "JSImplementation" or - identifier == "HeaderFile" or - identifier == "NavigatorProperty" or - identifier == "AvailableIn" or - identifier == "Func" or - identifier == "CheckPermissions"): - # Known extended attributes that take a string value - if not attr.hasValue(): - raise WebIDLError("[%s] must have a value" % identifier, - [attr.location]) - 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 addImplementedInterface(self, implementedInterface): - assert(isinstance(implementedInterface, IDLInterface)) - self.implementedInterfaces.add(implementedInterface) - - def getInheritedInterfaces(self): - """ - Returns a list of the interfaces this interface inherits from - (not including this interface itself). The list is in order - from most derived to least derived. - """ - assert(self._finished) - if not self.parent: - return [] - parentInterfaces = self.parent.getInheritedInterfaces() - 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. - """ - if self.parent: - if self.parent == otherInterface: - return self - 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 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 interface", - [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 - 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 getJSImplementation(self): - classId = self.getExtendedAttribute("JSImplementation") - if not classId: - return classId - assert isinstance(classId, list) - assert len(classId) == 1 - return classId[0] - - def isJSImplemented(self): - return bool(self.getJSImplementation()) - - def getNavigatorProperty(self): - naviProp = self.getExtendedAttribute("NavigatorProperty") - if not naviProp: - return None - assert len(naviProp) == 1 - assert isinstance(naviProp, list) - assert len(naviProp[0]) != 0 - return naviProp[0] - - def hasChildInterfaces(self): - return self._hasChildInterfaces - - def isOnGlobalProtoChain(self): - return self._isOnGlobalProtoChain - - def _getDependentObjects(self): - deps = set(self.members) - deps.union(self.implementedInterfaces) - if self.parent: - deps.add(self.parent) - return deps - - def hasMembersInSlots(self): - return self._ownMembersInSlots != 0 - -class IDLDictionary(IDLObjectWithScope): - def __init__(self, location, parentScope, name, parent, members): - assert isinstance(parentScope, IDLScope) - assert isinstance(name, IDLUnresolvedIdentifier) - assert not parent or isinstance(parent, IDLIdentifierPlaceholder) - - self.parent = parent - self._finished = False - self.members = list(members) - - IDLObjectWithScope.__init__(self, location, parentScope, name) - - def __str__(self): - return "Dictionary '%s'" % self.identifier.name - - def isDictionary(self): - return True; - - def finish(self, scope): - if self._finished: - return - - self._finished = True - - if self.parent: - assert isinstance(self.parent, IDLIdentifierPlaceholder) - oldParent = self.parent - self.parent = self.parent.finish(scope) - if not isinstance(self.parent, IDLDictionary): - raise WebIDLError("Dictionary %s has parent that is not a dictionary" % - self.identifier.name, - [oldParent.location, self.parent.location]) - - # Make sure the parent resolves all its members before we start - # looking at them. - self.parent.finish(scope) - - for member in self.members: - member.resolve(self) - if not member.isComplete(): - member.complete(scope) - assert member.type.isComplete() - - # Members of a dictionary are sorted in lexicographic order - self.members.sort(cmp=cmp, key=lambda x: x.identifier.name) - - inheritedMembers = [] - ancestor = self.parent - while ancestor: - if ancestor == self: - raise WebIDLError("Dictionary %s has itself as an ancestor" % - self.identifier.name, - [self.identifier.location]) - inheritedMembers.extend(ancestor.members) - ancestor = ancestor.parent - - # Catch name duplication - for inheritedMember in inheritedMembers: - for member in self.members: - if member.identifier.name == inheritedMember.identifier.name: - raise WebIDLError("Dictionary %s has two members with name %s" % - (self.identifier.name, member.identifier.name), - [member.location, inheritedMember.location]) - - def validate(self): - def typeContainsDictionary(memberType, dictionary): - """ - Returns a tuple whose: - - - First element is a Boolean value indicating whether - memberType contains dictionary. - - - Second element is: - A list of locations that leads from the type that was passed in - the memberType argument, to the dictionary being validated, - if the boolean value in the first element is True. - - None, if the boolean value in the first element is False. - """ - - if (memberType.nullable() or - memberType.isArray() or - memberType.isSequence() or - memberType.isMozMap()): - return typeContainsDictionary(memberType.inner, dictionary) - - if memberType.isDictionary(): - if memberType.inner == dictionary: - return (True, [memberType.location]) - - (contains, locations) = dictionaryContainsDictionary(memberType.inner, \ - dictionary) - if contains: - return (True, [memberType.location] + locations) - - if memberType.isUnion(): - for member in memberType.flatMemberTypes: - (contains, locations) = typeContainsDictionary(member, dictionary) - if contains: - return (True, locations) - - return (False, None) - - def dictionaryContainsDictionary(dictMember, dictionary): - for member in dictMember.members: - (contains, locations) = typeContainsDictionary(member.type, dictionary) - if contains: - return (True, [member.location] + locations) - - if dictMember.parent: - if dictMember.parent == dictionary: - return (True, [dictMember.location]) - else: - (contains, locations) = dictionaryContainsDictionary(dictMember.parent, dictionary) - if contains: - return (True, [dictMember.location] + locations) - - return (False, None) - - for member in self.members: - if member.type.isDictionary() and member.type.nullable(): - raise WebIDLError("Dictionary %s has member with nullable " - "dictionary type" % self.identifier.name, - [member.location]) - (contains, locations) = typeContainsDictionary(member.type, self) - if contains: - raise WebIDLError("Dictionary %s has member with itself as type." % - self.identifier.name, - [member.location] + locations) - - def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 - - def _getDependentObjects(self): - deps = set(self.members) - if (self.parent): - deps.add(self.parent) - return deps - -class IDLEnum(IDLObjectWithIdentifier): - def __init__(self, location, parentScope, name, values): - assert isinstance(parentScope, IDLScope) - assert isinstance(name, IDLUnresolvedIdentifier) - - if len(values) != len(set(values)): - raise WebIDLError("Enum %s has multiple identical strings" % name.name, - [location]) - - IDLObjectWithIdentifier.__init__(self, location, parentScope, name) - self._values = values - - def values(self): - return self._values - - def finish(self, scope): - pass - - def validate(self): - pass - - def isEnum(self): - return True - - def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 - - def _getDependentObjects(self): - return set() - -class IDLType(IDLObject): - Tags = enum( - # The integer types - 'int8', - 'uint8', - 'int16', - 'uint16', - 'int32', - 'uint32', - 'int64', - 'uint64', - # Additional primitive types - 'bool', - 'unrestricted_float', - 'float', - 'unrestricted_double', - # "double" last primitive type to match IDLBuiltinType - 'double', - # Other types - 'any', - 'domstring', - 'bytestring', - 'scalarvaluestring', - 'object', - 'date', - 'void', - # Funny stuff - 'interface', - 'dictionary', - 'enum', - 'callback', - 'union', - 'sequence', - 'mozmap', - 'array' - ) - - def __init__(self, location, name): - IDLObject.__init__(self, location) - self.name = name - self.builtin = False - - def __eq__(self, other): - return other and self.builtin == other.builtin and self.name == other.name - - def __ne__(self, other): - return not self == other - - def __str__(self): - return str(self.name) - - def isType(self): - return True - - def nullable(self): - return False - - def isPrimitive(self): - return False - - def isBoolean(self): - return False - - def isNumeric(self): - return False - - def isString(self): - return False - - def isByteString(self): - return False - - def isDOMString(self): - return False - - def isScalarValueString(self): - return False - - def isVoid(self): - return self.name == "Void" - - def isSequence(self): - return False - - def isMozMap(self): - return False - - def isArray(self): - return False - - def isArrayBuffer(self): - return False - - def isArrayBufferView(self): - return False - - def isTypedArray(self): - return False - - def isCallbackInterface(self): - return False - - def isNonCallbackInterface(self): - return False - - def isGeckoInterface(self): - """ Returns a boolean indicating whether this type is an 'interface' - type that is implemented in Gecko. At the moment, this returns - true for all interface types that are not types from the TypedArray - spec.""" - return self.isInterface() and not self.isSpiderMonkeyInterface() - - def isSpiderMonkeyInterface(self): - """ Returns a boolean indicating whether this type is an 'interface' - type that is implemented in Spidermonkey. At the moment, this - only returns true for the types from the TypedArray spec. """ - return self.isInterface() and (self.isArrayBuffer() or \ - self.isArrayBufferView() or \ - self.isTypedArray()) - - def isDictionary(self): - return False - - def isInterface(self): - return False - - def isAny(self): - return self.tag() == IDLType.Tags.any - - def isDate(self): - return self.tag() == IDLType.Tags.date - - def isObject(self): - return self.tag() == IDLType.Tags.object - - def isPromise(self): - return False - - def isComplete(self): - return True - - def includesRestrictedFloat(self): - return False - - def isFloat(self): - return False - - def isUnrestricted(self): - # Should only call this on float types - assert self.isFloat() - - def isSerializable(self): - return False - - def tag(self): - assert False # Override me! - - def treatNonCallableAsNull(self): - assert self.tag() == IDLType.Tags.callback - return self.nullable() and self.inner._treatNonCallableAsNull - - def treatNonObjectAsNull(self): - assert self.tag() == IDLType.Tags.callback - return self.nullable() and self.inner._treatNonObjectAsNull - - def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 - - def resolveType(self, parentScope): - pass - - def unroll(self): - return self - - def isDistinguishableFrom(self, other): - raise TypeError("Can't tell whether a generic type is or is not " - "distinguishable from other things") - - def isExposedInAllOf(self, exposureSet): - return True - -class IDLUnresolvedType(IDLType): - """ - Unresolved types are interface types - """ - - def __init__(self, location, name, promiseInnerType=None): - IDLType.__init__(self, location, name) - self._promiseInnerType = promiseInnerType - - def isComplete(self): - return False - - def complete(self, scope): - obj = None - try: - obj = scope._lookupIdentifier(self.name) - except: - raise WebIDLError("Unresolved type '%s'." % self.name, - [self.location]) - - assert obj - if obj.isType(): - # obj itself might not be complete; deal with that. - assert obj != self - if not obj.isComplete(): - obj = obj.complete(scope) - return obj - - if self._promiseInnerType and not self._promiseInnerType.isComplete(): - self._promiseInnerType = self._promiseInnerType.complete(scope) - - name = self.name.resolve(scope, None) - return IDLWrapperType(self.location, obj, self._promiseInnerType) - - def isDistinguishableFrom(self, other): - raise TypeError("Can't tell whether an unresolved type is or is not " - "distinguishable from other things") - -class IDLNullableType(IDLType): - def __init__(self, location, innerType): - assert not innerType.isVoid() - assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] - - IDLType.__init__(self, location, innerType.name) - self.inner = innerType - self.builtin = False - - def __eq__(self, other): - return isinstance(other, IDLNullableType) and self.inner == other.inner - - def __str__(self): - return self.inner.__str__() + "OrNull" - - def nullable(self): - return True - - def isCallback(self): - return self.inner.isCallback() - - def isPrimitive(self): - return self.inner.isPrimitive() - - def isBoolean(self): - return self.inner.isBoolean() - - def isNumeric(self): - return self.inner.isNumeric() - - def isString(self): - return self.inner.isString() - - def isByteString(self): - return self.inner.isByteString() - - def isDOMString(self): - return self.inner.isDOMString() - - def isScalarValueString(self): - return self.inner.isScalarValueString() - - def isFloat(self): - return self.inner.isFloat() - - def isUnrestricted(self): - return self.inner.isUnrestricted() - - def includesRestrictedFloat(self): - return self.inner.includesRestrictedFloat() - - def isInteger(self): - return self.inner.isInteger() - - def isVoid(self): - return False - - def isSequence(self): - return self.inner.isSequence() - - def isMozMap(self): - return self.inner.isMozMap() - - def isArray(self): - return self.inner.isArray() - - def isArrayBuffer(self): - return self.inner.isArrayBuffer() - - def isArrayBufferView(self): - return self.inner.isArrayBufferView() - - def isTypedArray(self): - return self.inner.isTypedArray() - - def isDictionary(self): - return self.inner.isDictionary() - - def isInterface(self): - return self.inner.isInterface() - - def isCallbackInterface(self): - return self.inner.isCallbackInterface() - - def isNonCallbackInterface(self): - return self.inner.isNonCallbackInterface() - - def isEnum(self): - return self.inner.isEnum() - - def isUnion(self): - return self.inner.isUnion() - - def isSerializable(self): - return self.inner.isSerializable() - - def tag(self): - return self.inner.tag() - - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolveType(parentScope) - - def isComplete(self): - return self.inner.isComplete() - - def complete(self, scope): - self.inner = self.inner.complete(scope) - if self.inner.nullable(): - raise WebIDLError("The inner type of a nullable type must not be " - "a nullable type", - [self.location, self.inner.location]) - if self.inner.isUnion(): - if self.inner.hasNullableType: - raise WebIDLError("The inner type of a nullable type must not " - "be a union type that itself has a nullable " - "type as a member type", [self.location]) - - self.name = self.inner.name - return self - - def unroll(self): - return self.inner.unroll() - - def isDistinguishableFrom(self, other): - if (other.nullable() or (other.isUnion() and other.hasNullableType) or - other.isDictionary()): - # Can't tell which type null should become - return False - return self.inner.isDistinguishableFrom(other) - - def _getDependentObjects(self): - return self.inner._getDependentObjects() - -class IDLSequenceType(IDLType): - def __init__(self, location, parameterType): - assert not parameterType.isVoid() - - IDLType.__init__(self, location, parameterType.name) - self.inner = parameterType - self.builtin = False - - def __eq__(self, other): - return isinstance(other, IDLSequenceType) and self.inner == other.inner - - def __str__(self): - return self.inner.__str__() + "Sequence" - - def nullable(self): - return False - - def isPrimitive(self): - return False; - - def isString(self): - return False; - - def isByteString(self): - return False - - def isDOMString(self): - return False - - def isScalarValueString(self): - return False - - def isVoid(self): - return False - - def isSequence(self): - return True - - def isArray(self): - return False - - def isDictionary(self): - return False - - def isInterface(self): - return False - - def isEnum(self): - return False - - def isSerializable(self): - return self.inner.isSerializable() - - def includesRestrictedFloat(self): - return self.inner.includesRestrictedFloat() - - def tag(self): - return IDLType.Tags.sequence - - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolveType(parentScope) - - def isComplete(self): - return self.inner.isComplete() - - def complete(self, scope): - self.inner = self.inner.complete(scope) - self.name = self.inner.name - return self - - def unroll(self): - return self.inner.unroll() - - def isDistinguishableFrom(self, other): - if other.isUnion(): - # Just forward to the union; it'll deal - return other.isDistinguishableFrom(self) - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isDate() or other.isNonCallbackInterface() or other.isMozMap()) - - def _getDependentObjects(self): - return self.inner._getDependentObjects() - -class IDLMozMapType(IDLType): - # XXXbz This is pretty similar to IDLSequenceType in various ways. - # And maybe to IDLNullableType. Should we have a superclass for - # "type containing this other type"? Bug 1015318. - def __init__(self, location, parameterType): - assert not parameterType.isVoid() - - IDLType.__init__(self, location, parameterType.name) - self.inner = parameterType - self.builtin = False - - def __eq__(self, other): - return isinstance(other, IDLMozMapType) and self.inner == other.inner - - def __str__(self): - return self.inner.__str__() + "MozMap" - - def isMozMap(self): - return True - - def includesRestrictedFloat(self): - return self.inner.includesRestrictedFloat() - - def tag(self): - return IDLType.Tags.mozmap - - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolveType(parentScope) - - def isComplete(self): - return self.inner.isComplete() - - def complete(self, scope): - self.inner = self.inner.complete(scope) - self.name = self.inner.name - return self - - def unroll(self): - # We do not unroll our inner. Just stop at ourselves. That - # lets us add headers for both ourselves and our inner as - # needed. - return self - - def isDistinguishableFrom(self, other): - if other.isUnion(): - # Just forward to the union; it'll deal - return other.isDistinguishableFrom(self) - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isDate() or other.isNonCallbackInterface() or other.isSequence()) - - def isExposedInAllOf(self, exposureSet): - return self.inner.unroll().isExposedInAllOf(exposureSet) - - def _getDependentObjects(self): - return self.inner._getDependentObjects() - -class IDLUnionType(IDLType): - def __init__(self, location, memberTypes): - IDLType.__init__(self, location, "") - self.memberTypes = memberTypes - self.hasNullableType = False - self.hasDictionaryType = False - self.flatMemberTypes = None - self.builtin = False - - def __eq__(self, other): - return isinstance(other, IDLUnionType) and self.memberTypes == other.memberTypes - - def isVoid(self): - return False - - def isUnion(self): - return True - - def isSerializable(self): - return all(m.isSerializable() for m in self.memberTypes) - - def includesRestrictedFloat(self): - return any(t.includesRestrictedFloat() for t in self.memberTypes) - - def tag(self): - return IDLType.Tags.union - - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - for t in self.memberTypes: - t.resolveType(parentScope) - - def isComplete(self): - return self.flatMemberTypes is not None - - def complete(self, scope): - def typeName(type): - if isinstance(type, IDLNullableType): - return typeName(type.inner) + "OrNull" - if isinstance(type, IDLWrapperType): - return typeName(type._identifier.object()) - if isinstance(type, IDLObjectWithIdentifier): - return typeName(type.identifier) - if (isinstance(type, IDLType) and - (type.isArray() or type.isSequence() or type.isMozMap)): - return str(type) - return type.name - - for (i, type) in enumerate(self.memberTypes): - if not type.isComplete(): - self.memberTypes[i] = type.complete(scope) - - self.name = "Or".join(typeName(type) for type in self.memberTypes) - self.flatMemberTypes = list(self.memberTypes) - i = 0 - while i < len(self.flatMemberTypes): - if self.flatMemberTypes[i].nullable(): - if self.hasNullableType: - raise WebIDLError("Can't have more than one nullable types in a union", - [nullableType.location, self.flatMemberTypes[i].location]) - if self.hasDictionaryType: - raise WebIDLError("Can't have a nullable type and a " - "dictionary type in a union", - [dictionaryType.location, - self.flatMemberTypes[i].location]) - self.hasNullableType = True - nullableType = self.flatMemberTypes[i] - self.flatMemberTypes[i] = self.flatMemberTypes[i].inner - continue - if self.flatMemberTypes[i].isDictionary(): - if self.hasNullableType: - raise WebIDLError("Can't have a nullable type and a " - "dictionary type in a union", - [nullableType.location, - self.flatMemberTypes[i].location]) - self.hasDictionaryType = True - dictionaryType = self.flatMemberTypes[i] - elif self.flatMemberTypes[i].isUnion(): - self.flatMemberTypes[i:i + 1] = self.flatMemberTypes[i].memberTypes - continue - i += 1 - - for (i, t) in enumerate(self.flatMemberTypes[:-1]): - for u in self.flatMemberTypes[i + 1:]: - if not t.isDistinguishableFrom(u): - raise WebIDLError("Flat member types of a union should be " - "distinguishable, " + str(t) + " is not " - "distinguishable from " + str(u), - [self.location, t.location, u.location]) - - return self - - def isDistinguishableFrom(self, other): - if self.hasNullableType and other.nullable(): - # Can't tell which type null should become - return False - if other.isUnion(): - otherTypes = other.unroll().memberTypes - else: - otherTypes = [other] - # For every type in otherTypes, check that it's distinguishable from - # every type in our types - for u in otherTypes: - if any(not t.isDistinguishableFrom(u) for t in self.memberTypes): - return False - return True - - def isExposedInAllOf(self, exposureSet): - # We could have different member types in different globals. Just make sure that each thing in exposureSet has one of our member types exposed in it. - for globalName in exposureSet: - if not any(t.unroll().isExposedInAllOf(set([globalName])) for t - in self.flatMemberTypes): - return False - return True - - def _getDependentObjects(self): - return set(self.memberTypes) - -class IDLArrayType(IDLType): - def __init__(self, location, parameterType): - assert not parameterType.isVoid() - if parameterType.isSequence(): - raise WebIDLError("Array type cannot parameterize over a sequence type", - [location]) - if parameterType.isMozMap(): - raise WebIDLError("Array type cannot parameterize over a MozMap type", - [location]) - if parameterType.isDictionary(): - raise WebIDLError("Array type cannot parameterize over a dictionary type", - [location]) - - IDLType.__init__(self, location, parameterType.name) - self.inner = parameterType - self.builtin = False - - def __eq__(self, other): - return isinstance(other, IDLArrayType) and self.inner == other.inner - - def __str__(self): - return self.inner.__str__() + "Array" - - def nullable(self): - return False - - def isPrimitive(self): - return False - - def isString(self): - return False - - def isByteString(self): - return False - - def isDOMString(self): - return False - - def isScalarValueString(self): - return False - - def isVoid(self): - return False - - def isSequence(self): - assert not self.inner.isSequence() - return False - - def isArray(self): - return True - - def isDictionary(self): - assert not self.inner.isDictionary() - return False - - def isInterface(self): - return False - - def isEnum(self): - return False - - def tag(self): - return IDLType.Tags.array - - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolveType(parentScope) - - def isComplete(self): - return self.inner.isComplete() - - def complete(self, scope): - self.inner = self.inner.complete(scope) - self.name = self.inner.name - - if self.inner.isDictionary(): - raise WebIDLError("Array type must not contain " - "dictionary as element type.", - [self.inner.location]) - - assert not self.inner.isSequence() - - return self - - def unroll(self): - return self.inner.unroll() - - def isDistinguishableFrom(self, other): - if other.isUnion(): - # Just forward to the union; it'll deal - return other.isDistinguishableFrom(self) - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isDate() or other.isNonCallbackInterface()) - - def _getDependentObjects(self): - return self.inner._getDependentObjects() - -class IDLTypedefType(IDLType, IDLObjectWithIdentifier): - def __init__(self, location, innerType, name): - IDLType.__init__(self, location, innerType.name) - - identifier = IDLUnresolvedIdentifier(location, name) - - IDLObjectWithIdentifier.__init__(self, location, None, identifier) - - self.inner = innerType - self.name = name - self.builtin = False - - def __eq__(self, other): - return isinstance(other, IDLTypedefType) and self.inner == other.inner - - def __str__(self): - return self.identifier.name - - def nullable(self): - return self.inner.nullable() - - def isPrimitive(self): - return self.inner.isPrimitive() - - def isBoolean(self): - return self.inner.isBoolean() - - def isNumeric(self): - return self.inner.isNumeric() - - def isString(self): - return self.inner.isString() - - def isByteString(self): - return self.inner.isByteString() - - def isDOMString(self): - return self.inner.isDOMString() - - def isScalarValueString(self): - return self.inner.isScalarValueString() - - def isVoid(self): - return self.inner.isVoid() - - def isSequence(self): - return self.inner.isSequence() - - def isMozMap(self): - return self.inner.isMozMap() - - def isArray(self): - return self.inner.isArray() - - def isDictionary(self): - return self.inner.isDictionary() - - def isArrayBuffer(self): - return self.inner.isArrayBuffer() - - def isArrayBufferView(self): - return self.inner.isArrayBufferView() - - def isTypedArray(self): - return self.inner.isTypedArray() - - def isInterface(self): - return self.inner.isInterface() - - def isCallbackInterface(self): - return self.inner.isCallbackInterface() - - def isNonCallbackInterface(self): - return self.inner.isNonCallbackInterface() - - def isComplete(self): - return False - - def complete(self, parentScope): - if not self.inner.isComplete(): - self.inner = self.inner.complete(parentScope) - assert self.inner.isComplete() - return self.inner - - def finish(self, parentScope): - # Maybe the IDLObjectWithIdentifier for the typedef should be - # a separate thing from the type? If that happens, we can - # remove some hackery around avoiding isInterface() in - # Configuration.py. - self.complete(parentScope) - - def validate(self): - pass - - # Do we need a resolveType impl? I don't think it's particularly useful.... - - def tag(self): - return self.inner.tag() - - def unroll(self): - return self.inner.unroll() - - def isDistinguishableFrom(self, other): - return self.inner.isDistinguishableFrom(other) - - def _getDependentObjects(self): - return self.inner._getDependentObjects() - -class IDLWrapperType(IDLType): - def __init__(self, location, inner, promiseInnerType=None): - IDLType.__init__(self, location, inner.identifier.name) - self.inner = inner - self._identifier = inner.identifier - self.builtin = False - assert not promiseInnerType or inner.identifier.name == "Promise" - self._promiseInnerType = promiseInnerType - - def __eq__(self, other): - return isinstance(other, IDLWrapperType) and \ - self._identifier == other._identifier and \ - self.builtin == other.builtin - - def __str__(self): - return str(self.name) + " (Wrapper)" - - def nullable(self): - return False - - def isPrimitive(self): - return False - - def isString(self): - return False - - def isByteString(self): - return False - - def isDOMString(self): - return False - - def isScalarValueString(self): - return False - - def isVoid(self): - return False - - def isSequence(self): - return False - - def isArray(self): - return False - - def isDictionary(self): - return isinstance(self.inner, IDLDictionary) - - def isInterface(self): - return isinstance(self.inner, IDLInterface) or \ - isinstance(self.inner, IDLExternalInterface) - - def isCallbackInterface(self): - return self.isInterface() and self.inner.isCallback() - - def isNonCallbackInterface(self): - return self.isInterface() and not self.inner.isCallback() - - def isEnum(self): - return isinstance(self.inner, IDLEnum) - - def isPromise(self): - return isinstance(self.inner, IDLInterface) and \ - self.inner.identifier.name == "Promise" - - def isSerializable(self): - if self.isInterface(): - if self.inner.isExternal(): - return False - return any(m.isMethod() and m.isJsonifier() for m in self.inner.members) - elif self.isEnum(): - return True - elif self.isDictionary(): - return all(m.type.isSerializable() for m in self.inner.members) - else: - raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " - "is serializable" % type(self.inner), [self.location]) - - def resolveType(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.inner.resolve(parentScope) - - def isComplete(self): - return True - - def tag(self): - if self.isInterface(): - return IDLType.Tags.interface - elif self.isEnum(): - return IDLType.Tags.enum - elif self.isDictionary(): - return IDLType.Tags.dictionary - else: - assert False - - def isDistinguishableFrom(self, other): - if other.isUnion(): - # Just forward to the union; it'll deal - return other.isDistinguishableFrom(self) - assert self.isInterface() or self.isEnum() or self.isDictionary() - if self.isEnum(): - return (other.isPrimitive() or other.isInterface() or other.isObject() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate()) - if self.isDictionary() and other.nullable(): - return False - if other.isPrimitive() or other.isString() or other.isEnum() or other.isDate(): - return True - if self.isDictionary(): - return other.isNonCallbackInterface() - - assert self.isInterface() - if other.isInterface(): - if other.isSpiderMonkeyInterface(): - # Just let |other| handle things - return other.isDistinguishableFrom(self) - assert self.isGeckoInterface() and other.isGeckoInterface() - if self.inner.isExternal() or other.unroll().inner.isExternal(): - return self != other - return (len(self.inner.interfacesBasedOnSelf & - other.unroll().inner.interfacesBasedOnSelf) == 0 and - (self.isNonCallbackInterface() or - other.isNonCallbackInterface())) - if (other.isDictionary() or other.isCallback() or - other.isSequence() or other.isMozMap() or other.isArray()): - return self.isNonCallbackInterface() - - # Not much else |other| can be - assert other.isObject() - return False - - def isExposedInAllOf(self, exposureSet): - if not self.isInterface(): - 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. - return True - if (iface.identifier.name == "Promise" and - # Check the internal type - not self._promiseInnerType.unroll().isExposedInAllOf(exposureSet)): - return False - return iface.exposureSet.issuperset(exposureSet) - - def _getDependentObjects(self): - # NB: The codegen for an interface type depends on - # a) That the identifier is in fact an interface (as opposed to - # a dictionary or something else). - # b) The native type of the interface. - # If we depend on the interface object we will also depend on - # anything the interface depends on which is undesirable. We - # considered implementing a dependency just on the interface type - # file, but then every modification to an interface would cause this - # to be regenerated which is still undesirable. We decided not to - # depend on anything, reasoning that: - # 1) Changing the concrete type of the interface requires modifying - # Bindings.conf, which is still a global dependency. - # 2) Changing an interface to a dictionary (or vice versa) with the - # same identifier should be incredibly rare. - return set() - -class IDLBuiltinType(IDLType): - - Types = enum( - # The integer types - 'byte', - 'octet', - 'short', - 'unsigned_short', - 'long', - 'unsigned_long', - 'long_long', - 'unsigned_long_long', - # Additional primitive types - 'boolean', - 'unrestricted_float', - 'float', - 'unrestricted_double', - # IMPORTANT: "double" must be the last primitive type listed - 'double', - # Other types - 'any', - 'domstring', - 'bytestring', - 'scalarvaluestring', - 'object', - 'date', - 'void', - # Funny stuff - 'ArrayBuffer', - 'ArrayBufferView', - 'Int8Array', - 'Uint8Array', - 'Uint8ClampedArray', - 'Int16Array', - 'Uint16Array', - 'Int32Array', - 'Uint32Array', - 'Float32Array', - 'Float64Array' - ) - - TagLookup = { - Types.byte: IDLType.Tags.int8, - Types.octet: IDLType.Tags.uint8, - Types.short: IDLType.Tags.int16, - Types.unsigned_short: IDLType.Tags.uint16, - Types.long: IDLType.Tags.int32, - Types.unsigned_long: IDLType.Tags.uint32, - Types.long_long: IDLType.Tags.int64, - Types.unsigned_long_long: IDLType.Tags.uint64, - Types.boolean: IDLType.Tags.bool, - Types.unrestricted_float: IDLType.Tags.unrestricted_float, - Types.float: IDLType.Tags.float, - Types.unrestricted_double: IDLType.Tags.unrestricted_double, - Types.double: IDLType.Tags.double, - Types.any: IDLType.Tags.any, - Types.domstring: IDLType.Tags.domstring, - Types.bytestring: IDLType.Tags.bytestring, - Types.scalarvaluestring: IDLType.Tags.scalarvaluestring, - Types.object: IDLType.Tags.object, - Types.date: IDLType.Tags.date, - Types.void: IDLType.Tags.void, - Types.ArrayBuffer: IDLType.Tags.interface, - Types.ArrayBufferView: IDLType.Tags.interface, - Types.Int8Array: IDLType.Tags.interface, - Types.Uint8Array: IDLType.Tags.interface, - Types.Uint8ClampedArray: IDLType.Tags.interface, - Types.Int16Array: IDLType.Tags.interface, - Types.Uint16Array: IDLType.Tags.interface, - Types.Int32Array: IDLType.Tags.interface, - Types.Uint32Array: IDLType.Tags.interface, - Types.Float32Array: IDLType.Tags.interface, - Types.Float64Array: IDLType.Tags.interface - } - - def __init__(self, location, name, type): - IDLType.__init__(self, location, name) - self.builtin = True - self._typeTag = type - - def isPrimitive(self): - return self._typeTag <= IDLBuiltinType.Types.double - - def isBoolean(self): - return self._typeTag == IDLBuiltinType.Types.boolean - - def isNumeric(self): - return self.isPrimitive() and not self.isBoolean() - - def isString(self): - return self._typeTag == IDLBuiltinType.Types.domstring or \ - self._typeTag == IDLBuiltinType.Types.bytestring or \ - self._typeTag == IDLBuiltinType.Types.scalarvaluestring - - def isByteString(self): - return self._typeTag == IDLBuiltinType.Types.bytestring - - def isDOMString(self): - return self._typeTag == IDLBuiltinType.Types.domstring - - def isScalarValueString(self): - return self._typeTag == IDLBuiltinType.Types.scalarvaluestring - - def isInteger(self): - return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long - - def isArrayBuffer(self): - return self._typeTag == IDLBuiltinType.Types.ArrayBuffer - - def isArrayBufferView(self): - return self._typeTag == IDLBuiltinType.Types.ArrayBufferView - - def isTypedArray(self): - return self._typeTag >= IDLBuiltinType.Types.Int8Array and \ - self._typeTag <= IDLBuiltinType.Types.Float64Array - - def isInterface(self): - # TypedArray things are interface types per the TypedArray spec, - # but we handle them as builtins because SpiderMonkey implements - # all of it internally. - return self.isArrayBuffer() or \ - self.isArrayBufferView() or \ - self.isTypedArray() - - def isNonCallbackInterface(self): - # All the interfaces we can be are non-callback - return self.isInterface() - - def isFloat(self): - return self._typeTag == IDLBuiltinType.Types.float or \ - self._typeTag == IDLBuiltinType.Types.double or \ - self._typeTag == IDLBuiltinType.Types.unrestricted_float or \ - self._typeTag == IDLBuiltinType.Types.unrestricted_double - - def isUnrestricted(self): - assert self.isFloat() - return self._typeTag == IDLBuiltinType.Types.unrestricted_float or \ - self._typeTag == IDLBuiltinType.Types.unrestricted_double - - def isSerializable(self): - return self.isPrimitive() or self.isDOMString() or self.isDate() - - def includesRestrictedFloat(self): - return self.isFloat() and not self.isUnrestricted() - - def tag(self): - return IDLBuiltinType.TagLookup[self._typeTag] - - def isDistinguishableFrom(self, other): - if other.isUnion(): - # Just forward to the union; it'll deal - return other.isDistinguishableFrom(self) - if self.isBoolean(): - return (other.isNumeric() or other.isString() or other.isEnum() or - other.isInterface() or other.isObject() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate()) - if self.isNumeric(): - return (other.isBoolean() or other.isString() or other.isEnum() or - other.isInterface() or other.isObject() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate()) - if self.isString(): - return (other.isPrimitive() or other.isInterface() or - other.isObject() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate()) - if self.isAny(): - # Can't tell "any" apart from anything - return False - if self.isObject(): - return other.isPrimitive() or other.isString() or other.isEnum() - if self.isDate(): - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isInterface() or other.isCallback() or - other.isDictionary() or other.isSequence() or - other.isMozMap() or other.isArray()) - if self.isVoid(): - return not other.isVoid() - # Not much else we could be! - assert self.isSpiderMonkeyInterface() - # Like interfaces, but we know we're not a callback - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isCallback() or other.isDictionary() or - other.isSequence() or other.isMozMap() or other.isArray() or - other.isDate() or - (other.isInterface() and ( - # ArrayBuffer is distinguishable from everything - # that's not an ArrayBuffer or a callback interface - (self.isArrayBuffer() and not other.isArrayBuffer()) or - # ArrayBufferView is distinguishable from everything - # that's not an ArrayBufferView or typed array. - (self.isArrayBufferView() and not other.isArrayBufferView() and - not other.isTypedArray()) or - # Typed arrays are distinguishable from everything - # except ArrayBufferView and the same type of typed - # array - (self.isTypedArray() and not other.isArrayBufferView() and not - (other.isTypedArray() and other.name == self.name))))) - - def _getDependentObjects(self): - return set() - -BuiltinTypes = { - IDLBuiltinType.Types.byte: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte", - IDLBuiltinType.Types.byte), - IDLBuiltinType.Types.octet: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Octet", - IDLBuiltinType.Types.octet), - IDLBuiltinType.Types.short: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Short", - IDLBuiltinType.Types.short), - IDLBuiltinType.Types.unsigned_short: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedShort", - IDLBuiltinType.Types.unsigned_short), - IDLBuiltinType.Types.long: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Long", - IDLBuiltinType.Types.long), - IDLBuiltinType.Types.unsigned_long: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedLong", - IDLBuiltinType.Types.unsigned_long), - IDLBuiltinType.Types.long_long: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "LongLong", - IDLBuiltinType.Types.long_long), - IDLBuiltinType.Types.unsigned_long_long: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnsignedLongLong", - IDLBuiltinType.Types.unsigned_long_long), - IDLBuiltinType.Types.boolean: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Boolean", - IDLBuiltinType.Types.boolean), - IDLBuiltinType.Types.float: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float", - IDLBuiltinType.Types.float), - IDLBuiltinType.Types.unrestricted_float: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnrestrictedFloat", - IDLBuiltinType.Types.unrestricted_float), - IDLBuiltinType.Types.double: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Double", - IDLBuiltinType.Types.double), - IDLBuiltinType.Types.unrestricted_double: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnrestrictedDouble", - IDLBuiltinType.Types.unrestricted_double), - IDLBuiltinType.Types.any: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Any", - IDLBuiltinType.Types.any), - IDLBuiltinType.Types.domstring: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "String", - IDLBuiltinType.Types.domstring), - IDLBuiltinType.Types.bytestring: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "ByteString", - IDLBuiltinType.Types.bytestring), - IDLBuiltinType.Types.scalarvaluestring: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "ScalarValueString", - IDLBuiltinType.Types.scalarvaluestring), - IDLBuiltinType.Types.object: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object", - IDLBuiltinType.Types.object), - IDLBuiltinType.Types.date: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Date", - IDLBuiltinType.Types.date), - IDLBuiltinType.Types.void: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Void", - IDLBuiltinType.Types.void), - IDLBuiltinType.Types.ArrayBuffer: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBuffer", - IDLBuiltinType.Types.ArrayBuffer), - IDLBuiltinType.Types.ArrayBufferView: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "ArrayBufferView", - IDLBuiltinType.Types.ArrayBufferView), - IDLBuiltinType.Types.Int8Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int8Array", - IDLBuiltinType.Types.Int8Array), - IDLBuiltinType.Types.Uint8Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8Array", - IDLBuiltinType.Types.Uint8Array), - IDLBuiltinType.Types.Uint8ClampedArray: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint8ClampedArray", - IDLBuiltinType.Types.Uint8ClampedArray), - IDLBuiltinType.Types.Int16Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int16Array", - IDLBuiltinType.Types.Int16Array), - IDLBuiltinType.Types.Uint16Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint16Array", - IDLBuiltinType.Types.Uint16Array), - IDLBuiltinType.Types.Int32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Int32Array", - IDLBuiltinType.Types.Int32Array), - IDLBuiltinType.Types.Uint32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Uint32Array", - IDLBuiltinType.Types.Uint32Array), - IDLBuiltinType.Types.Float32Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float32Array", - IDLBuiltinType.Types.Float32Array), - IDLBuiltinType.Types.Float64Array: - IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array", - IDLBuiltinType.Types.Float64Array) - } - - -integerTypeSizes = { - IDLBuiltinType.Types.byte: (-128, 127), - IDLBuiltinType.Types.octet: (0, 255), - IDLBuiltinType.Types.short: (-32768, 32767), - IDLBuiltinType.Types.unsigned_short: (0, 65535), - IDLBuiltinType.Types.long: (-2147483648, 2147483647), - IDLBuiltinType.Types.unsigned_long: (0, 4294967295), - IDLBuiltinType.Types.long_long: (-9223372036854775808, - 9223372036854775807), - IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615) - } - -def matchIntegerValueToType(value): - for type, extremes in integerTypeSizes.items(): - (min, max) = extremes - if value <= max and value >= min: - return BuiltinTypes[type] - - return None - -class IDLValue(IDLObject): - def __init__(self, location, type, value): - IDLObject.__init__(self, location) - self.type = type - assert isinstance(type, IDLType) - - self.value = value - - def coerceToType(self, type, location): - if type == self.type: - return self # Nothing to do - - # We first check for unions to ensure that even if the union is nullable - # we end up with the right flat member type, not the union's type. - 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: - coercedValue = self.coerceToType(subtype, location) - # Create a new IDLValue to make sure that we have the - # correct float/double type. This is necessary because we - # use the value's type when it is a default value of a - # union, and the union cares about the exact float type. - return IDLValue(self.location, subtype, coercedValue.value) - except: - pass - # If the type allows null, rerun this matching on the inner type, except - # nullable enums. We handle those specially, because we want our - # default string values to stay strings even when assigned to a nullable - # enum. - elif type.nullable() and not type.isEnum(): - innerValue = self.coerceToType(type.inner, location) - return IDLValue(self.location, type, innerValue.value) - - elif self.type.isInteger() and type.isInteger(): - # We're both integer types. See if we fit. - - (min, max) = integerTypeSizes[type._typeTag] - if self.value <= max and self.value >= min: - # Promote - return IDLValue(self.location, type, self.value) - else: - raise WebIDLError("Value %s is out of range for type %s." % - (self.value, type), [location]) - elif self.type.isInteger() and type.isFloat(): - # Convert an integer literal into float - if -2**24 <= self.value <= 2**24: - floatType = BuiltinTypes[IDLBuiltinType.Types.float] - return IDLValue(self.location, floatType, float(self.value)) - else: - raise WebIDLError("Converting value %s to %s will lose precision." % - (self.value, type), [location]) - elif self.type.isString() and type.isEnum(): - # Just keep our string, but make sure it's a valid value for this enum - enum = type.unroll().inner - if self.value not in enum.values(): - raise WebIDLError("'%s' is not a valid default value for enum %s" - % (self.value, enum.identifier.name), - [location, enum.location]) - return self - elif self.type.isFloat() and type.isFloat(): - if (not type.isUnrestricted() and - (self.value == float("inf") or self.value == float("-inf") or - math.isnan(self.value))): - raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted" - % self.value, [location]); - return self - elif self.type.isString() and type.isScalarValueString(): - # Allow ScalarValueStrings to use default value just like - # DOMString. No coercion is required in this case as Codegen.py - # treats ScalarValueString just like DOMString, but with an - # extra normalization step. - assert self.type.isDOMString() - return self - raise WebIDLError("Cannot coerce type %s to type %s." % - (self.type, type), [location]) - - def _getDependentObjects(self): - return set() - -class IDLNullValue(IDLObject): - def __init__(self, location): - IDLObject.__init__(self, location) - self.type = None - self.value = None - - 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]) - - nullValue = IDLNullValue(self.location) - if type.isUnion() and not type.nullable() and type.hasDictionaryType: - # We're actually a default value for the union's dictionary member. - # Use its type. - for t in type.flatMemberTypes: - if t.isDictionary(): - nullValue.type = t - return nullValue - nullValue.type = type - return nullValue - - def _getDependentObjects(self): - return set() - -class IDLEmptySequenceValue(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.isSequence(): - raise WebIDLError("Cannot coerce empty sequence value to type %s." % type, - [location]) - - emptySequenceValue = IDLEmptySequenceValue(self.location) - emptySequenceValue.type = type - return emptySequenceValue - - def _getDependentObjects(self): - return set() - -class IDLUndefinedValue(IDLObject): - def __init__(self, location): - IDLObject.__init__(self, location) - self.type = None - self.value = None - - def coerceToType(self, type, location): - if not type.isAny(): - raise WebIDLError("Cannot coerce undefined value to type %s." % type, - [location]) - - undefinedValue = IDLUndefinedValue(self.location) - undefinedValue.type = type - return undefinedValue - - def _getDependentObjects(self): - return set() - -class IDLInterfaceMember(IDLObjectWithIdentifier): - - Tags = enum( - 'Const', - 'Attr', - 'Method' - ) - - Special = enum( - 'Static', - 'Stringifier' - ) - - def __init__(self, location, identifier, tag): - IDLObjectWithIdentifier.__init__(self, location, None, identifier) - self.tag = tag - self._extendedAttrDict = {} - # _exposureGlobalNames are the global names listed in our [Exposed] - # extended attribute. exposureSet is the exposure set as defined in the - # Web IDL spec: it contains interface names. - self._exposureGlobalNames = set() - self.exposureSet = set() - - def isMethod(self): - return self.tag == IDLInterfaceMember.Tags.Method - - def isAttr(self): - return self.tag == IDLInterfaceMember.Tags.Attr - - def isConst(self): - return self.tag == IDLInterfaceMember.Tags.Const - - def addExtendedAttributes(self, attrs): - for attr in attrs: - self.handleExtendedAttribute(attr) - attrlist = attr.listValue() - self._extendedAttrDict[attr.identifier()] = attrlist if len(attrlist) else True - - def handleExtendedAttribute(self, attr): - pass - - def getExtendedAttribute(self, name): - return self._extendedAttrDict.get(name, None) - - def finish(self, scope): - for globalName in self._exposureGlobalNames: - if globalName not in scope.globalNames: - raise WebIDLError("Unknown [Exposed] value %s" % globalName, - [self.location]) - globalNameSetToExposureSet(scope, self._exposureGlobalNames, - self.exposureSet) - self._scope = scope - - def validate(self): - if (self.getExtendedAttribute("Pref") and - self.exposureSet != set([self._scope.primaryGlobalName])): - raise WebIDLError("[Pref] used on an interface member that is not " - "%s-only" % self._scope.primaryGlobalName, - [self.location]) - -class IDLConst(IDLInterfaceMember): - def __init__(self, location, identifier, type, value): - IDLInterfaceMember.__init__(self, location, identifier, - IDLInterfaceMember.Tags.Const) - - assert isinstance(type, IDLType) - if type.isDictionary(): - raise WebIDLError("A constant cannot be of a dictionary type", - [self.location]) - self.type = type - self.value = value - - if identifier.name == "prototype": - raise WebIDLError("The identifier of a constant must not be 'prototype'", - [location]) - - def __str__(self): - return "'%s' const '%s'" % (self.type, self.identifier) - - def finish(self, scope): - IDLInterfaceMember.finish(self, scope) - - if not self.type.isComplete(): - type = self.type.complete(scope) - if not type.isPrimitive() and not type.isString(): - locations = [self.type.location, type.location] - try: - locations.append(type.inner.location) - except: - pass - raise WebIDLError("Incorrect type for constant", locations) - self.type = type - - # The value might not match the type - coercedValue = self.value.coerceToType(self.type, self.location) - assert coercedValue - - self.value = coercedValue - - def validate(self): - IDLInterfaceMember.validate(self) - - def handleExtendedAttribute(self, attr): - identifier = attr.identifier() - if identifier == "Exposed": - convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) - elif (identifier == "Pref" or - identifier == "ChromeOnly" or - identifier == "Func" or - identifier == "AvailableIn" or - identifier == "CheckPermissions"): - # Known attributes that we don't need to do anything with here - pass - else: - raise WebIDLError("Unknown extended attribute %s on constant" % identifier, - [attr.location]) - IDLInterfaceMember.handleExtendedAttribute(self, attr) - - def _getDependentObjects(self): - return set([self.type, self.value]) - -class IDLAttribute(IDLInterfaceMember): - def __init__(self, location, identifier, type, readonly, inherit=False, - static=False, stringifier=False): - IDLInterfaceMember.__init__(self, location, identifier, - IDLInterfaceMember.Tags.Attr) - - assert isinstance(type, IDLType) - self.type = type - self.readonly = readonly - self.inherit = inherit - self.static = static - self.lenientThis = False - self._unforgeable = False - self.stringifier = stringifier - self.enforceRange = False - self.clamp = False - self.slotIndex = None - - if static and identifier.name == "prototype": - raise WebIDLError("The identifier of a static attribute must not be 'prototype'", - [location]) - - if readonly and inherit: - raise WebIDLError("An attribute cannot be both 'readonly' and 'inherit'", - [self.location]) - - def isStatic(self): - return self.static - - def __str__(self): - return "'%s' attribute '%s'" % (self.type, self.identifier) - - def finish(self, scope): - IDLInterfaceMember.finish(self, scope) - - if not self.type.isComplete(): - t = self.type.complete(scope) - - assert not isinstance(t, IDLUnresolvedType) - assert not isinstance(t, IDLTypedefType) - assert not isinstance(t.name, IDLUnresolvedIdentifier) - self.type = t - - if self.type.isDictionary() and not self.getExtendedAttribute("Cached"): - raise WebIDLError("An attribute cannot be of a dictionary type", - [self.location]) - if self.type.isSequence() and not self.getExtendedAttribute("Cached"): - raise WebIDLError("A non-cached attribute cannot be of a sequence " - "type", [self.location]) - if self.type.isMozMap() and not self.getExtendedAttribute("Cached"): - raise WebIDLError("A non-cached attribute cannot be of a MozMap " - "type", [self.location]) - if self.type.isUnion(): - for f in self.type.unroll().flatMemberTypes: - if f.isDictionary(): - raise WebIDLError("An attribute cannot be of a union " - "type if one of its member types (or " - "one of its member types's member " - "types, and so on) is a dictionary " - "type", [self.location, f.location]) - if f.isSequence(): - raise WebIDLError("An attribute cannot be of a union " - "type if one of its member types (or " - "one of its member types's member " - "types, and so on) is a sequence " - "type", [self.location, f.location]) - if f.isMozMap(): - raise WebIDLError("An attribute cannot be of a union " - "type if one of its member types (or " - "one of its member types's member " - "types, and so on) is a MozMap " - "type", [self.location, f.location]) - if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"): - raise WebIDLError("An attribute with [PutForwards] must have an " - "interface type as its type", [self.location]) - - if not self.type.isInterface() and self.getExtendedAttribute("SameObject"): - raise WebIDLError("An attribute with [SameObject] must have an " - "interface type as its type", [self.location]) - - def validate(self): - IDLInterfaceMember.validate(self) - - if ((self.getExtendedAttribute("Cached") or - self.getExtendedAttribute("StoreInSlot")) and - not self.getExtendedAttribute("Constant") and - not self.getExtendedAttribute("Pure")): - raise WebIDLError("Cached attributes and attributes stored in " - "slots must be constant or pure, since the " - "getter won't always be called.", - [self.location]) - if self.getExtendedAttribute("Frozen"): - if (not self.type.isSequence() and not self.type.isDictionary() and - not self.type.isMozMap()): - raise WebIDLError("[Frozen] is only allowed on " - "sequence-valued, dictionary-valued, and " - "MozMap-valued attributes", - [self.location]) - if not self.type.unroll().isExposedInAllOf(self.exposureSet): - raise WebIDLError("Attribute returns a type that is not exposed " - "everywhere where the attribute is exposed", - [self.location]) - - def handleExtendedAttribute(self, attr): - identifier = attr.identifier() - if identifier == "SetterThrows" and self.readonly: - raise WebIDLError("Readonly attributes must not be flagged as " - "[SetterThrows]", - [self.location]) - elif (((identifier == "Throws" or identifier == "GetterThrows") and - self.getExtendedAttribute("StoreInSlot")) or - (identifier == "StoreInSlot" and - (self.getExtendedAttribute("Throws") or - self.getExtendedAttribute("GetterThrows")))): - raise WebIDLError("Throwing things can't be [Pure] or [Constant] " - "or [SameObject] or [StoreInSlot]", - [attr.location]) - elif identifier == "LenientThis": - if not attr.noArguments(): - raise WebIDLError("[LenientThis] must take no arguments", - [attr.location]) - if self.isStatic(): - raise WebIDLError("[LenientThis] is only allowed on non-static " - "attributes", [attr.location, self.location]) - if self.getExtendedAttribute("CrossOriginReadable"): - raise WebIDLError("[LenientThis] is not allowed in combination " - "with [CrossOriginReadable]", - [attr.location, self.location]) - if self.getExtendedAttribute("CrossOriginWritable"): - raise WebIDLError("[LenientThis] is not allowed in combination " - "with [CrossOriginWritable]", - [attr.location, self.location]) - self.lenientThis = True - elif identifier == "Unforgeable": - if self.isStatic(): - raise WebIDLError("[Unforgeable] is only allowed on non-static " - "attributes", [attr.location, self.location]) - self._unforgeable = True - elif identifier == "SameObject" and not self.readonly: - raise WebIDLError("[SameObject] only allowed on readonly attributes", - [attr.location, self.location]) - elif identifier == "Constant" and not self.readonly: - raise WebIDLError("[Constant] only allowed on readonly attributes", - [attr.location, self.location]) - elif identifier == "PutForwards": - if not self.readonly: - raise WebIDLError("[PutForwards] is only allowed on readonly " - "attributes", [attr.location, self.location]) - if self.isStatic(): - raise WebIDLError("[PutForwards] is only allowed on non-static " - "attributes", [attr.location, self.location]) - if self.getExtendedAttribute("Replaceable") is not None: - raise WebIDLError("[PutForwards] and [Replaceable] can't both " - "appear on the same attribute", - [attr.location, self.location]) - if not attr.hasValue(): - raise WebIDLError("[PutForwards] takes an identifier", - [attr.location, self.location]) - elif identifier == "Replaceable": - if self.getExtendedAttribute("PutForwards") is not None: - raise WebIDLError("[PutForwards] and [Replaceable] can't both " - "appear on the same attribute", - [attr.location, self.location]) - elif identifier == "LenientFloat": - if self.readonly: - raise WebIDLError("[LenientFloat] used on a readonly attribute", - [attr.location, self.location]) - if not self.type.includesRestrictedFloat(): - raise WebIDLError("[LenientFloat] used on an attribute with a " - "non-restricted-float type", - [attr.location, self.location]) - elif identifier == "EnforceRange": - if self.readonly: - raise WebIDLError("[EnforceRange] used on a readonly attribute", - [attr.location, self.location]) - self.enforceRange = True - elif identifier == "Clamp": - if self.readonly: - raise WebIDLError("[Clamp] used on a readonly attribute", - [attr.location, self.location]) - self.clamp = True - elif identifier == "StoreInSlot": - if self.getExtendedAttribute("Cached"): - raise WebIDLError("[StoreInSlot] and [Cached] must not be " - "specified on the same attribute", - [attr.location, self.location]) - elif identifier == "Cached": - if self.getExtendedAttribute("StoreInSlot"): - raise WebIDLError("[Cached] and [StoreInSlot] must not be " - "specified on the same attribute", - [attr.location, self.location]) - elif (identifier == "CrossOriginReadable" or - identifier == "CrossOriginWritable"): - if not attr.noArguments() and identifier == "CrossOriginReadable": - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) - if self.isStatic(): - raise WebIDLError("[%s] is only allowed on non-static " - "attributes" % identifier, - [attr.location, self.location]) - if self.getExtendedAttribute("LenientThis"): - raise WebIDLError("[LenientThis] is not allowed in combination " - "with [%s]" % identifier, - [attr.location, self.location]) - elif identifier == "Exposed": - convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) - elif (identifier == "Pref" or - identifier == "SetterThrows" or - identifier == "Pure" or - identifier == "Throws" or - identifier == "GetterThrows" or - identifier == "ChromeOnly" or - identifier == "SameObject" or - identifier == "Constant" or - identifier == "Func" or - identifier == "Frozen" or - identifier == "AvailableIn" or - identifier == "NewObject" or - identifier == "CheckPermissions"): - # Known attributes that we don't need to do anything with here - pass - else: - raise WebIDLError("Unknown extended attribute %s on attribute" % identifier, - [attr.location]) - IDLInterfaceMember.handleExtendedAttribute(self, attr) - - def resolve(self, parentScope): - assert isinstance(parentScope, IDLScope) - self.type.resolveType(parentScope) - IDLObjectWithIdentifier.resolve(self, parentScope) - - def addExtendedAttributes(self, attrs): - attrs = self.checkForStringHandlingExtendedAttributes(attrs) - IDLInterfaceMember.addExtendedAttributes(self, attrs) - - def hasLenientThis(self): - return self.lenientThis - - def isUnforgeable(self): - return self._unforgeable - - def _getDependentObjects(self): - return set([self.type]) - -class IDLArgument(IDLObjectWithIdentifier): - def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False): - IDLObjectWithIdentifier.__init__(self, location, None, identifier) - - assert isinstance(type, IDLType) - self.type = type - - self.optional = optional - self.defaultValue = defaultValue - self.variadic = variadic - self.dictionaryMember = dictionaryMember - self._isComplete = False - self.enforceRange = False - self.clamp = False - self._allowTreatNonCallableAsNull = False - - assert not variadic or optional - - def addExtendedAttributes(self, attrs): - attrs = self.checkForStringHandlingExtendedAttributes( - attrs, - isDictionaryMember=self.dictionaryMember, - isOptional=self.optional) - for attribute in attrs: - identifier = attribute.identifier() - if identifier == "Clamp": - if not attribute.noArguments(): - raise WebIDLError("[Clamp] must take no arguments", - [attribute.location]) - if self.enforceRange: - raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", - [self.location]); - self.clamp = True - elif identifier == "EnforceRange": - if not attribute.noArguments(): - raise WebIDLError("[EnforceRange] must take no arguments", - [attribute.location]) - if self.clamp: - raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", - [self.location]); - self.enforceRange = True - elif identifier == "TreatNonCallableAsNull": - self._allowTreatNonCallableAsNull = True - else: - raise WebIDLError("Unhandled extended attribute on an argument", - [attribute.location]) - - def isComplete(self): - return self._isComplete - - def complete(self, scope): - if self._isComplete: - return - - self._isComplete = True - - if not self.type.isComplete(): - type = self.type.complete(scope) - assert not isinstance(type, IDLUnresolvedType) - assert not isinstance(type, IDLTypedefType) - 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): - # Default optional dictionaries to null, for simplicity, - # so the codegen doesn't have to special-case this. - self.defaultValue = IDLNullValue(self.location) - elif self.type.isAny(): - assert (self.defaultValue is None or - isinstance(self.defaultValue, IDLNullValue)) - # optional 'any' values always have a default value - if self.optional and not self.defaultValue and not self.variadic: - # Set the default value to undefined, for simplicity, so the - # codegen doesn't have to special-case this. - self.defaultValue = IDLUndefinedValue(self.location) - - # Now do the coercing thing; this needs to happen after the - # above creation of a default value. - if self.defaultValue: - self.defaultValue = self.defaultValue.coerceToType(self.type, - self.location) - assert self.defaultValue - - def allowTreatNonCallableAsNull(self): - return self._allowTreatNonCallableAsNull - - def _getDependentObjects(self): - deps = set([self.type]) - if self.defaultValue: - deps.add(self.defaultValue) - return deps - -class IDLCallbackType(IDLType, IDLObjectWithScope): - def __init__(self, location, parentScope, identifier, returnType, arguments): - assert isinstance(returnType, IDLType) - - IDLType.__init__(self, location, identifier.name) - - self._returnType = returnType - # Clone the list - self._arguments = list(arguments) - - IDLObjectWithScope.__init__(self, location, parentScope, identifier) - - for (returnType, arguments) in self.signatures(): - for argument in arguments: - argument.resolve(self) - - self._treatNonCallableAsNull = False - self._treatNonObjectAsNull = False - - def module(self): - return self.location.filename().split('/')[-1].split('.webidl')[0] + 'Binding' - - def isCallback(self): - return True - - def signatures(self): - return [(self._returnType, self._arguments)] - - def tag(self): - return IDLType.Tags.callback - - def finish(self, scope): - if not self._returnType.isComplete(): - type = self._returnType.complete(scope) - - assert not isinstance(type, IDLUnresolvedType) - assert not isinstance(type, IDLTypedefType) - assert not isinstance(type.name, IDLUnresolvedIdentifier) - self._returnType = type - - for argument in self._arguments: - if argument.type.isComplete(): - continue - - type = argument.type.complete(scope) - - assert not isinstance(type, IDLUnresolvedType) - assert not isinstance(type, IDLTypedefType) - assert not isinstance(type.name, IDLUnresolvedIdentifier) - argument.type = type - - def validate(self): - pass - - def isDistinguishableFrom(self, other): - if other.isUnion(): - # Just forward to the union; it'll deal - return other.isDistinguishableFrom(self) - return (other.isPrimitive() or other.isString() or other.isEnum() or - other.isNonCallbackInterface() or other.isDate()) - - def addExtendedAttributes(self, attrs): - unhandledAttrs = [] - for attr in attrs: - if attr.identifier() == "TreatNonCallableAsNull": - self._treatNonCallableAsNull = True - elif attr.identifier() == "TreatNonObjectAsNull": - self._treatNonObjectAsNull = True - else: - unhandledAttrs.append(attr) - if self._treatNonCallableAsNull and self._treatNonObjectAsNull: - raise WebIDLError("Cannot specify both [TreatNonCallableAsNull] " - "and [TreatNonObjectAsNull]", [self.location]) - if len(unhandledAttrs) != 0: - IDLType.addExtendedAttributes(self, unhandledAttrs) - - def _getDependentObjects(self): - return set([self._returnType] + self._arguments) - -class IDLMethodOverload: - """ - A class that represents a single overload of a WebIDL method. This is not - quite the same as an element of the "effective overload set" in the spec, - because separate IDLMethodOverloads are not created based on arguments being - optional. Rather, when multiple methods have the same name, there is an - IDLMethodOverload for each one, all hanging off an IDLMethod representing - the full set of overloads. - """ - def __init__(self, returnType, arguments, location): - self.returnType = returnType - # Clone the list of arguments, just in case - self.arguments = list(arguments) - self.location = location - - def _getDependentObjects(self): - deps = set(self.arguments) - deps.add(self.returnType) - return deps - -class IDLMethod(IDLInterfaceMember, IDLScope): - - Special = enum( - 'Getter', - 'Setter', - 'Creator', - 'Deleter', - 'LegacyCaller', - base=IDLInterfaceMember.Special - ) - - TypeSuffixModifier = enum( - 'None', - 'QMark', - 'Brackets' - ) - - NamedOrIndexed = enum( - 'Neither', - 'Named', - 'Indexed' - ) - - def __init__(self, location, identifier, returnType, arguments, - static=False, getter=False, setter=False, creator=False, - deleter=False, specialType=NamedOrIndexed.Neither, - legacycaller=False, stringifier=False, jsonifier=False): - # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. - IDLInterfaceMember.__init__(self, location, identifier, - IDLInterfaceMember.Tags.Method) - - self._hasOverloads = False - - assert isinstance(returnType, IDLType) - - # self._overloads is a list of IDLMethodOverloads - self._overloads = [IDLMethodOverload(returnType, arguments, location)] - - assert isinstance(static, bool) - self._static = static - assert isinstance(getter, bool) - self._getter = getter - assert isinstance(setter, bool) - self._setter = setter - assert isinstance(creator, bool) - self._creator = creator - assert isinstance(deleter, bool) - self._deleter = deleter - assert isinstance(legacycaller, bool) - self._legacycaller = legacycaller - assert isinstance(stringifier, bool) - self._stringifier = stringifier - assert isinstance(jsonifier, bool) - self._jsonifier = jsonifier - self._specialType = specialType - self._unforgeable = False - - if static and identifier.name == "prototype": - raise WebIDLError("The identifier of a static operation must not be 'prototype'", - [location]) - - self.assertSignatureConstraints() - - def __str__(self): - return "Method '%s'" % self.identifier - - def assertSignatureConstraints(self): - if self._getter or self._deleter: - assert len(self._overloads) == 1 - overload = self._overloads[0] - arguments = overload.arguments - assert len(arguments) == 1 - assert arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or \ - arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] - assert not arguments[0].optional and not arguments[0].variadic - assert not self._getter or not overload.returnType.isVoid() - - if self._setter or self._creator: - assert len(self._overloads) == 1 - arguments = self._overloads[0].arguments - assert len(arguments) == 2 - assert arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or \ - arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] - assert not arguments[0].optional and not arguments[0].variadic - assert not arguments[1].optional and not arguments[1].variadic - - if self._stringifier: - assert len(self._overloads) == 1 - overload = self._overloads[0] - assert len(overload.arguments) == 0 - assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] - - if self._jsonifier: - assert len(self._overloads) == 1 - overload = self._overloads[0] - assert len(overload.arguments) == 0 - assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.object] - - def isStatic(self): - return self._static - - def isGetter(self): - return self._getter - - def isSetter(self): - return self._setter - - def isCreator(self): - return self._creator - - def isDeleter(self): - return self._deleter - - def isNamed(self): - assert self._specialType == IDLMethod.NamedOrIndexed.Named or \ - self._specialType == IDLMethod.NamedOrIndexed.Indexed - return self._specialType == IDLMethod.NamedOrIndexed.Named - - def isIndexed(self): - assert self._specialType == IDLMethod.NamedOrIndexed.Named or \ - self._specialType == IDLMethod.NamedOrIndexed.Indexed - return self._specialType == IDLMethod.NamedOrIndexed.Indexed - - def isLegacycaller(self): - return self._legacycaller - - def isStringifier(self): - return self._stringifier - - def isJsonifier(self): - return self._jsonifier - - def hasOverloads(self): - return self._hasOverloads - - def isIdentifierLess(self): - return self.identifier.name[:2] == "__" and self.identifier.name != "__noSuchMethod__" - - def resolve(self, parentScope): - assert isinstance(parentScope, IDLScope) - IDLObjectWithIdentifier.resolve(self, parentScope) - IDLScope.__init__(self, self.location, parentScope, self.identifier) - for (returnType, arguments) in self.signatures(): - for argument in arguments: - argument.resolve(self) - - 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]) - - self._overloads.extend(method._overloads) - - self._hasOverloads = True - - if self.isStatic() != method.isStatic(): - raise WebIDLError("Overloaded identifier %s appears with different values of the 'static' attribute" % method.identifier, - [method.location]) - - if self.isLegacycaller() != method.isLegacycaller(): - raise WebIDLError("Overloaded identifier %s appears with different values of the 'legacycaller' attribute" % method.identifier, - [method.location]) - - # Can't overload special things! - assert not self.isGetter() - assert not method.isGetter() - assert not self.isSetter() - assert not method.isSetter() - assert not self.isCreator() - assert not method.isCreator() - assert not self.isDeleter() - assert not method.isDeleter() - assert not self.isStringifier() - assert not method.isStringifier() - assert not self.isJsonifier() - assert not method.isJsonifier() - - return self - - def signatures(self): - return [(overload.returnType, overload.arguments) for overload in - self._overloads] - - def finish(self, scope): - IDLInterfaceMember.finish(self, scope) - - overloadWithPromiseReturnType = None - overloadWithoutPromiseReturnType = None - for overload in self._overloads: - variadicArgument = None - - arguments = overload.arguments - for (idx, argument) in enumerate(arguments): - if not argument.isComplete(): - argument.complete(scope) - assert argument.type.isComplete() - - if (argument.type.isDictionary() or - (argument.type.isUnion() and - argument.type.unroll().hasDictionaryType)): - # Dictionaries and unions containing dictionaries at the - # end of the list or followed by optional arguments must be - # optional. - if (not argument.optional and - all(arg.optional for arg in arguments[idx+1:])): - raise WebIDLError("Dictionary argument or union " - "argument containing a dictionary " - "not followed by a required argument " - "must be optional", - [argument.location]) - - # An argument cannot be a Nullable Dictionary - if argument.type.nullable(): - raise WebIDLError("An argument cannot be a nullable " - "dictionary or nullable union " - "containing a dictionary", - [argument.location]) - - # Only the last argument can be variadic - if variadicArgument: - raise WebIDLError("Variadic argument is not last argument", - [variadicArgument.location]) - if argument.variadic: - variadicArgument = argument - - returnType = overload.returnType - if not returnType.isComplete(): - returnType = returnType.complete(scope) - assert not isinstance(returnType, IDLUnresolvedType) - assert not isinstance(returnType, IDLTypedefType) - assert not isinstance(returnType.name, IDLUnresolvedIdentifier) - overload.returnType = returnType - - if returnType.isPromise(): - overloadWithPromiseReturnType = overload - else: - overloadWithoutPromiseReturnType = overload - - # Make sure either all our overloads return Promises or none do - if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType: - raise WebIDLError("We have overloads with both Promise and " - "non-Promise return types", - [overloadWithPromiseReturnType.location, - overloadWithoutPromiseReturnType.location]) - - if overloadWithPromiseReturnType and self._legacycaller: - raise WebIDLError("May not have a Promise return type for a " - "legacycaller.", - [overloadWithPromiseReturnType.location]) - - # Now compute various information that will be used by the - # WebIDL overload resolution algorithm. - self.maxArgCount = max(len(s[1]) for s in self.signatures()) - self.allowedArgCounts = [ i for i in range(self.maxArgCount+1) - if len(self.signaturesForArgCount(i)) != 0 ] - - def validate(self): - IDLInterfaceMember.validate(self) - - # Make sure our overloads are properly distinguishable and don't have - # different argument types before the distinguishing args. - for argCount in self.allowedArgCounts: - possibleOverloads = self.overloadsForArgCount(argCount) - if len(possibleOverloads) == 1: - continue - distinguishingIndex = self.distinguishingIndexForArgCount(argCount) - for idx in range(distinguishingIndex): - firstSigType = possibleOverloads[0].arguments[idx].type - for overload in possibleOverloads[1:]: - if overload.arguments[idx].type != firstSigType: - raise WebIDLError( - "Signatures for method '%s' with %d arguments have " - "different types of arguments at index %d, which " - "is before distinguishing index %d" % - (self.identifier.name, argCount, idx, - distinguishingIndex), - [self.location, overload.location]) - - for overload in self._overloads: - if not overload.returnType.unroll().isExposedInAllOf(self.exposureSet): - raise WebIDLError("Overload returns a type that is not exposed " - "everywhere where the method is exposed", - [overload.location]) - - def overloadsForArgCount(self, argc): - return [overload for overload in self._overloads if - len(overload.arguments) == argc or - (len(overload.arguments) > argc and - all(arg.optional for arg in overload.arguments[argc:])) or - (len(overload.arguments) < argc and - len(overload.arguments) > 0 and - overload.arguments[-1].variadic)] - - def signaturesForArgCount(self, argc): - return [(overload.returnType, overload.arguments) for overload - in self.overloadsForArgCount(argc)] - - def locationsForArgCount(self, argc): - return [overload.location for overload in self.overloadsForArgCount(argc)] - - def distinguishingIndexForArgCount(self, argc): - def isValidDistinguishingIndex(idx, signatures): - for (firstSigIndex, (firstRetval, firstArgs)) in enumerate(signatures[:-1]): - for (secondRetval, secondArgs) in signatures[firstSigIndex+1:]: - if idx < len(firstArgs): - firstType = firstArgs[idx].type - else: - assert(firstArgs[-1].variadic) - firstType = firstArgs[-1].type - if idx < len(secondArgs): - secondType = secondArgs[idx].type - else: - assert(secondArgs[-1].variadic) - secondType = secondArgs[-1].type - if not firstType.isDistinguishableFrom(secondType): - return False - return True - signatures = self.signaturesForArgCount(argc) - for idx in range(argc): - if isValidDistinguishingIndex(idx, signatures): - return idx - # No valid distinguishing index. Time to throw - locations = self.locationsForArgCount(argc) - raise WebIDLError("Signatures with %d arguments for method '%s' are not " - "distinguishable" % (argc, self.identifier.name), - locations) - - def handleExtendedAttribute(self, attr): - identifier = attr.identifier() - if identifier == "GetterThrows": - raise WebIDLError("Methods must not be flagged as " - "[GetterThrows]", - [attr.location, self.location]) - elif identifier == "SetterThrows": - raise WebIDLError("Methods must not be flagged as " - "[SetterThrows]", - [attr.location, self.location]) - elif identifier == "Unforgeable": - if self.isStatic(): - raise WebIDLError("[Unforgeable] is only allowed on non-static " - "methods", [attr.location, self.location]) - self._unforgeable = True - elif identifier == "SameObject": - raise WebIDLError("Methods must not be flagged as [SameObject]", - [attr.location, self.location]); - elif identifier == "Constant": - raise WebIDLError("Methods must not be flagged as [Constant]", - [attr.location, self.location]); - elif identifier == "PutForwards": - raise WebIDLError("Only attributes support [PutForwards]", - [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(): - raise WebIDLError("[LenientFloat] used on a non-void method", - [attr.location, self.location]) - if not any(arg.type.includesRestrictedFloat() for arg in sig[1]): - raise WebIDLError("[LenientFloat] used on an operation with no " - "restricted float type arguments", - [attr.location, self.location]) - elif identifier == "Exposed": - convertExposedAttrToGlobalNameSet(attr, self._exposureGlobalNames) - elif (identifier == "Pure" or - identifier == "CrossOriginCallable" or - identifier == "WebGLHandlesContextLoss"): - # Known no-argument attributes. - if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier, - [attr.location]) - elif (identifier == "Throws" or - identifier == "NewObject" or - identifier == "ChromeOnly" or - identifier == "Pref" or - identifier == "Func" or - identifier == "AvailableIn" or - identifier == "CheckPermissions"): - # Known attributes that we don't need to do anything with here - pass - else: - raise WebIDLError("Unknown extended attribute %s on method" % identifier, - [attr.location]) - IDLInterfaceMember.handleExtendedAttribute(self, attr) - - def returnsPromise(self): - return self._overloads[0].returnType.isPromise() - - def isUnforgeable(self): - return self._unforgeable - - def _getDependentObjects(self): - deps = set() - for overload in self._overloads: - deps.union(overload._getDependentObjects()) - return deps - -class IDLImplementsStatement(IDLObject): - def __init__(self, location, implementor, implementee): - IDLObject.__init__(self, location) - self.implementor = implementor; - self.implementee = implementee - - def finish(self, scope): - 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) - - def validate(self): - pass - - def addExtendedAttributes(self, attrs): - assert len(attrs) == 0 - -class IDLExtendedAttribute(IDLObject): - """ - A class to represent IDL extended attributes so we can give them locations - """ - def __init__(self, location, tuple): - IDLObject.__init__(self, location) - self._tuple = tuple - - def identifier(self): - return self._tuple[0] - - def noArguments(self): - return len(self._tuple) == 1 - - def hasValue(self): - return len(self._tuple) >= 2 and isinstance(self._tuple[1], str) - - def value(self): - assert(self.hasValue()) - return self._tuple[1] - - def hasArgs(self): - return (len(self._tuple) == 2 and isinstance(self._tuple[1], list) or - len(self._tuple) == 3) - - def args(self): - assert(self.hasArgs()) - # Our args are our last element - return self._tuple[-1] - - def listValue(self): - """ - Backdoor for storing random data in _extendedAttrDict - """ - return list(self._tuple)[1:] - -# Parser - -class Tokenizer(object): - tokens = [ - "INTEGER", - "FLOATLITERAL", - "IDENTIFIER", - "STRING", - "WHITESPACE", - "OTHER" - ] - - def t_FLOATLITERAL(self, t): - r'(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN' - t.value = float(t.value) - return t - - def t_INTEGER(self, t): - r'-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)' - try: - # Can't use int(), because that doesn't handle octal properly. - t.value = parseInt(t.value) - except: - raise WebIDLError("Invalid integer literal", - [Location(lexer=self.lexer, - lineno=self.lexer.lineno, - lexpos=self.lexer.lexpos, - filename=self._filename)]) - return t - - def t_IDENTIFIER(self, t): - r'[A-Z_a-z][0-9A-Z_a-z-]*' - t.type = self.keywords.get(t.value, 'IDENTIFIER') - return t - - def t_STRING(self, t): - r'"[^"]*"' - t.value = t.value[1:-1] - return t - - def t_WHITESPACE(self, t): - r'[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+' - pass - - def t_ELLIPSIS(self, t): - r'\.\.\.' - t.type = self.keywords.get(t.value) - return t - - def t_OTHER(self, t): - r'[^\t\n\r 0-9A-Z_a-z]' - t.type = self.keywords.get(t.value, 'OTHER') - return t - - keywords = { - "module": "MODULE", - "interface": "INTERFACE", - "partial": "PARTIAL", - "dictionary": "DICTIONARY", - "exception": "EXCEPTION", - "enum": "ENUM", - "callback": "CALLBACK", - "typedef": "TYPEDEF", - "implements": "IMPLEMENTS", - "const": "CONST", - "null": "NULL", - "true": "TRUE", - "false": "FALSE", - "serializer": "SERIALIZER", - "stringifier": "STRINGIFIER", - "jsonifier": "JSONIFIER", - "unrestricted": "UNRESTRICTED", - "attribute": "ATTRIBUTE", - "readonly": "READONLY", - "inherit": "INHERIT", - "static": "STATIC", - "getter": "GETTER", - "setter": "SETTER", - "creator": "CREATOR", - "deleter": "DELETER", - "legacycaller": "LEGACYCALLER", - "optional": "OPTIONAL", - "...": "ELLIPSIS", - "::": "SCOPE", - "Date": "DATE", - "DOMString": "DOMSTRING", - "ByteString": "BYTESTRING", - "ScalarValueString": "SCALARVALUESTRING", - "any": "ANY", - "boolean": "BOOLEAN", - "byte": "BYTE", - "double": "DOUBLE", - "float": "FLOAT", - "long": "LONG", - "object": "OBJECT", - "octet": "OCTET", - "optional": "OPTIONAL", - "Promise": "PROMISE", - "sequence": "SEQUENCE", - "MozMap": "MOZMAP", - "short": "SHORT", - "unsigned": "UNSIGNED", - "void": "VOID", - ":": "COLON", - ";": "SEMICOLON", - "{": "LBRACE", - "}": "RBRACE", - "(": "LPAREN", - ")": "RPAREN", - "[": "LBRACKET", - "]": "RBRACKET", - "?": "QUESTIONMARK", - ",": "COMMA", - "=": "EQUALS", - "<": "LT", - ">": "GT", - "ArrayBuffer": "ARRAYBUFFER", - "or": "OR" - } - - tokens.extend(keywords.values()) - - def t_error(self, t): - raise WebIDLError("Unrecognized Input", - [Location(lexer=self.lexer, - lineno=self.lexer.lineno, - lexpos=self.lexer.lexpos, - filename = self.filename)]) - - def __init__(self, outputdir, lexer=None): - if lexer: - self.lexer = lexer - else: - self.lexer = lex.lex(object=self, - outputdir=outputdir, - lextab='webidllex', - reflags=re.DOTALL) - -class SqueakyCleanLogger(object): - errorWhitelist = [ - # Web IDL defines the WHITESPACE token, but doesn't actually - # use it ... so far. - "Token 'WHITESPACE' defined, but not used", - # And that means we have an unused token - "There is 1 unused token", - # Web IDL defines a OtherOrComma rule that's only used in - # ExtendedAttributeInner, which we don't use yet. - "Rule 'OtherOrComma' defined, but not used", - # And an unused rule - "There is 1 unused rule", - # And the OtherOrComma grammar symbol is unreachable. - "Symbol 'OtherOrComma' is unreachable", - # Which means the Other symbol is unreachable. - "Symbol 'Other' is unreachable", - ] - def __init__(self): - self.errors = [] - def debug(self, msg, *args, **kwargs): - pass - info = debug - def warning(self, msg, *args, **kwargs): - if msg == "%s:%d: Rule '%s' defined, but not used": - # Munge things so we don't have to hardcode filenames and - # line numbers in our whitelist. - whitelistmsg = "Rule '%s' defined, but not used" - whitelistargs = args[2:] - else: - whitelistmsg = msg - whitelistargs = args - if (whitelistmsg % whitelistargs) not in SqueakyCleanLogger.errorWhitelist: - self.errors.append(msg % args) - error = warning - - def reportGrammarErrors(self): - if self.errors: - raise WebIDLError("\n".join(self.errors), []) - -class Parser(Tokenizer): - def getLocation(self, p, i): - return Location(self.lexer, p.lineno(i), p.lexpos(i), self._filename) - - def globalScope(self): - return self._globalScope - - # The p_Foo functions here must match the WebIDL spec's grammar. - # It's acceptable to split things at '|' boundaries. - def p_Definitions(self, p): - """ - Definitions : ExtendedAttributeList Definition Definitions - """ - if p[2]: - p[0] = [p[2]] - p[2].addExtendedAttributes(p[1]) - else: - assert not p[1] - p[0] = [] - - p[0].extend(p[3]) - - def p_DefinitionsEmpty(self, p): - """ - Definitions : - """ - p[0] = [] - - def p_Definition(self, p): - """ - Definition : CallbackOrInterface - | PartialInterface - | Dictionary - | Exception - | Enum - | Typedef - | ImplementsStatement - """ - p[0] = p[1] - assert p[1] # We might not have implemented something ... - - def p_CallbackOrInterfaceCallback(self, p): - """ - CallbackOrInterface : CALLBACK CallbackRestOrInterface - """ - if p[2].isInterface(): - assert isinstance(p[2], IDLInterface) - p[2].setCallback(True) - - p[0] = p[2] - - def p_CallbackOrInterfaceInterface(self, p): - """ - CallbackOrInterface : Interface - """ - p[0] = p[1] - - def p_CallbackRestOrInterface(self, p): - """ - CallbackRestOrInterface : CallbackRest - | Interface - """ - assert p[1] - p[0] = p[1] - - def p_Interface(self, p): - """ - Interface : INTERFACE 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] - - try: - existingObj = self.globalScope()._lookupIdentifier(identifier) - if existingObj: - p[0] = existingObj - if not isinstance(p[0], IDLInterface): - raise WebIDLError("Interface has the same name as " - "non-interface object", - [location, p[0].location]) - p[0].setNonPartial(location, parent, members) - return - except Exception, ex: - if isinstance(ex, WebIDLError): - raise ex - pass - - p[0] = IDLInterface(location, self.globalScope(), identifier, parent, - members, isKnownNonPartial=True) - - def p_InterfaceForwardDecl(self, p): - """ - Interface : INTERFACE IDENTIFIER SEMICOLON - """ - location = self.getLocation(p, 1) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - - try: - if self.globalScope()._lookupIdentifier(identifier): - p[0] = self.globalScope()._lookupIdentifier(identifier) - if not isinstance(p[0], IDLExternalInterface): - raise WebIDLError("Name collision between external " - "interface declaration for identifier " - "%s and %s" % (identifier.name, p[0]), - [location, p[0].location]) - return - except Exception, ex: - if isinstance(ex, WebIDLError): - raise ex - pass - - p[0] = IDLExternalInterface(location, self.globalScope(), identifier) - - def p_PartialInterface(self, p): - """ - PartialInterface : PARTIAL INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON - """ - location = self.getLocation(p, 2) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) - members = p[5] - - nonPartialInterface = None - try: - nonPartialInterface = self.globalScope()._lookupIdentifier(identifier) - if nonPartialInterface: - if not isinstance(nonPartialInterface, IDLInterface): - raise WebIDLError("Partial interface has the same name as " - "non-interface object", - [location, nonPartialInterface.location]) - except Exception, ex: - if isinstance(ex, WebIDLError): - raise ex - pass - - if not nonPartialInterface: - nonPartialInterface = IDLInterface(location, self.globalScope(), - identifier, None, - [], isKnownNonPartial=False) - partialInterface = IDLPartialInterface(location, identifier, members, - nonPartialInterface) - p[0] = partialInterface - - def p_Inheritance(self, p): - """ - Inheritance : COLON ScopedName - """ - p[0] = IDLIdentifierPlaceholder(self.getLocation(p, 2), p[2]) - - def p_InheritanceEmpty(self, p): - """ - Inheritance : - """ - pass - - def p_InterfaceMembers(self, p): - """ - InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers - """ - p[0] = [p[2]] if p[2] else [] - - assert not p[1] or p[2] - p[2].addExtendedAttributes(p[1]) - - p[0].extend(p[3]) - - def p_InterfaceMembersEmpty(self, p): - """ - InterfaceMembers : - """ - p[0] = [] - - def p_InterfaceMember(self, p): - """ - InterfaceMember : Const - | AttributeOrOperation - """ - p[0] = p[1] - - def p_Dictionary(self, p): - """ - Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON - """ - location = self.getLocation(p, 1) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - members = p[5] - p[0] = IDLDictionary(location, self.globalScope(), identifier, p[3], members) - - def p_DictionaryMembers(self, p): - """ - DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers - | - """ - if len(p) == 1: - # We're at the end of the list - p[0] = [] - return - # Add our extended attributes - p[2].addExtendedAttributes(p[1]) - p[0] = [p[2]] - p[0].extend(p[3]) - - def p_DictionaryMember(self, p): - """ - DictionaryMember : Type IDENTIFIER Default SEMICOLON - """ - # These quack a lot like optional arguments, so just treat them that way. - t = p[1] - assert isinstance(t, IDLType) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - defaultValue = p[3] - - p[0] = IDLArgument(self.getLocation(p, 2), identifier, t, optional=True, - defaultValue=defaultValue, variadic=False, - dictionaryMember=True) - - def p_Default(self, p): - """ - Default : EQUALS DefaultValue - | - """ - if len(p) > 1: - p[0] = p[2] - else: - p[0] = None - - def p_DefaultValue(self, p): - """ - DefaultValue : ConstValue - | LBRACKET RBRACKET - """ - if len(p) == 2: - p[0] = p[1] - else: - assert len(p) == 3 # Must be [] - p[0] = IDLEmptySequenceValue(self.getLocation(p, 1)) - - def p_Exception(self, p): - """ - Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON - """ - pass - - def p_Enum(self, p): - """ - Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON - """ - location = self.getLocation(p, 1) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) - - values = p[4] - assert values - p[0] = IDLEnum(location, self.globalScope(), identifier, values) - - def p_EnumValueList(self, p): - """ - EnumValueList : STRING EnumValueListComma - """ - p[0] = [p[1]] - p[0].extend(p[2]) - - def p_EnumValueListComma(self, p): - """ - EnumValueListComma : COMMA EnumValueListString - """ - p[0] = p[2] - - def p_EnumValueListCommaEmpty(self, p): - """ - EnumValueListComma : - """ - p[0] = [] - - def p_EnumValueListString(self, p): - """ - EnumValueListString : STRING EnumValueListComma - """ - p[0] = [p[1]] - p[0].extend(p[2]) - - def p_EnumValueListStringEmpty(self, p): - """ - EnumValueListString : - """ - p[0] = [] - - def p_CallbackRest(self, p): - """ - CallbackRest : IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON - """ - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) - p[0] = IDLCallbackType(self.getLocation(p, 1), self.globalScope(), - identifier, p[3], p[5]) - - def p_ExceptionMembers(self, p): - """ - ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers - | - """ - pass - - def p_Typedef(self, p): - """ - Typedef : TYPEDEF Type IDENTIFIER SEMICOLON - """ - typedef = IDLTypedefType(self.getLocation(p, 1), p[2], p[3]) - typedef.resolve(self.globalScope()) - 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_Const(self, p): - """ - Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON - """ - location = self.getLocation(p, 1) - type = p[2] - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) - value = p[5] - p[0] = IDLConst(location, identifier, type, value) - - def p_ConstValueBoolean(self, p): - """ - ConstValue : BooleanLiteral - """ - location = self.getLocation(p, 1) - booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean] - p[0] = IDLValue(location, booleanType, p[1]) - - def p_ConstValueInteger(self, p): - """ - ConstValue : INTEGER - """ - location = self.getLocation(p, 1) - - # We don't know ahead of time what type the integer literal is. - # Determine the smallest type it could possibly fit in and use that. - integerType = matchIntegerValueToType(p[1]) - if integerType == None: - raise WebIDLError("Integer literal out of range", [location]) - - p[0] = IDLValue(location, integerType, p[1]) - - def p_ConstValueFloat(self, p): - """ - ConstValue : FLOATLITERAL - """ - location = self.getLocation(p, 1) - p[0] = IDLValue(location, BuiltinTypes[IDLBuiltinType.Types.unrestricted_float], p[1]) - - def p_ConstValueString(self, p): - """ - ConstValue : STRING - """ - location = self.getLocation(p, 1) - 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 - """ - p[0] = True - - def p_BooleanLiteralFalse(self, p): - """ - BooleanLiteral : FALSE - """ - p[0] = False - - def p_AttributeOrOperation(self, p): - """ - AttributeOrOperation : Attribute - | Operation - """ - p[0] = p[1] - - def p_AttributeWithQualifier(self, p): - """ - Attribute : Qualifier AttributeRest - """ - static = IDLInterfaceMember.Special.Static in p[1] - stringifier = IDLInterfaceMember.Special.Stringifier in p[1] - (location, identifier, type, readonly) = p[2] - p[0] = IDLAttribute(location, identifier, type, readonly, static=static, - stringifier=stringifier) - - def p_Attribute(self, p): - """ - Attribute : Inherit AttributeRest - """ - (location, identifier, type, readonly) = p[2] - p[0] = IDLAttribute(location, identifier, type, readonly, inherit=p[1]) - - def p_AttributeRest(self, p): - """ - AttributeRest : ReadOnly ATTRIBUTE Type IDENTIFIER SEMICOLON - """ - location = self.getLocation(p, 2) - readonly = p[1] - t = p[3] - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 4), p[4]) - p[0] = (location, identifier, t, readonly) - - def p_ReadOnly(self, p): - """ - ReadOnly : READONLY - """ - p[0] = True - - def p_ReadOnlyEmpty(self, p): - """ - ReadOnly : - """ - p[0] = False - - def p_Inherit(self, p): - """ - Inherit : INHERIT - """ - p[0] = True - - def p_InheritEmpty(self, p): - """ - Inherit : - """ - p[0] = False - - def p_Operation(self, p): - """ - Operation : Qualifiers OperationRest - """ - qualifiers = p[1] - - # Disallow duplicates in the qualifier set - if not len(set(qualifiers)) == len(qualifiers): - raise WebIDLError("Duplicate qualifiers are not allowed", - [self.getLocation(p, 1)]) - - static = IDLInterfaceMember.Special.Static in p[1] - # If static is there that's all that's allowed. This is disallowed - # by the parser, so we can assert here. - assert not static or len(qualifiers) == 1 - - stringifier = IDLInterfaceMember.Special.Stringifier in p[1] - # If stringifier is there that's all that's allowed. This is disallowed - # by the parser, so we can assert here. - assert not stringifier or len(qualifiers) == 1 - - getter = True if IDLMethod.Special.Getter in p[1] else False - setter = True if IDLMethod.Special.Setter in p[1] else False - creator = True if IDLMethod.Special.Creator in p[1] else False - deleter = True if IDLMethod.Special.Deleter in p[1] else False - legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False - - if getter or deleter: - if setter or creator: - raise WebIDLError("getter and deleter are incompatible with setter and creator", - [self.getLocation(p, 1)]) - - (returnType, identifier, arguments) = p[2] - - assert isinstance(returnType, IDLType) - - specialType = IDLMethod.NamedOrIndexed.Neither - - if getter or deleter: - if len(arguments) != 1: - raise WebIDLError("%s has wrong number of arguments" % - ("getter" if getter else "deleter"), - [self.getLocation(p, 2)]) - argType = arguments[0].type - if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: - specialType = IDLMethod.NamedOrIndexed.Named - elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: - specialType = IDLMethod.NamedOrIndexed.Indexed - else: - raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % - ("getter" if getter else "deleter"), - [arguments[0].location]) - if arguments[0].optional or arguments[0].variadic: - raise WebIDLError("%s cannot have %s argument" % - ("getter" if getter else "deleter", - "optional" if arguments[0].optional else "variadic"), - [arguments[0].location]) - if getter: - if returnType.isVoid(): - raise WebIDLError("getter cannot have void return type", - [self.getLocation(p, 2)]) - if setter or creator: - if len(arguments) != 2: - raise WebIDLError("%s has wrong number of arguments" % - ("setter" if setter else "creator"), - [self.getLocation(p, 2)]) - argType = arguments[0].type - if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: - specialType = IDLMethod.NamedOrIndexed.Named - elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: - specialType = IDLMethod.NamedOrIndexed.Indexed - else: - raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % - ("setter" if setter else "creator"), - [arguments[0].location]) - if arguments[0].optional or arguments[0].variadic: - raise WebIDLError("%s cannot have %s argument" % - ("setter" if setter else "creator", - "optional" if arguments[0].optional else "variadic"), - [arguments[0].location]) - if arguments[1].optional or arguments[1].variadic: - raise WebIDLError("%s cannot have %s argument" % - ("setter" if setter else "creator", - "optional" if arguments[1].optional else "variadic"), - [arguments[1].location]) - - if stringifier: - if len(arguments) != 0: - raise WebIDLError("stringifier has wrong number of arguments", - [self.getLocation(p, 2)]) - if not returnType.isDOMString(): - raise WebIDLError("stringifier must have DOMString return type", - [self.getLocation(p, 2)]) - - # identifier might be None. This is only permitted for special methods. - if not identifier: - if not getter and not setter and not creator and \ - not deleter and not legacycaller and not stringifier: - raise WebIDLError("Identifier required for non-special methods", - [self.getLocation(p, 2)]) - - location = BuiltinLocation("<auto-generated-identifier>") - identifier = IDLUnresolvedIdentifier(location, "__%s%s%s%s%s%s%s" % - ("named" if specialType == IDLMethod.NamedOrIndexed.Named else \ - "indexed" if specialType == IDLMethod.NamedOrIndexed.Indexed else "", - "getter" if getter else "", - "setter" if setter else "", - "deleter" if deleter else "", - "creator" if creator else "", - "legacycaller" if legacycaller else "", - "stringifier" if stringifier else ""), allowDoubleUnderscore=True) - - method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments, - static=static, getter=getter, setter=setter, creator=creator, - deleter=deleter, specialType=specialType, - legacycaller=legacycaller, stringifier=stringifier) - p[0] = method - - def p_Stringifier(self, p): - """ - Operation : STRINGIFIER SEMICOLON - """ - identifier = IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "__stringifier", - allowDoubleUnderscore=True) - method = IDLMethod(self.getLocation(p, 1), - identifier, - returnType=BuiltinTypes[IDLBuiltinType.Types.domstring], - arguments=[], - stringifier=True) - p[0] = method - - def p_Jsonifier(self, p): - """ - Operation : JSONIFIER SEMICOLON - """ - identifier = IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "__jsonifier", allowDoubleUnderscore=True) - method = IDLMethod(self.getLocation(p, 1), - identifier, - returnType=BuiltinTypes[IDLBuiltinType.Types.object], - arguments=[], - jsonifier=True) - p[0] = method - - def p_QualifierStatic(self, p): - """ - Qualifier : STATIC - """ - p[0] = [IDLInterfaceMember.Special.Static] - - def p_QualifierStringifier(self, p): - """ - Qualifier : STRINGIFIER - """ - p[0] = [IDLInterfaceMember.Special.Stringifier] - - def p_Qualifiers(self, p): - """ - Qualifiers : Qualifier - | Specials - """ - p[0] = p[1] - - def p_Specials(self, p): - """ - Specials : Special Specials - """ - p[0] = [p[1]] - p[0].extend(p[2]) - - def p_SpecialsEmpty(self, p): - """ - Specials : - """ - p[0] = [] - - def p_SpecialGetter(self, p): - """ - Special : GETTER - """ - p[0] = IDLMethod.Special.Getter - - def p_SpecialSetter(self, p): - """ - Special : SETTER - """ - p[0] = IDLMethod.Special.Setter - - def p_SpecialCreator(self, p): - """ - Special : CREATOR - """ - p[0] = IDLMethod.Special.Creator - - def p_SpecialDeleter(self, p): - """ - Special : DELETER - """ - p[0] = IDLMethod.Special.Deleter - - def p_SpecialLegacyCaller(self, p): - """ - Special : LEGACYCALLER - """ - p[0] = IDLMethod.Special.LegacyCaller - - def p_OperationRest(self, p): - """ - OperationRest : ReturnType OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON - """ - p[0] = (p[1], p[2], p[4]) - - def p_OptionalIdentifier(self, p): - """ - OptionalIdentifier : IDENTIFIER - """ - p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) - - def p_OptionalIdentifierEmpty(self, p): - """ - OptionalIdentifier : - """ - pass - - def p_ArgumentList(self, p): - """ - ArgumentList : Argument Arguments - """ - p[0] = [p[1]] if p[1] else [] - p[0].extend(p[2]) - - def p_ArgumentListEmpty(self, p): - """ - ArgumentList : - """ - p[0] = [] - - def p_Arguments(self, p): - """ - Arguments : COMMA Argument Arguments - """ - p[0] = [p[2]] if p[2] else [] - p[0].extend(p[3]) - - def p_ArgumentsEmpty(self, p): - """ - Arguments : - """ - p[0] = [] - - def p_Argument(self, p): - """ - Argument : ExtendedAttributeList Optional Type Ellipsis ArgumentName Default - """ - t = p[3] - assert isinstance(t, IDLType) - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 5), p[5]) - - optional = p[2] - variadic = p[4] - defaultValue = p[6] - - if not optional and defaultValue: - raise WebIDLError("Mandatory arguments can't have a default value.", - [self.getLocation(p, 6)]) - - # We can't test t.isAny() here and give it a default value as needed, - # since at this point t is not a fully resolved type yet (e.g. it might - # be a typedef). We'll handle the 'any' case in IDLArgument.complete. - - if variadic: - if optional: - raise WebIDLError("Variadic arguments should not be marked optional.", - [self.getLocation(p, 2)]) - optional = variadic - - p[0] = IDLArgument(self.getLocation(p, 5), identifier, t, optional, defaultValue, variadic) - p[0].addExtendedAttributes(p[1]) - - def p_ArgumentName(self, p): - """ - ArgumentName : IDENTIFIER - | ATTRIBUTE - | CALLBACK - | CONST - | CREATOR - | DELETER - | DICTIONARY - | ENUM - | EXCEPTION - | GETTER - | IMPLEMENTS - | INHERIT - | INTERFACE - | LEGACYCALLER - | PARTIAL - | SERIALIZER - | SETTER - | STATIC - | STRINGIFIER - | JSONIFIER - | TYPEDEF - | UNRESTRICTED - """ - p[0] = p[1] - - def p_Optional(self, p): - """ - Optional : OPTIONAL - """ - p[0] = True - - def p_OptionalEmpty(self, p): - """ - Optional : - """ - p[0] = False - - def p_Ellipsis(self, p): - """ - Ellipsis : ELLIPSIS - """ - p[0] = True - - def p_EllipsisEmpty(self, p): - """ - Ellipsis : - """ - p[0] = False - - def p_ExceptionMember(self, p): - """ - ExceptionMember : Const - | ExceptionField - """ - pass - - def p_ExceptionField(self, p): - """ - ExceptionField : Type IDENTIFIER SEMICOLON - """ - pass - - def p_ExtendedAttributeList(self, p): - """ - ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET - """ - p[0] = [p[2]] - if p[3]: - p[0].extend(p[3]) - - def p_ExtendedAttributeListEmpty(self, p): - """ - ExtendedAttributeList : - """ - p[0] = [] - - def p_ExtendedAttribute(self, p): - """ - ExtendedAttribute : ExtendedAttributeNoArgs - | ExtendedAttributeArgList - | ExtendedAttributeIdent - | ExtendedAttributeNamedArgList - | ExtendedAttributeIdentList - """ - p[0] = IDLExtendedAttribute(self.getLocation(p, 1), p[1]) - - def p_ExtendedAttributeEmpty(self, p): - """ - ExtendedAttribute : - """ - pass - - def p_ExtendedAttributes(self, p): - """ - ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes - """ - p[0] = [p[2]] if p[2] else [] - p[0].extend(p[3]) - - def p_ExtendedAttributesEmpty(self, p): - """ - ExtendedAttributes : - """ - p[0] = [] - - def p_Other(self, p): - """ - Other : INTEGER - | FLOATLITERAL - | IDENTIFIER - | STRING - | OTHER - | ELLIPSIS - | COLON - | SCOPE - | SEMICOLON - | LT - | EQUALS - | GT - | QUESTIONMARK - | DATE - | DOMSTRING - | BYTESTRING - | SCALARVALUESTRING - | ANY - | ATTRIBUTE - | BOOLEAN - | BYTE - | LEGACYCALLER - | CONST - | CREATOR - | DELETER - | DOUBLE - | EXCEPTION - | FALSE - | FLOAT - | GETTER - | IMPLEMENTS - | INHERIT - | INTERFACE - | LONG - | MODULE - | NULL - | OBJECT - | OCTET - | OPTIONAL - | SEQUENCE - | MOZMAP - | SETTER - | SHORT - | STATIC - | STRINGIFIER - | JSONIFIER - | TRUE - | TYPEDEF - | UNSIGNED - | VOID - """ - pass - - def p_OtherOrComma(self, p): - """ - OtherOrComma : Other - | COMMA - """ - pass - - def p_TypeSingleType(self, p): - """ - Type : SingleType - """ - p[0] = p[1] - - def p_TypeUnionType(self, p): - """ - Type : UnionType TypeSuffix - """ - p[0] = self.handleModifiers(p[1], p[2]) - - def p_SingleTypeNonAnyType(self, p): - """ - SingleType : NonAnyType - """ - p[0] = p[1] - - def p_SingleTypeAnyType(self, p): - """ - SingleType : ANY TypeSuffixStartingWithArray - """ - p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.any], p[2]) - - def p_UnionType(self, p): - """ - UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN - """ - types = [p[2], p[4]] - types.extend(p[5]) - p[0] = IDLUnionType(self.getLocation(p, 1), types) - - def p_UnionMemberTypeNonAnyType(self, p): - """ - UnionMemberType : NonAnyType - """ - p[0] = p[1] - - def p_UnionMemberTypeArrayOfAny(self, p): - """ - UnionMemberTypeArrayOfAny : ANY LBRACKET RBRACKET - """ - p[0] = IDLArrayType(self.getLocation(p, 2), - BuiltinTypes[IDLBuiltinType.Types.any]) - - def p_UnionMemberType(self, p): - """ - UnionMemberType : UnionType TypeSuffix - | UnionMemberTypeArrayOfAny TypeSuffix - """ - p[0] = self.handleModifiers(p[1], p[2]) - - def p_UnionMemberTypes(self, p): - """ - UnionMemberTypes : OR UnionMemberType UnionMemberTypes - """ - p[0] = [p[2]] - p[0].extend(p[3]) - - def p_UnionMemberTypesEmpty(self, p): - """ - UnionMemberTypes : - """ - p[0] = [] - - def p_NonAnyType(self, p): - """ - NonAnyType : PrimitiveOrStringType TypeSuffix - | ARRAYBUFFER TypeSuffix - | OBJECT TypeSuffix - """ - if p[1] == "object": - type = BuiltinTypes[IDLBuiltinType.Types.object] - elif p[1] == "ArrayBuffer": - type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer] - else: - type = BuiltinTypes[p[1]] - - p[0] = self.handleModifiers(type, p[2]) - - def p_NonAnyTypeSequenceType(self, p): - """ - NonAnyType : SEQUENCE LT Type GT Null - """ - innerType = p[3] - type = IDLSequenceType(self.getLocation(p, 1), innerType) - if p[5]: - type = IDLNullableType(self.getLocation(p, 5), type) - p[0] = type - - # Note: Promise<void> is allowed, so we want to parametrize on - # ReturnType, not Type. Also, we want this to end up picking up - # the Promise interface for now, hence the games with IDLUnresolvedType. - def p_NonAnyTypePromiseType(self, p): - """ - NonAnyType : PROMISE LT ReturnType GT Null - """ - innerType = p[3] - promiseIdent = IDLUnresolvedIdentifier(self.getLocation(p, 1), "Promise") - type = IDLUnresolvedType(self.getLocation(p, 1), promiseIdent, p[3]) - if p[5]: - type = IDLNullableType(self.getLocation(p, 5), type) - p[0] = type - - def p_NonAnyTypeMozMapType(self, p): - """ - NonAnyType : MOZMAP LT Type GT Null - """ - innerType = p[3] - type = IDLMozMapType(self.getLocation(p, 1), innerType) - if p[5]: - type = IDLNullableType(self.getLocation(p, 5), type) - p[0] = type - - def p_NonAnyTypeScopedName(self, p): - """ - NonAnyType : ScopedName TypeSuffix - """ - assert isinstance(p[1], IDLUnresolvedIdentifier) - - if p[1].name == "Promise": - raise WebIDLError("Promise used without saying what it's " - "parametrized over", - [self.getLocation(p, 1)]) - - type = None - - try: - if self.globalScope()._lookupIdentifier(p[1]): - obj = self.globalScope()._lookupIdentifier(p[1]) - if obj.isType(): - type = obj - else: - type = IDLWrapperType(self.getLocation(p, 1), p[1]) - p[0] = self.handleModifiers(type, p[2]) - return - except: - pass - - type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) - p[0] = self.handleModifiers(type, p[2]) - - def p_NonAnyTypeDate(self, p): - """ - NonAnyType : DATE TypeSuffix - """ - p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.date], - p[2]) - - def p_ConstType(self, p): - """ - ConstType : PrimitiveOrStringType Null - """ - type = BuiltinTypes[p[1]] - if p[2]: - type = IDLNullableType(self.getLocation(p, 1), type) - p[0] = type - - def p_ConstTypeIdentifier(self, p): - """ - ConstType : IDENTIFIER Null - """ - identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) - - type = IDLUnresolvedType(self.getLocation(p, 1), identifier) - if p[2]: - type = IDLNullableType(self.getLocation(p, 1), type) - p[0] = type - - def p_PrimitiveOrStringTypeUint(self, p): - """ - PrimitiveOrStringType : UnsignedIntegerType - """ - p[0] = p[1] - - def p_PrimitiveOrStringTypeBoolean(self, p): - """ - PrimitiveOrStringType : BOOLEAN - """ - p[0] = IDLBuiltinType.Types.boolean - - def p_PrimitiveOrStringTypeByte(self, p): - """ - PrimitiveOrStringType : BYTE - """ - p[0] = IDLBuiltinType.Types.byte - - def p_PrimitiveOrStringTypeOctet(self, p): - """ - PrimitiveOrStringType : OCTET - """ - p[0] = IDLBuiltinType.Types.octet - - def p_PrimitiveOrStringTypeFloat(self, p): - """ - PrimitiveOrStringType : FLOAT - """ - p[0] = IDLBuiltinType.Types.float - - def p_PrimitiveOrStringTypeUnrestictedFloat(self, p): - """ - PrimitiveOrStringType : UNRESTRICTED FLOAT - """ - p[0] = IDLBuiltinType.Types.unrestricted_float - - def p_PrimitiveOrStringTypeDouble(self, p): - """ - PrimitiveOrStringType : DOUBLE - """ - p[0] = IDLBuiltinType.Types.double - - def p_PrimitiveOrStringTypeUnrestictedDouble(self, p): - """ - PrimitiveOrStringType : UNRESTRICTED DOUBLE - """ - p[0] = IDLBuiltinType.Types.unrestricted_double - - def p_PrimitiveOrStringTypeDOMString(self, p): - """ - PrimitiveOrStringType : DOMSTRING - """ - p[0] = IDLBuiltinType.Types.domstring - - def p_PrimitiveOrStringTypeBytestring(self, p): - """ - PrimitiveOrStringType : BYTESTRING - """ - p[0] = IDLBuiltinType.Types.bytestring - - def p_PrimitiveOrStringTypeScalarValueString(self, p): - """ - PrimitiveOrStringType : SCALARVALUESTRING - """ - p[0] = IDLBuiltinType.Types.scalarvaluestring - - def p_UnsignedIntegerTypeUnsigned(self, p): - """ - UnsignedIntegerType : UNSIGNED IntegerType - """ - p[0] = p[2] + 1 # Adding one to a given signed integer type - # gets you the unsigned type. - - def p_UnsignedIntegerType(self, p): - """ - UnsignedIntegerType : IntegerType - """ - p[0] = p[1] - - def p_IntegerTypeShort(self, p): - """ - IntegerType : SHORT - """ - p[0] = IDLBuiltinType.Types.short - - def p_IntegerTypeLong(self, p): - """ - IntegerType : LONG OptionalLong - """ - if p[2]: - p[0] = IDLBuiltinType.Types.long_long - else: - p[0] = IDLBuiltinType.Types.long - - def p_OptionalLong(self, p): - """ - OptionalLong : LONG - """ - p[0] = True - - def p_OptionalLongEmpty(self, p): - """ - OptionalLong : - """ - p[0] = False - - def p_TypeSuffixBrackets(self, p): - """ - TypeSuffix : LBRACKET RBRACKET TypeSuffix - """ - p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))] - p[0].extend(p[3]) - - def p_TypeSuffixQMark(self, p): - """ - TypeSuffix : QUESTIONMARK TypeSuffixStartingWithArray - """ - p[0] = [(IDLMethod.TypeSuffixModifier.QMark, self.getLocation(p, 1))] - p[0].extend(p[2]) - - def p_TypeSuffixEmpty(self, p): - """ - TypeSuffix : - """ - p[0] = [] - - def p_TypeSuffixStartingWithArray(self, p): - """ - TypeSuffixStartingWithArray : LBRACKET RBRACKET TypeSuffix - """ - p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))] - p[0].extend(p[3]) - - def p_TypeSuffixStartingWithArrayEmpty(self, p): - """ - TypeSuffixStartingWithArray : - """ - p[0] = [] - - def p_Null(self, p): - """ - Null : QUESTIONMARK - | - """ - if len(p) > 1: - p[0] = True - else: - p[0] = False - - def p_ReturnTypeType(self, p): - """ - ReturnType : Type - """ - p[0] = p[1] - - def p_ReturnTypeVoid(self, p): - """ - ReturnType : VOID - """ - p[0] = BuiltinTypes[IDLBuiltinType.Types.void] - - def p_ScopedName(self, p): - """ - ScopedName : AbsoluteScopedName - | RelativeScopedName - """ - p[0] = p[1] - - def p_AbsoluteScopedName(self, p): - """ - AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts - """ - assert False - pass - - def p_RelativeScopedName(self, p): - """ - RelativeScopedName : IDENTIFIER ScopedNameParts - """ - assert not p[2] # Not implemented! - - p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) - - def p_ScopedNameParts(self, p): - """ - ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts - """ - assert False - pass - - def p_ScopedNamePartsEmpty(self, p): - """ - ScopedNameParts : - """ - p[0] = None - - def p_ExtendedAttributeNoArgs(self, p): - """ - ExtendedAttributeNoArgs : IDENTIFIER - """ - p[0] = (p[1],) - - def p_ExtendedAttributeArgList(self, p): - """ - ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN - """ - p[0] = (p[1], p[3]) - - def p_ExtendedAttributeIdent(self, p): - """ - ExtendedAttributeIdent : IDENTIFIER EQUALS STRING - | IDENTIFIER EQUALS IDENTIFIER - """ - p[0] = (p[1], p[3]) - - def p_ExtendedAttributeNamedArgList(self, p): - """ - ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN - """ - p[0] = (p[1], p[3], p[5]) - - def p_ExtendedAttributeIdentList(self, p): - """ - ExtendedAttributeIdentList : IDENTIFIER EQUALS LPAREN IdentifierList RPAREN - """ - p[0] = (p[1], p[4]) - - def p_IdentifierList(self, p): - """ - IdentifierList : IDENTIFIER Identifiers - """ - idents = list(p[2]) - idents.insert(0, p[1]) - p[0] = idents - - def p_IdentifiersList(self, p): - """ - Identifiers : COMMA IDENTIFIER Identifiers - """ - idents = list(p[3]) - idents.insert(0, p[2]) - p[0] = idents - - def p_IdentifiersEmpty(self, p): - """ - Identifiers : - """ - p[0] = [] - - def p_error(self, p): - if not p: - raise WebIDLError("Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both", - [self._filename]) - else: - raise WebIDLError("invalid syntax", [Location(self.lexer, p.lineno, p.lexpos, self._filename)]) - - def __init__(self, outputdir='', lexer=None): - Tokenizer.__init__(self, outputdir, lexer) - - logger = SqueakyCleanLogger() - self.parser = yacc.yacc(module=self, - outputdir=outputdir, - tabmodule='webidlyacc', - errorlog=logger - # Pickling the grammar is a speedup in - # some cases (older Python?) but a - # significant slowdown in others. - # We're not pickling for now, until it - # becomes a speedup again. - # , picklefile='WebIDLGrammar.pkl' - ) - logger.reportGrammarErrors() - - 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.globalNames.add("FakeTestPrimaryGlobal") - self._globalScope.globalNameMapping["FakeTestPrimaryGlobal"].add("FakeTestPrimaryGlobal") - self._installBuiltins(self._globalScope) - self._productions = [] - - self._filename = "<builtin>" - self.lexer.input(Parser._builtins) - self._filename = None - - self.parser.parse(lexer=self.lexer,tracking=True) - - def _installBuiltins(self, scope): - assert isinstance(scope, IDLScope) - - # xrange omits the last value. - for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): - builtin = BuiltinTypes[x] - name = builtin.name - - typedef = IDLTypedefType(BuiltinLocation("<builtin type>"), builtin, name) - typedef.resolve(scope) - - @ staticmethod - def handleModifiers(type, modifiers): - for (modifier, modifierLocation) in modifiers: - assert modifier == IDLMethod.TypeSuffixModifier.QMark or \ - modifier == IDLMethod.TypeSuffixModifier.Brackets - - if modifier == IDLMethod.TypeSuffixModifier.QMark: - type = IDLNullableType(modifierLocation, type) - elif modifier == IDLMethod.TypeSuffixModifier.Brackets: - type = IDLArrayType(modifierLocation, type) - - return type - - def parse(self, t, filename=None): - self.lexer.input(t) - - #for tok in iter(self.lexer.token, None): - # print tok - - self._filename = filename - self._productions.extend(self.parser.parse(lexer=self.lexer,tracking=True)) - self._filename = None - - def finish(self): - # First, 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)] - otherStatements = [ p for p in self._productions if - not isinstance(p, IDLImplementsStatement)] - for production in implementsStatements: - production.finish(self.globalScope()) - for production in otherStatements: - production.finish(self.globalScope()) - - # Do any post-finish validation we need to do - for production in self._productions: - production.validate() - - # De-duplicate self._productions, without modifying its order. - seen = set() - result = [] - for p in self._productions: - if p not in seen: - seen.add(p) - result.append(p) - return result - - def reset(self): - return Parser(lexer=self.lexer) - - # Builtin IDL defined by WebIDL - _builtins = """ - typedef unsigned long long DOMTimeStamp; - """ - -def main(): - # Parse arguments. - from optparse import OptionParser - usageString = "usage: %prog [options] files" - o = OptionParser(usage=usageString) - o.add_option("--cachedir", dest='cachedir', default=None, - help="Directory in which to cache lex/parse tables.") - o.add_option("--verbose-errors", action='store_true', default=False, - help="When an error happens, display the Python traceback.") - (options, args) = o.parse_args() - - if len(args) < 1: - o.error(usageString) - - fileList = args - baseDir = os.getcwd() - - # Parse the WebIDL. - parser = Parser(options.cachedir) - try: - for filename in fileList: - fullPath = os.path.normpath(os.path.join(baseDir, filename)) - f = open(fullPath, 'rb') - lines = f.readlines() - f.close() - print fullPath - parser.parse(''.join(lines), fullPath) - parser.finish() - except WebIDLError, e: - if options.verbose_errors: - traceback.print_exc() - else: - print e - -if __name__ == '__main__': - main() |