summaryrefslogtreecommitdiff
path: root/giscanner/codegen.py
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2010-07-27 06:16:37 -0400
committerColin Walters <walters@verbum.org>2010-08-31 16:05:56 -0400
commit36aa515f1036978ced8d4ffb808260844f7229e0 (patch)
tree93e06fb105a513a394365232bb632256f109dada /giscanner/codegen.py
parent552c1f1525e37a30376790151c1ba437776682c5 (diff)
downloadgobject-introspection-36aa515f1036978ced8d4ffb808260844f7229e0.tar.gz
Major rewrite
One of the first big changes in this rewrite is changing the Type object to have separate target_fundamental and target_giname properties, rather than just being strings. Previously in the scanner, it was awful because we used heuristics around strings. The ast.py is refactored so that not everything is a Node - that was a rather useless abstraction. Now, only things which can have a GIName are Node. E.g. Type and Field are no longer Node. More things were merged from glibast.py into ast.py, since it isn't a very useful split. transformer.py gains more intelligence and will e.g. turn GLib.List into a List() object earlier. The namespace processing is a lot cleaner now; since we parse the included .girs, we know the C prefix for each namespace, and have functions to parse both C type names (GtkFooBar) and symbols gtk_foo_bar into their symbols cleanly. Type resolution is much, much saner because we know Type(target_giname=Gtk.Foo) maps to the namespace Gtk. glibtransformer.py now just handles the XML processing from the dump, and a few miscellaneous things. The major heavy lifting now lives in primarytransformer.py, which is a combination of most of annotationparser.py and half of glibtransformer.py. annotationparser.py now literally just parses annotations; it's no longer in the business of e.g. guessing transfer too. finaltransformer.py is a new file which does post-analysis for "introspectability" mainly. girparser.c is fixed for some introspectable=0 processing.
Diffstat (limited to 'giscanner/codegen.py')
-rw-r--r--giscanner/codegen.py137
1 files changed, 137 insertions, 0 deletions
diff --git a/giscanner/codegen.py b/giscanner/codegen.py
new file mode 100644
index 00000000..0c0c559b
--- /dev/null
+++ b/giscanner/codegen.py
@@ -0,0 +1,137 @@
+# -*- 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.
+#
+
+from contextlib import contextmanager
+from . import ast
+
+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._function_bodies = {}
+ self.namespace = namespace
+
+ def gen_symbol(self, name):
+ name = name.replace(' ', '_')
+ return '%s_%s' % (self.namespace.symbol_prefixes[0], name)
+
+ def _typecontainer_to_ctype(self, param):
+ if (isinstance(param, ast.Parameter) and
+ param.direction in (ast.PARAM_DIRECTION_OUT,
+ ast.PARAM_DIRECTION_INOUT)):
+ suffix = '*'
+ else:
+ suffix = ''
+ if (param.type.is_equiv((ast.TYPE_STRING, ast.TYPE_FILENAME)) and
+ param.transfer == ast.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 (ast.PARAM_DIRECTION_OUT,
+ ast.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, ast.Function)
+ self._function_bodies[node] = body
+
+ def codegen(self):
+ self.out_h = open(self.out_h_filename, 'w')
+ self.out_c = open(self.out_c_filename, 'w')
+
+ self._codegen_start()
+
+ for node in self.namespace.itervalues():
+ if isinstance(node, ast.Function):
+ with self._function(node):
+ body = self._function_bodies.get(node)
+ if not body:
+ body = ''
+ self.out_c.write(body)
+
+ self._codegen_end()