Bug 763911. Add support for interface members of dictionaries. r=khuey

This commit is contained in:
Boris Zbarsky 2012-06-19 12:09:37 -04:00
parent 04c02edf69
commit 03bc840cdd
4 changed files with 137 additions and 51 deletions

View File

@ -8,6 +8,7 @@ import os
import string
from WebIDL import *
from Configuration import NoSuchDescriptorError
AUTOGENERATED_WARNING_COMMENT = \
"/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
@ -351,6 +352,12 @@ class CGHeaders(CGWrapper):
attrs = [a for a in members if a.isAttr()]
types.extend([a.type for a in attrs])
for dictionary in dictionaries:
curDict = dictionary
while curDict:
types.extend([m.type for m in curDict.members])
curDict = curDict.parent
for t in types:
if t.unroll().isInterface():
if t.unroll().isSpiderMonkeyInterface():
@ -1556,15 +1563,15 @@ for (uint32_t i = 0; i < length; ++i) {
elif descriptor.workers:
templateBody += "${declName} = &${val}.toObject();"
else:
# Either external, or new-binding non-castable. We always have a
# holder for these, because we don't actually know whether we have
# to addref when unwrapping or not. So we just pass an
# getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
# it'll put a non-null pointer in there.
# External interface. We always have a holder for these,
# because we don't actually know whether we have to addref
# when unwrapping or not. So we just pass an
# getter_AddRefs(nsRefPtr) to XPConnect and if we'll need
# a release it'll put a non-null pointer in there.
if forceOwningType:
# Don't return a holderType in this case; our declName
# will just own stuff.
templateBody += "nsRefPtr<" + typeName + "> ${holderName};"
templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
else:
holderType = "nsRefPtr<" + typeName + ">"
templateBody += (
@ -1756,11 +1763,13 @@ for (uint32_t i = 0; i < length; ++i) {
raise TypeError("Can't handle dictionaries when failureCode is not None")
if type.nullable():
typeName = type.inner.inner.identifier.name
typeName = CGDictionary.makeDictionaryName(type.inner.inner,
descriptorProvider.workers)
declType = CGGeneric("Nullable<%s>" % typeName)
selfRef = "${declName}.Value()"
else:
typeName = type.inner.identifier.name
typeName = CGDictionary.makeDictionaryName(type.inner,
descriptorProvider.workers)
declType = CGGeneric(typeName)
selfRef = "${declName}"
# If we're optional or a member of something else, the const
@ -3490,24 +3499,37 @@ class CGNamespacedEnum(CGThing):
assert False # Only for headers.
class CGDictionary(CGThing):
def __init__(self, dictionary, workers):
def __init__(self, dictionary, descriptorProvider):
self.dictionary = dictionary;
self.workers = workers
# Fake a descriptorProvider
# XXXbz this will fail for interface types!
for member in dictionary.members:
if member.type.unroll().isInterface():
raise TypeError("No support for interface members of dictionaries: %s.%s" %
(dictionary.identifier.name, member.identifier.name))
self.memberInfo = [
(member,
getJSToNativeConversionTemplate(member.type,
{ "workers": workers },
isMember=True,
isOptional=(not member.defaultValue)))
for member in dictionary.members ]
self.workers = descriptorProvider.workers
if dictionary.parent:
parentCGThing = CGDictionary(dictionary.parent, descriptorProvider)
self.generatable = parentCGThing.generatable
if not self.generatable:
# Nothing else to do here
return
else:
self.generatable = True
# Getting a conversion template for interface types can fail
# if we don't have a relevant descriptor when self.workers is True.
# If that happens, just mark ourselves as not being
# generatable and move on.
try:
self.memberInfo = [
(member,
getJSToNativeConversionTemplate(member.type,
descriptorProvider,
isMember=True,
isOptional=(not member.defaultValue)))
for member in dictionary.members ]
except NoSuchDescriptorError, err:
if not self.workers:
raise err
self.generatable = False
def declare(self):
if not self.generatable:
return ""
d = self.dictionary
if d.parent:
inheritance = ": public %s " % self.makeClassName(d.parent)
@ -3535,6 +3557,8 @@ class CGDictionary(CGThing):
"inheritance": inheritance }))
def define(self):
if not self.generatable:
return ""
d = self.dictionary
if d.parent:
initParent = ("// Per spec, we init the parent's members first\n"
@ -3590,10 +3614,14 @@ class CGDictionary(CGThing):
"idInit": CGIndenter(idinit).define()
})
def makeClassName(self, dictionary):
suffix = "Workers" if self.workers else ""
@staticmethod
def makeDictionaryName(dictionary, workers):
suffix = "Workers" if workers else ""
return dictionary.identifier.name + suffix
def makeClassName(self, dictionary):
return self.makeDictionaryName(dictionary, self.workers)
def getMemberType(self, memberInfo):
(member, (templateBody, declType,
holderType, dealWithOptional)) = memberInfo
@ -3604,7 +3632,6 @@ class CGDictionary(CGThing):
return declType.define()
def getMemberConversion(self, memberInfo):
# Fake a descriptorProvider
(member, (templateBody, declType,
holderType, dealWithOptional)) = memberInfo
replacements = { "val": "temp",
@ -3616,7 +3643,11 @@ class CGDictionary(CGThing):
# the guts of init to a static method which is passed
# an explicit reference to our dictionary object, so
# we couldn't screw this up even if we wanted to....
"declName": ("(this->%s)" % member.identifier.name) }
"declName": ("(this->%s)" % member.identifier.name),
# We need a holder name for external interfaces, but
# it's scoped down to the conversion so we can just use
# anything we want.
"holderName": "holder"}
# We can't handle having a holderType here
assert holderType is None
if dealWithOptional:
@ -3696,7 +3727,30 @@ class CGBindingRoot(CGThing):
forwardDeclares = [CGClassForwardDeclare('XPCWrappedNativeScope')]
for x in descriptors:
descriptorsForForwardDeclaration = list(descriptors)
for dictionary in dictionaries:
curDict = dictionary
ifacemembers = []
while curDict:
ifacemembers.extend([m.type.unroll().inner for m
in curDict.members
if m.type.unroll().isInterface()])
curDict = curDict.parent
# Put in all the non-worker descriptors
descriptorsForForwardDeclaration.extend(
[config.getDescriptor(iface.identifier.name, False) for
iface in ifacemembers])
# And now the worker ones. But these may not exist, so we
# have to be more careful.
for iface in ifacemembers:
try:
descriptorsForForwardDeclaration.append(
config.getDescriptor(iface.identifier.name, True))
except NoSuchDescriptorError:
# just move along
pass
for x in descriptorsForForwardDeclaration:
nativeType = x.nativeType
components = x.nativeType.split('::')
className = components[-1]
@ -3755,8 +3809,10 @@ class CGBindingRoot(CGThing):
reSortedDictionaries.extend(toMove)
dictionaries = reSortedDictionaries
cgthings.extend([CGDictionary(d, workers=True) for d in dictionaries])
cgthings.extend([CGDictionary(d, workers=False) for d in dictionaries])
cgthings.extend([CGDictionary(d, config.getDescriptorProvider(True))
for d in dictionaries])
cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
for d in dictionaries])
# Do codegen for all the descriptors
cgthings.extend([CGDescriptor(x) for x in descriptors])

