change run to use meson/ninja and then exec. - remove libvala code from application...
[roobuilder] / src / codegen / valaccodestructmodule.vala
1 /* valaccodestructmodule.vala
2  *
3  * Copyright (C) 2006-2009  Jürg Billeter
4  * Copyright (C) 2006-2008  Raffaele Sandrini
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19  *
20  * Author:
21  *      Jürg Billeter <j@bitron.ch>
22  *      Raffaele Sandrini <raffaele@sandrini.ch>
23  */
24
25 using GLib;
26
27 public abstract class Vala.CCodeStructModule : CCodeBaseModule {
28         public override void generate_struct_declaration (Struct st, CCodeFile decl_space) {
29                 if (add_symbol_declaration (decl_space, st, get_ccode_name (st))) {
30                         return;
31                 }
32
33                 if (st.base_struct != null) {
34                         generate_struct_declaration (st.base_struct, decl_space);
35                 } else if (!st.external_package) {
36                         // custom simple type structs cannot have a type id which depends on head-allocation
37                         if (st.get_attribute ("SimpleType") != null && !st.has_attribute_argument ("CCode", "type_id")) {
38                                 st.set_attribute_bool ("CCode", "has_type_id", false);
39                         }
40                 }
41
42                 if (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ()) {
43                         string typename;
44                         // See GTypeModule.visit_struct()
45                         if (st.base_struct != null) {
46                                 typename = get_ccode_name (st.base_struct);
47                         } else if (st.is_boolean_type ()) {
48                                 // typedef for boolean types
49                                 decl_space.add_include ("stdbool.h");
50                                 typename = "bool";
51                         } else if (st.is_integer_type ()) {
52                                 // typedef for integral types
53                                 decl_space.add_include ("stdint.h");
54                                 typename = "%sint%d_t".printf (st.signed ? "" : "u", st.width);
55                         } else if (st.is_floating_type ()) {
56                                 // typedef for floating types
57                                 typename = (st.width == 64 ? "double" : "float");
58                         } else {
59                                 assert_not_reached ();
60                         }
61                         decl_space.add_type_declaration (new CCodeTypeDefinition (typename, new CCodeVariableDeclarator (get_ccode_name (st))));
62                         return;
63                 }
64
65                 if (context.profile == Profile.GOBJECT) {
66                         if (get_ccode_has_type_id (st)) {
67                                 decl_space.add_include ("glib-object.h");
68                                 decl_space.add_type_declaration (new CCodeNewline ());
69                                 var macro = "(%s_get_type ())".printf (get_ccode_lower_case_name (st, null));
70                                 decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (st), macro));
71
72                                 var type_fun = new StructRegisterFunction (st);
73                                 type_fun.init_from_type (context, false, true);
74                                 decl_space.add_type_member_declaration (type_fun.get_declaration ());
75
76                                 requires_vala_extern = true;
77                         }
78                 }
79
80                 if (st.base_struct == null) {
81                         decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (get_ccode_name (st)), new CCodeVariableDeclarator (get_ccode_name (st))));
82                 } else {
83                         decl_space.add_type_declaration (new CCodeTypeDefinition (get_ccode_name (st.base_struct), new CCodeVariableDeclarator (get_ccode_name (st))));
84                 }
85
86                 var instance_struct = new CCodeStruct ("_%s".printf (get_ccode_name (st)));
87
88                 if (st.version.deprecated) {
89                         if (context.profile == Profile.GOBJECT) {
90                                 decl_space.add_include ("glib.h");
91                         }
92                         instance_struct.modifiers |= CCodeModifiers.DEPRECATED;
93                 }
94
95                 foreach (Field f in st.get_fields ()) {
96                         if (f.binding == MemberBinding.INSTANCE)  {
97                                 append_field (instance_struct, f, decl_space);
98                         }
99                 }
100
101                 if (st.base_struct == null) {
102                         decl_space.add_type_definition (instance_struct);
103                 }
104
105                 if (st.is_simple_type ()) {
106                         return;
107                 }
108
109                 var function = new CCodeFunction (get_ccode_dup_function (st), get_ccode_name (st) + "*");
110                 if (st.is_private_symbol ()) {
111                         function.modifiers = CCodeModifiers.STATIC;
112                 } else if (context.hide_internal && st.is_internal_symbol ()) {
113                         function.modifiers = CCodeModifiers.INTERNAL;
114                 } else {
115                         function.modifiers |= CCodeModifiers.EXTERN;
116                         requires_vala_extern = true;
117                 }
118                 function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
119                 decl_space.add_function_declaration (function);
120
121                 function = new CCodeFunction (get_ccode_free_function (st), "void");
122                 if (st.is_private_symbol ()) {
123                         function.modifiers = CCodeModifiers.STATIC;
124                 } else if (context.hide_internal && st.is_internal_symbol ()) {
125                         function.modifiers = CCodeModifiers.INTERNAL;
126                 } else {
127                         function.modifiers = CCodeModifiers.EXTERN;
128                         requires_vala_extern = true;
129                 }
130                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
131                 decl_space.add_function_declaration (function);
132
133                 if (st.is_disposable ()) {
134                         function = new CCodeFunction (get_ccode_copy_function (st), "void");
135                         if (st.is_private_symbol ()) {
136                                 function.modifiers = CCodeModifiers.STATIC;
137                         } else if (context.hide_internal && st.is_internal_symbol ()) {
138                                 function.modifiers = CCodeModifiers.INTERNAL;
139                         } else {
140                                 function.modifiers = CCodeModifiers.EXTERN;
141                                 requires_vala_extern = true;
142                         }
143                         function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
144                         function.add_parameter (new CCodeParameter ("dest", get_ccode_name (st) + "*"));
145                         decl_space.add_function_declaration (function);
146
147                         function = new CCodeFunction (get_ccode_destroy_function (st), "void");
148                         if (st.is_private_symbol ()) {
149                                 function.modifiers = CCodeModifiers.STATIC;
150                         } else if (context.hide_internal && st.is_internal_symbol ()) {
151                                 function.modifiers = CCodeModifiers.INTERNAL;
152                         } else {
153                                 function.modifiers = CCodeModifiers.EXTERN;
154                                 requires_vala_extern = true;
155                         }
156                         function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
157                         decl_space.add_function_declaration (function);
158                 }
159         }
160
161         public override void visit_struct (Struct st) {
162                 push_context (new EmitContext (st));
163                 push_line (st.source_reference);
164
165                 var old_instance_finalize_context = instance_finalize_context;
166                 instance_finalize_context = new EmitContext ();
167
168                 generate_struct_declaration (st, cfile);
169
170                 if (!st.is_internal_symbol ()) {
171                         generate_struct_declaration (st, header_file);
172                 }
173                 if (!st.is_private_symbol ()) {
174                         generate_struct_declaration (st, internal_header_file);
175                 }
176
177                 if (!st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type ()) {
178                         if (st.is_disposable ()) {
179                                 begin_struct_destroy_function (st);
180                         }
181                 }
182
183                 st.accept_children (this);
184
185                 if (!st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type ()) {
186                         if (st.is_disposable ()) {
187                                 add_struct_copy_function (st);
188                                 add_struct_destroy_function (st);
189                         }
190
191                         if (!st.is_simple_type ()) {
192                                 add_struct_dup_function (st);
193                                 add_struct_free_function (st);
194                         }
195                 }
196
197                 instance_finalize_context = old_instance_finalize_context;
198
199                 pop_line ();
200                 pop_context ();
201         }
202
203         void add_struct_dup_function (Struct st) {
204                 var function = new CCodeFunction (get_ccode_dup_function (st), get_ccode_name (st) + "*");
205                 if (st.access == SymbolAccessibility.PRIVATE) {
206                         function.modifiers = CCodeModifiers.STATIC;
207                 }
208
209                 function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
210
211                 push_function (function);
212
213                 ccode.add_declaration (get_ccode_name (st) + "*", new CCodeVariableDeclarator ("dup"));
214
215                 if (context.profile == Profile.GOBJECT) {
216                         // g_new0 needs glib.h
217                         cfile.add_include ("glib.h");
218                         var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
219                         creation_call.add_argument (new CCodeConstant (get_ccode_name (st)));
220                         creation_call.add_argument (new CCodeConstant ("1"));
221                         ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
222                 } else if (context.profile == Profile.POSIX) {
223                         // calloc needs stdlib.h
224                         cfile.add_include ("stdlib.h");
225
226                         var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
227                         sizeof_call.add_argument (new CCodeConstant (get_ccode_name (st)));
228
229                         var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
230                         creation_call.add_argument (new CCodeConstant ("1"));
231                         creation_call.add_argument (sizeof_call);
232                         ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
233                 }
234
235                 if (st.is_disposable ()) {
236                         var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
237                         copy_call.add_argument (new CCodeIdentifier ("self"));
238                         copy_call.add_argument (new CCodeIdentifier ("dup"));
239                         ccode.add_expression (copy_call);
240                 } else {
241                         cfile.add_include ("string.h");
242
243                         var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
244                         sizeof_call.add_argument (new CCodeConstant (get_ccode_name (st)));
245
246                         var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
247                         copy_call.add_argument (new CCodeIdentifier ("dup"));
248                         copy_call.add_argument (new CCodeIdentifier ("self"));
249                         copy_call.add_argument (sizeof_call);
250                         ccode.add_expression (copy_call);
251                 }
252
253                 ccode.add_return (new CCodeIdentifier ("dup"));
254
255                 pop_function ();
256
257                 cfile.add_function (function);
258         }
259
260         void add_struct_free_function (Struct st) {
261                 var function = new CCodeFunction (get_ccode_free_function (st), "void");
262                 if (st.is_private_symbol ()) {
263                         function.modifiers = CCodeModifiers.STATIC;
264                 } else if (context.hide_internal && st.is_internal_symbol ()) {
265                         function.modifiers = CCodeModifiers.INTERNAL;
266                 }
267
268                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
269
270                 push_function (function);
271
272                 if (st.is_disposable ()) {
273                         var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
274                         destroy_call.add_argument (new CCodeIdentifier ("self"));
275                         ccode.add_expression (destroy_call);
276                 }
277
278                 if (context.profile == Profile.GOBJECT) {
279                         // g_free needs glib.h
280                         cfile.add_include ("glib.h");
281                         var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
282                         free_call.add_argument (new CCodeIdentifier ("self"));
283                         ccode.add_expression (free_call);
284                 } else if (context.profile == Profile.POSIX) {
285                         // free needs stdlib.h
286                         cfile.add_include ("stdlib.h");
287                         var free_call = new CCodeFunctionCall (new CCodeIdentifier ("free"));
288                         free_call.add_argument (new CCodeIdentifier ("self"));
289                         ccode.add_expression (free_call);
290                 }
291
292                 pop_function ();
293
294                 cfile.add_function (function);
295         }
296
297         void add_struct_copy_function (Struct st) {
298                 var function = new CCodeFunction (get_ccode_copy_function (st), "void");
299                 if (st.is_private_symbol ()) {
300                         function.modifiers = CCodeModifiers.STATIC;
301                 } else if (context.hide_internal && st.is_internal_symbol ()) {
302                         function.modifiers = CCodeModifiers.INTERNAL;
303                 }
304
305                 function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
306                 function.add_parameter (new CCodeParameter ("dest", get_ccode_name (st) + "*"));
307
308                 push_function (function);
309
310                 var dest_struct = new GLibValue (SemanticAnalyzer.get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
311                 unowned Struct sym = st;
312                 while (sym.base_struct != null) {
313                         sym = sym.base_struct;
314                 }
315                 foreach (var f in sym.get_fields ()) {
316                         if (f.binding == MemberBinding.INSTANCE) {
317                                 var value = load_field (f, load_this_parameter ((TypeSymbol) st));
318                                 if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_copy (f.variable_type))  {
319                                         value = copy_value (value, f);
320                                         if (value == null) {
321                                                 // error case, continue to avoid critical
322                                                 continue;
323                                         }
324                                 }
325                                 store_field (f, dest_struct, value);
326                         }
327                 }
328
329                 pop_function ();
330
331                 cfile.add_function (function);
332         }
333
334         void begin_struct_destroy_function (Struct st) {
335                 push_context (instance_finalize_context);
336
337                 var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
338                 if (st.is_private_symbol ()) {
339                         function.modifiers = CCodeModifiers.STATIC;
340                 } else if (context.hide_internal && st.is_internal_symbol ()) {
341                         function.modifiers = CCodeModifiers.INTERNAL;
342                 }
343
344                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
345
346                 push_function (function);
347
348                 pop_context ();
349         }
350
351         void add_struct_destroy_function (Struct st) {
352                 unowned Struct sym = st;
353                 while (sym.base_struct != null) {
354                         sym = sym.base_struct;
355                 }
356                 if (st != sym) {
357                         push_context (instance_finalize_context);
358
359                         var destroy_func = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (sym)));
360                         destroy_func.add_argument (new CCodeIdentifier ("self"));
361                         ccode.add_expression (destroy_func);
362
363                         pop_context ();
364                 }
365
366                 cfile.add_function (instance_finalize_context.ccode);
367         }
368 }
369