Change license name
[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 import os
22 from contextlib import contextmanager
23
24 from . import ast
25
26
27 class CCodeGenerator(object):
28     def __init__(self, namespace,
29                  out_h_filename,
30                  out_c_filename,
31                  function_decoration=[],
32                  include_first_header=[],
33                  include_last_header=[],
34                  include_first_src=[],
35                  include_last_src=[]):
36         self.out_h_filename = out_h_filename
37         self.out_c_filename = out_c_filename
38         self.function_decoration = function_decoration
39         self.include_first_header = include_first_header
40         self.include_last_header = include_last_header
41         self.include_first_src = include_first_src
42         self.include_last_src = include_last_src
43         self._function_bodies = {}
44         self.namespace = namespace
45
46     def gen_symbol(self, name):
47         name = name.replace(' ', '_')
48         return '%s_%s' % (self.namespace.symbol_prefixes[0], name)
49
50     def _typecontainer_to_ctype(self, param):
51         if (isinstance(param, ast.Parameter)
52         and param.direction in (ast.PARAM_DIRECTION_OUT, ast.PARAM_DIRECTION_INOUT)):
53             suffix = '*'
54         else:
55             suffix = ''
56
57         if (param.type.is_equiv((ast.TYPE_STRING, ast.TYPE_FILENAME))
58         and param.transfer == ast.PARAM_TRANSFER_NONE):
59             return "const gchar*" + suffix
60
61         return param.type.ctype + suffix
62
63     def _write_prelude(self, out, func):
64         if self.function_decoration:
65             out.write("""
66 %s""" % " ".join(self.function_decoration))
67
68         out.write("""
69 %s
70 %s (""" % (self._typecontainer_to_ctype(func.retval), func.symbol))
71         l = len(func.parameters)
72         if func.parameters:
73             for i, param in enumerate(func.parameters):
74                 ctype = self._typecontainer_to_ctype(param)
75                 out.write('%s %s' % (ctype, param.argname))
76                 if i < l - 1:
77                     out.write(", ")
78         else:
79             out.write('void')
80         out.write(")")
81
82     def _write_prototype(self, func):
83         self._write_prelude(self.out_h, func)
84         self.out_h.write(";\n\n")
85
86     def _write_annotation_transfer(self, node):
87         if (node.type not in ast.BASIC_TYPES or
88                 node.type.ctype.endswith('*')):
89             self.out_c.write(" (transfer %s)" % (node.transfer, ))
90
91     def _write_docs(self, func):
92         self.out_c.write("/**\n * %s:\n" % (func.symbol, ))
93         for param in func.parameters:
94             self.out_c.write(" * @%s" % (param.argname, ))
95             if param.direction in (ast.PARAM_DIRECTION_OUT,
96                                    ast.PARAM_DIRECTION_INOUT):
97                 if param.caller_allocates:
98                     allocate_string = ' caller-allocates'
99                 else:
100                     allocate_string = ''
101                 self.out_c.write(": (%s%s) " % (param.direction,
102                                                 allocate_string))
103                 self._write_annotation_transfer(param)
104             self.out_c.write(":\n")
105         self.out_c.write(' *\n')
106         self.out_c.write(' * Undocumented.')
107         if func.retval.type != ast.TYPE_NONE:
108             self.out_c.write('\n *\n')
109             self.out_c.write(' * Returns: ')
110             self._write_annotation_transfer(func.retval)
111         self.out_c.write('\n */')
112
113     @contextmanager
114     def _function(self, func):
115         self._write_prototype(func)
116         self._write_docs(func)
117         self._write_prelude(self.out_c, func)
118         self.out_c.write("\n{\n")
119         yield
120         self.out_c.write("}\n\n")
121
122     def _codegen_start(self):
123         warning = '/* GENERATED BY testcodegen.py; DO NOT EDIT */\n\n'
124         self.out_h.write(warning)
125         nsupper = self.namespace.name.upper()
126
127         for header in self.include_first_header:
128             self.out_h.write("""#include "%s"\n""" % header)
129
130         self.out_h.write("""
131 #ifndef __%s_H__
132 #define __%s_H__
133
134 #include <glib-object.h>
135
136 """ % (nsupper, nsupper))
137
138         for header in self.include_last_header:
139             self.out_h.write("""#include "%s"\n""" % header)
140
141         self.out_c.write(warning)
142
143         for header in self.include_first_src:
144             self.out_c.write("""#include "%s"\n""" % header)
145
146         src_dir = os.path.dirname(os.path.realpath(self.out_c.name))
147         header = os.path.relpath(self.out_h_filename, src_dir)
148         self.out_c.write("""#include "%s"\n\n""" % (header, ))
149
150         for header in self.include_last_src:
151             self.out_c.write("""#include "%s"\n""" % header)
152
153     def _codegen_end(self):
154         self.out_h.write("""#endif\n""")
155
156         self.out_h.close()
157         self.out_c.close()
158
159     def set_function_body(self, node, body):
160         assert isinstance(node, ast.Function)
161         self._function_bodies[node] = body
162
163     def codegen(self):
164         self.out_h = open(self.out_h_filename, 'w', encoding='utf-8')
165         self.out_c = open(self.out_c_filename, 'w', encoding='utf-8')
166
167         self._codegen_start()
168
169         for node in self.namespace.values():
170             if isinstance(node, ast.Function):
171                 with self._function(node):
172                     body = self._function_bodies.get(node)
173                     if not body:
174                         body = ''
175                     self.out_c.write(body)
176
177         self._codegen_end()