Bug 796850 - Implement WebIDL parser support for Bytestring r=bz
authorJames Kitchener <jkitch.bug@gmail.com>
Thu, 13 Jun 2013 01:15:35 -0400
changeset 146409 864acd590539268af53937b95943def6efcf903c
parent 146408 7bf20eaca9ff40d75a045d6b7ab02705d4b089b8
child 146410 2cb618e6b57c7cf8cf559f1641b41b17069ebcd4
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs796850
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 796850 - Implement WebIDL parser support for Bytestring r=bz
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_bytestring.py
dom/bindings/parser/tests/test_union.py
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -379,17 +379,17 @@ class IDLObjectWithIdentifier(IDLObject)
         for attr in attrs:
             if not attr.hasValue():
                 unhandledAttrs.append(attr)
                 continue
 
             identifier = attr.identifier()
             value = attr.value()
             if identifier == "TreatNullAs":
-                if not self.type.isString() or self.type.nullable():
+                if not self.type.isDOMString() or self.type.nullable():
                     raise WebIDLError("[TreatNullAs] is only allowed on "
                                       "arguments or attributes whose type is "
                                       "DOMString",
                                       [self.location])
                 if isDictionaryMember:
                     raise WebIDLError("[TreatNullAs] is not allowed for "
                                       "dictionary members", [self.location])
                 if value != 'EmptyString':
@@ -402,28 +402,28 @@ class IDLObjectWithIdentifier(IDLObject)
                     raise WebIDLError("[TreatUndefinedAs] is not allowed for "
                                       "dictionary members", [self.location])
                 if value == 'Missing':
                     if not isOptional:
                         raise WebIDLError("[TreatUndefinedAs=Missing] is only "
                                           "allowed on optional arguments",
                                           [self.location])
                 elif value == 'Null':
-                    if not self.type.isString():
+                    if not self.type.isDOMString():
                         raise WebIDLError("[TreatUndefinedAs=Null] is only "
                                           "allowed on arguments or "
                                           "attributes whose type is "
                                           "DOMString or DOMString?",
                                           [self.location])
                     if not self.type.nullable():
                         raise WebIDLError("[TreatUndefinedAs=Null] is only "
                                           "allowed on arguments whose type "
                                           "is DOMString?", [self.location])
                 elif value == 'EmptyString':
