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
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
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
;
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
)));
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"))));
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 ());
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 ();
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 ();
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 ()));
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
;
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) {
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
));
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 ());
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
));
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 ();
362 header_type_declaration
= null;
363 header_type_definition
= null;
364 header_type_member_declaration
= null;
365 header_constant_declaration
= 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 ("__");
381 while (i
.len () > 0) {
382 var c
= i
.get_char ();
383 if (c
.isalnum () && c
< 0x80) {
384 define
.append_unichar (c
.toupper ());
386 define
.append_c ('_');
392 define
.append ("__");