From 0cca97fdf14cc7afa26391c05ac519d229165773 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 23 May 2014 17:32:38 -0400 Subject: [PATCH] Bug 1007878 part 1. Add parsing of MozMap to the WebIDL parser. r=khuey --- dom/bindings/parser/WebIDL.py | 121 ++++++++++++++++-- .../parser/tests/test_distinguishability.py | 4 + dom/bindings/parser/tests/test_mozmap.py | 39 ++++++ 3 files changed, 150 insertions(+), 14 deletions(-) create mode 100644 dom/bindings/parser/tests/test_mozmap.py diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index b6f27e753c36..7bf937ea74d3 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -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 diff --git a/dom/bindings/parser/tests/test_distinguishability.py b/dom/bindings/parser/tests/test_distinguishability.py index ee9a1372da35..044a42babcde 100644 --- a/dom/bindings/parser/tests/test_distinguishability.py +++ b/dom/bindings/parser/tests/test_distinguishability.py @@ -158,6 +158,7 @@ def WebIDLTest(parser, harness): "CallbackInterface?", "CallbackInterface2", "object", "Callback", "Callback2", "optional Dict", "optional Dict2", "sequence", "sequence", + "MozMap", "MozMap", "MozMap", "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", nonUserObjects) setDistinguishable("sequence", nonUserObjects) + setDistinguishable("MozMap", nonUserObjects) + setDistinguishable("MozMap", nonUserObjects) + setDistinguishable("MozMap", nonUserObjects) setDistinguishable("long[]", nonUserObjects) setDistinguishable("short[]", nonUserObjects) setDistinguishable("Date", allBut(argTypes, dates + ["object"])) diff --git a/dom/bindings/parser/tests/test_mozmap.py b/dom/bindings/parser/tests/test_mozmap.py new file mode 100644 index 000000000000..1a36fdd62c44 --- /dev/null +++ b/dom/bindings/parser/tests/test_mozmap.py @@ -0,0 +1,39 @@ +import WebIDL + +def WebIDLTest(parser, harness): + parser.parse(""" + dictionary Dict {}; + interface MozMapArg { + void foo(MozMap 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 arg); + }; + """) + + results = parser.finish() + except Exception,x: + threw = True + + harness.ok(threw, "Should have thrown.")