зеркало из https://github.com/mozilla/gecko-dev.git
Bug 815502. Implement support for variadic arguments in WebIDL. r=peterv
This commit is contained in:
Родитель
05e5ef448b
Коммит
d4de9b2c67
|
@ -2196,6 +2196,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
|
|||
if not isOptional:
|
||||
typeName = CGWrapper(typeName, pre="const ")
|
||||
|
||||
# NOTE: Keep this in sync with variadic conversions as needed
|
||||
templateBody = ("""JSObject* seq = &${val}.toObject();\n
|
||||
if (!IsArrayLike(cx, seq)) {
|
||||
%s
|
||||
|
@ -3042,9 +3043,6 @@ class CGArgumentConverter(CGThing):
|
|||
invalidEnumValueFatal=True, lenientFloatCode=None):
|
||||
CGThing.__init__(self)
|
||||
self.argument = argument
|
||||
if argument.variadic:
|
||||
raise TypeError("We don't support variadic arguments yet " +
|
||||
str(argument.location))
|
||||
assert(not argument.defaultValue or argument.optional)
|
||||
|
||||
replacer = {
|
||||
|
@ -3074,19 +3072,70 @@ class CGArgumentConverter(CGThing):
|
|||
self.lenientFloatCode = lenientFloatCode
|
||||
|
||||
def define(self):
|
||||
return instantiateJSToNativeConversionTemplate(
|
||||
getJSToNativeConversionTemplate(self.argument.type,
|
||||
self.descriptorProvider,
|
||||
isOptional=(self.argcAndIndex is not None),
|
||||
invalidEnumValueFatal=self.invalidEnumValueFatal,
|
||||
defaultValue=self.argument.defaultValue,
|
||||
treatNullAs=self.argument.treatNullAs,
|
||||
treatUndefinedAs=self.argument.treatUndefinedAs,
|
||||
isEnforceRange=self.argument.enforceRange,
|
||||
isClamp=self.argument.clamp,
|
||||
lenientFloatCode=self.lenientFloatCode),
|
||||
self.replacementVariables,
|
||||
self.argcAndIndex).define()
|
||||
typeConversion = getJSToNativeConversionTemplate(
|
||||
self.argument.type,
|
||||
self.descriptorProvider,
|
||||
isOptional=(self.argcAndIndex is not None and
|
||||
not self.argument.variadic),
|
||||
invalidEnumValueFatal=self.invalidEnumValueFatal,
|
||||
defaultValue=self.argument.defaultValue,
|
||||
treatNullAs=self.argument.treatNullAs,
|
||||
treatUndefinedAs=self.argument.treatUndefinedAs,
|
||||
isEnforceRange=self.argument.enforceRange,
|
||||
isClamp=self.argument.clamp,
|
||||
lenientFloatCode=self.lenientFloatCode,
|
||||
isMember=self.argument.variadic)
|
||||
|
||||
if not self.argument.variadic:
|
||||
return instantiateJSToNativeConversionTemplate(
|
||||
typeConversion,
|
||||
self.replacementVariables,
|
||||
self.argcAndIndex).define()
|
||||
|
||||
# Variadic arguments get turned into a sequence.
|
||||
(elementTemplate, elementDeclType,
|
||||
elementHolderType, dealWithOptional) = typeConversion
|
||||
if dealWithOptional:
|
||||
raise TypeError("Shouldn't have optional things in variadics")
|
||||
if elementHolderType is not None:
|
||||
raise TypeError("Shouldn't need holders for variadics")
|
||||
|
||||
replacer = dict(self.argcAndIndex, **self.replacementVariables)
|
||||
replacer["seqType"] = CGWrapper(elementDeclType, pre="Sequence< ", post=" >").define()
|
||||
replacer["elemType"] = elementDeclType.define()
|
||||
|
||||
# NOTE: Keep this in sync with sequence conversions as needed
|
||||
variadicConversion = string.Template("""const ${seqType} ${declName};
|
||||
if (${argc} > ${index}) {
|
||||
${seqType}& arr = const_cast< ${seqType}& >(${declName});
|
||||
if (!arr.SetCapacity(${argc} - ${index})) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) {
|
||||
${elemType}& slot = *arr.AppendElement();
|
||||
""").substitute(replacer)
|
||||
|
||||
val = string.Template("${argv}[variadicArg]").substitute(replacer)
|
||||
variadicConversion += CGIndenter(CGGeneric(
|
||||
string.Template(elementTemplate).substitute(
|
||||
{
|
||||
"val" : val,
|
||||
"valPtr": "&" + val,
|
||||
"declName" : "slot",
|
||||
# We only need holderName here to handle isExternal()
|
||||
# interfaces, which use an internal holder for the
|
||||
# conversion even when forceOwningType ends up true.
|
||||
"holderName": "tempHolder",
|
||||
# Use the same ${obj} as for the variadic arg itself
|
||||
"obj": replacer["obj"]
|
||||
}
|
||||
)), 4).define()
|
||||
|
||||
variadicConversion += ("\n"
|
||||
" }\n"
|
||||
"}")
|
||||
return variadicConversion
|
||||
|
||||
def getWrapTemplateForType(type, descriptorProvider, result, successCode,
|
||||
isCreator, exceptionCode):
|
||||
|
@ -3777,16 +3826,44 @@ class CGMethodCall(CGThing):
|
|||
|
||||
distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
|
||||
|
||||
for (_, args) in possibleSignatures:
|
||||
def distinguishingArgument(signature):
|
||||
args = signature[1]
|
||||
if distinguishingIndex < len(args):
|
||||
return args[distinguishingIndex]
|
||||
assert args[-1].variadic
|
||||
return args[-1]
|
||||
|
||||
def distinguishingType(signature):
|
||||
return distinguishingArgument(signature).type
|
||||
|
||||
for sig in possibleSignatures:
|
||||
# We should not have "any" args at distinguishingIndex,
|
||||
# since we have multiple possible signatures remaining,
|
||||
# but "any" is never distinguishable from anything else.
|
||||
assert not args[distinguishingIndex].type.isAny()
|
||||
assert not distinguishingType(sig).isAny()
|
||||
# We can't handle unions at the distinguishing index.
|
||||
if args[distinguishingIndex].type.isUnion():
|
||||
if distinguishingType(sig).isUnion():
|
||||
raise TypeError("No support for unions as distinguishing "
|
||||
"arguments yet: %s",
|
||||
args[distinguishingIndex].location)
|
||||
distinguishingArgument(sig).location)
|
||||
# We don't support variadics as the distinguishingArgument yet.
|
||||
# If you want to add support, consider this case:
|
||||
#
|
||||
# void(long... foo);
|
||||
# void(long bar, Int32Array baz);
|
||||
#
|
||||
# in which we have to convert argument 0 to long before picking
|
||||
# an overload... but all the variadic stuff needs to go into a
|
||||
# single array in case we pick that overload, so we have to have
|
||||
# machinery for converting argument 0 to long and then either
|
||||
# placing it in the variadic bit or not. Or something. We may
|
||||
# be able to loosen this restriction if the variadic arg is in
|
||||
# fact at distinguishingIndex, perhaps. Would need to
|
||||
# double-check.
|
||||
if distinguishingArgument(sig).variadic:
|
||||
raise TypeError("No support for variadics as distinguishing "
|
||||
"arguments yet: %s",
|
||||
distinguishingArgument(sig).location)
|
||||
|
||||
# Convert all our arguments up to the distinguishing index.
|
||||
# Doesn't matter which of the possible signatures we use, since
|
||||
|
@ -3816,9 +3893,6 @@ class CGMethodCall(CGThing):
|
|||
return True
|
||||
return False
|
||||
|
||||
def distinguishingType(signature):
|
||||
return signature[1][distinguishingIndex].type
|
||||
|
||||
def tryCall(signature, indent, isDefinitelyObject=False,
|
||||
isNullOrUndefined=False):
|
||||
assert not isDefinitelyObject or not isNullOrUndefined
|
||||
|
@ -6818,7 +6892,7 @@ class CGBindingRoot(CGThing):
|
|||
class CGNativeMember(ClassMethod):
|
||||
def __init__(self, descriptor, member, name, signature, extendedAttrs,
|
||||
breakAfter=True, passCxAsNeeded=True, visibility="public",
|
||||
jsObjectsArePtr=False):
|
||||
jsObjectsArePtr=False, variadicIsSequence=False):
|
||||
"""
|
||||
If jsObjectsArePtr is true, typed arrays and "object" will be
|
||||
passed as JSObject*
|
||||
|
@ -6830,6 +6904,7 @@ class CGNativeMember(ClassMethod):
|
|||
self.extendedAttrs)
|
||||
self.passCxAsNeeded = passCxAsNeeded
|
||||
self.jsObjectsArePtr = jsObjectsArePtr
|
||||
self.variadicIsSequence = variadicIsSequence
|
||||
breakAfterSelf = "\n" if breakAfter else ""
|
||||
ClassMethod.__init__(self, name,
|
||||
self.getReturnType(signature[0], False),
|
||||
|
@ -7110,7 +7185,8 @@ class CGNativeMember(ClassMethod):
|
|||
decl = CGWrapper(decl, pre="Nullable< ", post=" >")
|
||||
ref = True
|
||||
if variadic:
|
||||
decl = CGWrapper(decl, pre="nsTArray< ", post=" >")
|
||||
arrayType = "Sequence" if self.variadicIsSequence else "nsTArray"
|
||||
decl = CGWrapper(decl, pre="%s< " % arrayType, post=" >")
|
||||
ref = True
|
||||
elif optional:
|
||||
# Note: All variadic args claim to be optional, but we can just use
|
||||
|
@ -7140,7 +7216,8 @@ class CGExampleMethod(CGNativeMember):
|
|||
method),
|
||||
signature,
|
||||
descriptor.getExtendedAttributes(method),
|
||||
breakAfter)
|
||||
breakAfter=breakAfter,
|
||||
variadicIsSequence=True)
|
||||
def define(self, cgClass):
|
||||
return ''
|
||||
|
||||
|
|
|
@ -2607,24 +2607,32 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
return [overload for overload in self._overloads if
|
||||
len(overload.arguments) == argc or
|
||||
(len(overload.arguments) > argc and
|
||||
overload.arguments[argc].optional)]
|
||||
overload.arguments[argc].optional) or
|
||||
(len(overload.arguments) < argc and
|
||||
len(overload.arguments) > 0 and
|
||||
overload.arguments[-1].variadic)]
|
||||
|
||||
def signaturesForArgCount(self, argc):
|
||||
return [(overload.returnType, overload.arguments) for overload
|
||||
in self.overloadsForArgCount(argc)]
|
||||
|
||||
def locationsForArgCount(self, argc):
|
||||
return [overload.location for overload in self._overloads if
|
||||
len(overload.arguments) == argc or
|
||||
(len(overload.arguments) > argc and
|
||||
overload.arguments[argc].optional)]
|
||||
return [overload.location for overload in self.overloadsForArgCount(argc)]
|
||||
|
||||
def distinguishingIndexForArgCount(self, argc):
|
||||
def isValidDistinguishingIndex(idx, signatures):
|
||||
for (firstSigIndex, (firstRetval, firstArgs)) in enumerate(signatures[:-1]):
|
||||
for (secondRetval, secondArgs) in signatures[firstSigIndex+1:]:
|
||||
firstType = firstArgs[idx].type
|
||||
secondType = secondArgs[idx].type
|
||||
if idx < len(firstArgs):
|
||||
firstType = firstArgs[idx].type
|
||||
else:
|
||||
assert(firstArgs[-1].variadic)
|
||||
firstType = firstArgs[-1].type
|
||||
if idx < len(secondArgs):
|
||||
secondType = secondArgs[idx].type
|
||||
else:
|
||||
assert(secondArgs[-1].variadic)
|
||||
secondType = secondArgs[-1].type
|
||||
if not firstType.isDistinguishableFrom(secondType):
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -8,6 +8,9 @@ def WebIDLTest(parser, harness):
|
|||
boolean abitharder(TestOverloads foo);
|
||||
boolean abitharder(boolean foo);
|
||||
void abitharder(ArrayBuffer? foo);
|
||||
void withVariadics(long... numbers);
|
||||
void withVariadics(TestOverloads iface);
|
||||
void withVariadics(long num, TestOverloads iface);
|
||||
};
|
||||
""")
|
||||
|
||||
|
@ -20,7 +23,7 @@ def WebIDLTest(parser, harness):
|
|||
"Should be an IDLInterface")
|
||||
harness.check(iface.identifier.QName(), "::TestOverloads", "Interface has the right QName")
|
||||
harness.check(iface.identifier.name, "TestOverloads", "Interface has the right name")
|
||||
harness.check(len(iface.members), 2, "Expect %s members" % 2)
|
||||
harness.check(len(iface.members), 3, "Expect %s members" % 3)
|
||||
|
||||
member = iface.members[0]
|
||||
harness.check(member.identifier.QName(), "::TestOverloads::basic", "Method has the right QName")
|
||||
|
|
|
@ -37,3 +37,16 @@ def WebIDLTest(parser, harness):
|
|||
threw = True
|
||||
|
||||
harness.ok(threw, "Should have thrown.")
|
||||
|
||||
threw = False
|
||||
try:
|
||||
results = parser.parse("""
|
||||
interface VariadicConstraints4 {
|
||||
void foo(byte... arg1 = 0);
|
||||
};
|
||||
""")
|
||||
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw, "Should have thrown on variadic argument with default value.")
|
||||
|
|
|
@ -154,6 +154,7 @@ public:
|
|||
void PassOptionalByteWithDefault(int8_t);
|
||||
void PassNullableByte(const Nullable<int8_t>&);
|
||||
void PassOptionalNullableByte(const Optional< Nullable<int8_t> >&);
|
||||
void PassVariadicByte(const Sequence<int8_t>&);
|
||||
|
||||
int16_t ReadonlyShort();
|
||||
int16_t WritableShort();
|
||||
|
@ -381,6 +382,7 @@ public:
|
|||
void PassOptionalStringWithDefaultValue(const nsAString&);
|
||||
void PassOptionalNullableString(const Optional<nsAString>&);
|
||||
void PassOptionalNullableStringWithDefaultValue(const nsAString&);
|
||||
void PassVariadicString(const Sequence<nsString>&);
|
||||
|
||||
// Enumerated types
|
||||
void PassEnum(TestEnum);
|
||||
|
@ -473,6 +475,14 @@ public:
|
|||
static bool StaticAttribute(nsISupports*);
|
||||
static void SetStaticAttribute(nsISupports*, bool);
|
||||
|
||||
// Overload resolution tests
|
||||
bool Overload1(TestInterface&);
|
||||
TestInterface* Overload1(const nsAString&, TestInterface&);
|
||||
|
||||
// Variadic handling
|
||||
void PassVariadicThirdArg(const nsAString&, int32_t,
|
||||
const Sequence<OwningNonNull<TestInterface> >&);
|
||||
|
||||
// Miscellania
|
||||
int32_t AttrWithLenientThis();
|
||||
void SetAttrWithLenientThis(int32_t);
|
||||
|
@ -522,6 +532,7 @@ private:
|
|||
void PassOptionalByte(const Optional<T>&) MOZ_DELETE;
|
||||
template<typename T>
|
||||
void PassOptionalByteWithDefault(T) MOZ_DELETE;
|
||||
void PassVariadicByte(Sequence<int8_t>&) MOZ_DELETE;
|
||||
|
||||
void SetReadonlyShort(int16_t) MOZ_DELETE;
|
||||
template<typename T>
|
||||
|
@ -631,7 +642,7 @@ private:
|
|||
void PassOptionalStringWithDefaultValue(nsAString&) MOZ_DELETE;
|
||||
void PassOptionalNullableString(Optional<nsAString>&) MOZ_DELETE;
|
||||
void PassOptionalNullableStringWithDefaultValue(nsAString&) MOZ_DELETE;
|
||||
|
||||
void PassVariadicString(Sequence<nsString>&) MOZ_DELETE;
|
||||
};
|
||||
|
||||
class TestIndexedGetterInterface : public nsISupports,
|
||||
|
|
|
@ -100,6 +100,7 @@ interface TestInterface {
|
|||
void passOptionalByteWithDefault(optional byte arg = 0);
|
||||
void passNullableByte(byte? arg);
|
||||
void passOptionalNullableByte(optional byte? arg);
|
||||
void passVariadicByte(byte... arg);
|
||||
|
||||
readonly attribute short readonlyShort;
|
||||
attribute short writableShort;
|
||||
|
@ -333,6 +334,7 @@ interface TestInterface {
|
|||
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
|
||||
void passOptionalNullableString(optional DOMString? arg);
|
||||
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
|
||||
void passVariadicString(DOMString... arg);
|
||||
|
||||
// Enumerated types
|
||||
void passEnum(TestEnum arg);
|
||||
|
@ -424,6 +426,14 @@ interface TestInterface {
|
|||
static attribute boolean staticAttribute;
|
||||
static void staticMethod(boolean arg);
|
||||
|
||||
// Overload resolution tests
|
||||
//void overload1(DOMString... strs);
|
||||
boolean overload1(TestInterface arg);
|
||||
TestInterface overload1(DOMString strs, TestInterface arg);
|
||||
|
||||
// Variadic handling
|
||||
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
|
||||
|
||||
// Miscellania
|
||||
[LenientThis] attribute long attrWithLenientThis;
|
||||
[Unforgeable] readonly attribute long unforgeableAttr;
|
||||
|
|
|
@ -21,6 +21,7 @@ interface TestExampleInterface {
|
|||
void passOptionalByteWithDefault(optional byte arg = 0);
|
||||
void passNullableByte(byte? arg);
|
||||
void passOptionalNullableByte(optional byte? arg);
|
||||
void passVariadicByte(byte... arg);
|
||||
|
||||
readonly attribute short readonlyShort;
|
||||
attribute short writableShort;
|
||||
|
@ -254,6 +255,7 @@ interface TestExampleInterface {
|
|||
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
|
||||
void passOptionalNullableString(optional DOMString? arg);
|
||||
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
|
||||
void passVariadicString(DOMString... arg);
|
||||
|
||||
// Enumerated types
|
||||
void passEnum(TestEnum arg);
|
||||
|
@ -345,6 +347,14 @@ interface TestExampleInterface {
|
|||
static attribute boolean staticAttribute;
|
||||
static void staticMethod(boolean arg);
|
||||
|
||||
// Overload resolution tests
|
||||
//void overload1(DOMString... strs);
|
||||
boolean overload1(TestInterface arg);
|
||||
TestInterface overload1(DOMString strs, TestInterface arg);
|
||||
|
||||
// Variadic handling
|
||||
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);
|
||||
|
||||
// Miscellania
|
||||
[LenientThis] attribute long attrWithLenientThis;
|
||||
[Unforgeable] readonly attribute long unforgeableAttr;
|
||||
|
|
Загрузка…
Ссылка в новой задаче