-                    if not self.type.isString():
+                    if not self.type.isDOMString():
                         raise WebIDLError("[TreatUndefinedAs=EmptyString] "
                                           "is only allowed on arguments or "
                                           "attributes whose type is "
                                           "DOMString or DOMString?",
                                           [self.location])
                 else:
                     raise WebIDLError("[TreatUndefinedAs] must take the "
                                       "identifiers EmptyString or Null or "
@@ -1212,16 +1212,17 @@ class IDLType(IDLObject):
         'unrestricted_float',
         'float',
         'unrestricted_double',
         # "double" last primitive type to match IDLBuiltinType
         'double',
         # Other types
         'any',
         'domstring',
+        'bytestring',
         'object',
         'date',
         'void',
         # Funny stuff
         'interface',
         'dictionary',
         'enum',
         'callback',
@@ -1251,16 +1252,22 @@ class IDLType(IDLObject):
         return False
 
     def isPrimitive(self):
         return False
 
     def isString(self):
         return False
 
+    def isByteString(self):
+        return False
+
+    def isDOMString(self):
+        return False
+
     def isVoid(self):
         return self.name == "Void"
 
     def isSequence(self):
         return False
 
     def isArray(self):
         return False
@@ -1399,16 +1406,22 @@ class IDLNullableType(IDLType):
         return self.inner.isCallback()
 
     def isPrimitive(self):
         return self.inner.isPrimitive()
 
     def isString(self):
         return self.inner.isString()
 
+    def isByteString(self):
+        return self.inner.isByteString()
+
+    def isDOMString(self):
+        return self.inner.isDOMString()
+
     def isFloat(self):
         return self.inner.isFloat()
 
     def isUnrestricted(self):
         return self.inner.isUnrestricted()
 
     def includesRestrictedFloat(self):
         return self.inner.includesRestrictedFloat()
@@ -1508,16 +1521,22 @@ class IDLSequenceType(IDLType):
         return False
 
     def isPrimitive(self):
         return False;
 
     def isString(self):
         return False;
 
+    def isByteString(self):
+        return False
+
+    def isDOMString(self):
+        return False
+
     def isVoid(self):
         return False
 
     def isSequence(self):
         return True
 
     def isArray(self):
         return False
@@ -1692,16 +1711,22 @@ class IDLArrayType(IDLType):
         return False
 
     def isPrimitive(self):
         return False
 
     def isString(self):
         return False
 
+    def isByteString(self):
+        return False
+
+    def isDOMString(self):
+        return False
+
     def isVoid(self):
         return False
 
     def isSequence(self):
         assert not self.inner.isSequence()
         return False
 
     def isArray(self):
@@ -1775,16 +1800,22 @@ class IDLTypedefType(IDLType, IDLObjectW
         return self.inner.nullable()
 
     def isPrimitive(self):
         return self.inner.isPrimitive()
 
     def isString(self):
         return self.inner.isString()
 
+    def isByteString(self):
+        return self.inner.isByteString()
+
+    def isDOMString(self):
+        return self.inner.isDOMString()
+
     def isVoid(self):
         return self.inner.isVoid()
 
     def isSequence(self):
         return self.inner.isSequence()
 
     def isArray(self):
         return self.inner.isArray()
@@ -1862,16 +1893,22 @@ class IDLWrapperType(IDLType):
         return False
 
     def isPrimitive(self):
         return False
 
     def isString(self):
         return False
 
+    def isByteString(self):
+        return False
+
+    def isDOMString(self):
+        return False
+
     def isVoid(self):
         return False
 
     def isSequence(self):
         return False
 
     def isArray(self):
         return False
@@ -1980,16 +2017,17 @@ class IDLBuiltinType(IDLType):
         'unrestricted_float',
         'float',
         'unrestricted_double',
         # IMPORTANT: "double" must be the last primitive type listed
         'double',
         # Other types
         'any',
         'domstring',
+        'bytestring',
         'object',
         'date',
         'void',
         # Funny stuff
         'ArrayBuffer',
         'ArrayBufferView',
         'Int8Array',
         'Uint8Array',
@@ -2013,16 +2051,17 @@ class IDLBuiltinType(IDLType):
             Types.unsigned_long_long: IDLType.Tags.uint64,
             Types.boolean: IDLType.Tags.bool,
             Types.unrestricted_float: IDLType.Tags.unrestricted_float,
             Types.float: IDLType.Tags.float,
             Types.unrestricted_double: IDLType.Tags.unrestricted_double,
             Types.double: IDLType.Tags.double,
             Types.any: IDLType.Tags.any,
             Types.domstring: IDLType.Tags.domstring,
+            Types.bytestring: IDLType.Tags.bytestring,
             Types.object: IDLType.Tags.object,
             Types.date: IDLType.Tags.date,
             Types.void: IDLType.Tags.void,
             Types.ArrayBuffer: IDLType.Tags.interface,
             Types.ArrayBufferView: IDLType.Tags.interface,
             Types.Int8Array: IDLType.Tags.interface,
             Types.Uint8Array: IDLType.Tags.interface,
             Types.Uint8ClampedArray: IDLType.Tags.interface,
@@ -2038,16 +2077,23 @@ class IDLBuiltinType(IDLType):
         IDLType.__init__(self, location, name)
         self.builtin = True
         self._typeTag = type
 
     def isPrimitive(self):
         return self._typeTag <= IDLBuiltinType.Types.double
 
     def isString(self):
+        return self._typeTag == IDLBuiltinType.Types.domstring or \
+               self._typeTag == IDLBuiltinType.Types.bytestring
+
+    def isByteString(self):
+        return self._typeTag == IDLBuiltinType.Types.bytestring
+
+    def isDOMString(self):
         return self._typeTag == IDLBuiltinType.Types.domstring
 
     def isInteger(self):
         return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long
 
     def isArrayBuffer(self):
         return self._typeTag == IDLBuiltinType.Types.ArrayBuffer
 
@@ -2172,16 +2218,19 @@ BuiltinTypes = {
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "UnrestrictedDouble",
                          IDLBuiltinType.Types.unrestricted_double),
       IDLBuiltinType.Types.any:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Any",
                          IDLBuiltinType.Types.any),
       IDLBuiltinType.Types.domstring:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "String",
                          IDLBuiltinType.Types.domstring),
+      IDLBuiltinType.Types.bytestring:
+          IDLBuiltinType(BuiltinLocation("<builtin type>"), "ByteString",
+                         IDLBuiltinType.Types.bytestring),
       IDLBuiltinType.Types.object:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Object",
                          IDLBuiltinType.Types.object),
       IDLBuiltinType.Types.date:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Date",
                          IDLBuiltinType.Types.date),
       IDLBuiltinType.Types.void:
           IDLBuiltinType(BuiltinLocation("<builtin type>"), "Void",
@@ -3255,16 +3304,17 @@ class Tokenizer(object):
         "creator": "CREATOR",
         "deleter": "DELETER",
         "legacycaller": "LEGACYCALLER",
         "optional": "OPTIONAL",
         "...": "ELLIPSIS",
         "::": "SCOPE",
         "Date": "DATE",
         "DOMString": "DOMSTRING",
+        "ByteString": "BYTESTRING",
         "any": "ANY",
         "boolean": "BOOLEAN",
         "byte": "BYTE",
         "double": "DOUBLE",
         "float": "FLOAT",
         "long": "LONG",
         "object": "OBJECT",
         "octet": "OCTET",
@@ -3812,18 +3862,18 @@ class Parser(Tokenizer):
                                   ("setter" if setter else "creator",
                                    "optional" if arguments[1].optional else "variadic"),
                                   [arguments[1].location])
 
         if stringifier:
             if len(arguments) != 0:
                 raise WebIDLError("stringifier has wrong number of arguments",
                                   [self.getLocation(p, 2)])
