[gobject-introspection/wip/transformer] [codegen] Split out C code generation into separate module



commit 4646377db284d9c2e69651d68bda53dc92b42a08
Author: Colin Walters <walters verbum org>
Date:   Fri Jul 30 08:41:52 2010 -0400

    [codegen] Split out C code generation into separate module
    
    The Everything generator just becomes a particular instance of
    a generation from a GIR ast to C code.

 giscanner/Makefile.am    |    2 +
 giscanner/codegen.py     |  173 ++++++++++++++++++++++++++++++++++++++++++++++
 giscanner/scannermain.py |    9 ++-
 giscanner/testcodegen.py |  150 +++++++++-------------------------------
 4 files changed, 214 insertions(+), 120 deletions(-)
---
diff --git a/giscanner/Makefile.am b/giscanner/Makefile.am
index 6a83826..1eaea76 100644
--- a/giscanner/Makefile.am
+++ b/giscanner/Makefile.am
@@ -36,6 +36,7 @@ pkgpyexec_PYTHON = 		\
 	annotationparser.py	\
 	ast.py			\
 	cachestore.py		\
+	codegen.py		\
 	config.py		\
 	dumper.py		\
 	finaltransformer.py	\
@@ -49,6 +50,7 @@ pkgpyexec_PYTHON = 		\
 	shlibs.py		\
 	scannermain.py		\
 	sourcescanner.py	\
+	testcodegen.py		\
 	transformer.py		\
 	utils.py		\
 	xmlwriter.py
