Bug 883493: Switch CGUnionReturnValueStruct to use CGClass r=bz
authorDavid Zbarsky <dzbarsky@gmail.com>
Fri, 09 Aug 2013 21:17:51 -0400
changeset 142153 cb152e57f23b30944a940f6381a7192df73153a6
parent 142152 667ff57c79bcc3d043397bc398b06d1ab6fb3fc9
child 142154 803d0a3d53072291cedea96ae7eecdd15143faee
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbz
bugs883493
milestone26.0a1
Bug 883493: Switch CGUnionReturnValueStruct to use CGClass r=bz
dom/bindings/Codegen.py
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6192,144 +6192,106 @@ class CGUnionReturnValueStruct(CGThing):
         self.type = type.unroll()
         self.descriptorProvider = descriptorProvider
         self.templateVars = map(
             lambda t: getUnionTypeTemplateVars(self.type, t,
                                                self.descriptorProvider,
                                                isReturnValue=True),
             self.type.flatMemberTypes)
 
+        self.struct = self.getStruct()
+
     def declare(self):
-        templateVars = self.templateVars
-
-        enumValues = []
-        methods = []
-        if self.type.hasNullableType:
-            enumValues.append("eNull")
-            methods.append("""  bool IsNull() const
-  {
-    return mType == eNull;
-  }
-
-  bool SetNull()
-  {
-    mType = eNull;
-    return true;
-  }""")
-
-        enumValues.extend(mapTemplate("e${name}", templateVars))
-        methodTemplate = "  ${structType}& SetAs${name}();"
-        methods.extend(mapTemplate(methodTemplate, templateVars))
-        values = mapTemplate("UnionMember<${structType} > m${name};", templateVars)
-        return string.Template("""
-class ${structName}ReturnValue {
-public:
-  ${structName}ReturnValue() : mType(eUninitialized)
-  {
-  }
-  ~${structName}ReturnValue();
-
-${methods}
-
-  bool ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj,
-               JS::MutableHandle<JS::Value> rval) const;
-
-private:
-  // Disallow copy-construction and assignment
-  ${structName}ReturnValue(const ${structName}ReturnValue&) MOZ_DELETE;
-  void operator=(const ${structName}ReturnValue&) MOZ_DELETE;
-
-  enum Type {
-    eUninitialized,
-    ${enumValues}
-  };
-  union Value {
-    ${values}
-  };
-
-  Type mType;
-  Value mValue;
-};
-
-""").substitute(
-    {
-       "structName": self.type.__str__(),
-       "methods": "\n\n".join(methods),
-       "enumValues": ",\n    ".join(enumValues),
-       "values": "\n    ".join(values)
-       })
+        return self.struct.declare()
 
     def define(self):
