Update the WebIDL parser

This commit is contained in:
Anthony Ramine 2018-09-14 11:15:35 +02:00
parent 70a0174b0a
commit 2b574bbdf8
6 changed files with 284 additions and 108 deletions

View file

@ -684,7 +684,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
def __init__(self, location, parentScope, name, parent, members, def __init__(self, location, parentScope, name, parent, members,
isKnownNonPartial): isKnownNonPartial, toStringTag):
assert isinstance(parentScope, IDLScope) assert isinstance(parentScope, IDLScope)
assert isinstance(name, IDLUnresolvedIdentifier) assert isinstance(name, IDLUnresolvedIdentifier)
assert isKnownNonPartial or not parent assert isKnownNonPartial or not parent
@ -722,6 +722,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
# interface we're iterating for in order to get its nativeType. # interface we're iterating for in order to get its nativeType.
self.iterableInterface = None self.iterableInterface = None
self.toStringTag = toStringTag
IDLObjectWithScope.__init__(self, location, parentScope, name) IDLObjectWithScope.__init__(self, location, parentScope, name)
IDLExposureMixins.__init__(self, location) IDLExposureMixins.__init__(self, location)
@ -1017,10 +1019,9 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
[self.location]) [self.location])
for m in self.members: for m in self.members:
if ((m.isMethod() and m.isJsonifier()) or if m.identifier.name == "toJSON":
m.identifier.name == "toJSON"):
raise WebIDLError("Unforgeable interface %s has a " raise WebIDLError("Unforgeable interface %s has a "
"jsonifier so we won't be able to add " "toJSON so we won't be able to add "
"one ourselves" % self.identifier.name, "one ourselves" % self.identifier.name,
[self.location, m.location]) [self.location, m.location])
@ -1044,6 +1045,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
(member.getExtendedAttribute("StoreInSlot") or (member.getExtendedAttribute("StoreInSlot") or
member.getExtendedAttribute("Cached"))) or member.getExtendedAttribute("Cached"))) or
member.isMaplikeOrSetlike()): member.isMaplikeOrSetlike()):
if self.isJSImplemented() and not member.isMaplikeOrSetlike():
raise WebIDLError("Interface %s is JS-implemented and we "
"don't support [Cached] or [StoreInSlot] "
"on JS-implemented interfaces" %
self.identifier.name,
[self.location, member.location])
if member.slotIndices is None: if member.slotIndices is None:
member.slotIndices = dict() member.slotIndices = dict()
member.slotIndices[self.identifier.name] = self.totalMembersInSlots member.slotIndices[self.identifier.name] = self.totalMembersInSlots
@ -1115,15 +1122,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
memberType = "deleters" memberType = "deleters"
elif member.isStringifier(): elif member.isStringifier():
memberType = "stringifiers" memberType = "stringifiers"
elif member.isJsonifier():
memberType = "jsonifiers"
elif member.isLegacycaller(): elif member.isLegacycaller():
memberType = "legacycallers" memberType = "legacycallers"
else: else:
continue continue
if (memberType != "stringifiers" and memberType != "legacycallers" and if (memberType != "stringifiers" and memberType != "legacycallers"):
memberType != "jsonifiers"):
if member.isNamed(): if member.isNamed():
memberType = "named " + memberType memberType = "named " + memberType
else: else:
@ -1573,9 +1577,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
class IDLInterface(IDLInterfaceOrNamespace): class IDLInterface(IDLInterfaceOrNamespace):
def __init__(self, location, parentScope, name, parent, members, def __init__(self, location, parentScope, name, parent, members,
isKnownNonPartial): isKnownNonPartial, classNameOverride=None,
toStringTag=None):
IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, IDLInterfaceOrNamespace.__init__(self, location, parentScope, name,
parent, members, isKnownNonPartial) parent, members, isKnownNonPartial,
toStringTag)
self.classNameOverride = classNameOverride
def __str__(self): def __str__(self):
return "Interface '%s'" % self.identifier.name return "Interface '%s'" % self.identifier.name
@ -1583,6 +1590,11 @@ class IDLInterface(IDLInterfaceOrNamespace):
def isInterface(self): def isInterface(self):
return True return True
def getClassName(self):
if self.classNameOverride:
return self.classNameOverride
return self.identifier.name
def addExtendedAttributes(self, attrs): def addExtendedAttributes(self, attrs):
for attr in attrs: for attr in attrs:
identifier = attr.identifier() identifier = attr.identifier()
@ -1677,14 +1689,6 @@ class IDLInterface(IDLInterfaceOrNamespace):
elif newMethod not in self.namedConstructors: elif newMethod not in self.namedConstructors:
raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface",
[method.location, newMethod.location]) [method.location, newMethod.location])
elif (identifier == "ArrayClass"):
if not attr.noArguments():
raise WebIDLError("[ArrayClass] must take no arguments",
[attr.location])
if self.parent:
raise WebIDLError("[ArrayClass] must not be specified on "
"an interface with inherited interfaces",
[attr.location, self.location])
elif (identifier == "ExceptionClass"): elif (identifier == "ExceptionClass"):
if not attr.noArguments(): if not attr.noArguments():
raise WebIDLError("[ExceptionClass] must take no arguments", raise WebIDLError("[ExceptionClass] must take no arguments",
@ -1738,6 +1742,7 @@ class IDLInterface(IDLInterfaceOrNamespace):
identifier == "ProbablyShortLivingWrapper" or identifier == "ProbablyShortLivingWrapper" or
identifier == "LegacyUnenumerableNamedProperties" or identifier == "LegacyUnenumerableNamedProperties" or
identifier == "RunConstructorInCallerCompartment" or identifier == "RunConstructorInCallerCompartment" or
identifier == "WantsEventListenerHooks" or
identifier == "NonOrdinaryGetPrototypeOf" or identifier == "NonOrdinaryGetPrototypeOf" or
identifier == "Abstract" or identifier == "Abstract" or
identifier == "Inline"): identifier == "Inline"):
@ -1769,7 +1774,8 @@ class IDLInterface(IDLInterfaceOrNamespace):
class IDLNamespace(IDLInterfaceOrNamespace): class IDLNamespace(IDLInterfaceOrNamespace):
def __init__(self, location, parentScope, name, members, isKnownNonPartial): def __init__(self, location, parentScope, name, members, isKnownNonPartial):
IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, IDLInterfaceOrNamespace.__init__(self, location, parentScope, name,
None, members, isKnownNonPartial) None, members, isKnownNonPartial,
toStringTag=None)
def __str__(self): def __str__(self):
return "Namespace '%s'" % self.identifier.name return "Namespace '%s'" % self.identifier.name
@ -2152,7 +2158,7 @@ class IDLType(IDLObject):
# Should only call this on float types # Should only call this on float types
assert self.isFloat() assert self.isFloat()
def isSerializable(self): def isJSONType(self):
return False return False
def tag(self): def tag(self):
@ -2350,8 +2356,8 @@ class IDLNullableType(IDLParametrizedType):
def isUnion(self): def isUnion(self):
return self.inner.isUnion() return self.inner.isUnion()
def isSerializable(self): def isJSONType(self):
return self.inner.isSerializable() return self.inner.isJSONType()
def tag(self): def tag(self):
return self.inner.tag() return self.inner.tag()
@ -2430,8 +2436,8 @@ class IDLSequenceType(IDLParametrizedType):
def isEnum(self): def isEnum(self):
return False return False
def isSerializable(self): def isJSONType(self):
return self.inner.isSerializable() return self.inner.isJSONType()
def tag(self): def tag(self):
return IDLType.Tags.sequence return IDLType.Tags.sequence
@ -2476,6 +2482,9 @@ class IDLRecordType(IDLParametrizedType):
def isRecord(self): def isRecord(self):
return True return True
def isJSONType(self):
return self.inner.isJSONType()
def tag(self): def tag(self):
return IDLType.Tags.record return IDLType.Tags.record
@ -2525,8 +2534,8 @@ class IDLUnionType(IDLType):
def isUnion(self): def isUnion(self):
return True return True
def isSerializable(self): def isJSONType(self):
return all(m.isSerializable() for m in self.memberTypes) return all(m.isJSONType() for m in self.memberTypes)
def includesRestrictedFloat(self): def includesRestrictedFloat(self):
return any(t.includesRestrictedFloat() for t in self.memberTypes) return any(t.includesRestrictedFloat() for t in self.memberTypes)
@ -2676,6 +2685,9 @@ class IDLTypedefType(IDLType):
def isVoid(self): def isVoid(self):
return self.inner.isVoid() return self.inner.isVoid()
def isJSONType(self):
return self.inner.isJSONType()
def isSequence(self): def isSequence(self):
return self.inner.isSequence() return self.inner.isSequence()
@ -2817,15 +2829,25 @@ class IDLWrapperType(IDLType):
def isEnum(self): def isEnum(self):
return isinstance(self.inner, IDLEnum) return isinstance(self.inner, IDLEnum)
def isSerializable(self): def isJSONType(self):
if self.isInterface(): if self.isInterface():
if self.inner.isExternal(): if self.inner.isExternal():
return False return False
return any(m.isMethod() and m.isJsonifier() for m in self.inner.members) iface = self.inner
while iface:
if any(m.isMethod() and m.isToJSON() for m in iface.members):
return True
iface = iface.parent
return False
elif self.isEnum(): elif self.isEnum():
return True return True
elif self.isDictionary(): elif self.isDictionary():
return all(m.type.isSerializable() for m in self.inner.members) dictionary = self.inner
while dictionary:
if not all(m.type.isJSONType() for m in dictionary.members):
return False
dictionary = dictionary.parent
return True
else: else:
raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " raise WebIDLError("IDLWrapperType wraps type %s that we don't know if "
"is serializable" % type(self.inner), [self.location]) "is serializable" % type(self.inner), [self.location])
@ -3111,8 +3133,8 @@ class IDLBuiltinType(IDLType):
return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or
self._typeTag == IDLBuiltinType.Types.unrestricted_double) self._typeTag == IDLBuiltinType.Types.unrestricted_double)
def isSerializable(self): def isJSONType(self):
return self.isPrimitive() or self.isString() or self.isDate() return self.isPrimitive() or self.isString() or self.isObject()
def includesRestrictedFloat(self): def includesRestrictedFloat(self):
return self.isFloat() and not self.isUnrestricted() return self.isFloat() and not self.isUnrestricted()
@ -4665,7 +4687,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
def __init__(self, location, identifier, returnType, arguments, def __init__(self, location, identifier, returnType, arguments,
static=False, getter=False, setter=False, static=False, getter=False, setter=False,
deleter=False, specialType=NamedOrIndexed.Neither, deleter=False, specialType=NamedOrIndexed.Neither,
legacycaller=False, stringifier=False, jsonifier=False, legacycaller=False, stringifier=False,
maplikeOrSetlikeOrIterable=None, htmlConstructor=False): maplikeOrSetlikeOrIterable=None, htmlConstructor=False):
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
IDLInterfaceMember.__init__(self, location, identifier, IDLInterfaceMember.__init__(self, location, identifier,
@ -4690,8 +4712,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
self._legacycaller = legacycaller self._legacycaller = legacycaller
assert isinstance(stringifier, bool) assert isinstance(stringifier, bool)
self._stringifier = stringifier self._stringifier = stringifier
assert isinstance(jsonifier, bool)
self._jsonifier = jsonifier
assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase)
self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable
assert isinstance(htmlConstructor, bool) assert isinstance(htmlConstructor, bool)
@ -4739,12 +4759,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
assert len(overload.arguments) == 0 assert len(overload.arguments) == 0
assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring]
if self._jsonifier:
assert len(self._overloads) == 1
overload = self._overloads[0]
assert len(overload.arguments) == 0
assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.object]
def isStatic(self): def isStatic(self):
return self._static return self._static
@ -4776,8 +4790,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
def isStringifier(self): def isStringifier(self):
return self._stringifier return self._stringifier
def isJsonifier(self): def isToJSON(self):
return self._jsonifier return self.identifier.name == "toJSON"
def isDefaultToJSON(self):
return self.isToJSON() and self.getExtendedAttribute("Default")
def isMaplikeOrSetlikeOrIterableMethod(self): def isMaplikeOrSetlikeOrIterableMethod(self):
""" """
@ -4791,8 +4808,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
self.isSetter() or self.isSetter() or
self.isDeleter() or self.isDeleter() or
self.isLegacycaller() or self.isLegacycaller() or
self.isStringifier() or self.isStringifier())
self.isJsonifier())
def isHTMLConstructor(self): def isHTMLConstructor(self):
return self._htmlConstructor return self._htmlConstructor
@ -4848,8 +4864,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
assert not method.isDeleter() assert not method.isDeleter()
assert not self.isStringifier() assert not self.isStringifier()
assert not method.isStringifier() assert not method.isStringifier()
assert not self.isJsonifier()
assert not method.isJsonifier()
assert not self.isHTMLConstructor() assert not self.isHTMLConstructor()
assert not method.isHTMLConstructor() assert not method.isHTMLConstructor()
@ -4972,6 +4986,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
" methods on JS-implemented classes only.", " methods on JS-implemented classes only.",
[self.location]) [self.location])
# Ensure that toJSON methods satisfy the spec constraints on them.
if self.identifier.name == "toJSON":
if len(self.signatures()) != 1:
raise WebIDLError("toJSON method has multiple overloads",
[self._overloads[0].location,
self._overloads[1].location])
if len(self.signatures()[0][1]) != 0:
raise WebIDLError("toJSON method has arguments",
[self.location])
if not self.signatures()[0][0].isJSONType():
raise WebIDLError("toJSON method has non-JSON return type",
[self.location])
def overloadsForArgCount(self, argc): def overloadsForArgCount(self, argc):
return [overload for overload in self._overloads if return [overload for overload in self._overloads if
len(overload.arguments) == argc or len(overload.arguments) == argc or
@ -5105,6 +5132,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
raise WebIDLError("[CEReactions] is only allowed on operation, " raise WebIDLError("[CEReactions] is only allowed on operation, "
"attribute, setter, and deleter", "attribute, setter, and deleter",
[attr.location, self.location]) [attr.location, self.location])
elif identifier == "Default":
if not attr.noArguments():
raise WebIDLError("[Default] must take no arguments",
[attr.location])
if not self.isToJSON():
raise WebIDLError("[Default] is only allowed on toJSON operations",
[attr.location, self.location])
if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]:
raise WebIDLError("The return type of the default toJSON "
"operation must be 'object'",
[attr.location, self.location]);
elif (identifier == "Throws" or elif (identifier == "Throws" or
identifier == "CanOOM" or identifier == "CanOOM" or
identifier == "NewObject" or identifier == "NewObject" or
@ -5292,7 +5332,6 @@ class Tokenizer(object):
"false": "FALSE", "false": "FALSE",
"serializer": "SERIALIZER", "serializer": "SERIALIZER",
"stringifier": "STRINGIFIER", "stringifier": "STRINGIFIER",
"jsonifier": "JSONIFIER",
"unrestricted": "UNRESTRICTED", "unrestricted": "UNRESTRICTED",
"attribute": "ATTRIBUTE", "attribute": "ATTRIBUTE",
"readonly": "READONLY", "readonly": "READONLY",
@ -6123,19 +6162,6 @@ class Parser(Tokenizer):
stringifier=True) stringifier=True)
p[0] = method p[0] = method
def p_Jsonifier(self, p):
"""
Operation : JSONIFIER SEMICOLON
"""
identifier = IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"),
"__jsonifier", allowDoubleUnderscore=True)
method = IDLMethod(self.getLocation(p, 1),
identifier,
returnType=BuiltinTypes[IDLBuiltinType.Types.object],
arguments=[],
jsonifier=True)
p[0] = method
def p_QualifierStatic(self, p): def p_QualifierStatic(self, p):
""" """
Qualifier : STATIC Qualifier : STATIC
@ -6289,7 +6315,6 @@ class Parser(Tokenizer):
| SETTER | SETTER
| STATIC | STATIC
| STRINGIFIER | STRINGIFIER
| JSONIFIER
| TYPEDEF | TYPEDEF
| UNRESTRICTED | UNRESTRICTED
| NAMESPACE | NAMESPACE
@ -6441,7 +6466,6 @@ class Parser(Tokenizer):
| SHORT | SHORT
| STATIC | STATIC
| STRINGIFIER | STRINGIFIER
| JSONIFIER
| TRUE | TRUE
| TYPEDEF | TYPEDEF
| UNSIGNED | UNSIGNED
@ -6958,9 +6982,12 @@ class Parser(Tokenizer):
nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
itr_ident = IDLUnresolvedIdentifier(iface.location, itr_ident = IDLUnresolvedIdentifier(iface.location,
iface.identifier.name + "Iterator") iface.identifier.name + "Iterator")
toStringTag = iface.identifier.name + " Iterator"
itr_iface = IDLInterface(iface.location, self.globalScope(), itr_iface = IDLInterface(iface.location, self.globalScope(),
itr_ident, None, [nextMethod], itr_ident, None, [nextMethod],
isKnownNonPartial=True) isKnownNonPartial=True,
classNameOverride=toStringTag,
toStringTag=toStringTag)
itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")]) itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")])
# Make sure the exposure set for the iterator interface is the # Make sure the exposure set for the iterator interface is the
# same as the exposure set for the iterable interface, because # same as the exposure set for the iterable interface, because

