~ubuntu-branches/ubuntu/utopic/gobject-introspection/utopic-proposed

1.3.9 by Robert Ancell
Import upstream version 0.9.12
1
# -*- Mode: Python -*-
2
# GObject-Introspection - a framework for introspecting GObject libraries
3
# Copyright (C) 2010  Red Hat, Inc.
4
#
5
# This library is free software; you can redistribute it and/or
6
# modify it under the terms of the GNU Lesser General Public
7
# License as published by the Free Software Foundation; either
8
# version 2 of the License, or (at your option) any later version.
9
#
10
# This library is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
# Lesser General Public License for more details.
14
#
15
# You should have received a copy of the GNU Lesser General Public
16
# License along with this library; if not, write to the
17
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
# Boston, MA 02111-1307, USA.
19
#
20
21
from __future__ import with_statement
22
23
from contextlib import contextmanager
24
25
from . import ast
26
1.4.29 by Martin Pitt
Import upstream version 1.37.4
27
1.3.9 by Robert Ancell
Import upstream version 0.9.12
28
class CCodeGenerator(object):
29
    def __init__(self, namespace, out_h_filename, out_c_filename):
30
        self.out_h_filename = out_h_filename
31
        self.out_c_filename = out_c_filename
32
        self._function_bodies = {}
33
        self.namespace = namespace
34
35
    def gen_symbol(self, name):
36
        name = name.replace(' ', '_')
37
        return '%s_%s' % (self.namespace.symbol_prefixes[0], name)
38
39
    def _typecontainer_to_ctype(self, param):
1.4.29 by Martin Pitt
Import upstream version 1.37.4
40
        if (isinstance(param, ast.Parameter)
41
        and param.direction in (ast.PARAM_DIRECTION_OUT, ast.PARAM_DIRECTION_INOUT)):
1.3.9 by Robert Ancell
Import upstream version 0.9.12
42
            suffix = '*'
43
        else:
44
            suffix = ''
1.4.29 by Martin Pitt
Import upstream version 1.37.4
45
46
        if (param.type.is_equiv((ast.TYPE_STRING, ast.TYPE_FILENAME))
47
        and param.transfer == ast.PARAM_TRANSFER_NONE):
1.3.9 by Robert Ancell
Import upstream version 0.9.12
48
            return "const gchar*" + suffix
1.4.29 by Martin Pitt
Import upstream version 1.37.4
49
1.3.9 by Robert Ancell
Import upstream version 0.9.12
50
        return param.type.ctype + suffix
51
52
    def _write_prelude(self, out, func):
53
        out.write("""
54
%s
55
%s (""" % (self._typecontainer_to_ctype(func.retval), func.symbol))
56
        l = len(func.parameters)
57
        if func.parameters:
58
            for i, param in enumerate(func.parameters):
59
                ctype = self._typecontainer_to_ctype(param)
60
                out.write('%s %s' % (ctype, param.argname))
61
                if i < l - 1:
62
                    out.write(", ")
63
        else:
64
            out.write('void')
65
        out.write(")")
66
67
    def _write_prototype(self, func):
68
        self._write_prelude(self.out_h, func)
69
        self.out_h.write(";\n\n")
70
71
    def _write_annotation_transfer(self, transfer):
72
        self.out_c.write("(transfer %s)" % (transfer, ))
73
74
    def _write_docs(self, func):
75
        self.out_c.write("/**\n * %s:\n" % (func.symbol, ))
76
        for param in func.parameters:
77
            self.out_c.write(" * @%s: " % (param.argname, ))
78
            if param.direction in (ast.PARAM_DIRECTION_OUT,
79
                                   ast.PARAM_DIRECTION_INOUT):
80
                if param.caller_allocates:
81
                    allocate_string = ' caller-allocates'
82
                else:
83
                    allocate_string = ''
84
                self.out_c.write("(%s%s) " % (param.direction,
85
                                              allocate_string))
86
                self._write_annotation_transfer(param.transfer)
87
            self.out_c.write(":\n")
88
        self.out_c.write(' *\n')
89
        self.out_c.write(' * Undocumented.\n')
90
        self.out_c.write(' *\n')
91
        self.out_c.write(' * Returns: ')
92
        self._write_annotation_transfer(func.retval.transfer)
93
        self.out_c.write('\n */')
94
95
    @contextmanager
96
    def _function(self, func):
97
        self._write_prototype(func)
98
        self._write_docs(func)
99
        self._write_prelude(self.out_c, func)
100
        self.out_c.write("\n{\n")
101
        yield
102
        self.out_c.write("}\n\n")
103
104
    def _codegen_start(self):
105
        warning = '/* GENERATED BY testcodegen.py; DO NOT EDIT */\n\n'
106
        self.out_h.write(warning)
107
        nsupper = self.namespace.name.upper()
108
        self.out_h.write("""
109
#ifndef __%s_H__
110
#define __%s_H__
111
112
#include <glib-object.h>
113
""" % (nsupper, nsupper))
114
115
        self.out_c.write(warning)
116
        self.out_c.write("""#include "%s"\n\n""" % (self.out_h_filename, ))
117
118
    def _codegen_end(self):
119
        self.out_h.write("""#endif\n""")
120
121
        self.out_h.close()
122
        self.out_c.close()
123
124
    def set_function_body(self, node, body):
125
        assert isinstance(node, ast.Function)
126
        self._function_bodies[node] = body
127
128
    def codegen(self):
129
        self.out_h = open(self.out_h_filename, 'w')
130
        self.out_c = open(self.out_c_filename, 'w')
131
132
        self._codegen_start()
133
134
        for node in self.namespace.itervalues():
135
            if isinstance(node, ast.Function):
136
                with self._function(node):
137
                    body = self._function_bodies.get(node)
138
                    if not body:
139
                        body = ''
140
                    self.out_c.write(body)
141
142
        self._codegen_end()