-            if not returnType.isString():
-                raise WebIDLError("stringifier must have string return type",
+            if not returnType.isDOMString():
+                raise WebIDLError("stringifier must have DOMString return type",
                                   [self.getLocation(p, 2)])
 
         inOptionalArguments = False
         variadicArgument = False
         for argument in arguments:
             # Only the last argument can be variadic
             if variadicArgument:
                 raise WebIDLError("Only the last argument can be variadic",
@@ -4122,16 +4172,17 @@ class Parser(Tokenizer):
                   | SCOPE
                   | SEMICOLON
                   | LT
                   | EQUALS
                   | GT
                   | QUESTIONMARK
                   | DATE
                   | DOMSTRING
+                  | BYTESTRING
                   | ANY
                   | ATTRIBUTE
                   | BOOLEAN
                   | BYTE
                   | LEGACYCALLER
                   | CONST
                   | CREATOR
                   | DELETER
@@ -4357,16 +4408,22 @@ class Parser(Tokenizer):
         p[0] = IDLBuiltinType.Types.unrestricted_double
 
     def p_PrimitiveOrStringTypeDOMString(self, p):
         """
             PrimitiveOrStringType : DOMSTRING
         """
         p[0] = IDLBuiltinType.Types.domstring
 
+    def p_PrimitiveOrStringTypeBytestring(self, p):
+        """
+            PrimitiveOrStringType : BYTESTRING
+        """
+        p[0] = IDLBuiltinType.Types.bytestring
+
     def p_UnsignedIntegerTypeUnsigned(self, p):
         """
             UnsignedIntegerType : UNSIGNED IntegerType
         """
         p[0] = p[2] + 1 # Adding one to a given signed integer type
                         # gets you the unsigned type.
 
     def p_UnsignedIntegerType(self, p):
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/tests/test_bytestring.py
@@ -0,0 +1,72 @@
+# -*- coding: UTF-8 -*-
+
+import WebIDL
+
+def WebIDLTest(parser, harness):
+    parser.parse("""
+        interface TestByteString {
+          attribute ByteString bs;
+          attribute DOMString ds;
+          };
+    """)
+
+    results = parser.finish();
+
+    harness.ok(True, "TestByteString interface parsed without error.")
+    
+    harness.check(len(results), 1, "Should be one production")
+    harness.ok(isinstance(results[0], WebIDL.IDLInterface),
+               "Should be an IDLInterface")
+    iface = results[0]
+    harness.check(iface.identifier.QName(), "::TestByteString", "Interface has the right QName")
+    harness.check(iface.identifier.name, "TestByteString", "Interface has the right name")
+    harness.check(iface.parent, None, "Interface has no parent")
+
+    members = iface.members
+    harness.check(len(members), 2, "Should be two productions")
+
+    attr = members[0]
+    harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute")
+    harness.check(attr.identifier.QName(), "::TestByteString::bs", "Attr has correct QName")
+    harness.check(attr.identifier.name, "bs", "Attr has correct name")
+    harness.check(str(attr.type), "ByteString", "Attr type is the correct name")
+    harness.ok(attr.type.isByteString(), "Should be ByteString type")
+    harness.ok(attr.type.isString(), "Should be String collective type")
+    harness.ok(not attr.type.isDOMString(), "Should be not be DOMString type")
+
+    # now check we haven't broken DOMStrings in the process.
+    attr = members[1]
+    harness.ok(isinstance(attr, WebIDL.IDLAttribute), "Should be an IDLAttribute")
+    harness.check(attr.identifier.QName(), "::TestByteString::ds", "Attr has correct QName")
+    harness.check(attr.identifier.name, "ds", "Attr has correct name")
+    harness.check(str(attr.type), "String", "Attr type is the correct name")
+    harness.ok(attr.type.isDOMString(), "Should be DOMString type")
+    harness.ok(attr.type.isString(), "Should be String collective type")
+    harness.ok(not attr.type.isByteString(), "Should be not be ByteString type")
+
+    # Cannot represent constant ByteString in IDL.
+    threw = False
+    try:
+        parser.parse("""
+            interface ConstByteString {
+              const ByteString foo = "hello"
+              };
+        """)
+    except WebIDL.WebIDLError:
+        threw = True
+    harness.ok(threw, "Should have thrown a WebIDL error")
+
+    # Cannot have optional ByteStrings with default values
+    threw = False
+    try:
+        parser.parse("""
+            interface OptionalByteString {
+              void passByteString(optional ByteString arg = "hello");
+              };
+        """)
+        results2 = parser.finish();
+    except WebIDL.WebIDLError:
+        threw = True
+
+    harness.ok(threw, "Should have thrown a WebIDL error")
+
--- a/dom/bindings/parser/tests/test_union.py
+++ b/dom/bindings/parser/tests/test_union.py
@@ -57,16 +57,17 @@ def WebIDLTest(parser, harness):
              "long",
              "unsigned long",
              "long long",
              "unsigned long long",
              "boolean",
              "byte",
              "octet",
              "DOMString",
+             "ByteString",
              #"sequence<float>",
              "object",
              "ArrayBuffer",
              #"Date",
              "TestInterface1",
              "TestInterface2"]
 
     testPre = """