View file

@ -1,9 +1,9 @@
--- WebIDL.py --- WebIDL.py
+++ WebIDL.py +++ WebIDL.py
@@ -1744,7 +1744,8 @@ @@ -1744,7 +1744,8 @@
identifier == "ProbablyShortLivingWrapper" or
identifier == "LegacyUnenumerableNamedProperties" or identifier == "LegacyUnenumerableNamedProperties" or
identifier == "RunConstructorInCallerCompartment" or identifier == "RunConstructorInCallerCompartment" or
identifier == "WantsEventListenerHooks" or
- identifier == "NonOrdinaryGetPrototypeOf"): - identifier == "NonOrdinaryGetPrototypeOf"):
+ identifier == "NonOrdinaryGetPrototypeOf" or + identifier == "NonOrdinaryGetPrototypeOf" or
+ identifier == "Abstract"): + identifier == "Abstract"):

View file

@ -131,17 +131,3 @@ def WebIDLTest(parser, harness):
harness.ok(threw, harness.ok(threw,
"Should have thrown for [CEReactions] used on a stringifier") "Should have thrown for [CEReactions] used on a stringifier")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface Foo {
[CEReactions] jsonifier;
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown for [CEReactions] used on a jsonifier")

View file

@ -374,32 +374,3 @@ def WebIDLTest(parser, harness):
threw = True threw = True
harness.ok(threw, harness.ok(threw,
"Should not allow unknown extended attributes on interfaces") "Should not allow unknown extended attributes on interfaces")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface B {};
[ArrayClass]
interface A : B {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw,
"Should not allow [ArrayClass] on interfaces with parents")
parser = parser.reset()
threw = False
try:
parser.parse("""
[ArrayClass]
interface A {
};
""")
results = parser.finish()
except:
threw = True
harness.ok(not threw,
"Should allow [ArrayClass] on interfaces without parents")

View file

@ -0,0 +1,192 @@
def WebIDLTest(parser, harness):
threw = False
try:
parser.parse(
"""
interface Test {
object toJSON();
};
""")
results = parser.finish()
except:
threw = True
harness.ok(not threw, "Should allow a toJSON method.")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Test {
object toJSON(object arg);
object toJSON(long arg);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should not allow overloads of a toJSON method.")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Test {
object toJSON(object arg);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should not allow a toJSON method with arguments.")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Test {
long toJSON();
};
""")
results = parser.finish()
except:
threw = True
harness.ok(not threw, "Should allow a toJSON method with 'long' as return type.")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Test {
[Default] object toJSON();
};
""")
results = parser.finish()
except:
threw = True
harness.ok(not threw, "Should allow a default toJSON method with 'object' as return type.")
parser = parser.reset()
threw = False
try:
parser.parse(
"""
interface Test {
[Default] long toJSON();
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should not allow a default toJSON method with non-'object' as return type.")
JsonTypes = [ "byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long",
"unsigned long long", "float", "unrestricted float", "double", "unrestricted double", "boolean",
"DOMString", "ByteString", "USVString", "Enum", "InterfaceWithToJSON", "object" ]
nonJsonTypes = [ "InterfaceWithoutToJSON", "any", "Int8Array", "Int16Array", "Int32Array","Uint8Array",
"Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array", "ArrayBuffer" ]
def doTest(testIDL, shouldThrow, description):
p = parser.reset()
threw = False
try:
p.parse(testIDL +
"""
enum Enum { "a", "b", "c" };
interface InterfaceWithToJSON { long toJSON(); };
interface InterfaceWithoutToJSON {};
""");
p.finish();
except Exception as x:
threw = True
harness.ok(x.message == "toJSON method has non-JSON return type", x)
harness.check(threw, shouldThrow, description)
for type in JsonTypes:
doTest("interface Test { %s toJSON(); };" % type, False,
"%s should be a JSON type" % type)
doTest("interface Test { sequence<%s> toJSON(); };" % type, False,
"sequence<%s> should be a JSON type" % type)
doTest("dictionary Foo { %s foo; }; "
"interface Test { Foo toJSON(); }; " % type, False,
"dictionary containing only JSON type (%s) should be a JSON type" % type)
doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; "
"interface Test { Bar toJSON(); }; " % type, False,
"dictionary whose ancestors only contain JSON types should be a JSON type")
doTest("dictionary Foo { any foo; }; dictionary Bar : Foo { %s bar; };"
"interface Test { Bar toJSON(); };" % type, True,
"dictionary whose ancestors contain non-JSON types should not be a JSON type")
doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, False,
"record<DOMString, %s> should be a JSON type" % type)
doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, False,
"record<ByteString, %s> should be a JSON type" % type)
doTest("interface Test { record<USVString, %s> toJSON(); };" % type, False,
"record<USVString, %s> should be a JSON type" % type)
otherUnionType = "Foo" if type != "object" else "long"
doTest("interface Foo { object toJSON(); };"
"interface Test { (%s or %s) toJSON(); };" % (otherUnionType, type), False,
"union containing only JSON types (%s or %s) should be a JSON type" %(otherUnionType, type))
doTest("interface test { %s? toJSON(); };" % type, False,
"Nullable type (%s) should be a JSON type" % type)
doTest("interface Foo : InterfaceWithoutToJSON { %s toJSON(); };"
"interface Test { Foo toJSON(); };" % type, False,
"interface with toJSON should be a JSON type")
doTest("interface Foo : InterfaceWithToJSON { };"
"interface Test { Foo toJSON(); };", False,
"inherited interface with toJSON should be a JSON type")
for type in nonJsonTypes:
doTest("interface Test { %s toJSON(); };" % type, True,
"%s should not be a JSON type" % type)
doTest("interface Test { sequence<%s> toJSON(); };" % type, True,
"sequence<%s> should not be a JSON type" % type)
doTest("dictionary Foo { %s foo; }; "
"interface Test { Foo toJSON(); }; " % type, True,
"Dictionary containing a non-JSON type (%s) should not be a JSON type" % type)
doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; "
"interface Test { Bar toJSON(); }; " % type, True,
"dictionary whose ancestors only contain non-JSON types should not be a JSON type")
doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, True,
"record<DOMString, %s> should not be a JSON type" % type)
doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, True,
"record<ByteString, %s> should not be a JSON type" % type)
doTest("interface Test { record<USVString, %s> toJSON(); };" % type, True,
"record<USVString, %s> should not be a JSON type" % type)
if type != "any":
doTest("interface Foo { object toJSON(); }; "
"interface Test { (Foo or %s) toJSON(); };" % type, True,
"union containing a non-JSON type (%s) should not be a JSON type" % type)
doTest("interface test { %s? toJSON(); };" % type, True,
"Nullable type (%s) should not be a JSON type" % type)
doTest("dictionary Foo { long foo; any bar; };"
"interface Test { Foo toJSON(); };", True,
"dictionary containing a non-JSON type should not be a JSON type")
doTest("interface Foo : InterfaceWithoutToJSON { }; "
"interface Test { Foo toJSON(); };", True,
"interface without toJSON should not be a JSON type")