diff --git a/giscanner/codegen.py b/giscanner/codegen.py
new file mode 100644
index 0000000..1f4b56c
--- /dev/null
+++ b/giscanner/codegen.py
@@ -0,0 +1,173 @@
+# -*- Mode: Python -*-
+# GObject-Introspection - a framework for introspecting GObject libraries
+# Copyright (C) 2010  Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+import os, sys
+from contextlib import contextmanager
+from .ast import *
+from .glibast import *
+
+class CCodeGenerator(object):
+    def __init__(self, namespace, out_h_filename, out_c_filename):
+        self.out_h_filename = out_h_filename
+        self.out_c_filename = out_c_filename
+        self.out_h = open(out_h_filename, 'w')
+        self.out_c = open(out_c_filename, 'w')
+        self._function_bodies = {}
+        self.namespace = namespace
+
+    def gen_symbol(self, name):
+        name = name.replace(' ', '_')
+        return '%s_%s' % (self.namespace.uscore_prefix, name)
+
+    def _typecontainer_to_ctype(self, param):
+        if (isinstance(param, Parameter) and
+            param.direction in (PARAM_DIRECTION_OUT,
+                                PARAM_DIRECTION_INOUT)):
+            suffix = '*'
+        else:
+            suffix = ''
+        if (param.type.is_equiv((TYPE_STRING, TYPE_FILENAME)) and
+            param.transfer == PARAM_TRANSFER_NONE):
+            return "const gchar*" + suffix
+        return param.type.ctype + suffix
+
+    def _write_prelude(self, out, func):
+        out.write("""
+%s
+%s (""" % (self._typecontainer_to_ctype(func.retval), func.symbol))
+        l = len(func.parameters)
+        if func.parameters:
+            for i,param in enumerate(func.parameters):
+                ctype = self._typecontainer_to_ctype(param)
+                out.write('%s %s' % (ctype, param.argname))
+                if i < l - 1:
+                    out.write(", ")
+        else:
+            out.write('void')
+        out.write(")")
+
+    def _write_prototype(self, func):
+        self._write_prelude(self.out_h, func)
+        self.out_h.write(";\n\n")
+
+    def _write_annotation_transfer(self, transfer):
+        self.out_c.write("(transfer %s)" % (transfer, ))
+
+    def _write_docs(self, func):
+        self.out_c.write("/**\n * %s:\n" % (func.symbol, ))
+        for param in func.parameters:
+            self.out_c.write(" * @%s: " % (param.argname, ))
+            if param.direction in (PARAM_DIRECTION_OUT, PARAM_DIRECTION_INOUT):
+                if param.caller_allocates:
+                    allocate_string = ' caller-allocates'
+                else:
+                    allocate_string = ''
+                self.out_c.write("(%s%s) " % (param.direction, allocate_string))
+                self._write_annotation_transfer(param.transfer)
+            self.out_c.write(":\n")
+        self.out_c.write(' *\n')
+        self.out_c.write(' * Undocumented.\n')
+        self.out_c.write(' *\n')
+        self.out_c.write(' * Returns: ')
+        self._write_annotation_transfer(func.retval.transfer)
+        self.out_c.write('\n */')
+
+    @contextmanager
+    def _function(self, func):
+        self._write_prototype(func)
+        self._write_docs(func)
+        self._write_prelude(self.out_c, func)
+        self.out_c.write("\n{\n")
+        yield
+        self.out_c.write("}\n\n")
+
+    def _codegen_start(self):
+        warning = '/* GENERATED BY testcodegen.py; DO NOT EDIT */\n\n'
+        self.out_h.write(warning)
+        nsupper = self.namespace.name.upper()
+        self.out_h.write("""
+#ifndef __%s_H__
+#define __%s_H__
+
+#include <glib-object.h>
+""" % (nsupper, nsupper))
+
+        self.out_c.write(warning)
+        self.out_c.write("""#include "%s"\n\n""" % (self.out_h_filename, ))
+
+    def _codegen_end(self):
+        self.out_h.write("""#endif\n""")
+        
+        self.out_h.close()
+        self.out_c.close()
+
+    def set_function_body(self, node, body):
+        assert isinstance(node, Function)
+        self._function_bodies[node] = body
+
+    def codegen(self):
+        self._codegen_start()
+
+        for node in self.namespace.itervalues():
+            if isinstance(node, Function):
+                with self._function(node):
+                    yield (node, out_c)
+
+        # First pass, generate constant returns
+        prefix = 'const return '
+        for typeval in INTROSPECTABLE_BASIC:
+            name = uscore_from_type(typeval)
+            sym = self._gen_symbol(prefix + typeval.target_fundamental)
+            func = Function(name, Return(typeval, transfer=PARAM_TRANSFER_NONE),
+                            [], False, sym)
+            with self._function(func):
+                default = get_default_for_typeval(typeval)
+                self.out_c.write("  return %s;\n" % (default, ))
+
+        # Void return, one parameter
+        prefix = 'oneparam '
+        for typeval in INTROSPECTABLE_BASIC:
+            if typeval is TYPE_NONE:
+                continue
+            name = uscore_from_type(typeval)
+            sym = self._gen_symbol(prefix + typeval.target_fundamental)
+            func = Function(name, Return(TYPE_NONE, transfer=PARAM_TRANSFER_NONE),
+                            [Parameter('arg0', typeval, transfer=PARAM_TRANSFER_NONE,
+                                       direction=PARAM_DIRECTION_IN)], False, sym)
+            with self._function(func):
+                self.out_c.write("  return;\n")
+
+        # Void return, one (out) parameter
+        prefix = 'one_outparam '
+        for typeval in INTROSPECTABLE_BASIC:
+            if typeval is TYPE_NONE:
+                continue
+            name = uscore_from_type(typeval)
+            sym = self._gen_symbol(prefix + typeval.target_fundamental)
+            func = Function(name, Return(TYPE_NONE, transfer=PARAM_TRANSFER_NONE),
+                            [Parameter('arg0', typeval, transfer=PARAM_TRANSFER_NONE,
+                                       direction=PARAM_DIRECTION_OUT)], False, sym)
+            with self._function(func):
+                default = get_default_for_typeval(func.retval)
+                self.out_c.write("  *arg0 = %s;\n" % (default, ))
+                self.out_c.write("  return;\n")
+
+
+        self._codegen_end()
diff --git a/giscanner/scannermain.py b/giscanner/scannermain.py
index 1c741ac..574dfff 100644
--- a/giscanner/scannermain.py
+++ b/giscanner/scannermain.py
@@ -158,9 +158,12 @@ def passthrough_gir(path, f):
 
 def test_codegen(optstring):
     (namespace, out_h_filename, out_c_filename) = optstring.split(',')
