gimarshallingtests: Add string_ to boxed structure
[platform/upstream/gobject-introspection.git] / giscanner / codegen.py
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
27 class CCodeGenerator(object):
28     def __init__(self, namespace, out_h_filename, out_c_filename):
29         self.out_h_filename = out_h_filename
30         self.out_c_filename = out_c_filename
31         self._function_bodies = {}
32         self.namespace = namespace
33
34     def gen_symbol(self, name):
35         name = name.replace(' ', '_')
36         return '%s_%s' % (self.namespace.symbol_prefixes[0], name)
37
38     def _typecontainer_to_ctype(self, param):
39         if (isinstance(param, ast.Parameter) and
40             param.direction in (ast.PARAM_DIRECTION_OUT,
41                                 ast.PARAM_DIRECTION_INOUT)):
42             suffix = '*'
43         else:
44             suffix = ''
45         if (param.type.is_equiv((ast.TYPE_STRING, ast.TYPE_FILENAME)) and
46             param.transfer == ast.PARAM_TRANSFER_NONE):
47             return "const gchar*" + suffix
48         return param.type.ctype + suffix
49
50     def _write_prelude(self, out, func):
51         out.write("""
52 %s
53 %s (""" % (self._typecontainer_to_ctype(func.retval), func.symbol))
54         l = len(func.parameters)
55         if func.parameters:
56             for i, param in enumerate(func.parameters):
57                 ctype = self._typecontainer_to_ctype(param)
58                 out.write('%s %s' % (ctype, param.argname))
59                 if i < l - 1:
60                     out.write(", ")
61         else:
62             out.write('void')
63         out.write(")")
64
65     def _write_prototype(self, func):
66         self._write_prelude(self.out_h, func)
67         self.out_h.write(";\n\n")
68
69     def _write_annotation_transfer(self, transfer):
70         self.out_c.write("(transfer %s)" % (transfer, ))
71
72     def _write_docs(self, func):
73         self.out_c.write("/**\n * %s:\n" % (func.symbol, ))
74         for param in func.parameters:
75             self.out_c.write(" * @%s: " % (param.argname, ))
76             if param.direction in (ast.PARAM_DIRECTION_OUT,
77                                    ast.PARAM_DIRECTION_INOUT):
78                 if param.caller_allocates:
79                     allocate_string = ' caller-allocates'
80                 else:
81                     allocate_string = ''
82                 self.out_c.write("(%s%s) " % (param.direction,
83                                               allocate_string))
84                 self._write_annotation_transfer(param.transfer)
85             self.out_c.write(":\n")
86         self.out_c.write(' *\n')
87         self.out_c.write(' * Undocumented.\n')
88         self.out_c.write(' *\n')
89         self.out_c.write(' * Returns: ')
90         self._write_annotation_transfer(func.retval.transfer)
91         self.out_c.write('\n */')
92
93     @contextmanager
94     def _function(self, func):
95         self._write_prototype(func)
96         self._write_docs(func)
97         self._write_prelude(self.out_c, func)
98         self.out_c.write("\n{\n")
99         yield
100         self.out_c.write("}\n\n")
101
102     def _codegen_start(self):
103         warning = '/* GENERATED BY testcodegen.py; DO NOT EDIT */\n\n'
104         self.out_h.write(warning)
105         nsupper = self.namespace.name.upper()
106         self.out_h.write("""
107 #ifndef __%s_H__
108 #define __%s_H__
109
110 #include <glib-object.h>
111 """ % (nsupper, nsupper))
112
113         self.out_c.write(warning)
114         self.out_c.write("""#include "%s"\n\n""" % (self.out_h_filename, ))
115
116     def _codegen_end(self):
117         self.out_h.write("""#endif\n""")
118
119         self.out_h.close()
120         self.out_c.close()
121
122     def set_function_body(self, node, body):
123         assert isinstance(node, ast.Function)
124         self._function_bodies[node] = body
125
126     def codegen(self):
127         self.out_h = open(self.out_h_filename, 'w')
128         self.out_c = open(self.out_c_filename, 'w')
129
130         self._codegen_start()
131
132         for node in self.namespace.itervalues():
133             if isinstance(node, ast.Function):
134                 with self._function(node):
135                     body = self._function_bodies.get(node)
136                     if not body:
137                         body = ''
138                     self.out_c.write(body)
139
140         self._codegen_end()