-        templateVars = self.templateVars
+        return self.struct.define()
+
+    def toJSValMethod(self):
         conversionsToJS = []
         if self.type.hasNullableType:
             conversionsToJS.append("    case eNull:\n"
                                    "    {\n"
                                    "      rval.setNull();\n"
                                    "      return true;\n"
                                    "    }")
         conversionsToJS.extend(
             map(self.getConversionToJS,
-                zip(templateVars, self.type.flatMemberTypes)))
-
-        toJSVal = string.Template("""
-
-bool
-${structName}ReturnValue::ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj, JS::MutableHandle<JS::Value> rval) const
-{
-  switch (mType) {
-${doConversionsToJS}
-
-    case eUninitialized:
-    {
-      break;
-    }
-  }
-  return false;
-}
-""").substitute({
-                "structName": str(self.type),
-                "doConversionsToJS": "\n\n".join(conversionsToJS)
-                })
-        templateVars = self.templateVars
-
-        methods = []
-        methodTemplate = """${structType}&
-%sReturnValue::SetAs${name}()
-{
-  mType = e${name};
-  return mValue.m${name}.SetValue();
-}""" % str(self.type)
-        methods.extend(mapTemplate(methodTemplate, templateVars))
-
-        callDestructors = []
-        if self.type.hasNullableType:
-            callDestructors.append("      case eNull:\n"
-                                   "        break;")
-        callDestructors.extend(mapTemplate("    case e${name}:\n"
-                                           "       mValue.m${name}.Destroy();\n"
-                                           "       mType = eUninitialized;\n"
-                                           "       break;", templateVars))
-        destructor = string.Template("""
-${structName}ReturnValue::~${structName}ReturnValue()
-{
-  switch (mType) {
-${callDestructors}
-    case eUninitialized:
-      break;
+                zip(self.templateVars, self.type.flatMemberTypes)))
+
+        body = """
+switch (mType) {
+%s
+  case eUninitialized:
+  {
+    break;
   }
 }
-
-""").substitute(
-    {
-       "structName": self.type.__str__(),
-       "callDestructors": "\n".join(callDestructors),
-       })
-
-        return destructor + "\n\n".join(methods) + toJSVal
+return false;
+""" % ("\n\n".join(conversionsToJS))
+
+        return ClassMethod("ToJSVal", "bool", [
+            Argument("JSContext*", "cx"),
+            Argument("JS::Handle<JSObject*>", "scopeObj"),
+            Argument("JS::MutableHandle<JS::Value>", "rval")
+        ], body=body, const=True)
+
+    def getStruct(self):
+
+        members = [ClassMember("mType", "Type", body="eUninitialized"),
+                   ClassMember("mValue", "Value")]
+        ctor = ClassConstructor([], bodyInHeader=True, visibility="public",
+                                explicit=True)
+
+        templateVars = self.templateVars
+        methods = [self.toJSValMethod()]
+        enumValues = ["eUninitialized"]
+        unionValues = []
+        callDestructors = ""
+        if self.type.hasNullableType:
+            enumValues.append("eNull")
+            methods.append(ClassMethod("IsNull", "bool", [], const=True, inline=True,
+                                       body="return mType == eNull;"))
+            methods.append(ClassMethod("SetNull", "void", [], inline=True,
+                                       body="mType = eNull;"))
+            callDestructors += ("\n  case eNull:\n"
+                                "    break;")
+        for t in self.type.flatMemberTypes:
+            vars = getUnionTypeTemplateVars(self.type,
+                       t, self.descriptorProvider, isReturnValue=True)
+            body=string.Template("mType = e${name};\n"
+                                 "return mValue.m${name}.SetValue();").substitute(vars)
+            methods.append(ClassMethod("SetAs" + vars["name"],
+                                       vars["structType"] + "&",
+                                       [],
+                                       body=body))
+            unionValues.append(string.Template("UnionMember<${structType} > "
+                                               "m${name}").substitute(vars))
+            enumValues.append("e" + vars["name"])
+
+            callDestructors += string.Template("case e${name}:\n"
+                                               "  mValue.m${name}.Destroy();\n"
+                                               "  mType = eUninitialized;\n"
+                                               "  break;").substitute(vars)
+
+        dtor = """
+switch (mType) {%s
+  case eUninitialized:
+    break;
+}
+""" % callDestructors
+
+        return CGClass(self.type.__str__() + "ReturnValue",
+                       members=members,
+                       constructors=[ctor],
+                       methods=methods,
+                       disallowCopyConstruction=True,
+                       destructor=ClassDestructor(visibility="public", body=dtor),
+                       enums=[ClassEnum("Type", enumValues, visibility="private")],
+                       unions=[ClassUnion("Value", unionValues, visibility="private")])
 
     def getConversionToJS(self, arg):
         (templateVars, type) = arg
         assert not type.nullable() # flatMemberTypes never has nullable types
         val = "mValue.m%(name)s.Value()" % templateVars
         wrapCode = wrapForType(
             type, self.descriptorProvider,
             {
@@ -6338,17 +6300,17 @@ bool
                 "obj": "scopeObj",
                 "result": val,
                 })
         return CGIndenter(CGList([CGGeneric("case e%(name)s:" % templateVars),
                                   CGWrapper(CGIndenter(CGGeneric(wrapCode)),
                                             pre="{\n",
                                             post="\n}")],
                                  "\n"),
-                          4).define()
+                          2).define()
 
 class CGUnionConversionStruct(CGThing):
     def __init__(self, type, descriptorProvider):
         CGThing.__init__(self)
         self.type = type.unroll()
         self.descriptorProvider = descriptorProvider
 
     def declare(self):
