Bug 1007878 part 1. Add parsing of MozMap to the WebIDL parser. r=khuey

This commit is contained in:
Boris Zbarsky 2014-05-23 17:32:38 -04:00
parent 851ee8aa7c
commit 67e904587e
3 changed files with 150 additions and 14 deletions

View File

@ -1200,9 +1200,10 @@ class IDLDictionary(IDLObjectWithScope):
None, if the boolean value in the first element is False.
"""
if memberType.nullable() or \
memberType.isArray() or \
memberType.isSequence():
if (memberType.nullable() or
memberType.isArray() or
memberType.isSequence() or
memberType.isMozMap()):
return typeContainsDictionary(memberType.inner, dictionary)
if memberType.isDictionary():
@ -1320,6 +1321,7 @@ class IDLType(IDLObject):
'callback',
'union',
'sequence',
'mozmap',
'array'
)
@ -1367,6 +1369,9 @@ class IDLType(IDLObject):
def isSequence(self):
return False
def isMozMap(self):
return False
def isArray(self):
return False
@ -1549,6 +1554,9 @@ class IDLNullableType(IDLType):
def isSequence(self):
return self.inner.isSequence()
def isMozMap(self):
return self.inner.isMozMap()
def isArray(self):
return self.inner.isArray()
@ -1701,6 +1709,60 @@ class IDLSequenceType(IDLType):
def _getDependentObjects(self):
return self.inner._getDependentObjects()
class IDLMozMapType(IDLType):
# XXXbz This is pretty similar to IDLSequenceType in various ways.
# And maybe to IDLNullableType. Should we have a superclass for
# "type containing this other type"? Bug 1015318.
def __init__(self, location, parameterType):
assert not parameterType.isVoid()
IDLType.__init__(self, location, parameterType.name)
self.inner = parameterType
self.builtin = False
def __eq__(self, other):
return isinstance(other, IDLMozMapType) and self.inner == other.inner
def __str__(self):
return self.inner.__str__() + "MozMap"
def isMozMap(self):
return True
def includesRestrictedFloat(self):
return self.inner.includesRestrictedFloat()
def tag(self):
return IDLType.Tags.mozmap
def resolveType(self, parentScope):
assert isinstance(parentScope, IDLScope)
self.inner.resolveType(parentScope)
def isComplete(self):
return self.inner.isComplete()
def complete(self, scope):
self.inner = self.inner.complete(scope)
self.name = self.inner.name
return self
def unroll(self):
# We do not unroll our inner. Just stop at ourselves. That
# lets us add headers for both ourselves and our inner as
# needed.
return self
def isDistinguishableFrom(self, other):
if other.isUnion():
# Just forward to the union; it'll deal
return other.isDistinguishableFrom(self)
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isDate() or other.isNonCallbackInterface())
def _getDependentObjects(self):
return self.inner._getDependentObjects()
class IDLUnionType(IDLType):
def __init__(self, location, memberTypes):
IDLType.__init__(self, location, "")
@ -1744,7 +1806,8 @@ class IDLUnionType(IDLType):
return typeName(type._identifier.object())
if isinstance(type, IDLObjectWithIdentifier):
return typeName(type.identifier)
if isinstance(type, IDLType) and (type.isArray() or type.isSequence()):
if (isinstance(type, IDLType) and
(type.isArray() or type.isSequence() or type.isMozMap)):
return str(type)
return type.name
@ -1816,6 +1879,9 @@ class IDLArrayType(IDLType):
if parameterType.isSequence():
raise WebIDLError("Array type cannot parameterize over a sequence type",
[location])
if parameterType.isMozMap():
raise WebIDLError("Array type cannot parameterize over a MozMap type",
[location])
if parameterType.isDictionary():
raise WebIDLError("Array type cannot parameterize over a dictionary type",
[location])
@ -1946,6 +2012,9 @@ class IDLTypedefType(IDLType, IDLObjectWithIdentifier):
def isSequence(self):
return self.inner.isSequence()
def isMozMap(self):
return self.inner.isMozMap()
def isArray(self):
return self.inner.isArray()
@ -2100,7 +2169,7 @@ class IDLWrapperType(IDLType):
if self.isEnum():
return (other.isPrimitive() or other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isArray() or
other.isSequence() or other.isMozMap() or other.isArray() or
other.isDate())
if self.isDictionary() and other.nullable():
return False
@ -2122,7 +2191,7 @@ class IDLWrapperType(IDLType):
(self.isNonCallbackInterface() or
other.isNonCallbackInterface()))
if (other.isDictionary() or other.isCallback() or
other.isSequence() or other.isArray()):
other.isSequence() or other.isMozMap() or other.isArray()):
return self.isNonCallbackInterface()
# Not much else |other| can be
@ -2296,19 +2365,19 @@ class IDLBuiltinType(IDLType):
return (other.isNumeric() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isArray() or
other.isSequence() or other.isMozMap() or other.isArray() or
other.isDate())
if self.isNumeric():
return (other.isBoolean() or other.isString() or other.isEnum() or
other.isInterface() or other.isObject() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isArray() or
other.isSequence() or other.isMozMap() or other.isArray() or
other.isDate())
if self.isString():
return (other.isPrimitive() or other.isInterface() or
other.isObject() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isArray() or
other.isSequence() or other.isMozMap() or other.isArray() or
other.isDate())
if self.isAny():
# Can't tell "any" apart from anything
@ -2319,7 +2388,7 @@ class IDLBuiltinType(IDLType):
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isInterface() or other.isCallback() or
other.isDictionary() or other.isSequence() or
other.isArray())
other.isMozMap() or other.isArray())
if self.isVoid():
return not other.isVoid()
# Not much else we could be!
@ -2327,7 +2396,8 @@ class IDLBuiltinType(IDLType):
# Like interfaces, but we know we're not a callback
return (other.isPrimitive() or other.isString() or other.isEnum() or
other.isCallback() or other.isDictionary() or
other.isSequence() or other.isArray() or other.isDate() or
other.isSequence() or other.isMozMap() or other.isArray() or
other.isDate() or
(other.isInterface() and (
# ArrayBuffer is distinguishable from everything
# that's not an ArrayBuffer or a callback interface
@ -2710,6 +2780,9 @@ class IDLAttribute(IDLInterfaceMember):
if self.type.isSequence() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("A non-cached attribute cannot be of a sequence "
"type", [self.location])
if self.type.isMozMap() and not self.getExtendedAttribute("Cached"):
raise WebIDLError("A non-cached attribute cannot be of a MozMap "
"type", [self.location])
if self.type.isUnion():
for f in self.type.unroll().flatMemberTypes:
if f.isDictionary():
@ -2724,6 +2797,12 @@ class IDLAttribute(IDLInterfaceMember):
"one of its member types's member "
"types, and so on) is a sequence "
"type", [self.location, f.location])
if f.isMozMap():
raise WebIDLError("An attribute cannot be of a union "
"type if one of its member types (or "
"one of its member types's member "
"types, and so on) is a MozMap "
"type", [self.location, f.location])
if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"):
raise WebIDLError("An attribute with [PutForwards] must have an "
"interface type as its type", [self.location])
@ -2742,9 +2821,11 @@ class IDLAttribute(IDLInterfaceMember):
"getter won't always be called.",
[self.location])
if self.getExtendedAttribute("Frozen"):
if not self.type.isSequence() and not self.type.isDictionary():
raise WebIDLError("[Frozen] is only allowed on sequence-valued "
"and dictionary-valued attributes",
if (not self.type.isSequence() and not self.type.isDictionary() and
not self.type.isMozMap()):
raise WebIDLError("[Frozen] is only allowed on "
"sequence-valued, dictionary-valued, and "
"MozMap-valued attributes",
[self.location])
def handleExtendedAttribute(self, attr):
@ -3627,6 +3708,7 @@ class Tokenizer(object):
"octet": "OCTET",
"optional": "OPTIONAL",
"sequence": "SEQUENCE",
"MozMap": "MOZMAP",
"short": "SHORT",
"unsigned": "UNSIGNED",
"void": "VOID",
@ -4523,6 +4605,7 @@ class Parser(Tokenizer):
| OCTET
| OPTIONAL
| SEQUENCE
| MOZMAP
| SETTER
| SHORT
| STATIC
@ -4632,6 +4715,16 @@ class Parser(Tokenizer):
type = IDLNullableType(self.getLocation(p, 5), type)
p[0] = type
def p_NonAnyTypeMozMapType(self, p):
"""
NonAnyType : MOZMAP LT Type GT Null
"""
innerType = p[3]
type = IDLMozMapType(self.getLocation(p, 1), innerType)
if p[5]:
type = IDLNullableType(self.getLocation(p, 5), type)
p[0] = type
def p_NonAnyTypeScopedName(self, p):
"""
NonAnyType : ScopedName TypeSuffix

