Line data Source code
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 2930 : public abstract class Vala.CCodeStructModule : CCodeBaseModule {
28 37247 : public override void generate_struct_declaration (Struct st, CCodeFile decl_space) {
29 36904 : if (add_symbol_declaration (decl_space, st, get_ccode_name (st))) {
30 : return;
31 : }
32 :
33 408 : if (st.base_struct != null) {
34 58 : generate_struct_declaration (st.base_struct, decl_space);
35 350 : } else if (!st.external_package) {
36 : // custom simple type structs cannot have a type id which depends on head-allocation
37 350 : if (st.has_attribute ("SimpleType") && !st.has_attribute_argument ("CCode", "type_id")) {
38 31 : st.set_attribute_bool ("CCode", "has_type_id", false);
39 : }
40 : }
41 :
42 408 : if (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ()) {
43 : string typename;
44 : // See GTypeModule.visit_struct()
45 51 : if (st.base_struct != null) {
46 32 : typename = get_ccode_name (st.base_struct);
47 19 : } else if (st.is_boolean_type ()) {
48 : // typedef for boolean types
49 5 : decl_space.add_include ("stdbool.h");
50 5 : typename = "bool";
51 14 : } else if (st.is_integer_type ()) {
52 : // typedef for integral types
53 10 : decl_space.add_include ("stdint.h");
54 10 : typename = "%sint%d_t".printf (st.signed ? "" : "u", st.width);
55 4 : } else if (st.is_floating_type ()) {
56 : // typedef for floating types
57 8 : typename = (st.width == 64 ? "double" : "float");
58 : } else {
59 0 : assert_not_reached ();
60 : }
61 51 : decl_space.add_type_declaration (new CCodeTypeDefinition (typename, new CCodeVariableDeclarator (get_ccode_name (st))));
62 51 : return;
63 : }
64 :
65 357 : if (context.profile == Profile.GOBJECT) {
66 649 : if (get_ccode_has_type_id (st)) {
67 303 : decl_space.add_include ("glib-object.h");
68 303 : decl_space.add_type_declaration (new CCodeNewline ());
69 303 : var macro = "(%s_get_type ())".printf (get_ccode_lower_case_name (st, null));
70 303 : decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (st), macro));
71 :
72 303 : var type_fun = new StructRegisterFunction (st);
73 303 : type_fun.init_from_type (context, false, true);
74 303 : decl_space.add_type_member_declaration (type_fun.get_declaration ());
75 :
76 303 : requires_vala_extern = true;
77 : }
78 : }
79 :
80 357 : if (st.base_struct == null) {
81 331 : decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (get_ccode_name (st)), new CCodeVariableDeclarator (get_ccode_name (st))));
82 : } else {
83 26 : decl_space.add_type_declaration (new CCodeTypeDefinition (get_ccode_name (st.base_struct), new CCodeVariableDeclarator (get_ccode_name (st))));
84 : }
85 :
86 357 : var instance_struct = new CCodeStruct ("_%s".printf (get_ccode_name (st)));
87 :
88 357 : if (st.version.deprecated) {
89 4 : if (context.profile == Profile.GOBJECT) {
90 4 : decl_space.add_include ("glib.h");
91 : }
92 4 : instance_struct.modifiers |= CCodeModifiers.DEPRECATED;
93 : }
94 :
95 1325 : foreach (Field f in st.get_fields ()) {
96 484 : if (f.binding == MemberBinding.INSTANCE) {
97 472 : append_field (instance_struct, f, decl_space);
98 : }
99 : }
100 :
101 357 : if (st.base_struct == null) {
102 331 : decl_space.add_type_definition (instance_struct);
103 : }
104 :
105 357 : if (st.is_simple_type ()) {
106 14 : return;
107 : }
108 :
109 343 : var function = new CCodeFunction (get_ccode_dup_function (st), get_ccode_name (st) + "*");
110 343 : if (st.is_private_symbol ()) {
111 1 : function.modifiers = CCodeModifiers.STATIC;
112 342 : } else if (context.hide_internal && st.is_internal_symbol ()) {
113 0 : function.modifiers = CCodeModifiers.INTERNAL;
114 : } else {
115 342 : function.modifiers |= CCodeModifiers.EXTERN;
116 342 : requires_vala_extern = true;
117 : }
118 343 : function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
119 343 : decl_space.add_function_declaration (function);
120 :
121 343 : function = new CCodeFunction (get_ccode_free_function (st), "void");
122 343 : if (st.is_private_symbol ()) {
123 1 : function.modifiers = CCodeModifiers.STATIC;
124 342 : } else if (context.hide_internal && st.is_internal_symbol ()) {
125 0 : function.modifiers = CCodeModifiers.INTERNAL;
126 : } else {
127 342 : function.modifiers = CCodeModifiers.EXTERN;
128 342 : requires_vala_extern = true;
129 : }
130 343 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
131 343 : decl_space.add_function_declaration (function);
132 :
133 343 : if (st.is_disposable ()) {
134 104 : function = new CCodeFunction (get_ccode_copy_function (st), "void");
135 104 : if (st.is_private_symbol ()) {
136 0 : function.modifiers = CCodeModifiers.STATIC;
137 104 : } else if (context.hide_internal && st.is_internal_symbol ()) {
138 0 : function.modifiers = CCodeModifiers.INTERNAL;
139 : } else {
140 104 : function.modifiers = CCodeModifiers.EXTERN;
141 104 : requires_vala_extern = true;
142 : }
143 104 : function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
144 104 : function.add_parameter (new CCodeParameter ("dest", get_ccode_name (st) + "*"));
145 104 : decl_space.add_function_declaration (function);
146 :
147 104 : function = new CCodeFunction (get_ccode_destroy_function (st), "void");
148 104 : if (st.is_private_symbol ()) {
149 0 : function.modifiers = CCodeModifiers.STATIC;
150 104 : } else if (context.hide_internal && st.is_internal_symbol ()) {
151 0 : function.modifiers = CCodeModifiers.INTERNAL;
152 : } else {
153 104 : function.modifiers = CCodeModifiers.EXTERN;
154 104 : requires_vala_extern = true;
155 : }
156 104 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
157 104 : decl_space.add_function_declaration (function);
158 : }
159 :
160 343 : if (context.profile == Profile.GOBJECT) {
161 332 : generate_auto_cleanup_clear (st, decl_space);
162 : }
163 : }
164 :
165 332 : void generate_auto_cleanup_clear (Struct st, CCodeFile decl_space) {
166 434 : if (st.is_disposable ()
167 102 : && (context.header_filename == null|| decl_space.file_type == CCodeFileType.PUBLIC_HEADER
168 0 : || (decl_space.file_type == CCodeFileType.INTERNAL_HEADER && st.is_internal_symbol ()))) {
169 102 : string auto_cleanup_clear_func = get_ccode_destroy_function (st);
170 102 : if (auto_cleanup_clear_func == null || auto_cleanup_clear_func == "") {
171 0 : Report.error (st.source_reference, "internal error: auto_cleanup_clear_func not available");
172 : }
173 102 : decl_space.add_type_member_declaration (new CCodeIdentifier ("G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (%s, %s)".printf (get_ccode_name (st), auto_cleanup_clear_func)));
174 102 : decl_space.add_type_member_declaration (new CCodeNewline ());
175 : }
176 : }
177 :
178 380 : public override void visit_struct (Struct st) {
179 190 : push_context (new EmitContext (st));
180 190 : push_line (st.source_reference);
181 :
182 380 : var old_instance_finalize_context = instance_finalize_context;
183 190 : instance_finalize_context = new EmitContext ();
184 :
185 190 : generate_struct_declaration (st, cfile);
186 :
187 190 : if (!st.is_internal_symbol ()) {
188 31 : generate_struct_declaration (st, header_file);
189 : }
190 190 : if (!st.is_private_symbol ()) {
191 189 : generate_struct_declaration (st, internal_header_file);
192 : }
193 :
194 190 : if (!st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type ()) {
195 164 : if (st.is_disposable ()) {
196 49 : begin_struct_destroy_function (st);
197 : }
198 : }
199 :
200 190 : st.accept_children (this);
201 :
202 190 : if (!st.is_boolean_type () && !st.is_integer_type () && !st.is_floating_type ()) {
203 164 : if (st.is_disposable ()) {
204 49 : add_struct_copy_function (st);
205 49 : add_struct_destroy_function (st);
206 : }
207 :
208 164 : if (!st.is_simple_type ()) {
209 157 : add_struct_dup_function (st);
210 157 : add_struct_free_function (st);
211 : }
212 : }
213 :
214 192 : instance_finalize_context = old_instance_finalize_context;
215 :
216 190 : pop_line ();
217 190 : pop_context ();
218 : }
219 :
220 314 : void add_struct_dup_function (Struct st) {
221 157 : var function = new CCodeFunction (get_ccode_dup_function (st), get_ccode_name (st) + "*");
222 157 : if (st.access == SymbolAccessibility.PRIVATE) {
223 1 : function.modifiers = CCodeModifiers.STATIC;
224 : }
225 :
226 157 : function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
227 :
228 157 : push_function (function);
229 :
230 157 : ccode.add_declaration (get_ccode_name (st) + "*", new CCodeVariableDeclarator ("dup"));
231 :
232 309 : if (context.profile == Profile.GOBJECT) {
233 : // g_new0 needs glib.h
234 152 : cfile.add_include ("glib.h");
235 152 : var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
236 152 : creation_call.add_argument (new CCodeConstant (get_ccode_name (st)));
237 152 : creation_call.add_argument (new CCodeConstant ("1"));
238 152 : ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
239 10 : } else if (context.profile == Profile.POSIX) {
240 : // calloc needs stdlib.h
241 5 : cfile.add_include ("stdlib.h");
242 :
243 5 : var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
244 5 : sizeof_call.add_argument (new CCodeConstant (get_ccode_name (st)));
245 :
246 5 : var creation_call = new CCodeFunctionCall (new CCodeIdentifier ("calloc"));
247 5 : creation_call.add_argument (new CCodeConstant ("1"));
248 5 : creation_call.add_argument (sizeof_call);
249 5 : ccode.add_assignment (new CCodeIdentifier ("dup"), creation_call);
250 : }
251 :
252 314 : if (st.is_disposable ()) {
253 49 : var copy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_copy_function (st)));
254 49 : copy_call.add_argument (new CCodeIdentifier ("self"));
255 49 : copy_call.add_argument (new CCodeIdentifier ("dup"));
256 49 : ccode.add_expression (copy_call);
257 : } else {
258 108 : cfile.add_include ("string.h");
259 :
260 108 : var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
261 108 : sizeof_call.add_argument (new CCodeConstant (get_ccode_name (st)));
262 :
263 108 : var copy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
264 108 : copy_call.add_argument (new CCodeIdentifier ("dup"));
265 108 : copy_call.add_argument (new CCodeIdentifier ("self"));
266 108 : copy_call.add_argument (sizeof_call);
267 108 : ccode.add_expression (copy_call);
268 : }
269 :
270 157 : ccode.add_return (new CCodeIdentifier ("dup"));
271 :
272 157 : pop_function ();
273 :
274 157 : cfile.add_function (function);
275 : }
276 :
277 314 : void add_struct_free_function (Struct st) {
278 157 : var function = new CCodeFunction (get_ccode_free_function (st), "void");
279 157 : if (st.is_private_symbol ()) {
280 1 : function.modifiers = CCodeModifiers.STATIC;
281 156 : } else if (context.hide_internal && st.is_internal_symbol ()) {
282 0 : function.modifiers = CCodeModifiers.INTERNAL;
283 : }
284 :
285 157 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
286 :
287 157 : push_function (function);
288 :
289 206 : if (st.is_disposable ()) {
290 49 : var destroy_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (st)));
291 49 : destroy_call.add_argument (new CCodeIdentifier ("self"));
292 49 : ccode.add_expression (destroy_call);
293 : }
294 :
295 309 : if (context.profile == Profile.GOBJECT) {
296 : // g_free needs glib.h
297 152 : cfile.add_include ("glib.h");
298 152 : var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
299 152 : free_call.add_argument (new CCodeIdentifier ("self"));
300 152 : ccode.add_expression (free_call);
301 10 : } else if (context.profile == Profile.POSIX) {
302 : // free needs stdlib.h
303 5 : cfile.add_include ("stdlib.h");
304 5 : var free_call = new CCodeFunctionCall (new CCodeIdentifier ("free"));
305 5 : free_call.add_argument (new CCodeIdentifier ("self"));
306 5 : ccode.add_expression (free_call);
307 : }
308 :
309 157 : pop_function ();
310 :
311 157 : cfile.add_function (function);
312 : }
313 :
314 98 : void add_struct_copy_function (Struct st) {
315 49 : var function = new CCodeFunction (get_ccode_copy_function (st), "void");
316 49 : if (st.is_private_symbol ()) {
317 0 : function.modifiers = CCodeModifiers.STATIC;
318 49 : } else if (context.hide_internal && st.is_internal_symbol ()) {
319 0 : function.modifiers = CCodeModifiers.INTERNAL;
320 : }
321 :
322 49 : function.add_parameter (new CCodeParameter ("self", "const " + get_ccode_name (st) + "*"));
323 49 : function.add_parameter (new CCodeParameter ("dest", get_ccode_name (st) + "*"));
324 :
325 49 : push_function (function);
326 :
327 49 : var dest_struct = new GLibValue (SemanticAnalyzer.get_data_type_for_symbol (st), new CCodeIdentifier ("(*dest)"), true);
328 : unowned Struct sym = st;
329 54 : while (sym.base_struct != null) {
330 5 : sym = sym.base_struct;
331 : }
332 217 : foreach (var f in sym.get_fields ()) {
333 168 : if (f.binding == MemberBinding.INSTANCE) {
334 84 : var value = load_field (f, load_this_parameter ((TypeSymbol) st));
335 84 : if ((!(f.variable_type is DelegateType) || get_ccode_delegate_target (f)) && requires_copy (f.variable_type)) {
336 50 : value = copy_value (value, f);
337 50 : if (value == null) {
338 : // error case, continue to avoid critical
339 0 : continue;
340 : }
341 : }
342 84 : store_field (f, dest_struct, value, false);
343 : }
344 : }
345 :
346 49 : pop_function ();
347 :
348 49 : cfile.add_function (function);
349 : }
350 :
351 98 : void begin_struct_destroy_function (Struct st) {
352 49 : push_context (instance_finalize_context);
353 :
354 49 : var function = new CCodeFunction (get_ccode_destroy_function (st), "void");
355 49 : if (st.is_private_symbol ()) {
356 0 : function.modifiers = CCodeModifiers.STATIC;
357 49 : } else if (context.hide_internal && st.is_internal_symbol ()) {
358 0 : function.modifiers = CCodeModifiers.INTERNAL;
359 : }
360 :
361 49 : function.add_parameter (new CCodeParameter ("self", get_ccode_name (st) + "*"));
362 :
363 49 : push_function (function);
364 :
365 49 : pop_context ();
366 : }
367 :
368 49 : void add_struct_destroy_function (Struct st) {
369 : unowned Struct sym = st;
370 54 : while (sym.base_struct != null) {
371 5 : sym = sym.base_struct;
372 : }
373 54 : if (st != sym) {
374 5 : push_context (instance_finalize_context);
375 :
376 5 : var destroy_func = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_destroy_function (sym)));
377 5 : destroy_func.add_argument (new CCodeIdentifier ("self"));
378 5 : ccode.add_expression (destroy_func);
379 :
380 5 : pop_context ();
381 : }
382 :
383 49 : cfile.add_function (instance_finalize_context.ccode);
384 : }
385 : }
386 :
|