update for 0.3.3 release
[vala-lang.git] / gobject / valaccodegeneratorsourcefile.vala
blobc77d4951041f5ae13fd6361f78a2a866991b290c
1 /* valaccodegeneratorsourcefile.vala
3 * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
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.1 of the License, or (at your option) any later version.
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.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using GLib;
25 using Gee;
27 public class Vala.CCodeGenerator {
28 private CCodeIncludeDirective get_internal_include (string filename) {
29 return new CCodeIncludeDirective (filename, context.library == null);
32 private CCodeForStatement get_vala_array_free_loop (bool have_length) {
33 var cbody = new CCodeBlock ();
34 var cptrarray = new CCodeCastExpression (new CCodeIdentifier ("array"), "gpointer*");
35 var cea = new CCodeElementAccess (cptrarray, new CCodeIdentifier ("i"));
37 var cfreecall = new CCodeFunctionCall (new CCodeIdentifier ("destroy_func"));
38 cfreecall.add_argument (cea);
40 CCodeExpression cforcond;
42 if (have_length) {
43 var cfreecond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
44 cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("array_length"));
45 cbody.add_statement (new CCodeIfStatement (cfreecond, new CCodeExpressionStatement (cfreecall)));
46 } else {
47 cforcond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, cea, new CCodeConstant ("NULL"));
48 cbody.add_statement (new CCodeExpressionStatement (cfreecall));
51 var cfor = new CCodeForStatement (cforcond, cbody);
52 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
53 cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("i"), new CCodeConstant ("1"))));
55 return cfor;
58 private void append_vala_array_free () {
59 var fun = new CCodeFunction ("_vala_array_free", "void");
60 fun.modifiers = CCodeModifiers.STATIC;
61 fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
62 fun.add_parameter (new CCodeFormalParameter ("array_length", "gint"));
63 fun.add_parameter (new CCodeFormalParameter ("destroy_func", "GDestroyNotify"));
64 source_type_member_declaration.append (fun.copy ());
66 var cdofree = new CCodeBlock ();
68 var citdecl = new CCodeDeclaration ("int");
69 citdecl.add_declarator (new CCodeVariableDeclarator ("i"));
70 cdofree.add_statement (citdecl);
72 var clencheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN_OR_EQUAL, new CCodeIdentifier ("array_length"), new CCodeConstant ("0"));
73 var ciflen = new CCodeIfStatement (clencheck, get_vala_array_free_loop (true), get_vala_array_free_loop (false));
74 cdofree.add_statement (ciflen);
76 var ccondarr = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("array"), new CCodeConstant ("NULL"));
77 var ccondfunc = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("destroy_func"), new CCodeConstant ("NULL"));
78 var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccondarr, ccondfunc), cdofree);
79 fun.block = new CCodeBlock ();
80 fun.block.add_statement (cif);
82 var carrfree = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
83 carrfree.add_argument (new CCodeIdentifier ("array"));
84 fun.block.add_statement (new CCodeExpressionStatement (carrfree));
86 source_type_member_definition.append (fun);
89 private void append_vala_array_move () {
90 string_h_needed = true;
92 // assumes that overwritten array elements are null before invocation
93 // FIXME will leak memory if that's not the case
94 var fun = new CCodeFunction ("_vala_array_move", "void");
95 fun.modifiers = CCodeModifiers.STATIC;
96 fun.add_parameter (new CCodeFormalParameter ("array", "gpointer"));
97 fun.add_parameter (new CCodeFormalParameter ("element_size", "gsize"));
98 fun.add_parameter (new CCodeFormalParameter ("src", "gint"));
99 fun.add_parameter (new CCodeFormalParameter ("dest", "gint"));
100 fun.add_parameter (new CCodeFormalParameter ("length", "gint"));
101 source_type_member_declaration.append (fun.copy ());
103 var array = new CCodeIdentifier ("array");
104 var element_size = new CCodeIdentifier ("element_size");
105 var length = new CCodeIdentifier ("length");
106 var src = new CCodeIdentifier ("src");
107 var dest = new CCodeIdentifier ("dest");
108 var src_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, src, element_size));
109 var dest_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, dest, element_size));
110 var dest_end_address = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, array, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dest, length)), element_size));
112 fun.block = new CCodeBlock ();
114 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_memmove"));
115 ccall.add_argument (dest_address);
116 ccall.add_argument (src_address);
117 ccall.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, length, element_size));
118 fun.block.add_statement (new CCodeExpressionStatement (ccall));
120 var czero1 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
121 czero1.add_argument (new CCodeCastExpression (src_address, "char *"));
122 czero1.add_argument (new CCodeConstant ("0"));
123 czero1.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, dest, src)), element_size));
124 var czeroblock1 = new CCodeBlock ();
125 czeroblock1.add_statement (new CCodeExpressionStatement (czero1));
127 var czero2 = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
128 czero2.add_argument (new CCodeCastExpression (dest_end_address, "char *"));
129 czero2.add_argument (new CCodeConstant ("0"));
130 czero2.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, src, dest)), element_size));
131 var czeroblock2 = new CCodeBlock ();
132 czeroblock2.add_statement (new CCodeExpressionStatement (czero2));
134 fun.block.add_statement (new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, src, dest), czeroblock1, czeroblock2));
136 source_type_member_definition.append (fun);
139 private void append_vala_strcmp0 () {
140 var fun = new CCodeFunction ("_vala_strcmp0", "int");
141 fun.modifiers = CCodeModifiers.STATIC;
142 fun.add_parameter (new CCodeFormalParameter ("str1", "const char *"));
143 fun.add_parameter (new CCodeFormalParameter ("str2", "const char *"));
144 source_type_member_declaration.append (fun.copy ());
146 // (str1 != str2)
147 var cineq = new CCodeParenthesizedExpression (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("str1"), new CCodeIdentifier ("str2")));
149 fun.block = new CCodeBlock ();
151 var cblock = new CCodeBlock ();
152 // if (str1 == NULL)
153 var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("str1"), new CCodeConstant ("NULL")), cblock);
154 // return -(str1 != str2);
155 cblock.add_statement (new CCodeReturnStatement (new CCodeUnaryExpression (CCodeUnaryOperator.MINUS, cineq)));
156 fun.block.add_statement (cif);
158 cblock = new CCodeBlock ();
159 // if (str2 == NULL)
160 cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("str2"), new CCodeConstant ("NULL")), cblock);
161 // return (str1 != str2);
162 cblock.add_statement (new CCodeReturnStatement (cineq));
163 fun.block.add_statement (cif);
165 // strcmp (str1, str2)
166 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
167 ccall.add_argument (new CCodeIdentifier ("str1"));
168 ccall.add_argument (new CCodeIdentifier ("str2"));
169 // return strcmp (str1, str2);
170 fun.block.add_statement (new CCodeReturnStatement (ccall));
172 source_type_member_definition.append (fun);
175 public override void visit_source_file (SourceFile source_file) {
176 header_begin = new CCodeFragment ();
177 header_type_declaration = new CCodeFragment ();
178 header_type_definition = new CCodeFragment ();
179 header_type_member_declaration = new CCodeFragment ();
180 header_constant_declaration = new CCodeFragment ();
181 source_begin = new CCodeFragment ();
182 source_include_directives = new CCodeFragment ();
183 source_type_declaration = new CCodeFragment ();
184 source_type_definition = new CCodeFragment ();
185 source_type_member_declaration = new CCodeFragment ();
186 source_constant_declaration = new CCodeFragment ();
187 source_type_member_definition = new CCodeFragment ();
188 source_signal_marshaller_definition = new CCodeFragment ();
189 source_signal_marshaller_declaration = new CCodeFragment ();
191 user_marshal_set = new HashSet<string> (str_hash, str_equal);
193 next_temp_var_id = 0;
195 string_h_needed = false;
196 dbus_glib_h_needed = false;
197 requires_free_checked = false;
198 requires_array_free = false;
199 requires_array_move = false;
200 requires_strcmp0 = false;
202 wrappers = new HashSet<string> (str_hash, str_equal);
204 header_begin.append (new CCodeIncludeDirective ("glib.h"));
205 header_begin.append (new CCodeIncludeDirective ("glib-object.h"));
206 if (context.basedir != null || context.library != null) {
207 source_include_directives.append (new CCodeIncludeDirective (source_file.get_cinclude_filename ()));
208 } else {
209 source_include_directives.append (new CCodeIncludeDirective (source_file.get_cinclude_filename (), true));
212 Gee.List<string> used_includes = new ArrayList<string> (str_equal);
213 used_includes.add ("glib.h");
214 used_includes.add ("glib-object.h");
215 used_includes.add (source_file.get_cinclude_filename ());
217 foreach (string filename in source_file.get_header_external_includes ()) {
218 if (!used_includes.contains (filename)) {
219 header_begin.append (new CCodeIncludeDirective (filename));
220 used_includes.add (filename);
223 foreach (string filename in source_file.get_header_internal_includes ()) {
224 if (!used_includes.contains (filename)) {
225 header_begin.append (get_internal_include (filename));
226 used_includes.add (filename);
229 foreach (string filename in source_file.get_source_external_includes ()) {
230 if (!used_includes.contains (filename)) {
231 source_include_directives.append (new CCodeIncludeDirective (filename));
232 used_includes.add (filename);
235 foreach (string filename in source_file.get_source_internal_includes ()) {
236 if (!used_includes.contains (filename)) {
237 source_include_directives.append (get_internal_include (filename));
238 used_includes.add (filename);
241 if (source_file.is_cycle_head) {
242 foreach (SourceFile cycle_file in source_file.cycle.files) {
243 foreach (CodeNode node in cycle_file.get_nodes ()) {
244 if (node is Struct) {
245 var st = (Struct) node;
246 header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (st.get_cname ()), new CCodeVariableDeclarator (st.get_cname ())));
247 } else if (node is Class) {
248 var cl = (Class) node;
249 if (!cl.is_static) {
250 header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (cl.get_cname ()), new CCodeVariableDeclarator (cl.get_cname ())));
251 header_type_declaration.append (new CCodeTypeDefinition ("struct _%sClass".printf (cl.get_cname ()), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ()))));
253 } else if (node is Interface) {
254 var iface = (Interface) node;
255 if (!iface.is_static) {
256 header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_cname ()), new CCodeVariableDeclarator (iface.get_cname ())));
257 header_type_declaration.append (new CCodeTypeDefinition ("struct _%s".printf (iface.get_type_cname ()), new CCodeVariableDeclarator (iface.get_type_cname ())));
264 source_file.accept_children (this);
266 if (Report.get_errors () > 0) {
267 return;
270 var header_define = get_define_for_filename (source_file.get_cinclude_filename ());
272 /* generate hardcoded "well-known" macros */
273 if (requires_free_checked) {
274 source_begin.append (new CCodeMacroReplacement ("VALA_FREE_CHECKED(o,f)", "((o) == NULL ? NULL : ((o) = (f (o), NULL)))"));
276 if (requires_array_free) {
277 append_vala_array_free ();
279 if (requires_array_move) {
280 append_vala_array_move ();
282 if (requires_strcmp0) {
283 append_vala_strcmp0 ();
286 if (string_h_needed) {
287 source_include_directives.append (new CCodeIncludeDirective ("string.h"));
290 if (dbus_glib_h_needed) {
291 source_include_directives.append (new CCodeIncludeDirective ("dbus/dbus-glib.h"));
294 CCodeComment comment = null;
295 if (source_file.comment != null) {
296 comment = new CCodeComment (source_file.comment);
299 var writer = new CCodeWriter (source_file.get_cheader_filename ());
300 if (!writer.open ()) {
301 Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
302 return;
304 if (comment != null) {
305 comment.write (writer);
307 writer.write_newline ();
308 var once = new CCodeOnceSection (header_define);
309 once.append (new CCodeNewline ());
310 once.append (header_begin);
311 once.append (new CCodeNewline ());
312 once.append (new CCodeIdentifier ("G_BEGIN_DECLS"));
313 once.append (new CCodeNewline ());
314 once.append (new CCodeNewline ());
315 once.append (header_type_declaration);
316 once.append (new CCodeNewline ());
317 once.append (header_type_definition);
318 once.append (new CCodeNewline ());
319 once.append (header_type_member_declaration);
320 once.append (new CCodeNewline ());
321 once.append (header_constant_declaration);
322 once.append (new CCodeNewline ());
323 once.append (new CCodeIdentifier ("G_END_DECLS"));
324 once.append (new CCodeNewline ());
325 once.append (new CCodeNewline ());
326 once.write (writer);
327 writer.close ();
329 writer = new CCodeWriter (source_file.get_csource_filename ());
330 if (!writer.open ()) {
331 Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
332 return;
334 writer.line_directives = context.debug;
335 if (comment != null) {
336 comment.write (writer);
338 source_begin.write (writer);
339 writer.write_newline ();
340 source_include_directives.write (writer);
341 writer.write_newline ();
342 source_type_declaration.write_combined (writer);
343 writer.write_newline ();
344 source_type_definition.write_combined (writer);
345 writer.write_newline ();
346 source_type_member_declaration.write_declaration (writer);
347 writer.write_newline ();
348 source_type_member_declaration.write (writer);
349 writer.write_newline ();
350 source_constant_declaration.write (writer);
351 writer.write_newline ();
352 source_signal_marshaller_declaration.write_declaration (writer);
353 source_signal_marshaller_declaration.write (writer);
354 writer.write_newline ();
355 source_type_member_definition.write (writer);
356 writer.write_newline ();
357 source_signal_marshaller_definition.write (writer);
358 writer.write_newline ();
359 writer.close ();
361 header_begin = null;
362 header_type_declaration = null;
363 header_type_definition = null;
364 header_type_member_declaration = null;
365 header_constant_declaration = null;
366 source_begin = null;
367 source_include_directives = null;
368 source_type_declaration = null;
369 source_type_definition = null;
370 source_type_member_declaration = null;
371 source_constant_declaration = null;
372 source_type_member_definition = null;
373 source_signal_marshaller_definition = null;
374 source_signal_marshaller_declaration = null;
377 private static string get_define_for_filename (string filename) {
378 var define = new StringBuilder ("__");
380 var i = filename;
381 while (i.len () > 0) {
382 var c = i.get_char ();
383 if (c.isalnum () && c < 0x80) {
384 define.append_unichar (c.toupper ());
385 } else {
386 define.append_c ('_');
389 i = i.next_char ();
392 define.append ("__");
394 return define.str;