View File

@ -75,13 +75,55 @@ class Configuration:
return filter(lambda e: e.filename() == webIDLFile, self.enums)
def getDictionaries(self, webIDLFile):
return filter(lambda d: d.filename() == webIDLFile, self.dictionaries)
def getDescriptor(self, interfaceName, workers):
"""
Gets the appropriate descriptor for the given interface name
and the given workers boolean.
"""
iface = self.getInterface(interfaceName)
descriptors = self.getDescriptors(interface=iface)
class Descriptor:
# The only filter we currently have is workers vs non-workers.
matches = filter(lambda x: x.workers is workers, descriptors)
# After filtering, we should have exactly one result.
if len(matches) is not 1:
raise NoSuchDescriptorError("For " + interfaceName + " found " +
str(len(matches)) + " matches");
return matches[0]
def getDescriptorProvider(self, workers):
"""
Gets a descriptor provider that can provide descriptors as needed,
for the given workers boolean
"""
return DescriptorProvider(self, workers)
class NoSuchDescriptorError(TypeError):
def __init__(self, str):
TypeError.__init__(self, str)
class DescriptorProvider:
"""
A way of getting descriptors for interface names
"""
def __init__(self, config, workers):
self.config = config
self.workers = workers
def getDescriptor(self, interfaceName):
"""
Gets the appropriate descriptor for the given interface name given the
context of the current descriptor. This selects the appropriate
implementation for cases like workers.
"""
return self.config.getDescriptor(interfaceName, self.workers)
class Descriptor(DescriptorProvider):
"""
Represents a single descriptor for an interface. See Bindings.conf.
"""
def __init__(self, config, interface, desc):
self.config = config
DescriptorProvider.__init__(self, config, desc.get('workers', False))
self.interface = interface
# Read the desc, and fill in the relevant defaults.
@ -109,7 +151,6 @@ class Descriptor:
self.prefable = desc.get('prefable', False)
self.workers = desc.get('workers', False)
self.nativeIsISupports = not self.workers
self.customTrace = desc.get('customTrace', self.workers)
self.customFinalize = desc.get('customFinalize', self.workers)
@ -166,24 +207,6 @@ class Descriptor:
return self.interface.hasInterfaceObject() or self.interface.hasInterfacePrototypeObject()
def getDescriptor(self, interfaceName):
"""
Gets the appropriate descriptor for the given interface name given the
context of the current descriptor. This selects the appropriate
implementation for cases like workers.
"""
iface = self.config.getInterface(interfaceName)
descriptors = self.config.getDescriptors(interface=iface)
# The only filter we currently have is workers vs non-workers.
matches = filter(lambda x: x.workers is self.workers, descriptors)
# After filtering, we should have exactly one result.
if len(matches) is not 1:
raise TypeError("For " + interfaceName + " found " +
str(len(matches)) + " matches");
return matches[0]
def getExtendedAttributes(self, member, getter=False, setter=False):
name = member.identifier.name
if member.isMethod():

View File

@ -634,6 +634,11 @@ class IDLDictionary(IDLObjectWithScope):
for member in self.members:
member.resolve(self)
if not member.type.isComplete():
type = member.type.complete(scope)
assert not isinstance(type, IDLUnresolvedType)
assert not isinstance(type.name, IDLUnresolvedIdentifier)
member.type = type
# Members of a dictionary are sorted in lexicographic order
self.members.sort(cmp=cmp, key=lambda x: x.identifier.name)

View File

@ -304,4 +304,6 @@ dictionary Dict : ParentDict {
dictionary ParentDict : GrandparentDict {
long c = 5;
TestInterface someInterface;
TestExternalInterface someExternalInterface;
};