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