@@ -6745,48 +6707,61 @@ class ClassEnum(ClassItem):
     def __init__(self, name, entries, values=None, visibility="public"):
         self.entries = entries
         self.values = values
         ClassItem.__init__(self, name, visibility)
 
     def declare(self, cgClass):
         entries = []
         for i in range(0, len(self.entries)):
-            if i >= len(self.values):
+            if not self.values or i >= len(self.values):
                 entry = '%s' % self.entries[i]
             else:
                 entry = '%s = %s' % (self.entries[i], self.values[i])
             entries.append(entry)
         name = '' if not self.name else ' ' + self.name
         return 'enum%s\n{\n  %s\n};\n' % (name, ',\n  '.join(entries))
 
     def define(self, cgClass):
         # Only goes in the header
         return ''
 
+class ClassUnion(ClassItem):
+    def __init__(self, name, entries, visibility="public"):
+        self.entries = [entry + ";" for entry in entries]
+        ClassItem.__init__(self, name, visibility)
+
+    def declare(self, cgClass):
+        return 'union %s\n{\n  %s\n};\n' % (self.name, '\n  '.join(self.entries))
+
+    def define(self, cgClass):
+        # Only goes in the header
+        return ''
+
 class CGClass(CGThing):
     def __init__(self, name, bases=[], members=[], constructors=[],
                  destructor=None, methods=[],
-                 typedefs = [], enums=[], templateArgs=[],
+                 typedefs = [], enums=[], unions=[], templateArgs=[],
                  templateSpecialization=[], isStruct=False,
                  disallowCopyConstruction=False, indent='',
                  decorators='',
                  extradeclarations='',
                  extradefinitions=''):
         CGThing.__init__(self)
         self.name = name
         self.bases = bases
         self.members = members
         self.constructors = constructors
         # We store our single destructor in a list, since all of our
         # code wants lists of members.
         self.destructors = [destructor] if destructor else []
         self.methods = methods
         self.typedefs = typedefs
         self.enums = enums
+        self.unions = unions
         self.templateArgs = templateArgs
         self.templateSpecialization = templateSpecialization
         self.isStruct = isStruct
         self.disallowCopyConstruction = disallowCopyConstruction
         self.indent = indent
         self.defaultVisibility ='public' if isStruct else 'private'
         self.decorators = decorators
         self.extradeclarations = extradeclarations
@@ -6872,22 +6847,24 @@ class CGClass(CGThing):
             return (result, lastVisibility, itemCount)
 
         if self.disallowCopyConstruction:
             class DisallowedCopyConstructor(object):
                 def __init__(self):
                     self.visibility = "private"
                 def declare(self, cgClass):
                     name = cgClass.getNameString()
-                    return "%s(const %s&) MOZ_DELETE;\n" % (name, name)
+                    return ("%s(const %s&) MOZ_DELETE;\n"
+                            "void operator=(const %s) MOZ_DELETE;\n" % (name, name, name))
             disallowedCopyConstructors = [DisallowedCopyConstructor()]
         else:
             disallowedCopyConstructors = []
 
-        order = [(self.enums, ''), (self.typedefs, ''), (self.members, ''),
+        order = [(self.enums, ''), (self.unions, ''),
+                 (self.typedefs, ''), (self.members, ''),
                  (self.constructors + disallowedCopyConstructors, '\n'),
                  (self.destructors, '\n'), (self.methods, '\n')]
 
         lastVisibility = self.defaultVisibility
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, lastVisibility, itemCount) = \
                 declareMembers(self, memberList, lastVisibility, itemCount,