diff options
author | Colin Walters <walters@verbum.org> | 2010-07-27 06:16:37 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2010-08-31 16:05:56 -0400 |
commit | 36aa515f1036978ced8d4ffb808260844f7229e0 (patch) | |
tree | 93e06fb105a513a394365232bb632256f109dada /giscanner/codegen.py | |
parent | 552c1f1525e37a30376790151c1ba437776682c5 (diff) | |
download | gobject-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.py | 137 |
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() |