-    from .testcodegen import CCodeGenerator
-    gen = CCodeGenerator(namespace, out_h_filename, out_c_filename)
-    gen.codegen()
+    if namespace == 'Everything':
+        from .testcodegen import EverythingCodeGenerator
+        gen = EverythingCodeGenerator(out_h_filename, out_c_filename)
+        gen.write()
+    else:
+        raise ValueError("Invaild namespace %r" % (namespace, ))
     return 0
 
 def validate(assertions, path):
diff --git a/giscanner/testcodegen.py b/giscanner/testcodegen.py
index c8e853c..3dfb4d4 100644
--- a/giscanner/testcodegen.py
+++ b/giscanner/testcodegen.py
@@ -19,9 +19,11 @@
 #
 
 import os, sys
+from StringIO import StringIO
 from contextlib import contextmanager
 from .ast import *
 from .glibast import *
+from .codegen import CCodeGenerator
 
 INTROSPECTABLE_BASIC = filter(lambda x: x not in (TYPE_LONG_LONG, TYPE_LONG_ULONG, TYPE_LONG_DOUBLE), GIR_TYPES)
 
@@ -39,144 +41,58 @@ def get_default_for_typeval(typeval):
     return "0"
 
 def uscore_from_type(typeval):
-    return typeval.ctype.replace('*', 'P').replace(' ', '_')
-
-class CCodeGenerator(object):
-    def __init__(self, namespace, out_h_filename, out_c_filename):
-        self.out_h_filename = out_h_filename
-        self.out_c_filename = out_c_filename
-        self.out_h = open(out_h_filename, 'w')
-        self.out_c = open(out_c_filename, 'w')
-        self.namespace = namespace
-        self._lnamespace = self.namespace.lower()
-
-    def _gen_symbol(self, name):
-        name = name.replace(' ', '_')
-        return '%s_%s' % (self._lnamespace, name)
-
-    def _typecontainer_to_ctype(self, param):
-        if (isinstance(param, Parameter) and
-            param.direction in (PARAM_DIRECTION_OUT,
-                                PARAM_DIRECTION_INOUT)):
-            suffix = '*'
-        else:
-            suffix = ''
-        if (param.type.is_equiv((TYPE_STRING, TYPE_FILENAME)) and
-            param.transfer == PARAM_TRANSFER_NONE):
-            return "const gchar*" + suffix
-        return param.type.ctype + suffix
-
-    def _write_prelude(self, out, func):
-        out.write("""
-%s
-%s (""" % (self._typecontainer_to_ctype(func.retval), func.symbol))
-        l = len(func.parameters)
-        if func.parameters:
-            for i,param in enumerate(func.parameters):
-                ctype = self._typecontainer_to_ctype(param)
-                out.write('%s %s' % (ctype, param.argname))
-                if i < l - 1:
-                    out.write(", ")
-        else:
-            out.write('void')
-        out.write(")")
-
-    def _write_prototype(self, func):
-        self._write_prelude(self.out_h, func)
-        self.out_h.write(";\n\n")
-
-    def _write_annotation_transfer(self, transfer):
-        self.out_c.write("(transfer %s)" % (transfer, ))
-
-    def _write_docs(self, func):
-        self.out_c.write("/**\n * %s:\n" % (func.symbol, ))
-        for param in func.parameters:
-            self.out_c.write(" * @%s: " % (param.argname, ))
-            if param.direction in (PARAM_DIRECTION_OUT, PARAM_DIRECTION_INOUT):
-                if param.caller_allocates:
-                    allocate_string = ' caller-allocates'
-                else:
-                    allocate_string = ''
-                self.out_c.write("(%s%s) " % (param.direction, allocate_string))
-                self._write_annotation_transfer(param.transfer)
-            self.out_c.write(":\n")
-        self.out_c.write(' *\n')
-        self.out_c.write(' * Undocumented.\n')
-        self.out_c.write(' *\n')
-        self.out_c.write(' * Returns: ')
-        self._write_annotation_transfer(func.retval.transfer)
-        self.out_c.write('\n */')
-
-    @contextmanager
-    def _function(self, func):
-        self._write_prototype(func)
-        self._write_docs(func)
-        self._write_prelude(self.out_c, func)
-        self.out_c.write("\n{\n")
-        yield
-        self.out_c.write("}\n\n")
-
-    def _codegen_start(self):
-        warning = '/* GENERATED BY testcodegen.py; DO NOT EDIT */\n\n'
-        self.out_h.write(warning)
-        nsupper = self.namespace.upper()
-        self.out_h.write("""
-#ifndef __%s_H__
-#define __%s_H__
-
-#include <glib-object.h>
-""" % (nsupper, nsupper))
-
-        self.out_c.write(warning)
-        self.out_c.write("""#include "%s"\n\n""" % (self.out_h_filename, ))
-
-    def _codegen_end(self):
-        self.out_h.write("""#endif\n""")
-        
-        self.out_h.close()
-        self.out_c.close()
-
-    def codegen(self):
-        self._codegen_start()
-
+    if typeval.target_fundamental:
+        return typeval.target_fundamental.replace(' ', '_')
+    elif typeval.target_giname:
+        return typeval.target_giname.replace('.', '').lower()
+    else:
+        assert False, typeval
+
+class EverythingCodeGenerator(object):
+    def __init__(self, out_h_filename, out_c_filename):
+        self.namespace = Namespace('Everything', '1.0')
+        self.gen = CCodeGenerator(self.namespace, out_h_filename, out_c_filename)
+
+    def write(self):
         # First pass, generate constant returns
         prefix = 'const return '
         for typeval in INTROSPECTABLE_BASIC:
