Bug 810641. Implement support for variadic callback arguments in WebIDL. r=peterv

This commit is contained in:
Boris Zbarsky 2012-11-26 21:14:45 -05:00
parent 6c53836aa3
commit 8fef42994e
2 changed files with 54 additions and 17 deletions

View File

@ -6942,7 +6942,7 @@ class CGNativeMember(ClassMethod):
if nullable:
type = type.inner
elementType = type.inner
decl = CGWrapper(self.getArgType(elementType, False, True)[0],
decl = CGWrapper(self.getArgType(elementType, False, False, True)[0],
pre="Sequence< ", post=" >")
return decl.define(), True, True
@ -7028,17 +7028,23 @@ class CGNativeMember(ClassMethod):
return builtinNames[type.tag()], False, True
def getArgType(self, type, optional, isMember):
def getArgType(self, type, optional, variadic, isMember):
"""
Get the type of an argument declaration. Returns the type CGThing, and
whether this should be a const ref.
"""
(decl, ref, handleNullable) = self.doGetArgType(type, optional, isMember)
(decl, ref, handleNullable) = self.doGetArgType(type, optional,
isMember or variadic)
decl = CGGeneric(decl)
if handleNullable and type.nullable():
decl = CGWrapper(decl, pre="Nullable< ", post=" >")
ref = True
if optional:
if variadic:
decl = CGWrapper(decl, pre="nsTArray< ", post=" >")
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 = CGWrapper(decl, pre="Optional< ", post=" >")
ref = True
return (decl, ref)
@ -7049,6 +7055,7 @@ class CGNativeMember(ClassMethod):
"""
(decl, ref) = self.getArgType(arg.type,
arg.optional and not arg.defaultValue,
arg.variadic,
False)
if ref:
decl = CGWrapper(decl, pre="const ", post="&")
@ -7410,6 +7417,15 @@ class CallCallback(CGNativeMember):
self.callback = callback
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
CGNativeMember.__init__(self, descriptorProvider, FakeMember(),
"Call", (self.retvalType, args),
extendedAttrs={},
@ -7425,25 +7441,32 @@ class CallCallback(CGNativeMember):
def getImpl(self):
replacements = {
"errorReturn" : self.getDefaultRetval(),
"argCount": self.argCount,
"returnResult": self.getResultConversion(),
"convertArgs": self.getArgConversions()
"convertArgs": self.getArgConversions(),
}
if self.argCount > 0:
replacements["argCount"] = self.argCountStr
replacements["argvDecl"] = string.Template(
"JS::Value argv[${argCount}];\n").substitute(replacements)
replacements["argv"] = "argv"
"JS::AutoValueVector argv(cx);\n"
"if (!argv.resize(${argCount})) {\n"
" aRv.Throw(NS_ERROR_OUT_OF_MEMORY);\n"
" return${errorReturn};\n"
"}\n"
).substitute(replacements)
replacements["argv"] = "argv.begin()"
replacements["argc"] = "argc"
else:
# Avoid weird 0-sized arrays
replacements["argvDecl"] = ""
replacements["argv"] = "nullptr"
replacements["argc"] = "0"
return string.Template(
"JS::Value rval = JSVAL_VOID;\n"
"${argvDecl}" # Newlines and semicolons are in the value
"${convertArgs}"
"if (!JS_CallFunctionValue(cx, aThisObj, JS::ObjectValue(*mCallable),\n"
" argc, ${argv}, &rval)) {\n"
" ${argc}, ${argv}, &rval)) {\n"
" aRv.Throw(NS_ERROR_UNEXPECTED);\n"
" return${errorReturn};\n"
"}\n"
@ -7486,15 +7509,22 @@ class CallCallback(CGNativeMember):
pre="do {\n",
post="\n} while (0);")
for c in argConversions]
argConversions.insert(0,
CGGeneric("unsigned argc = %d;" % self.argCount));
if self.argCount > 0:
argConversions.insert(0,
CGGeneric("unsigned argc = %s;" % self.argCountStr));
# And slap them together.
return CGList(argConversions, "\n\n").define() + "\n\n"
def getArgConversion(self, i, arg):
argval = arg.identifier.name
if arg.optional:
argval += ".Value()"
if arg.variadic:
argval = argval + "[idx]"
jsvalIndex = "%d + idx" % i
else:
jsvalIndex = "%d" % i
if arg.optional:
argval += ".Value()"
if arg.type.isString():
# XPConnect string-to-JS conversion wants to mutate the string. So
# let's give it a string it can mutate
@ -7509,16 +7539,22 @@ class CallCallback(CGNativeMember):
arg.type, self.descriptor,
{
'result' : result,
'successCode' : "break;",
'jsvalRef' : "argv[%d]" % i,
'jsvalPtr' : "&argv[%d]" % i,
'successCode' : "continue;" if arg.variadic else "break;",
'jsvalRef' : "argv[%s]" % jsvalIndex,
'jsvalPtr' : "&argv[%s]" % jsvalIndex,
# XXXbz we don't have anything better to use for 'obj',
# really...
'obj' : 'mCallable',
'isCreator': False,
'exceptionCode' : self.exceptionCode
})
if arg.optional:
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:
conversion = (
CGIfWrapper(CGGeneric(conversion),
"%s.WasPassed()" % arg.identifier.name).define() +

View File

@ -33,6 +33,7 @@ webidl_files = \
EventTarget.webidl \
FileList.webidl \
FileReaderSync.webidl \
Function.webidl \
GainNode.webidl \
HTMLCollection.webidl \
HTMLOptionsCollection.webidl \