Switch more stuff to the CodegenThing infrastructure.
authorBobby Holley <bobbyholley@gmail.com>
Thu, 26 Jan 2012 19:36:15 +0100
changeset 85150 cc2e300dab5b4a3beea5b95d2e9b32337cb032a0
parent 85149 4119ff5bd1104150455174319f6f1edba3d41c8f
child 85151 45bb8983777618c73775dcb52c81255764b5ae38
push id52
push userbobbyholley@gmail.com
push dateThu, 26 Jan 2012 18:36:36 +0000
milestone12.0a1
Switch more stuff to the CodegenThing infrastructure.
dom/bindings/BindingGen.py
dom/bindings/Codegen.py
--- a/dom/bindings/BindingGen.py
+++ b/dom/bindings/BindingGen.py
@@ -1,16 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import os
 import cPickle
 import WebIDL
-from Codegen import Configuration, DOMClass, DOMClassImplementation
+from Codegen import *
 
 def generate_binding_header(config, outputprefix):
     """
     protoList is the list of prototypes defined by this binding
     outputprefix is a prefix to use for the header guards and filename
     """
 
     filename = outputprefix + ".h"
@@ -25,60 +25,37 @@ def generate_binding_header(config, outp
 
 #include "mozilla/dom/bindings/DOMJSClass.h"
 #include "mozilla/dom/bindings/Utils.h"
 
 namespace mozilla {
 namespace dom {
 namespace bindings {
 namespace prototypes {
+
 """ % (outputprefix, outputprefix)
 
-    chunk = """
-namespace %s {
-  extern DOMJSClass Class;
-
-  JSObject* CreateProtoObject(JSContext* aCx, JSObject* aGlobal);
-
-  /* Get the prototype object for this class.  This will create the prototype
-     as needed. */
-  JSObject* GetProtoObject(JSContext* aCx, JSObject* aGlobal) {
-    /* Make sure our global is sane.  Hopefully we can remove this sometime */
-    if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
-      return NULL;
-    }
-    /* Check to see whether the prototype is already installed */
-    JSObject **protoArray =
-      static_cast<JSObject**>(js::GetReservedSlot(aGlobal, DOM_PROTOTYPE_SLOT).toPrivate());
-    JSObject *ourProto = protoArray[id::%s];
-    if (!ourProto) {
-      ourProto = protoArray[id::%s] = CreateProtoObject(aCx, aGlobal);
-    }
-
-    /* ourProto might _still_ be null, but that's OK */
-    return ourProto;
-  }
-}
-"""
-
     epilogue = """
 } // namespace prototypes
 } // namespace bindings
 } // namespace dom
 } // namespace mozilla
 
 #endif // %s_h
 """ % (outputprefix)
 
     # Write from templates.
     f.write(prologue)
     for domClass in config.dom_classes.values():
         for implementation in domClass.implementations:
-            f.write(chunk % (implementation.name, implementation.name,
-                             implementation.name))
+            f.write("namespace %s {\n" % (implementation.name))
+            for cgThing in implementation.codegenThings:
+                f.write(cgThing.declare())
+            f.write("\n} // namespace %s\n\n" % (implementation.name))
+
     f.write(epilogue)
     f.close()
 
 def generate_binding_cpp(config, outputprefix):
     """
     protoStructure is a list containing information about the prototypes
     this binding file defines.  Each entry is a dict with the following entries:
 