View File

@ -158,6 +158,7 @@ def WebIDLTest(parser, harness):
"CallbackInterface?", "CallbackInterface2",
"object", "Callback", "Callback2", "optional Dict",
"optional Dict2", "sequence<long>", "sequence<short>",
"MozMap<object>", "MozMap<Dict>", "MozMap<long>",
"long[]", "short[]", "Date", "Date?", "any" ]
# When we can parse Date and RegExp, we need to add them here.
@ -219,6 +220,9 @@ def WebIDLTest(parser, harness):
setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables))
setDistinguishable("sequence<long>", nonUserObjects)
setDistinguishable("sequence<short>", nonUserObjects)
setDistinguishable("MozMap<object>", nonUserObjects)
setDistinguishable("MozMap<Dict>", nonUserObjects)
setDistinguishable("MozMap<long>", nonUserObjects)
setDistinguishable("long[]", nonUserObjects)
setDistinguishable("short[]", nonUserObjects)
setDistinguishable("Date", allBut(argTypes, dates + ["object"]))

View File

@ -0,0 +1,39 @@
import WebIDL
def WebIDLTest(parser, harness):
parser.parse("""
dictionary Dict {};
interface MozMapArg {
void foo(MozMap<Dict> arg);
};
""")
results = parser.finish()
harness.check(len(results), 2, "Should know about two things");
harness.ok(isinstance(results[1], WebIDL.IDLInterface),
"Should have an interface here");
members = results[1].members
harness.check(len(members), 1, "Should have one member")
harness.ok(members[0].isMethod(), "Should have method")
signature = members[0].signatures()[0]
args = signature[1]
harness.check(len(args), 1, "Should have one arg")
harness.ok(args[0].type.isMozMap(), "Should have a MozMap type here")
harness.ok(args[0].type.inner.isDictionary(),
"Should have a dictionary inner type")
parser = parser.reset()
threw = False
try:
parser.parse("""
interface MozMapVoidArg {
void foo(MozMap<void> arg);
};
""")
results = parser.finish()
except Exception,x:
threw = True
harness.ok(threw, "Should have thrown.")