Permalink
Browse files

Update the WebIDL parser

  • Loading branch information...
nox committed Sep 14, 2018
1 parent e699a80 commit dd9d526d149ba0060a3a35d9217b4a055130d0ff
@@ -684,7 +684,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
def __init__(self, location, parentScope, name, parent, members,
isKnownNonPartial):
isKnownNonPartial, toStringTag):
assert isinstance(parentScope, IDLScope)
assert isinstance(name, IDLUnresolvedIdentifier)
assert isKnownNonPartial or not parent
@@ -722,6 +722,8 @@ def __init__(self, location, parentScope, name, parent, members,
# interface we're iterating for in order to get its nativeType.
self.iterableInterface = None
self.toStringTag = toStringTag
IDLObjectWithScope.__init__(self, location, parentScope, name)
IDLExposureMixins.__init__(self, location)
@@ -1017,10 +1019,9 @@ def finish(self, scope):
[self.location])
for m in self.members:
if ((m.isMethod() and m.isJsonifier()) or
m.identifier.name == "toJSON"):
if m.identifier.name == "toJSON":
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,
[self.location, m.location])
@@ -1044,6 +1045,12 @@ def finish(self, scope):
(member.getExtendedAttribute("StoreInSlot") or
member.getExtendedAttribute("Cached"))) or
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:
member.slotIndices = dict()
member.slotIndices[self.identifier.name] = self.totalMembersInSlots
@@ -1115,15 +1122,12 @@ def finish(self, scope):
memberType = "deleters"
elif member.isStringifier():
memberType = "stringifiers"
elif member.isJsonifier():
memberType = "jsonifiers"
elif member.isLegacycaller():
memberType = "legacycallers"
else:
continue
if (memberType != "stringifiers" and memberType != "legacycallers" and
memberType != "jsonifiers"):
if (memberType != "stringifiers" and memberType != "legacycallers"):
if member.isNamed():
memberType = "named " + memberType
else:
@@ -1573,16 +1577,24 @@ def isExposedConditionally(self, exclusions=[]):
class IDLInterface(IDLInterfaceOrNamespace):
def __init__(self, location, parentScope, name, parent, members,
isKnownNonPartial):
isKnownNonPartial, classNameOverride=None,
toStringTag=None):
IDLInterfaceOrNamespace.__init__(self, location, parentScope, name,
parent, members, isKnownNonPartial)
parent, members, isKnownNonPartial,
toStringTag)
self.classNameOverride = classNameOverride
def __str__(self):
return "Interface '%s'" % self.identifier.name
def isInterface(self):
return True
def getClassName(self):
if self.classNameOverride:
return self.classNameOverride
return self.identifier.name
def addExtendedAttributes(self, attrs):
for attr in attrs:
identifier = attr.identifier()
@@ -1677,14 +1689,6 @@ def addExtendedAttributes(self, attrs):
elif newMethod not in self.namedConstructors:
raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface",
[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"):
if not attr.noArguments():
raise WebIDLError("[ExceptionClass] must take no arguments",
@@ -1738,6 +1742,7 @@ def addExtendedAttributes(self, attrs):
identifier == "ProbablyShortLivingWrapper" or
identifier == "LegacyUnenumerableNamedProperties" or
identifier == "RunConstructorInCallerCompartment" or
identifier == "WantsEventListenerHooks" or
identifier == "NonOrdinaryGetPrototypeOf" or
identifier == "Abstract" or
identifier == "Inline"):
@@ -1769,7 +1774,8 @@ def addExtendedAttributes(self, attrs):
class IDLNamespace(IDLInterfaceOrNamespace):
def __init__(self, location, parentScope, name, members, isKnownNonPartial):
IDLInterfaceOrNamespace.__init__(self, location, parentScope, name,
None, members, isKnownNonPartial)
None, members, isKnownNonPartial,
toStringTag=None)
def __str__(self):
return "Namespace '%s'" % self.identifier.name
@@ -2152,7 +2158,7 @@ def isUnrestricted(self):
# Should only call this on float types
assert self.isFloat()
def isSerializable(self):
def isJSONType(self):
return False
def tag(self):
@@ -2350,8 +2356,8 @@ def isEnum(self):
def isUnion(self):
return self.inner.isUnion()
def isSerializable(self):
return self.inner.isSerializable()
def isJSONType(self):
return self.inner.isJSONType()
def tag(self):
return self.inner.tag()
@@ -2430,8 +2436,8 @@ def isInterface(self):
def isEnum(self):
return False
def isSerializable(self):
return self.inner.isSerializable()
def isJSONType(self):
return self.inner.isJSONType()
def tag(self):
return IDLType.Tags.sequence
@@ -2476,6 +2482,9 @@ def __str__(self):
def isRecord(self):
return True
def isJSONType(self):
return self.inner.isJSONType()
def tag(self):
return IDLType.Tags.record
@@ -2525,8 +2534,8 @@ def isVoid(self):
def isUnion(self):
return True
def isSerializable(self):
return all(m.isSerializable() for m in self.memberTypes)
def isJSONType(self):
return all(m.isJSONType() for m in self.memberTypes)
def includesRestrictedFloat(self):
return any(t.includesRestrictedFloat() for t in self.memberTypes)
@@ -2676,6 +2685,9 @@ def isUSVString(self):
def isVoid(self):
return self.inner.isVoid()
def isJSONType(self):
return self.inner.isJSONType()
def isSequence(self):
return self.inner.isSequence()
@@ -2817,15 +2829,25 @@ def isNonCallbackInterface(self):
def isEnum(self):
return isinstance(self.inner, IDLEnum)
def isSerializable(self):
def isJSONType(self):
if self.isInterface():
if self.inner.isExternal():
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():
return True
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:
raise WebIDLError("IDLWrapperType wraps type %s that we don't know if "
"is serializable" % type(self.inner), [self.location])
@@ -3111,8 +3133,8 @@ def isUnrestricted(self):
return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or
self._typeTag == IDLBuiltinType.Types.unrestricted_double)
def isSerializable(self):
return self.isPrimitive() or self.isString() or self.isDate()
def isJSONType(self):
return self.isPrimitive() or self.isString() or self.isObject()
def includesRestrictedFloat(self):
return self.isFloat() and not self.isUnrestricted()
@@ -4665,7 +4687,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
def __init__(self, location, identifier, returnType, arguments,
static=False, getter=False, setter=False,
deleter=False, specialType=NamedOrIndexed.Neither,
legacycaller=False, stringifier=False, jsonifier=False,
legacycaller=False, stringifier=False,
maplikeOrSetlikeOrIterable=None, htmlConstructor=False):
# REVIEW: specialType is NamedOrIndexed -- wow, this is messed up.
IDLInterfaceMember.__init__(self, location, identifier,
@@ -4690,8 +4712,6 @@ def __init__(self, location, identifier, returnType, arguments,
self._legacycaller = legacycaller
assert isinstance(stringifier, bool)
self._stringifier = stringifier
assert isinstance(jsonifier, bool)
self._jsonifier = jsonifier
assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase)
self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable
assert isinstance(htmlConstructor, bool)
@@ -4739,12 +4759,6 @@ def assertSignatureConstraints(self):
assert len(overload.arguments) == 0
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):
return self._static
@@ -4776,8 +4790,11 @@ def isLegacycaller(self):
def isStringifier(self):
return self._stringifier
def isJsonifier(self):
return self._jsonifier
def isToJSON(self):
return self.identifier.name == "toJSON"
def isDefaultToJSON(self):
return self.isToJSON() and self.getExtendedAttribute("Default")
def isMaplikeOrSetlikeOrIterableMethod(self):
"""
@@ -4791,8 +4808,7 @@ def isSpecial(self):
self.isSetter() or
self.isDeleter() or
self.isLegacycaller() or
self.isStringifier() or
self.isJsonifier())
self.isStringifier())
def isHTMLConstructor(self):
return self._htmlConstructor
@@ -4848,8 +4864,6 @@ def addOverload(self, method):
assert not method.isDeleter()
assert not self.isStringifier()
assert not method.isStringifier()
assert not self.isJsonifier()
assert not method.isJsonifier()
assert not self.isHTMLConstructor()
assert not method.isHTMLConstructor()
@@ -4972,6 +4986,19 @@ def validate(self):
" methods on JS-implemented classes only.",
[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):
return [overload for overload in self._overloads if
len(overload.arguments) == argc or
@@ -5105,6 +5132,19 @@ def handleExtendedAttribute(self, attr):
raise WebIDLError("[CEReactions] is only allowed on operation, "
"attribute, setter, and deleter",
[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
identifier == "CanOOM" or
identifier == "NewObject" or
@@ -5292,7 +5332,6 @@ def t_OTHER(self, t):
"false": "FALSE",
"serializer": "SERIALIZER",
"stringifier": "STRINGIFIER",
"jsonifier": "JSONIFIER",
"unrestricted": "UNRESTRICTED",
"attribute": "ATTRIBUTE",
"readonly": "READONLY",
@@ -6123,19 +6162,6 @@ def p_Stringifier(self, p):
stringifier=True)
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):
"""
Qualifier : STATIC
@@ -6289,7 +6315,6 @@ def p_ArgumentName(self, p):
| SETTER
| STATIC
| STRINGIFIER
| JSONIFIER
| TYPEDEF
| UNRESTRICTED
| NAMESPACE
@@ -6441,7 +6466,6 @@ def p_Other(self, p):
| SHORT
| STATIC
| STRINGIFIER
| JSONIFIER
| TRUE
| TYPEDEF
| UNSIGNED
@@ -6958,9 +6982,12 @@ def simpleExtendedAttr(str):
nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")])
itr_ident = IDLUnresolvedIdentifier(iface.location,
iface.identifier.name + "Iterator")
toStringTag = iface.identifier.name + " Iterator"
itr_iface = IDLInterface(iface.location, self.globalScope(),
itr_ident, None, [nextMethod],
isKnownNonPartial=True)
isKnownNonPartial=True,
classNameOverride=toStringTag,
toStringTag=toStringTag)
itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")])
# Make sure the exposure set for the iterator interface is the
# same as the exposure set for the iterable interface, because
@@ -1,9 +1,9 @@
--- WebIDL.py
+++ WebIDL.py
@@ -1744,7 +1744,8 @@
identifier == "ProbablyShortLivingWrapper" or
identifier == "LegacyUnenumerableNamedProperties" or
identifier == "RunConstructorInCallerCompartment" or
identifier == "WantsEventListenerHooks" or
- identifier == "NonOrdinaryGetPrototypeOf"):
+ identifier == "NonOrdinaryGetPrototypeOf" or
+ identifier == "Abstract"):
Oops, something went wrong.

0 comments on commit dd9d526

Please sign in to comment.