@@ -108,80 +85,36 @@ def generate_binding_cpp(config, outputp
 
 %s
 #include "%s.h"
 
 namespace mozilla {
 namespace dom {
 namespace bindings {
 namespace prototypes {
+
 """ % (includes, outputprefix)
 
-    chunk = """
-namespace %s {
-
-DOMJSClass Class = {
-  { "%s",
-    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
-    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-  },
-    {%s}, -1, %s
-};
-
-JSObject*
-CreateProtoObject(JSContext* aCx, JSObject* aGlobal)
-{
-%s
-}
-
-} // namespace %s
-"""
-
-    createProtoTemplate = """  JSObject* parentProto = %s;
-  if (!parentProto) {
-    return NULL;
-  }
-
-  JSObject* ourProto = JS_NewObject(aCx, NULL, parentProto, aGlobal);
-  if (!ourProto) {
-    return NULL;
-  }
-  // XXXbz actually set up methods/properties here
-  return ourProto;
-"""
-
     epilogue = """
 } // namespace prototypes
 } // namespace bindings
 } // namespace dom
 } // namespace mozilla
 """
 
     # Write from templates.
     f.write(prologue)
     for domClass in config.dom_classes.values():
         for implementation in domClass.implementations:
-            interfaceChain = domClass.interfaceChain
-            interfaceChainString = ', '.join(['id::' + iface for iface in interfaceChain])
-            if (len(interfaceChain) == 1):
-                getParentProto = "GetCanonicalObjectProto(aCx, aGlobal)"
-            else:
-                # The last entry of interfaceChain is ourselves; we want
-                # the entry before that one.
-                parentProtoName = interfaceChain[-2]
-                getParentProto = ("%s::GetProtoObject(aCx, aGlobal)" %
-                                  parentProtoName)
-
-            createProto = createProtoTemplate % (getParentProto)
-                
-            f.write(chunk % (implementation.name, domClass.name, interfaceChainString,
-                             str(implementation.nativeIsISupports).lower(),
-                             createProto, implementation.name))
+            f.write("namespace %s {\n\n" % (implementation.name))
+            for cgThing in implementation.codegenThings:
+                definition = cgThing.define()
+                if definition:
+                    f.write(cgThing.define() + "\n")
+            f.write("} // namespace %s\n\n" % (implementation.name))
     f.write(epilogue)
     f.close()
 
 def main():
 
     # Parse arguments.
     from optparse import OptionParser
     usagestring = "usage: %prog configFile outputPrefix webIDLFile"
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -8,62 +8,140 @@ class CodegenThing():
     """
     Abstract base case for things that spit out code within a class.
     """
     def __init__(self, implementation):
         self.implementation = implementation
     def declare(self):
         """Produce code for a header file."""
         return "" # Override me!
-    def implement(self):
+    def define(self):
         """Produce code for a cpp file."""
         return "" # Override me!
 
+class DOMJSClass(CodegenThing):
+    def __init__(self, implementation):
+        CodegenThing.__init__(self, implementation)
+    def declare(self):
+        return "extern DOMJSClass Class;\n\n"
+    def define(self):
+        interfaceChainString = ', '.join(['id::' + iface \
+                                          for iface in self.implementation.domClass.interfaceChain])
+        return """DOMJSClass Class = {
+  { "%s",
+    JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+  },
+    {%s}, -1, %s
+};
+""" % (self.implementation.domClass.name, interfaceChainString,
+       str(self.implementation.nativeIsISupports).lower())
+
+
+
+
 class Argument():
     def __init__(self, argType, name):
         self.argType = argType
         self.name = name
     def __str__(self):
         return self.argType + ' ' + self.name
 
 class AbstractMethod(CodegenThing):
-    def __init__(self, implementation, name, returnType, args):
+    def __init__(self, implementation, name, returnType, args, inline=False):
         CodegenThing.__init__(self, implementation)
         self.name = name
         self.returnType = returnType
         self.args = args
+        self.inline = inline
+    def _argstring(self):
+        return ', '.join([str(a) for a in self.args])
     def declare(self):
-        return "%s %s(%s);\n" % (self.returnType, self.name, ', '.join(self.args))
+        if self.inline:
+            return self._define()
+        return "%s %s(%s);\n" % (self.returnType, self.name, self._argstring())
+    def _define(self):
+        return self.definition_prologue() + self.definition_body() + self.definition_epilogue()
     def define(self):
-        return self.definition_prologue() + self.definition_body() + self.definition_epilogue()
+        return "" if self.inline else self._define()
     def definition_prologue(self):
-        return "%s\n%s(%s)\n{\n"
+        maybeNewline = "" if self.inline else "\n"
+        return "%s%s%s(%s)\n{" % (self.returnType, maybeNewline, self.name, self._argstring())
     def definition_epilogue(self):
         return "\n}\n"
     def definition_body(self):
         return "" # Override me!
 
-class InstallMethod(AbstractMethod):
+class CreateProtoObjectMethod(AbstractMethod):
     def __init__(self, implementation):
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
-        AbstractMethod.__init__(self, implementation, 'Install', 'bool', args)
+        AbstractMethod.__init__(self, implementation, 'CreateProtoObject', 'JSObject*', args)
     def definition_body(self):
-        return 'return false;\n'
+        interfaceChain = self.implementation.domClass.interfaceChain
+        if len(interfaceChain) == 1:
+            getParentProto = "GetCanonicalObjectProto(aCx, aGlobal)"
+        else:
+            parentProtoName = self.implementation.domClass.interfaceChain[-2]
+            getParentProto = "%s::GetProtoObject(aCx, aGlobal)" % (parentProtoName)
+        return """
+  JSObject* parentProto = %s;
+  if (!parentProto) {
+    return NULL;
+  }
+
+  JSObject* ourProto = JS_NewObject(aCx, NULL, parentProto, aGlobal);
+  if (!ourProto) {
+    return NULL;
+  }
+  // XXXbz actually set up methods/properties here
+  return ourProto;""" % (getParentProto)
+
+class GetProtoObjectMethod(AbstractMethod):
+    def __init__(self, implementation):
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal')]
+        AbstractMethod.__init__(self, implementation, 'GetProtoObject',
+                                'JSObject*', args, inline=True)
+    def definition_body(self):
+        return """
+    /* Get the prototype object for this class.  This will create the prototype
+       as needed. */
+
+    /* Make sure our global is sane.  Hopefully we can remove this sometime */
+    if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
+      return NULL;
+    }
+    /* Check to see whether the prototype is already installed */
+    JSObject **protoArray =
+      static_cast<JSObject**>(js::GetReservedSlot(aGlobal, DOM_PROTOTYPE_SLOT).toPrivate());
+    JSObject *ourProto = protoArray[id::%s];
+    if (!ourProto) {
+      ourProto = protoArray[id::%s] = CreateProtoObject(aCx, aGlobal);
+    }
+
+    /* ourProto might _still_ be null, but that's OK */
+    return ourProto;""" % (self.implementation.domClass.name, self.implementation.domClass.name)
+
 
 class DOMClassImplementation():
     def __init__(self, domClass, implConf):
         self.domClass = domClass
         self.nativeClass = implConf['nativeClass']
         self.workers = implConf.get('workers', False)
         if self.workers:
             self.name = domClass.name + '_workers'
         else:
             self.name = domClass.name
         self.nativeIsISupports = not self.workers
 
+        # XXXbholley - Not everything should actually have a jsclass.
+        self.codegenThings = [DOMJSClass(self), CreateProtoObjectMethod(self),
+                              GetProtoObjectMethod(self)]
+
 class DOMClass():
     def __init__(self, classConf, interface):
         self.name = classConf['name']
         self.implementations = [DOMClassImplementation(self, implConf) for implConf in classConf['implementations']]
 
         # Build the interface chain.
         self.interfaceChain = [self.name]
         parent = interface.parent