aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/script/dom/bindings/codegen
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2013-10-31 17:25:44 -0400
committerJosh Matthews <josh@joshmatthews.net>2013-11-05 12:57:02 -0500
commit06b1db8818c09201989b017434eef105f4d99e51 (patch)
tree0e4e0271c873a79034c476665f10bc3eac5843c7 /src/components/script/dom/bindings/codegen
parentd00736a9c059f08c8b411b3aada795e8bb9e2ea3 (diff)
downloadservo-06b1db8818c09201989b017434eef105f4d99e51.tar.gz
servo-06b1db8818c09201989b017434eef105f4d99e51.zip
Import unmodified callbacks-related codegen source from Gecko.
Diffstat (limited to 'src/components/script/dom/bindings/codegen')
-rw-r--r--src/components/script/dom/bindings/codegen/CodegenRust.py1558
-rw-r--r--src/components/script/dom/bindings/codegen/Configuration.py26
-rw-r--r--src/components/script/dom/bindings/codegen/parser/WebIDL.py173
3 files changed, 1734 insertions, 23 deletions
diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py
index 5734df036c6..0d012d2b1c8 100644
--- a/src/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/src/components/script/dom/bindings/codegen/CodegenRust.py
@@ -9,7 +9,7 @@ import string
import operator
from WebIDL import *
-from Configuration import NoSuchDescriptorError
+from Configuration import NoSuchDescriptorError, Descriptor
AUTOGENERATED_WARNING_COMMENT = \
"/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
@@ -445,7 +445,10 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
treatNullAs="Default",
treatUndefinedAs="Default",
isEnforceRange=False,
- isClamp=False):
+ isClamp=False,
+ exceptionCode=None,
+ isCallbackReturnValue=False,
+ sourceDescription="value"):
"""
Get a template for converting a JS value to a native object based on the
given type and descriptor. If failureCode is given, then we're actually
@@ -517,16 +520,40 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
# Also, we should not have a defaultValue if we know we're an object
assert(not isDefinitelyObject or defaultValue is None)
+ # If exceptionCode is not set, we'll just rethrow the exception we got.
+ # Note that we can't just set failureCode to exceptionCode, because setting
+ # failureCode will prevent pending exceptions from being set in cases when
+ # they really should be!
+ if exceptionCode is None:
+ exceptionCode = "return false;"
+ # We often want exceptionCode to be indented, since it often appears in an
+ # if body.
+ exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode))
+
+ # Unfortunately, .capitalize() on a string will lowercase things inside the
+ # string, which we do not want.
+ def firstCap(string):
+ return string[0].upper() + string[1:]
+
+ # Helper functions for dealing with failures due to the JS value being the
+ # wrong type of value
# Helper functions for dealing with failures due to the JS value being the
# wrong type of value
def onFailureNotAnObject(failureCode):
- return CGWrapper(CGGeneric(
+ return CGWrapper(
+ CGGeneric(
failureCode or
- 'return 0; //XXXjdm return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n")
+ ('//XXXjdm ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n'
+ '%s' % (firstCap(sourceDescription), exceptionCode))),
+ post="\n")
def onFailureBadType(failureCode, typeName):
- return CGWrapper(CGGeneric(
+ return CGWrapper(
+ CGGeneric(
failureCode or
- 'return 0; //XXXjdm return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n")
+ ('//XXXjdm ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s")\n;'
+ '%s' % (firstCap(sourceDescription), typeName,
+ exceptionCode))),
+ post="\n")
# A helper function for handling default values. Takes a template
# body and the C++ code to set the default value and wraps the
@@ -886,6 +913,22 @@ for (uint32_t i = 0; i < length; ++i) {
descriptor = descriptorProvider.getDescriptor(
type.unroll().inner.identifier.name)
+
+ if descriptor.interface.isCallback():
+ name = descriptor.interface.identifier.name
+ if type.nullable() or isCallbackReturnValue:
+ declType = CGGeneric("nsRefPtr<%s>" % name);
+ else:
+ declType = CGGeneric("OwningNonNull<%s>" % name)
+ conversion = (
+ " ${declName} = new %s(&${val}.toObject());\n" % name)
+
+ template = wrapObjectTemplate(conversion, type,
+ "${declName} = nullptr",
+ failureCode)
+ return JSToNativeConversionInfo(template, declType=declType,
+ dealWithOptional=isOptional)
+
# This is an interface that we implement as a concrete class
# or an XPCOM interface.
@@ -1218,6 +1261,12 @@ for (uint32_t i = 0; i < length; ++i) {
return (template, declType, None, False, None)
+ if type.isVoid():
+ assert not isOptional
+ # This one only happens for return values, and its easy: Just
+ # ignore the jsval.
+ return JSToNativeConversionInfo("")
+
if not type.isPrimitive():
raise TypeError("Need conversion for argument type '%s'" % str(type))
@@ -1422,7 +1471,7 @@ class CGArgumentConverter(CGThing):
self.argcAndIndex).define()
def getWrapTemplateForType(type, descriptorProvider, result, successCode,
- isCreator):
+ isCreator, exceptionCode):
"""
Reflect a C++ value stored in "result", of IDL type "type" into JS. The
"successCode" is the code to run once we have successfully done the
@@ -1435,6 +1484,10 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
if not haveSuccessCode:
successCode = "return 1;"
+ # We often want exceptionCode to be indented, since it often appears in an
+ # if body.
+ exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode))
+
def setValue(value, callWrapValue=False):
"""
Returns the code to set the jsval to value. If "callWrapValue" is true
@@ -1478,7 +1531,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode,
# Nullable sequences are Nullable< nsTArray<T> >
(recTemplate, recInfall) = getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode,
- isCreator)
+ isCreator, exceptionCode)
return ("""
if (%s.IsNull()) {
%s
@@ -1611,7 +1664,7 @@ if %(resultStr)s.is_null() {
if type.nullable():
(recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider,
"%s.Value()" % result, successCode,
- isCreator)
+ isCreator, exceptionCode)
return ("if (%s.IsNull()) {\n" % result +
CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
"}\n" + recTemplate, recInfal)
@@ -1661,7 +1714,9 @@ def wrapForType(type, descriptorProvider, templateValues):
wrap = getWrapTemplateForType(type, descriptorProvider,
templateValues.get('result', 'result'),
templateValues.get('successCode', None),
- templateValues.get('isCreator', False))[0]
+ templateValues.get('isCreator', False),
+ templateValues.get('exceptionCode',
+ "return 0;"),)[0]
defaultValues = {'obj': 'obj'}
return string.Template(wrap).substitute(defaultValues, **templateValues)
@@ -2363,11 +2418,17 @@ class Argument():
"""
A class for outputting the type and name of an argument
"""
- def __init__(self, argType, name):
+ def __init__(self, argType, name, default=None):
self.argType = argType
self.name = name
- def __str__(self):
- return self.name + ': ' + self.argType
+ self.default = default
+ def declare(self):
+ string = self.argType + ' ' + self.name
+ if self.default is not None:
+ string += " = " + self.default
+ return string
+ def define(self):
+ return self.argType + ' ' + self.name
class CGAbstractMethod(CGThing):
"""
@@ -2408,8 +2469,8 @@ class CGAbstractMethod(CGThing):
self.templateArgs = templateArgs
self.pub = pub;
self.unsafe = unsafe
- def _argstring(self):
- return ', '.join([str(a) for a in self.args])
+ def _argstring(self, declare):
+ return ', '.join([a.declare() if declare else a.define() for a in self.args])
def _template(self):
if self.templateArgs is None:
return ''
@@ -2450,13 +2511,13 @@ class CGAbstractMethod(CGThing):
# self._argstring(), self._returnType())
return ""
- def _define(self):
- return self.definition_prologue() + "\n" + self.definition_body() + self.definition_epilogue()
+ def _define(self, fromDeclare=False):
+ return self.definition_prologue(fromDeclare) + "\n" + self.definition_body() + self.definition_epilogue()
def define(self):
return "" if self.inline else self._define()
- def definition_prologue(self):
+ def definition_prologue(self, fromDeclare):
return "%sfn %s%s(%s)%s {%s" % (self._decorators(), self.name, self._template(),
- self._argstring(), self._returnType(), self._unsafe_open())
+ self._argstring(fromDeclare), self._returnType(), self._unsafe_open())
def definition_epilogue(self):
return "%s}\n" % self._unsafe_close()
def definition_body(self):
@@ -2885,6 +2946,21 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
*aEnabled = true;
return %s(aCx, global, aReceiver).is_not_null();""" % (getter))
+def isResultAlreadyAddRefed(extendedAttributes):
+ return not 'resultNotAddRefed' in extendedAttributes
+
+def needCx(returnType, arguments, extendedAttributes, considerTypes):
+ return (considerTypes and
+ (typeNeedsCx(returnType, True) or
+ any(typeNeedsCx(a.type) for a in arguments)) or
+ 'implicitJSContext' in extendedAttributes)
+
+def needScopeObject(returnType, arguments, extendedAttributes,
+ isWrapperCached, considerTypes):
+ return (considerTypes and not isWrapperCached and
+ (typeNeedsScopeObject(returnType, True) or
+ any(typeNeedsScopeObject(a.type) for a in arguments)))
+
class CGCallGenerator(CGThing):
"""
A class to generate an actual call to a C++ object. Assumes that the C++
@@ -3386,7 +3462,7 @@ def infallibleForMember(member, type, descriptorProvider):
failure conditions.
"""
return getWrapTemplateForType(type, descriptorProvider, 'result', None,\
- memberIsCreator(member))[1]
+ memberIsCreator(member), "return false;",)[1]
class CGMemberJITInfo(CGThing):
"""
@@ -3488,6 +3564,543 @@ class CGEnum(CGThing):
""" % (",\n ".join(map(getEnumValueName, self.enum.values())),
",\n ".join(['EnumEntry {value: &"' + val + '", length: ' + str(len(val)) + '}' for val in self.enum.values()]))
+class ClassItem:
+ """ Use with CGClass """
+ def __init__(self, name, visibility):
+ self.name = name
+ self.visibility = visibility
+ def declare(self, cgClass):
+ assert False
+ def define(self, cgClass):
+ assert False
+
+class ClassBase(ClassItem):
+ def __init__(self, name, visibility='public'):
+ ClassItem.__init__(self, name, visibility)
+ def declare(self, cgClass):
+ return '%s %s' % (self.visibility, self.name)
+ def define(self, cgClass):
+ # Only in the header
+ return ''
+
+class ClassMethod(ClassItem):
+ def __init__(self, name, returnType, args, inline=False, static=False,
+ virtual=False, const=False, bodyInHeader=False,
+ templateArgs=None, visibility='public', body=None,
+ breakAfterReturnDecl="\n",
+ breakAfterSelf="\n", override=False):
+ """
+ override indicates whether to flag the method as MOZ_OVERRIDE
+ """
+ assert not override or virtual
+ self.returnType = returnType
+ self.args = args
+ self.inline = inline or bodyInHeader
+ self.static = static
+ self.virtual = virtual
+ self.const = const
+ self.bodyInHeader = bodyInHeader
+ self.templateArgs = templateArgs
+ self.body = body
+ self.breakAfterReturnDecl = breakAfterReturnDecl
+ self.breakAfterSelf = breakAfterSelf
+ self.override = override
+ ClassItem.__init__(self, name, visibility)
+
+ def getDecorators(self, declaring):
+ decorators = []
+ if self.inline:
+ decorators.append('inline')
+ if declaring:
+ if self.static:
+ decorators.append('static')
+ if self.virtual:
+ decorators.append('virtual')
+ if decorators:
+ return ' '.join(decorators) + ' '
+ return ''
+
+ def getBody(self):
+ # Override me or pass a string to constructor
+ assert self.body is not None
+ return self.body
+
+ def declare(self, cgClass):
+ templateClause = 'template <%s>\n' % ', '.join(self.templateArgs) \
+ if self.bodyInHeader and self.templateArgs else ''
+ args = ', '.join([a.declare() for a in self.args])
+ if self.bodyInHeader:
+ body = CGIndenter(CGGeneric(self.getBody())).define()
+ body = '\n{\n' + body + '\n}'
+ else:
+ body = ';'
+
+ return string.Template("${templateClause}${decorators}${returnType}%s"
+ "${name}(${args})${const}${override}${body}%s" %
+ (self.breakAfterReturnDecl, self.breakAfterSelf)
+ ).substitute({
+ 'templateClause': templateClause,
+ 'decorators': self.getDecorators(True),
+ 'returnType': self.returnType,
+ 'name': self.name,
+ 'const': ' const' if self.const else '',
+ 'override': ' MOZ_OVERRIDE' if self.override else '',
+ 'args': args,
+ 'body': body
+ })
+
+ def define(self, cgClass):
+ if self.bodyInHeader:
+ return ''
+
+ templateArgs = cgClass.templateArgs
+ if templateArgs:
+ if cgClass.templateSpecialization:
+ templateArgs = \
+ templateArgs[len(cgClass.templateSpecialization):]
+
+ if templateArgs:
+ templateClause = \
+ 'template <%s>\n' % ', '.join([str(a) for a in templateArgs])
+ else:
+ templateClause = ''
+
+ args = ', '.join([a.define() for a in self.args])
+
+ body = CGIndenter(CGGeneric(self.getBody())).define()
+
+ return string.Template("""${templateClause}${decorators}${returnType}
+${className}::${name}(${args})${const}
+{
+${body}
+}
+""").substitute({ 'templateClause': templateClause,
+ 'decorators': self.getDecorators(False),
+ 'returnType': self.returnType,
+ 'className': cgClass.getNameString(),
+ 'name': self.name,
+ 'args': args,
+ 'const': ' const' if self.const else '',
+ 'body': body })
+
+class ClassUsingDeclaration(ClassItem):
+ """"
+ Used for importing a name from a base class into a CGClass
+
+ baseClass is the name of the base class to import the name from
+
+ name is the name to import
+
+ visibility determines the visibility of the name (public,
+ protected, private), defaults to public.
+ """
+ def __init__(self, baseClass, name, visibility='public'):
+ self.baseClass = baseClass
+ ClassItem.__init__(self, name, visibility)
+
+ def declare(self, cgClass):
+ return string.Template("""using ${baseClass}::${name};
+""").substitute({ 'baseClass': self.baseClass,
+ 'name': self.name })
+
+ def define(self, cgClass):
+ return ''
+
+class ClassConstructor(ClassItem):
+ """
+ Used for adding a constructor to a CGClass.
+
+ args is a list of Argument objects that are the arguments taken by the
+ constructor.
+
+ inline should be True if the constructor should be marked inline.
+
+ bodyInHeader should be True if the body should be placed in the class
+ declaration in the header.
+
+ visibility determines the visibility of the constructor (public,
+ protected, private), defaults to private.
+
+ explicit should be True if the constructor should be marked explicit.
+
+ baseConstructors is a list of strings containing calls to base constructors,
+ defaults to None.
+
+ body contains a string with the code for the constructor, defaults to empty.
+ """
+ def __init__(self, args, inline=False, bodyInHeader=False,
+ visibility="private", explicit=False, baseConstructors=None,
+ body=""):
+ self.args = args
+ self.inline = inline or bodyInHeader
+ self.bodyInHeader = bodyInHeader
+ self.explicit = explicit
+ self.baseConstructors = baseConstructors or []
+ self.body = body
+ ClassItem.__init__(self, None, visibility)
+
+ def getDecorators(self, declaring):
+ decorators = []
+ if self.explicit:
+ decorators.append('explicit')
+ if self.inline and declaring:
+ decorators.append('inline')
+ if decorators:
+ return ' '.join(decorators) + ' '
+ return ''
+
+ def getInitializationList(self, cgClass):
+ items = [str(c) for c in self.baseConstructors]
+ for m in cgClass.members:
+ if not m.static:
+ initialize = m.body
+ if initialize:
+ items.append(m.name + "(" + initialize + ")")
+
+ if len(items) > 0:
+ return '\n : ' + ',\n '.join(items)
+ return ''
+
+ def getBody(self):
+ return self.body
+
+ def declare(self, cgClass):
+ args = ', '.join([a.declare() for a in self.args])
+ if self.bodyInHeader:
+ body = ' ' + self.getBody();
+ body = stripTrailingWhitespace(body.replace('\n', '\n '))
+ if len(body) > 0:
+ body += '\n'
+ body = self.getInitializationList(cgClass) + '\n{\n' + body + '}'
+ else:
+ body = ';'
+
+ return string.Template("""${decorators}${className}(${args})${body}
+""").substitute({ 'decorators': self.getDecorators(True),
+ 'className': cgClass.getNameString(),
+ 'args': args,
+ 'body': body })
+
+ def define(self, cgClass):
+ if self.bodyInHeader:
+ return ''
+
+ args = ', '.join([a.define() for a in self.args])
+
+ body = ' ' + self.getBody()
+ body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n '))
+ if len(body) > 0:
+ body += '\n'
+
+ return string.Template("""${decorators}
+${className}::${className}(${args})${initializationList}
+{${body}}
+""").substitute({ 'decorators': self.getDecorators(False),
+ 'className': cgClass.getNameString(),
+ 'args': args,
+ 'initializationList': self.getInitializationList(cgClass),
+ 'body': body })
+
+class ClassDestructor(ClassItem):
+ """
+ Used for adding a destructor to a CGClass.
+
+ inline should be True if the destructor should be marked inline.
+
+ bodyInHeader should be True if the body should be placed in the class
+ declaration in the header.
+
+ visibility determines the visibility of the destructor (public,
+ protected, private), defaults to private.
+
+ body contains a string with the code for the destructor, defaults to empty.
+
+ virtual determines whether the destructor is virtual, defaults to False.
+ """
+ def __init__(self, inline=False, bodyInHeader=False,
+ visibility="private", body='', virtual=False):
+ self.inline = inline or bodyInHeader
+ self.bodyInHeader = bodyInHeader
+ self.body = body
+ self.virtual = virtual
+ ClassItem.__init__(self, None, visibility)
+
+ def getDecorators(self, declaring):
+ decorators = []
+ if self.virtual and declaring:
+ decorators.append('virtual')
+ if self.inline and declaring:
+ decorators.append('inline')
+ if decorators:
+ return ' '.join(decorators) + ' '
+ return ''
+
+ def getBody(self):
+ return self.body
+
+ def declare(self, cgClass):
+ if self.bodyInHeader:
+ body = ' ' + self.getBody();
+ body = stripTrailingWhitespace(body.replace('\n', '\n '))
+ if len(body) > 0:
+ body += '\n'
+ body = '\n{\n' + body + '}'
+ else:
+ body = ';'
+
+ return string.Template("""${decorators}~${className}()${body}
+""").substitute({ 'decorators': self.getDecorators(True),
+ 'className': cgClass.getNameString(),
+ 'body': body })
+
+ def define(self, cgClass):
+ if self.bodyInHeader:
+ return ''
+
+ body = ' ' + self.getBody()
+ body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n '))
+ if len(body) > 0:
+ body += '\n'
+
+ return string.Template("""${decorators}
+${className}::~${className}()
+{${body}}
+""").substitute({ 'decorators': self.getDecorators(False),
+ 'className': cgClass.getNameString(),
+ 'body': body })
+
+class ClassMember(ClassItem):
+ def __init__(self, name, type, visibility="private", static=False,
+ body=None):
+ self.type = type;
+ self.static = static
+ self.body = body
+ ClassItem.__init__(self, name, visibility)
+
+ def declare(self, cgClass):
+ return '%s%s %s;\n' % ('static ' if self.static else '', self.type,
+ self.name)
+
+ def define(self, cgClass):
+ if not self.static:
+ return ''
+ if self.body:
+ body = " = " + self.body
+ else:
+ body = ""
+ return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
+ self.name, body)
+
+class ClassTypedef(ClassItem):
+ def __init__(self, name, type, visibility="public"):
+ self.type = type
+ ClassItem.__init__(self, name, visibility)
+
+ def declare(self, cgClass):
+ return 'typedef %s %s;\n' % (self.type, self.name)
+
+ def define(self, cgClass):
+ # Only goes in the header
+ return ''
+
+class ClassEnum(ClassItem):
+ def __init__(self, name, entries, values=None, visibility="public"):
+ self.entries = entries
+ self.values = values
+ ClassItem.__init__(self, name, visibility)
+
+ def declare(self, cgClass):
+ entries = []
+ for i in range(0, len(self.entries)):
+ if not self.values or i >= len(self.values):
+ entry = '%s' % self.entries[i]
+ else:
+ entry = '%s = %s' % (self.entries[i], self.values[i])
+ entries.append(entry)
+ name = '' if not self.name else ' ' + self.name
+ return 'enum%s\n{\n %s\n};\n' % (name, ',\n '.join(entries))
+
+ def define(self, cgClass):
+ # Only goes in the header
+ return ''
+
+class ClassUnion(ClassItem):
+ def __init__(self, name, entries, visibility="public"):
+ self.entries = [entry + ";" for entry in entries]
+ ClassItem.__init__(self, name, visibility)
+
+ def declare(self, cgClass):
+ return 'union %s\n{\n %s\n};\n' % (self.name, '\n '.join(self.entries))
+
+ def define(self, cgClass):
+ # Only goes in the header
+ return ''
+
+class CGClass(CGThing):
+ def __init__(self, name, bases=[], members=[], constructors=[],
+ destructor=None, methods=[],
+ typedefs = [], enums=[], unions=[], templateArgs=[],
+ templateSpecialization=[], isStruct=False,
+ disallowCopyConstruction=False, indent='',
+ decorators='',
+ extradeclarations='',
+ extradefinitions=''):
+ CGThing.__init__(self)
+ self.name = name
+ self.bases = bases
+ self.members = members
+ self.constructors = constructors
+ # We store our single destructor in a list, since all of our
+ # code wants lists of members.
+ self.destructors = [destructor] if destructor else []
+ self.methods = methods
+ self.typedefs = typedefs
+ self.enums = enums
+ self.unions = unions
+ self.templateArgs = templateArgs
+ self.templateSpecialization = templateSpecialization
+ self.isStruct = isStruct
+ self.disallowCopyConstruction = disallowCopyConstruction
+ self.indent = indent
+ self.defaultVisibility ='public' if isStruct else 'private'
+ self.decorators = decorators
+ self.extradeclarations = extradeclarations
+ self.extradefinitions = extradefinitions
+
+ def getNameString(self):
+ className = self.name
+ if self.templateSpecialization:
+ className = className + \
+ '<%s>' % ', '.join([str(a) for a
+ in self.templateSpecialization])
+ return className
+
+ def declare(self):
+ result = ''
+ if self.templateArgs:
+ templateArgs = [a.declare() for a in self.templateArgs]
+ templateArgs = templateArgs[len(self.templateSpecialization):]
+ result = result + self.indent + 'template <%s>\n' \
+ % ','.join([str(a) for a in templateArgs])
+
+ type = 'struct' if self.isStruct else 'class'
+
+ if self.templateSpecialization:
+ specialization = \
+ '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
+ else:
+ specialization = ''
+
+ myself = '%s%s %s%s' % (self.indent, type, self.name, specialization)
+ if self.decorators != '':
+ myself += " " + self.decorators
+ result += myself
+
+ if self.bases:
+ inherit = ' : '
+ result += inherit
+ # Grab our first base
+ baseItems = [CGGeneric(b.declare(self)) for b in self.bases]
+ bases = baseItems[:1]
+ # Indent the rest
+ bases.extend(CGIndenter(b, len(myself) + len(inherit)) for
+ b in baseItems[1:])
+ result += ",\n".join(b.define() for b in bases)
+
+ result = result + '\n%s{\n' % self.indent
+
+ result += CGIndenter(CGGeneric(self.extradeclarations),
+ len(self.indent)).define()
+
+ def declareMembers(cgClass, memberList, defaultVisibility, itemCount,
+ separator=''):
+ members = { 'private': [], 'protected': [], 'public': [] }
+
+ for member in memberList:
+ members[member.visibility].append(member)
+
+
+ if defaultVisibility == 'public':
+ order = [ 'public', 'protected', 'private' ]
+ else:
+ order = [ 'private', 'protected', 'public' ]
+
+ result = ''
+
+ lastVisibility = defaultVisibility
+ for visibility in order:
+ list = members[visibility]
+ if list:
+ if visibility != lastVisibility:
+ if itemCount:
+ result = result + '\n'
+ result = result + visibility + ':\n'
+ itemCount = 0
+ for member in list:
+ if itemCount != 0:
+ result = result + separator
+ declaration = member.declare(cgClass)
+ declaration = CGIndenter(CGGeneric(declaration)).define()
+ result = result + declaration
+ itemCount = itemCount + 1
+ lastVisibility = visibility
+ return (result, lastVisibility, itemCount)
+
+ if self.disallowCopyConstruction:
+ class DisallowedCopyConstructor(object):
+ def __init__(self):
+ self.visibility = "private"
+ def declare(self, cgClass):
+ name = cgClass.getNameString()
+ return ("%s(const %s&) MOZ_DELETE;\n"
+ "void operator=(const %s) MOZ_DELETE;\n" % (name, name, name))
+ disallowedCopyConstructors = [DisallowedCopyConstructor()]
+ else:
+ disallowedCopyConstructors = []
+
+ order = [(self.enums, ''), (self.unions, ''),
+ (self.typedefs, ''), (self.members, ''),
+ (self.constructors + disallowedCopyConstructors, '\n'),
+ (self.destructors, '\n'), (self.methods, '\n')]
+
+ lastVisibility = self.defaultVisibility
+ itemCount = 0
+ for (memberList, separator) in order:
+ (memberString, lastVisibility, itemCount) = \
+ declareMembers(self, memberList, lastVisibility, itemCount,
+ separator)
+ if self.indent:
+ memberString = CGIndenter(CGGeneric(memberString),
+ len(self.indent)).define()
+ result = result + memberString
+
+ result = result + self.indent + '};\n'
+ return result
+
+ def define(self):
+ def defineMembers(cgClass, memberList, itemCount, separator=''):
+ result = ''
+ for member in memberList:
+ if itemCount != 0:
+ result = result + separator
+ definition = member.define(cgClass)
+ if definition:
+ # Member variables would only produce empty lines here.
+ result += definition
+ itemCount += 1
+ return (result, itemCount)
+
+ order = [(self.members, ''), (self.constructors, '\n'),
+ (self.destructors, '\n'), (self.methods, '\n')]
+
+ result = self.extradefinitions
+ itemCount = 0
+ for (memberList, separator) in order:
+ (memberString, itemCount) = defineMembers(self, memberList,
+ itemCount, separator)
+ result = result + memberString
+ return result
+
class CGXrayHelper(CGAbstractExternMethod):
def __init__(self, descriptor, name, args, properties):
CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args)
@@ -4610,10 +5223,15 @@ class CGBindingRoot(CGThing):
def __init__(self, config, prefix, webIDLFile):
descriptors = config.getDescriptors(webIDLFile=webIDLFile,
hasInterfaceOrInterfacePrototypeObject=True)
- dictionaries = config.getDictionaries(webIDLFile)
+ dictionaries = config.getDictionaries(webIDLFile=webIDLFile)
cgthings = []
+ mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
+ workers=False)
+ callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
+ isCallback=True)
+
# Do codegen for all the enums
def makeEnum(e):
return CGNamespace.build([e.identifier.name + "Values"],
@@ -4654,9 +5272,17 @@ class CGBindingRoot(CGThing):
cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
for d in dictionaries])
+ # Do codegen for all the callbacks.
+ cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(False))
+ for c in mainCallbacks)
+
# Do codegen for all the descriptors
cgthings.extend([CGDescriptor(x) for x in descriptors])
+ # Do codegen for all the callback interfaces. Skip worker callbacks.
+ cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors if
+ not x.workers])
+
# And make sure we have the right number of newlines at the end
curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
@@ -4705,6 +5331,896 @@ class CGBindingRoot(CGThing):
def define(self):
return stripTrailingWhitespace(self.root.define())
+class CGNativeMember(ClassMethod):
+ def __init__(self, descriptorProvider, member, name, signature, extendedAttrs,
+ breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
+ jsObjectsArePtr=False, variadicIsSequence=False):
+ """
+ If jsObjectsArePtr is true, typed arrays and "object" will be
+ passed as JSObject*.
+
+ If passJSBitsAsNeeded is false, we don't automatically pass in a
+ JSContext* or a JSObject* based on the return and argument types. We
+ can still pass it based on 'implicitJSContext' annotations.
+ """
+ self.descriptorProvider = descriptorProvider
+ self.member = member
+ self.extendedAttrs = extendedAttrs
+ self.resultAlreadyAddRefed = isResultAlreadyAddRefed(self.extendedAttrs)
+ self.passJSBitsAsNeeded = passJSBitsAsNeeded
+ self.jsObjectsArePtr = jsObjectsArePtr
+ self.variadicIsSequence = variadicIsSequence
+ breakAfterSelf = "\n" if breakAfter else ""
+ ClassMethod.__init__(self, name,
+ self.getReturnType(signature[0], False),
+ self.getArgs(signature[0], signature[1]),
+ static=member.isStatic(),
+ # Mark our getters, which are attrs that
+ # have a non-void return type, as const.
+ const=(not member.isStatic() and member.isAttr() and
+ not signature[0].isVoid()),
+ breakAfterReturnDecl=" ",
+ breakAfterSelf=breakAfterSelf,
+ visibility=visibility)
+
+ def getReturnType(self, type, isMember):
+ return self.getRetvalInfo(type, isMember)[0]
+
+ def getRetvalInfo(self, type, isMember):
+ """
+ Returns a tuple:
+
+ The first element is the type declaration for the retval
+
+ The second element is a default value that can be used on error returns.
+ For cases whose behavior depends on isMember, the second element will be
+ None if isMember is true.
+
+ The third element is a template for actually returning a value stored in
+ "${declName}" and "${holderName}". This means actually returning it if
+ we're not outparam, else assigning to the "retval" outparam. If
+ isMember is true, this can be None, since in that case the caller will
+ never examine this value.
+ """
+ if type.isVoid():
+ return "void", "", ""
+ if type.isPrimitive() and type.tag() in builtinNames:
+ result = CGGeneric(builtinNames[type.tag()])
+ defaultReturnArg = "0"
+ if type.nullable():
+ result = CGTemplatedType("Nullable", result)
+ defaultReturnArg = ""
+ return (result.define(),
+ "%s(%s)" % (result.define(), defaultReturnArg),
+ "return ${declName};")
+ if type.isDOMString():
+ if isMember:
+ # No need for a third element in the isMember case
+ return "nsString", None, None
+ # Outparam
+ return "void", "", "retval = ${declName};"
+ if type.isByteString():
+ if isMember:
+ # No need for a third element in the isMember case
+ return "nsCString", None, None
+ # Outparam
+ return "void", "", "retval = ${declName};"
+ if type.isEnum():
+ enumName = type.unroll().inner.identifier.name
+ if type.nullable():
+ enumName = CGTemplatedType("Nullable",
+ CGGeneric(enumName)).define()
+ defaultValue = "%s()" % enumName
+ else:
+ defaultValue = "%s(0)" % enumName
+ return enumName, defaultValue, "return ${declName};"
+ if type.isGeckoInterface():
+ iface = type.unroll().inner;
+ nativeType = self.descriptorProvider.getDescriptor(
+ iface.identifier.name).nativeType
+ # Now trim off unnecessary namespaces
+ nativeType = nativeType.split("::")
+ if nativeType[0] == "mozilla":
+ nativeType.pop(0)
+ if nativeType[0] == "dom":
+ nativeType.pop(0)
+ result = CGGeneric("::".join(nativeType))
+ if self.resultAlreadyAddRefed:
+ if isMember:
+ holder = "nsRefPtr"
+ else:
+ holder = "already_AddRefed"
+ if memberReturnsNewObject(self.member):
+ warning = ""
+ else:
+ warning = "// Mark this as resultNotAddRefed to return raw pointers\n"
+ result = CGWrapper(result,
+ pre=("%s%s<" % (warning, holder)),
+ post=">")
+ else:
+ result = CGWrapper(result, post="*")
+ # Since we always force an owning type for callback return values,
+ # our ${declName} is an OwningNonNull or nsRefPtr. So we can just
+ # .forget() to get our already_AddRefed.
+ return result.define(), "nullptr", "return ${declName}.forget();"
+ if type.isCallback():
+ return ("already_AddRefed<%s>" % type.unroll().identifier.name,
+ "nullptr", "return ${declName}.forget();")
+ if type.isAny():
+ return "JS::Value", "JS::UndefinedValue()", "return ${declName};"
+ if type.isObject():
+ return "JSObject*", "nullptr", "return ${declName};"
+ if type.isSpiderMonkeyInterface():
+ if type.nullable():
+ returnCode = "return ${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();"
+ else:
+ returnCode = "return ${declName}.Obj();"
+ return "JSObject*", "nullptr", returnCode
+ if type.isSequence():
+ # If we want to handle sequence-of-sequences return values, we're
+ # going to need to fix example codegen to not produce nsTArray<void>
+ # for the relevant argument...
+ assert not isMember
+ # Outparam.
+ if type.nullable():
+ returnCode = ("if (${declName}.IsNull()) {\n"
+ " retval.SetNull();\n"
+ "} else {\n"
+ " retval.SetValue().SwapElements(${declName}.Value());\n"
+ "}")
+ else:
+ returnCode = "retval.SwapElements(${declName});"
+ return "void", "", returnCode
+ if type.isDate():
+ result = CGGeneric("Date")
+ if type.nullable():
+ result = CGTemplatedType("Nullable", result)
+ return (result.define(), "%s()" % result.define(),
+ "return ${declName};")
+ raise TypeError("Don't know how to declare return value for %s" %
+ type)
+
+ def getArgs(self, returnType, argList):
+ args = [self.getArg(arg) for arg in argList]
+ # Now the outparams
+ if returnType.isDOMString():
+ args.append(Argument("nsString&", "retval"))
+ if returnType.isByteString():
+ args.append(Argument("nsCString&", "retval"))
+ elif returnType.isSequence():
+ nullable = returnType.nullable()
+ if nullable:
+ returnType = returnType.inner
+ # And now the actual underlying type
+ elementDecl = self.getReturnType(returnType.inner, True)
+ type = CGTemplatedType("nsTArray", CGGeneric(elementDecl))
+ if nullable:
+ type = CGTemplatedType("Nullable", type)
+ args.append(Argument("%s&" % type.define(), "retval"))
+ # And the ErrorResult
+ if not 'infallible' in self.extendedAttrs:
+ # Use aRv so it won't conflict with local vars named "rv"
+ args.append(Argument("ErrorResult&", "aRv"))
+ # The legacycaller thisval
+ if self.member.isMethod() and self.member.isLegacycaller():
+ # If it has an identifier, we can't deal with it yet
+ assert self.member.isIdentifierLess()
+ args.insert(0, Argument("JS::Value", "aThisVal"))
+ # And jscontext bits.
+ if needCx(returnType, argList, self.extendedAttrs,
+ self.passJSBitsAsNeeded):
+ args.insert(0, Argument("JSContext*", "cx"))
+ if needScopeObject(returnType, argList, self.extendedAttrs,
+ self.descriptorProvider,
+ self.passJSBitsAsNeeded):
+ args.insert(1, Argument("JS::Handle<JSObject*>", "obj"))
+ # And if we're static, a global
+ if self.member.isStatic():
+ args.insert(0, Argument("const GlobalObject&", "global"))
+ return args
+
+ def doGetArgType(self, type, optional, isMember):
+ """
+ The main work of getArgType. Returns a string type decl, whether this
+ is a const ref, as well as whether the type should be wrapped in
+ Nullable as needed.
+
+ isMember can be false or one of the strings "Sequence" or "Variadic"
+ """
+ if type.isArray():
+ raise TypeError("Can't handle array arguments yet")
+
+ if type.isSequence():
+ nullable = type.nullable()
+ if nullable:
+ type = type.inner
+ elementType = type.inner
+ argType = self.getArgType(elementType, False, "Sequence")[0]
+ decl = CGTemplatedType("Sequence", argType)
+ return decl.define(), True, True
+
+ if type.isUnion():
+ if type.nullable():
+ type = type.inner
+ return str(type), True, True
+
+ if type.isGeckoInterface() and not type.isCallbackInterface():
+ iface = type.unroll().inner
+ argIsPointer = type.nullable() or iface.isExternal()
+ forceOwningType = iface.isCallback() or isMember
+ if argIsPointer:
+ if (optional or isMember) and forceOwningType:
+ typeDecl = "nsRefPtr<%s>"
+ else:
+ typeDecl = "%s*"
+ else:
+ if optional or isMember:
+ if forceOwningType:
+ typeDecl = "OwningNonNull<%s>"
+ else:
+ typeDecl = "NonNull<%s>"
+ else:
+ typeDecl = "%s&"
+ return ((typeDecl %
+ self.descriptorProvider.getDescriptor(iface.identifier.name).nativeType),
+ False, False)
+
+ if type.isSpiderMonkeyInterface():
+ if self.jsObjectsArePtr:
+ return "JSObject*", False, False
+
+ return type.name, True, True
+
+ if type.isDOMString():
+ if isMember:
+ declType = "nsString"
+ else:
+ declType = "nsAString"
+ return declType, True, False
+
+ if type.isByteString():
+ declType = "nsCString"
+ return declType, True, False
+
+ if type.isEnum():
+ return type.unroll().inner.identifier.name, False, True
+
+ if type.isCallback() or type.isCallbackInterface():
+ forceOwningType = optional or isMember
+ if type.nullable():
+ if forceOwningType:
+ declType = "nsRefPtr<%s>"
+ else:
+ declType = "%s*"
+ else:
+ if forceOwningType:
+ declType = "OwningNonNull<%s>"
+ else:
+ declType = "%s&"
+ if type.isCallback():
+ name = type.unroll().identifier.name
+ else:
+ name = type.unroll().inner.identifier.name
+ return declType % name, False, False
+
+ if type.isAny():
+ # Don't do the rooting stuff for variadics for now
+ if isMember:
+ declType = "JS::Value"
+ else:
+ declType = "JS::Handle<JS::Value>"
+ return declType, False, False
+
+ if type.isObject():
+ if isMember:
+ declType = "JSObject*"
+ else:
+ declType = "JS::Handle<JSObject*>"
+ return declType, False, False
+
+ if type.isDictionary():
+ typeName = CGDictionary.makeDictionaryName(type.inner)
+ return typeName, True, True
+
+ if type.isDate():
+ return "Date", False, True
+
+ assert type.isPrimitive()
+
+ return builtinNames[type.tag()], False, True
+
+ def getArgType(self, type, optional, isMember):
+ """
+ Get the type of an argument declaration. Returns the type CGThing, and
+ whether this should be a const ref.
+
+ isMember can be False, "Sequence", or "Variadic"
+ """
+ (decl, ref, handleNullable) = self.doGetArgType(type, optional,
+ isMember)
+ decl = CGGeneric(decl)
+ if handleNullable and type.nullable():
+ decl = CGTemplatedType("Nullable", decl)
+ ref = True
+ if isMember == "Variadic":
+ arrayType = "Sequence" if self.variadicIsSequence else "nsTArray"
+ decl = CGTemplatedType(arrayType, decl)
+ ref = True
+ elif optional:
+ # Note: All variadic args claim to be optional, but we can just use
+ # empty arrays to represent them not being present.
+ decl = CGTemplatedType("Optional", decl)
+ ref = True
+ return (decl, ref)
+
+ def getArg(self, arg):
+ """
+ Get the full argument declaration for an argument
+ """
+ (decl, ref) = self.getArgType(arg.type,
+ arg.optional and not arg.defaultValue,
+ "Variadic" if arg.variadic else False)
+ if ref:
+ decl = CGWrapper(decl, pre="const ", post="&")
+
+ return Argument(decl.define(), arg.identifier.name)
+
+def isJSImplementedDescriptor(descriptorProvider):
+ return (isinstance(descriptorProvider, Descriptor) and
+ descriptorProvider.interface.isJSImplemented())
+
+class CGCallback(CGClass):
+ def __init__(self, idlObject, descriptorProvider, baseName, methods,
+ getters=[], setters=[]):
+ self.baseName = baseName
+ self._deps = idlObject.getDeps()
+ name = idlObject.identifier.name
+ if isJSImplementedDescriptor(descriptorProvider):
+ name = jsImplName(name)
+ # For our public methods that needThisHandling we want most of the
+ # same args and the same return type as what CallbackMember
+ # generates. So we want to take advantage of all its
+ # CGNativeMember infrastructure, but that infrastructure can't deal
+ # with templates and most especially template arguments. So just
+ # cheat and have CallbackMember compute all those things for us.
+ realMethods = []
+ for method in methods:
+ if not method.needThisHandling:
+ realMethods.append(method)
+ else:
+ realMethods.extend(self.getMethodImpls(method))
+ CGClass.__init__(self, name,
+ bases=[ClassBase(baseName)],
+ constructors=self.getConstructors(),
+ methods=realMethods+getters+setters)
+
+ def getConstructors(self):
+ return [ClassConstructor(
+ [Argument("JSObject*", "aCallback")],
+ bodyInHeader=True,
+ visibility="public",
+ explicit=True,
+ baseConstructors=[
+ "%s(aCallback)" % self.baseName
+ ])]
+
+ def getMethodImpls(self, method):
+ assert method.needThisHandling
+ args = list(method.args)
+ # Strip out the JSContext*/JSObject* args
+ # that got added.
+ assert args[0].name == "cx" and args[0].argType == "JSContext*"
+ assert args[1].name == "aThisObj" and args[1].argType == "JS::Handle<JSObject*>"
+ args = args[2:]
+ # Record the names of all the arguments, so we can use them when we call
+ # the private method.
+ argnames = [arg.name for arg in args]
+ argnamesWithThis = ["s.GetContext()", "thisObjJS"] + argnames
+ argnamesWithoutThis = ["s.GetContext()", "JS::NullPtr()"] + argnames
+ # Now that we've recorded the argnames for our call to our private
+ # method, insert our optional argument for deciding whether the
+ # CallSetup should re-throw exceptions on aRv.
+ args.append(Argument("ExceptionHandling", "aExceptionHandling",
+ "eReportExceptions"))
+ # And now insert our template argument.
+ argsWithoutThis = list(args)
+ args.insert(0, Argument("const T&", "thisObj"))
+
+ setupCall = ("CallSetup s(CallbackPreserveColor(), aRv, aExceptionHandling);\n"
+ "if (!s.GetContext()) {\n"
+ " aRv.Throw(NS_ERROR_UNEXPECTED);\n"
+ " return${errorReturn};\n"
+ "}\n")
+
+ bodyWithThis = string.Template(
+ setupCall+
+ "JS::Rooted<JSObject*> thisObjJS(s.GetContext(),\n"
+ " WrapCallThisObject(s.GetContext(), CallbackPreserveColor(), thisObj));\n"
+ "if (!thisObjJS) {\n"
+ " aRv.Throw(NS_ERROR_FAILURE);\n"
+ " return${errorReturn};\n"
+ "}\n"
+ "return ${methodName}(${callArgs});").substitute({
+ "errorReturn" : method.getDefaultRetval(),
+ "callArgs" : ", ".join(argnamesWithThis),
+ "methodName": method.name,
+ })
+ bodyWithoutThis = string.Template(
+ setupCall +
+ "return ${methodName}(${callArgs});").substitute({
+ "errorReturn" : method.getDefaultRetval(),
+ "callArgs" : ", ".join(argnamesWithoutThis),
+ "methodName": method.name,
+ })
+ return [ClassMethod(method.name, method.returnType, args,
+ bodyInHeader=True,
+ templateArgs=["typename T"],
+ body=bodyWithThis),
+ ClassMethod(method.name, method.returnType, argsWithoutThis,
+ bodyInHeader=True,
+ body=bodyWithoutThis),
+ method]
+
+ def deps(self):
+ return self._deps
+
+class CGCallbackFunction(CGCallback):
+ def __init__(self, callback, descriptorProvider):
+ CGCallback.__init__(self, callback, descriptorProvider,
+ "CallbackFunction",
+ methods=[CallCallback(callback, descriptorProvider)])
+
+ def getConstructors(self):
+ return CGCallback.getConstructors(self) + [
+ ClassConstructor(
+ [Argument("CallbackFunction*", "aOther")],
+ bodyInHeader=True,
+ visibility="public",
+ explicit=True,
+ baseConstructors=[
+ "CallbackFunction(aOther)"
+ ])]
+
+# We're always fallible
+def callbackGetterName(attr):
+ return "Get" + MakeNativeName(attr.identifier.name)
+
+def callbackSetterName(attr):
+ return "Set" + MakeNativeName(attr.identifier.name)
+
+class CGCallbackFunction(CGCallback):
+ def __init__(self, callback, descriptorProvider):
+ CGCallback.__init__(self, callback, descriptorProvider,
+ "CallbackFunction",
+ methods=[CallCallback(callback, descriptorProvider)])
+
+ def getConstructors(self):
+ return CGCallback.getConstructors(self) + [
+ ClassConstructor(
+ [Argument("CallbackFunction*", "aOther")],
+ bodyInHeader=True,
+ visibility="public",
+ explicit=True,
+ baseConstructors=[
+ "CallbackFunction(aOther)"
+ ])]
+
+class CGCallbackInterface(CGCallback):
+ def __init__(self, descriptor):
+ iface = descriptor.interface
+ attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()]
+ getters = [CallbackGetter(a, descriptor) for a in attrs]
+ setters = [CallbackSetter(a, descriptor) for a in attrs
+ if not a.readonly]
+ methods = [m for m in iface.members
+ if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()]
+ methods = [CallbackOperation(m, sig, descriptor) for m in methods
+ for sig in m.signatures()]
+ if iface.isJSImplemented() and iface.ctor():
+ sigs = descriptor.interface.ctor().signatures()
+ if len(sigs) != 1:
+ raise TypeError("We only handle one constructor. See bug 869268.")
+ methods.append(CGJSImplInitOperation(sigs[0], descriptor))
+ CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
+ methods, getters=getters, setters=setters)
+
+class FakeMember():
+ def __init__(self):
+ self.treatUndefinedAs = self.treatNullAs = "Default"
+ def isStatic(self):
+ return False
+ def isAttr(self):
+ return False
+ def isMethod(self):
+ return False
+ def getExtendedAttribute(self, name):
+ # Claim to be a [NewObject] so we can avoid the "mark this
+ # resultNotAddRefed" comments CGNativeMember codegen would
+ # otherwise stick in.
+ if name == "NewObject":
+ return True
+ return None
+
+class CallbackMember(CGNativeMember):
+ def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
+ """
+ needThisHandling is True if we need to be able to accept a specified
+ thisObj, False otherwise.
+ """
+ assert not rethrowContentException or not needThisHandling
+
+ self.retvalType = sig[0]
+ self.originalSig = sig
+ args = sig[1]
+ self.argCount = len(args)
+ if self.argCount > 0:
+ # Check for variadic arguments
+ lastArg = args[self.argCount-1]
+ if lastArg.variadic:
+ self.argCountStr = (
+ "(%d - 1) + %s.Length()" % (self.argCount,
+ lastArg.identifier.name))
+ else:
+ self.argCountStr = "%d" % self.argCount
+ self.needThisHandling = needThisHandling
+ # If needThisHandling, we generate ourselves as private and the caller
+ # will handle generating public versions that handle the "this" stuff.
+ visibility = "private" if needThisHandling else "public"
+ self.rethrowContentException = rethrowContentException
+ # We don't care, for callback codegen, whether our original member was
+ # a method or attribute or whatnot. Just always pass FakeMember()
+ # here.
+ CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
+ name, (self.retvalType, args),
+ extendedAttrs={},
+ passJSBitsAsNeeded=False,
+ visibility=visibility,
+ jsObjectsArePtr=True)
+ # We have to do all the generation of our body now, because
+ # the caller relies on us throwing if we can't manage it.
+ self.exceptionCode=("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
+ "return%s;" % self.getDefaultRetval())
+ self.body = self.getImpl()
+
+ def getImpl(self):
+ replacements = {
+ "declRval": self.getRvalDecl(),
+ "errorReturn" : self.getDefaultRetval(),
+ "returnResult": self.getResultConversion(),
+ "convertArgs": self.getArgConversions(),
+ "doCall": self.getCall(),
+ "setupCall": self.getCallSetup(),
+ }
+ if self.argCount > 0:
+ replacements["argCount"] = self.argCountStr
+ replacements["argvDecl"] = string.Template(
+ "JS::AutoValueVector argv(cx);\n"
+ "if (!argv.resize(${argCount})) {\n"
+ " aRv.Throw(NS_ERROR_OUT_OF_MEMORY);\n"
+ " return${errorReturn};\n"
+ "}\n"
+ ).substitute(replacements)
+ else:
+ # Avoid weird 0-sized arrays
+ replacements["argvDecl"] = ""
+
+ return string.Template(
+ # Newlines and semicolons are in the values
+ "${setupCall}"
+ "${declRval}"
+ "${argvDecl}"
+ "${convertArgs}"
+ "${doCall}"
+ "${returnResult}").substitute(replacements)
+
+ def getResultConversion(self):
+ replacements = {
+ "val": "rval",
+ "mutableVal": "&rval",
+ "holderName" : "rvalHolder",
+ "declName" : "rvalDecl",
+ # We actually want to pass in a null scope object here, because
+ # wrapping things into our current compartment (that of mCallback)
+ # is what we want.
+ "obj": "nullptr"
+ }
+
+ if isJSImplementedDescriptor(self.descriptorProvider):
+ isCallbackReturnValue = "JSImpl"
+ else:
+ isCallbackReturnValue = "Callback"
+ convertType = instantiateJSToNativeConversion(
+ getJSToNativeConversionInfo(self.retvalType,
+ self.descriptorProvider,
+ exceptionCode=self.exceptionCode,
+ isCallbackReturnValue=isCallbackReturnValue,
+ # XXXbz we should try to do better here
+ sourceDescription="return value"),
+ replacements)
+ assignRetval = string.Template(
+ self.getRetvalInfo(self.retvalType,
+ False)[2]).substitute(replacements)
+ return convertType.define() + "\n" + assignRetval
+
+ def getArgConversions(self):
+ # Just reget the arglist from self.originalSig, because our superclasses
+ # just have way to many members they like to clobber, so I can't find a
+ # safe member name to store it in.
+ argConversions = [self.getArgConversion(i, arg) for (i, arg)
+ in enumerate(self.originalSig[1])]
+ # Do them back to front, so our argc modifications will work
+ # correctly, because we examine trailing arguments first.
+ argConversions.reverse();
+ # Wrap each one in a scope so that any locals it has don't leak out, and
+ # also so that we can just "break;" for our successCode.
+ argConversions = [CGWrapper(CGIndenter(CGGeneric(c)),
+ pre="do {\n",
+ post="\n} while (0);")
+ for c in argConversions]
+ if self.argCount > 0:
+ argConversions.insert(0, self.getArgcDecl())
+ # And slap them together.
+ return CGList(argConversions, "\n\n").define() + "\n\n"
+
+ def getArgConversion(self, i, arg):
+ argval = arg.identifier.name
+
+ if arg.variadic:
+ argval = argval + "[idx]"
+ jsvalIndex = "%d + idx" % i
+ else:
+ jsvalIndex = "%d" % i
+ if arg.optional and not arg.defaultValue:
+ argval += ".Value()"
+ if arg.type.isDOMString():
+ # XPConnect string-to-JS conversion wants to mutate the string. So
+ # let's give it a string it can mutate
+ # XXXbz if we try to do a sequence of strings, this will kinda fail.
+ result = "mutableStr"
+ prepend = "nsString mutableStr(%s);\n" % argval
+ else:
+ result = argval
+ prepend = ""
+
+ conversion = prepend + wrapForType(
+ arg.type, self.descriptorProvider,
+ {
+ 'result' : result,
+ 'successCode' : "continue;" if arg.variadic else "break;",
+ 'jsvalRef' : "argv.handleAt(%s)" % jsvalIndex,
+ 'jsvalHandle' : "argv.handleAt(%s)" % jsvalIndex,
+ # XXXbz we don't have anything better to use for 'obj',
+ # really... It's OK to use CallbackPreserveColor because
+ # CallSetup already handled the unmark-gray bits for us.
+ 'obj' : 'CallbackPreserveColor()',
+ 'returnsNewObject': False,
+ 'exceptionCode' : self.exceptionCode
+ })
+ if arg.variadic:
+ conversion = string.Template(
+ "for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) {\n" +
+ CGIndenter(CGGeneric(conversion)).define() + "\n"
+ "}\n"
+ "break;").substitute({ "arg": arg.identifier.name })
+ elif arg.optional and not arg.defaultValue:
+ conversion = (
+ CGIfWrapper(CGGeneric(conversion),
+ "%s.WasPassed()" % arg.identifier.name).define() +
+ " else if (argc == %d) {\n"
+ " // This is our current trailing argument; reduce argc\n"
+ " --argc;\n"
+ "} else {\n"
+ " argv[%d] = JS::UndefinedValue();\n"
+ "}" % (i+1, i))
+ return conversion
+
+ def getDefaultRetval(self):
+ default = self.getRetvalInfo(self.retvalType, False)[1]
+ if len(default) != 0:
+ default = " " + default
+ return default
+
+ def getArgs(self, returnType, argList):
+ args = CGNativeMember.getArgs(self, returnType, argList)
+ if not self.needThisHandling:
+ # Since we don't need this handling, we're the actual method that
+ # will be called, so we need an aRethrowExceptions argument.
+ if self.rethrowContentException:
+ args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
+ else:
+ args.append(Argument("ExceptionHandling", "aExceptionHandling",
+ "eReportExceptions"))
+ return args
+ # We want to allow the caller to pass in a "this" object, as
+ # well as a JSContext.
+ return [Argument("JSContext*", "cx"),
+ Argument("JS::Handle<JSObject*>", "aThisObj")] + args
+
+ def getCallSetup(self):
+ if self.needThisHandling:
+ # It's been done for us already
+ return ""
+ callSetup = "CallSetup s(CallbackPreserveColor(), aRv"
+ if self.rethrowContentException:
+ # getArgs doesn't add the aExceptionHandling argument but does add
+ # aCompartment for us.
+ callSetup += ", eRethrowContentExceptions, aCompartment"
+ else:
+ callSetup += ", aExceptionHandling"
+ callSetup += ");"
+ return string.Template(
+ "${callSetup}\n"
+ "JSContext* cx = s.GetContext();\n"
+ "if (!cx) {\n"
+ " aRv.Throw(NS_ERROR_UNEXPECTED);\n"
+ " return${errorReturn};\n"
+ "}\n").substitute({
+ "callSetup": callSetup,
+ "errorReturn" : self.getDefaultRetval(),
+ })
+
+ def getArgcDecl(self):
+ return CGGeneric("unsigned argc = %s;" % self.argCountStr);
+
+ @staticmethod
+ def ensureASCIIName(idlObject):
+ type = "attribute" if idlObject.isAttr() else "operation"
+ if re.match("[^\x20-\x7E]", idlObject.identifier.name):
+ raise SyntaxError('Callback %s name "%s" contains non-ASCII '
+ "characters. We can't handle that. %s" %
+ (type, idlObject.identifier.name,
+ idlObject.location))
+ if re.match('"', idlObject.identifier.name):
+ raise SyntaxError("Callback %s name '%s' contains "
+ "double-quote character. We can't handle "
+ "that. %s" %
+ (type, idlObject.identifier.name,
+ idlObject.location))
+
+class CallbackMethod(CallbackMember):
+ def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False):
+ CallbackMember.__init__(self, sig, name, descriptorProvider,
+ needThisHandling, rethrowContentException)
+ def getRvalDecl(self):
+ return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
+
+ def getCall(self):
+ replacements = {
+ "errorReturn" : self.getDefaultRetval(),
+ "thisObj": self.getThisObj(),
+ "getCallable": self.getCallableDecl()
+ }
+ if self.argCount > 0:
+ replacements["argv"] = "argv.begin()"
+ replacements["argc"] = "argc"
+ else:
+ replacements["argv"] = "nullptr"
+ replacements["argc"] = "0"
+ return string.Template("${getCallable}"
+ "if (!JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
+ " ${argc}, ${argv}, rval.address())) {\n"
+ " aRv.Throw(NS_ERROR_UNEXPECTED);\n"
+ " return${errorReturn};\n"
+ "}\n").substitute(replacements)
+
+class CallCallback(CallbackMethod):
+ def __init__(self, callback, descriptorProvider):
+ CallbackMethod.__init__(self, callback.signatures()[0], "Call",
+ descriptorProvider, needThisHandling=True)
+
+ def getThisObj(self):
+ return "aThisObj"
+
+ def getCallableDecl(self):
+ return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n"
+
+class CallbackOperationBase(CallbackMethod):
+ """
+ Common class for implementing various callback operations.
+ """
+ def __init__(self, signature, jsName, nativeName, descriptor, singleOperation, rethrowContentException=False):
+ self.singleOperation = singleOperation
+ self.methodName = jsName
+ CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation, rethrowContentException)
+
+ def getThisObj(self):
+ if not self.singleOperation:
+ return "mCallback"
+ # This relies on getCallableDecl declaring a boolean
+ # isCallable in the case when we're a single-operation
+ # interface.
+ return "isCallable ? aThisObj.get() : mCallback"
+
+ def getCallableDecl(self):
+ replacements = {
+ "errorReturn" : self.getDefaultRetval(),
+ "methodName": self.methodName
+ }
+ getCallableFromProp = string.Template(
+ 'if (!GetCallableProperty(cx, "${methodName}", &callable)) {\n'
+ ' aRv.Throw(NS_ERROR_UNEXPECTED);\n'
+ ' return${errorReturn};\n'
+ '}\n').substitute(replacements)
+ if not self.singleOperation:
+ return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
+ return (
+ 'bool isCallable = JS_ObjectIsCallable(cx, mCallback);\n'
+ 'JS::Rooted<JS::Value> callable(cx);\n'
+ 'if (isCallable) {\n'
+ ' callable = JS::ObjectValue(*mCallback);\n'
+ '} else {\n'
+ '%s'
+ '}\n' % CGIndenter(CGGeneric(getCallableFromProp)).define())
+
+class CallbackOperation(CallbackOperationBase):
+ """
+ Codegen actual WebIDL operations on callback interfaces.
+ """
+ def __init__(self, method, signature, descriptor):
+ self.ensureASCIIName(method)
+ jsName = method.identifier.name
+ CallbackOperationBase.__init__(self, signature,
+ jsName, MakeNativeName(jsName),
+ descriptor, descriptor.interface.isSingleOperationInterface(),
+ rethrowContentException=descriptor.interface.isJSImplemented())
+
+class CallbackGetter(CallbackMember):
+ def __init__(self, attr, descriptor):
+ self.ensureASCIIName(attr)
+ self.attrName = attr.identifier.name
+ CallbackMember.__init__(self,
+ (attr.type, []),
+ callbackGetterName(attr),
+ descriptor,
+ needThisHandling=False,
+ rethrowContentException=descriptor.interface.isJSImplemented())
+
+ def getRvalDecl(self):
+ return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
+
+ def getCall(self):
+ replacements = {
+ "errorReturn" : self.getDefaultRetval(),
+ "attrName": self.attrName
+ }
+ return string.Template(
+ 'if (!JS_GetProperty(cx, mCallback, "${attrName}", &rval)) {\n'
+ ' aRv.Throw(NS_ERROR_UNEXPECTED);\n'
+ ' return${errorReturn};\n'
+ '}\n').substitute(replacements);
+
+class CallbackSetter(CallbackMember):
+ def __init__(self, attr, descriptor):
+ self.ensureASCIIName(attr)
+ self.attrName = attr.identifier.name
+ CallbackMember.__init__(self,
+ (BuiltinTypes[IDLBuiltinType.Types.void],
+ [FakeArgument(attr.type, attr)]),
+ callbackSetterName(attr),
+ descriptor,
+ needThisHandling=False,
+ rethrowContentException=descriptor.interface.isJSImplemented())
+
+ def getRvalDecl(self):
+ # We don't need an rval
+ return ""
+
+ def getCall(self):
+ replacements = {
+ "errorReturn" : self.getDefaultRetval(),
+ "attrName": self.attrName,
+ "argv": "argv.handleAt(0)",
+ }
+ return string.Template(
+ 'MOZ_ASSERT(argv.length() == 1);\n'
+ 'if (!JS_SetProperty(cx, mCallback, "${attrName}", ${argv})) {\n'
+ ' aRv.Throw(NS_ERROR_UNEXPECTED);\n'
+ ' return${errorReturn};\n'
+ '}\n').substitute(replacements)
+
+ def getArgcDecl(self):
+ return None
+
class GlobalGenRoots():
"""
Roots for global codegen.
diff --git a/src/components/script/dom/bindings/codegen/Configuration.py b/src/components/script/dom/bindings/codegen/Configuration.py
index 32918d272b3..0c87ead0259 100644
--- a/src/components/script/dom/bindings/codegen/Configuration.py
+++ b/src/components/script/dom/bindings/codegen/Configuration.py
@@ -42,6 +42,8 @@ class Configuration:
self.enums = [e for e in parseData if e.isEnum()]
self.dictionaries = [d for d in parseData if d.isDictionary()]
+ self.callbacks = [c for c in parseData if
+ c.isCallback() and not c.isInterface()]
# Keep the descriptor list sorted for determinism.
self.descriptors.sort(lambda x,y: cmp(x.name, y.name))
@@ -66,14 +68,34 @@ class Configuration:
getter = lambda x: x.interface.isCallback()
elif key == 'isExternal':
getter = lambda x: x.interface.isExternal()
+ elif key == 'isJSImplemented':
+ getter = lambda x: x.interface.isJSImplemented()
else:
getter = lambda x: getattr(x, key)
curr = filter(lambda x: getter(x) == val, curr)
return curr
def getEnums(self, webIDLFile):
return filter(lambda e: e.filename() == webIDLFile, self.enums)
- def getDictionaries(self, webIDLFile):
- return filter(lambda d: d.filename() == webIDLFile, self.dictionaries)
+
+ @staticmethod
+ def _filterForFileAndWorkers(items, filters):
+ """Gets the items that match the given filters."""
+ for key, val in filters.iteritems():
+ if key == 'webIDLFile':
+ items = filter(lambda x: x.filename() == val, items)
+ elif key == 'workers':
+ if val:
+ items = filter(lambda x: x.getUserData("workers", False), items)
+ else:
+ items = filter(lambda x: x.getUserData("mainThread", False), items)
+ else:
+ assert(0) # Unknown key
+ return items
+ def getDictionaries(self, **filters):
+ return self._filterForFileAndWorkers(self.dictionaries, filters)
+ def getCallbacks(self, **filters):
+ return self._filterForFileAndWorkers(self.callbacks, filters)
+
def getDescriptor(self, interfaceName, workers):
"""
Gets the appropriate descriptor for the given interface name
diff --git a/src/components/script/dom/bindings/codegen/parser/WebIDL.py b/src/components/script/dom/bindings/codegen/parser/WebIDL.py
index 1aab3debc6a..046b8130dff 100644
--- a/src/components/script/dom/bindings/codegen/parser/WebIDL.py
+++ b/src/components/script/dom/bindings/codegen/parser/WebIDL.py
@@ -146,6 +146,23 @@ class IDLObject(object):
def isCallback(self):
return False
+ def isSingleOperationInterface(self):
+ assert self.isCallback() or self.isJSImplemented()
+ return (
+ # JS-implemented things should never need the
+ # this-handling weirdness of single-operation interfaces.
+ not self.isJSImplemented() and
+ # Not inheriting from another interface
+ not self.parent and
+ # No consequential interfaces
+ len(self.getConsequentialInterfaces()) == 0 and
+ # No attributes of any kinds
+ not any(m.isAttr() for m in self.members) and
+ # There is at least one regular operation, and all regular
+ # operations have the same identifier
+ len(set(m.identifier.name for m in self.members if
+ m.isMethod() and not m.isStatic())) == 1)
+
def isType(self):
return False
@@ -167,6 +184,38 @@ class IDLObject(object):
def handleExtendedAttribute(self, attr):
assert False # Override me!
+ def _getDependentObjects(self):
+ assert False # Override me!
+
+ def getDeps(self, visited=None):
+ """ Return a set of files that this object depends on. If any of
+ these files are changed the parser needs to be rerun to regenerate
+ a new IDLObject.
+
+ The visited argument is a set of all the objects already visited.
+ We must test to see if we are in it, and if so, do nothing. This
+ prevents infinite recursion."""
+
+ # NB: We can't use visited=set() above because the default value is
+ # evaluated when the def statement is evaluated, not when the function
+ # is executed, so there would be one set for all invocations.
+ if visited == None:
+ visited = set()
+
+ if self in visited:
+ return set()
+
+ visited.add(self)
+
+ deps = set()
+ if self.filename() != "<builtin>":
+ deps.add(self.filename())
+
+ for d in self._getDependentObjects():
+ deps = deps.union(d.getDeps(visited))
+
+ return deps
+
class IDLScope(IDLObject):
def __init__(self, location, parentScope, identifier):
IDLObject.__init__(self, location)
@@ -428,6 +477,15 @@ class IDLExternalInterface(IDLObjectWithIdentifier):
def resolve(self, parentScope):
pass
+ def getJSImplementation(self):
+ return None
+
+ def isJSImplemented(self):
+ return False
+
+ def _getDependentObjects(self):
+ return set()
+
class IDLInterface(IDLObjectWithScope):
def __init__(self, location, parentScope, name, parent, members,
isPartial):
@@ -777,6 +835,24 @@ class IDLInterface(IDLObjectWithScope):
# Put the new members at the beginning
self.members = members + self.members
+ def getJSImplementation(self):
+ classId = self.getExtendedAttribute("JSImplementation")
+ if not classId:
+ return classId
+ assert isinstance(classId, list)
+ assert len(classId) == 1
+ return classId[0]
+
+ def isJSImplemented(self):
+ return bool(self.getJSImplementation())
+
+ def _getDependentObjects(self):
+ deps = set(self.members)
+ deps.union(self.implementedInterfaces)
+ if self.parent:
+ deps.add(self.parent)
+ return deps
+
class IDLDictionary(IDLObjectWithScope):
def __init__(self, location, parentScope, name, parent, members):
assert isinstance(parentScope, IDLScope)
@@ -847,6 +923,11 @@ class IDLDictionary(IDLObjectWithScope):
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
+ def _getDependentObjects(self):
+ deps = set(self.members)
+ if (self.parent):
+ deps.add(self.parent)
+ return deps
class IDLEnum(IDLObjectWithIdentifier):
def __init__(self, location, parentScope, name, values):
@@ -875,6 +956,9 @@ class IDLEnum(IDLObjectWithIdentifier):
def addExtendedAttributes(self, attrs):
assert len(attrs) == 0
+ def _getDependentObjects(self):
+ return set()
+
class IDLType(IDLObject):
Tags = enum(
# The integer types
@@ -893,6 +977,7 @@ class IDLType(IDLObject):
# Other types
'any',
'domstring',
+ 'bytestring',
'object',
'date',
'void',
@@ -930,6 +1015,12 @@ class IDLType(IDLObject):
def isString(self):
return False
+ def isByteString(self):
+ return False
+
+ def isDOMString(self):
+ return False
+
def isVoid(self):
return self.name == "Void"
@@ -1075,6 +1166,12 @@ class IDLNullableType(IDLType):
def isString(self):
return self.inner.isString()
+ def isByteString(self):
+ return self.inner.isByteString()
+
+ def isDOMString(self):
+ return self.inner.isDOMString()
+
def isFloat(self):
return self.inner.isFloat()
@@ -1163,6 +1260,9 @@ class IDLNullableType(IDLType):
return False
return self.inner.isDistinguishableFrom(other)
+ def _getDependentObjects(self):
+ return self.inner._getDependentObjects()
+
class IDLSequenceType(IDLType):
def __init__(self, location, parameterType):
assert not parameterType.isVoid()
@@ -1231,6 +1331,9 @@ class IDLSequenceType(IDLType):
other.isDictionary() or other.isDate() or
other.isNonCallbackInterface())
+ def _getDependentObjects(self):
+ return self.inner._getDependentObjects()
+
class IDLUnionType(IDLType):
def __init__(self, location, memberTypes):
IDLType.__init__(self, location, "")
@@ -1317,6 +1420,9 @@ class IDLUnionType(IDLType):
return False
return True
+ def _getDependentObjects(self):
+ return set(self.memberTypes)
+
class IDLArrayType(IDLType):
def __init__(self, location, parameterType):
assert not parameterType.isVoid()
@@ -1393,6 +1499,9 @@ class IDLArrayType(IDLType):
other.isDictionary() or other.isDate() or
other.isNonCallbackInterface())
+ def _getDependentObjects(self):
+ return self.inner._getDependentObjects()
+
class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
def __init__(self, location, innerType, name):
IDLType.__init__(self, location, innerType.name)
@@ -1478,6 +1587,9 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
def isDistinguishableFrom(self, other):
return self.inner.isDistinguishableFrom(other)
+ def _getDependentObjects(self):
+ return self.inner._getDependentObjects()
+
class IDLWrapperType(IDLType):
def __init__(self, location, inner):
IDLType.__init__(self, location, inner.identifier.name)
@@ -1583,6 +1695,23 @@ class IDLWrapperType(IDLType):
assert other.isObject()
return False
+ def _getDependentObjects(self):
+ # NB: The codegen for an interface type depends on
+ # a) That the identifier is in fact an interface (as opposed to
+ # a dictionary or something else).
+ # b) The native type of the interface.
+ # If we depend on the interface object we will also depend on
+ # anything the interface depends on which is undesirable. We
+ # considered implementing a dependency just on the interface type
+ # file, but then every modification to an interface would cause this
+ # to be regenerated which is still undesirable. We decided not to
+ # depend on anything, reasoning that:
+ # 1) Changing the concrete type of the interface requires modifying
+ # Bindings.conf, which is still a global dependency.
+ # 2) Changing an interface to a dictionary (or vice versa) with the
+ # same identifier should be incredibly rare.
+ return set()
+
class IDLBuiltinType(IDLType):
Types = enum(
@@ -1602,6 +1731,7 @@ class IDLBuiltinType(IDLType):
# Other types
'any',
'domstring',
+ 'bytestring',
'object',
'date',
'void',
@@ -1633,6 +1763,7 @@ class IDLBuiltinType(IDLType):
Types.double: IDLType.Tags.double,
Types.any: IDLType.Tags.any,
Types.domstring: IDLType.Tags.domstring,
+ Types.bytestring: IDLType.Tags.bytestring,
Types.object: IDLType.Tags.object,
Types.date: IDLType.Tags.date,
Types.void: IDLType.Tags.void,
@@ -1658,6 +1789,13 @@ class IDLBuiltinType(IDLType):
return self._typeTag <= IDLBuiltinType.Types.double
def isString(self):
+ return self._typeTag == IDLBuiltinType.Types.domstring or \
+ self._typeTag == IDLBuiltinType.Types.bytestring
+
+ def isByteString(self):
+ return self._typeTag == IDLBuiltinType.Types.bytestring
+
+ def isDOMString(self):
return self._typeTag == IDLBuiltinType.Types.domstring
def isInteger(self):
@@ -1733,6 +1871,9 @@ class IDLBuiltinType(IDLType):
(self.isTypedArray() and not other.isArrayBufferView() and not
(other.isTypedArray() and other.name == self.name)))))
+ def _getDependentObjects(self):
+ return set()
+
BuiltinTypes = {
IDLBuiltinType.Types.byte:
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Byte",
@@ -1877,6 +2018,9 @@ class IDLValue(IDLObject):
raise WebIDLError("Cannot coerce type %s to type %s." %
(self.type, type), [location])
+ def _getDependentObjects(self):
+ return set()
+
class IDLNullValue(IDLObject):
def __init__(self, location):
IDLObject.__init__(self, location)
@@ -1895,6 +2039,9 @@ class IDLNullValue(IDLObject):
nullValue.type = type
return nullValue
+ def _getDependentObjects(self):
+ return set()
+
class IDLInterfaceMember(IDLObjectWithIdentifier):
@@ -1966,6 +2113,9 @@ class IDLConst(IDLInterfaceMember):
def validate(self):
pass
+ def _getDependentObjects(self):
+ return set([self.type, self.value])
+
class IDLAttribute(IDLInterfaceMember):
def __init__(self, location, identifier, type, readonly, inherit,
static=False):
@@ -2052,6 +2202,9 @@ class IDLAttribute(IDLInterfaceMember):
def hasLenientThis(self):
return self.lenientThis
+ def _getDependentObjects(self):
+ return set([self.type])
+
class IDLArgument(IDLObjectWithIdentifier):
def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False):
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
@@ -2124,6 +2277,12 @@ class IDLArgument(IDLObjectWithIdentifier):
self.location)
assert self.defaultValue
+ def _getDependentObjects(self):
+ deps = set([self.type])
+ if self.defaultValue:
+ deps.add(self.defaultValue)
+ return deps
+
class IDLCallbackType(IDLType, IDLObjectWithScope):
def __init__(self, location, parentScope, identifier, returnType, arguments):
assert isinstance(returnType, IDLType)
@@ -2179,6 +2338,9 @@ class IDLCallbackType(IDLType, IDLObjectWithScope):
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isNonCallbackInterface() or other.isDate())
+ def _getDependentObjects(self):
+ return set([self._returnType] + self._arguments)
+
class IDLMethodOverload:
"""
A class that represents a single overload of a WebIDL method. This is not
@@ -2194,6 +2356,11 @@ class IDLMethodOverload:
self.arguments = list(arguments)
self.location = location
+ def _getDependentObjects(self):
+ deps = set(self.arguments)
+ deps.add(self.returnType)
+ return deps
+
class IDLMethod(IDLInterfaceMember, IDLScope):
Special = enum(
@@ -2494,6 +2661,12 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
[attr.location, self.location])
IDLInterfaceMember.handleExtendedAttribute(self, attr)
+ def _getDependentObjects(self):
+ deps = set()
+ for overload in self._overloads:
+ deps.union(overload._getDependentObjects())
+ return deps
+
class IDLImplementsStatement(IDLObject):
def __init__(self, location, implementor, implementee):
IDLObject.__init__(self, location)