Commit a8de8277 authored by Boris Zbarsky's avatar Boris Zbarsky
Browse files

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

parent 9cfc6466
Loading
Loading
Loading
Loading
+53 −17
Original line number Diff line number Diff line
@@ -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,13 +7509,20 @@ class CallCallback(CGNativeMember):
                                    pre="do {\n",
                                    post="\n} while (0);")
                          for c in argConversions]
        if self.argCount > 0:
            argConversions.insert(0,
                              CGGeneric("unsigned argc = %d;" % self.argCount));
                                  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.variadic:
            argval = argval + "[idx]"
            jsvalIndex = "%d + idx" % i
        else:
            jsvalIndex = "%d" % i
            if arg.optional:
                argval += ".Value()"
        if arg.type.isString():
@@ -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() +
+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ webidl_files = \
  EventTarget.webidl \
  FileList.webidl \
  FileReaderSync.webidl \
  Function.webidl \
  GainNode.webidl \
  HTMLCollection.webidl \
  HTMLOptionsCollection.webidl \