[gobject-introspection/wip/transformer] [codegen] Split out C code generation into separate module
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gobject-introspection/wip/transformer] [codegen] Split out C code generation into separate module
- Date: Fri, 30 Jul 2010 12:42:14 +0000 (UTC)
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]