-            name = uscore_from_type(typeval)
-            sym = self._gen_symbol(prefix + typeval.target_fundamental)
+            name = prefix + uscore_from_type(typeval)
+            sym = self.gen.gen_symbol(name)
             func = Function(name, Return(typeval, transfer=PARAM_TRANSFER_NONE),
                             [], False, sym)
-            with self._function(func):
-                default = get_default_for_typeval(typeval)
-                self.out_c.write("  return %s;\n" % (default, ))
+            self.namespace.append(func)
+            default = get_default_for_typeval(typeval)
+            body = "  return %s;\n" % (default, )
+            self.gen.set_function_body(func, body)
 
         # Void return, one parameter
         prefix = 'oneparam '
         for typeval in INTROSPECTABLE_BASIC:
             if typeval is TYPE_NONE:
                 continue
-            name = uscore_from_type(typeval)
-            sym = self._gen_symbol(prefix + typeval.target_fundamental)
+            name = prefix + uscore_from_type(typeval)
+            sym = self.gen.gen_symbol(name)
             func = Function(name, Return(TYPE_NONE, transfer=PARAM_TRANSFER_NONE),
                             [Parameter('arg0', typeval, transfer=PARAM_TRANSFER_NONE,
                                        direction=PARAM_DIRECTION_IN)], False, sym)
-            with self._function(func):
-                self.out_c.write("  return;\n")
+            self.namespace.append(func)
+            self.gen.set_function_body(func, "  return;\n")
 
         # Void return, one (out) parameter
         prefix = 'one_outparam '
         for typeval in INTROSPECTABLE_BASIC:
             if typeval is TYPE_NONE:
                 continue
-            name = uscore_from_type(typeval)
-            sym = self._gen_symbol(prefix + typeval.target_fundamental)
+            name = prefix + uscore_from_type(typeval)
+            sym = self.gen.gen_symbol(name)
             func = Function(name, Return(TYPE_NONE, transfer=PARAM_TRANSFER_NONE),
                             [Parameter('arg0', typeval, transfer=PARAM_TRANSFER_NONE,
                                        direction=PARAM_DIRECTION_OUT)], False, sym)
-            with self._function(func):
-                default = get_default_for_typeval(func.retval)
-                self.out_c.write("  *arg0 = %s;\n" % (default, ))
-                self.out_c.write("  return;\n")
-
+            self.namespace.append(func)
+            body = StringIO('w')
+            default = get_default_for_typeval(func.retval)
+            body.write("  *arg0 = %s;\n" % (default, ))
+            body.write("  return;\n")
+            self.gen.set_function_body(func, body.getvalue())
 
-        self._codegen_end()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]