Line data Source code
1 : /* valatyperegisterfunction.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
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.1 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 Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * C function to register a type at runtime.
27 : */
28 10027 : public abstract class Vala.TypeRegisterFunction {
29 : /**
30 : * Specifies the enum to be registered.
31 : */
32 40548 : public weak TypeSymbol type_symbol { get; private set; }
33 :
34 6338 : CCodeFragment source_declaration_fragment = new CCodeFragment ();
35 6338 : CCodeFragment declaration_fragment = new CCodeFragment ();
36 6338 : CCodeFragment definition_fragment = new CCodeFragment ();
37 :
38 6338 : protected TypeRegisterFunction (TypeSymbol sym) {
39 3169 : type_symbol = sym;
40 : }
41 :
42 : /**
43 : * Constructs the C function from the specified type.
44 : */
45 6338 : public void init_from_type (CodeContext context, bool plugin, bool declaration_only) {
46 3169 : bool fundamental = false;
47 3169 : unowned Class? cl = type_symbol as Class;
48 2263 : if (cl != null && !cl.is_compact && cl.base_class == null) {
49 824 : fundamental = true;
50 : }
51 :
52 3169 : string type_id_name = "%s_type_id".printf (get_ccode_lower_case_name (type_symbol));
53 :
54 3169 : var type_block = new CCodeBlock ();
55 3169 : var type_once_block = new CCodeBlock ();
56 : CCodeDeclaration cdecl;
57 3169 : if (!plugin) {
58 3165 : cdecl = new CCodeDeclaration ("gsize");
59 3165 : cdecl.add_declarator (new CCodeVariableDeclarator (type_id_name + "__once", new CCodeConstant ("0")));
60 3165 : if (context.require_glib_version (2, 68)) {
61 11 : cdecl.modifiers = CCodeModifiers.STATIC;
62 : } else {
63 3154 : cdecl.modifiers = CCodeModifiers.STATIC | CCodeModifiers.VOLATILE;
64 : }
65 3165 : type_block.add_statement (cdecl);
66 : } else {
67 4 : cdecl = new CCodeDeclaration ("GType");
68 4 : cdecl.add_declarator (new CCodeVariableDeclarator (type_id_name, new CCodeConstant ("0")));
69 4 : cdecl.modifiers = CCodeModifiers.STATIC;
70 4 : source_declaration_fragment.append (cdecl);
71 : }
72 :
73 : CCodeFunction fun;
74 3169 : CCodeFunction fun_once = null;
75 3173 : if (!plugin) {
76 3165 : fun = new CCodeFunction (get_ccode_type_function (type_symbol), "GType");
77 3165 : fun.modifiers = CCodeModifiers.CONST;
78 :
79 : /* Function will not be prototyped anyway */
80 3165 : if (type_symbol.access == SymbolAccessibility.PRIVATE) {
81 : // avoid C warning as this function is not always used
82 36 : fun.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
83 3129 : } else if (context.hide_internal && type_symbol.access == SymbolAccessibility.INTERNAL) {
84 : // avoid C warning as this function is not always used
85 34 : fun.modifiers |= CCodeModifiers.INTERNAL | CCodeModifiers.UNUSED;
86 : } else {
87 3095 : fun.modifiers |= CCodeModifiers.EXTERN;
88 : }
89 :
90 3165 : fun.is_declaration = true;
91 3165 : declaration_fragment.append (fun.copy ());
92 3165 : fun.is_declaration = false;
93 :
94 3165 : fun_once = new CCodeFunction ("%s_once".printf (fun.name), "GType");
95 3165 : fun_once.modifiers = CCodeModifiers.STATIC;
96 3165 : if (context.require_glib_version (2, 58)) {
97 11 : fun_once.modifiers |= CCodeModifiers.NO_INLINE;
98 : }
99 :
100 3165 : fun_once.is_declaration = true;
101 3165 : source_declaration_fragment.append (fun_once.copy ());
102 3165 : fun_once.is_declaration = false;
103 : } else {
104 4 : fun = new CCodeFunction ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol)), "GType");
105 4 : fun.add_parameter (new CCodeParameter ("module", "GTypeModule *"));
106 :
107 4 : fun.is_declaration = true;
108 4 : declaration_fragment.append (fun.copy ());
109 4 : fun.is_declaration = false;
110 :
111 4 : var get_fun = new CCodeFunction (get_ccode_type_function (type_symbol), "GType");
112 4 : get_fun.modifiers = CCodeModifiers.CONST | CCodeModifiers.EXTERN;
113 :
114 4 : get_fun.is_declaration = true;
115 4 : declaration_fragment.append (get_fun.copy ());
116 4 : get_fun.is_declaration = false;
117 :
118 4 : get_fun.block = new CCodeBlock ();
119 4 : get_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
120 :
121 4 : definition_fragment.append (get_fun);
122 : }
123 :
124 3169 : string type_value_table_decl_name = null;
125 3169 : var type_init = new CCodeBlock ();
126 :
127 3993 : if (fundamental) {
128 824 : var cgtypetabledecl = new CCodeDeclaration ("const GTypeValueTable");
129 824 : cgtypetabledecl.modifiers = CCodeModifiers.STATIC;
130 :
131 824 : cgtypetabledecl.add_declarator (new CCodeVariableDeclarator ( "g_define_type_value_table", new CCodeConstant ("{ %s, %s, %s, %s, \"p\", %s, \"p\", %s }".printf (get_gtype_value_table_init_function_name (), get_gtype_value_table_free_function_name (), get_gtype_value_table_copy_function_name (), get_gtype_value_table_peek_pointer_function_name (), get_gtype_value_table_collect_value_function_name (), get_gtype_value_table_lcopy_value_function_name ()))));
132 824 : type_value_table_decl_name = "&g_define_type_value_table";
133 824 : type_init.add_statement ( cgtypetabledecl );
134 : }
135 : else {
136 2345 : type_value_table_decl_name = "NULL";
137 : }
138 :
139 :
140 5791 : if (type_symbol is ObjectTypeSymbol) {
141 2622 : var ctypedecl = new CCodeDeclaration ("const GTypeInfo");
142 2622 : ctypedecl.modifiers = CCodeModifiers.STATIC;
143 2622 : ctypedecl.add_declarator (new CCodeVariableDeclarator ("g_define_type_info", new CCodeConstant ("{ sizeof (%s), (GBaseInitFunc) %s, (GBaseFinalizeFunc) %s, (GClassInitFunc) %s, (GClassFinalizeFunc) %s, NULL, %s, 0, (GInstanceInitFunc) %s, %s }".printf (get_type_struct_name (), get_base_init_func_name (), (plugin) ? get_base_finalize_func_name () : "NULL", get_class_init_func_name (), get_class_finalize_func_name (), get_instance_struct_size (), get_instance_init_func_name (), type_value_table_decl_name))));
144 2622 : type_init.add_statement (ctypedecl);
145 3446 : if (fundamental) {
146 824 : var ctypefundamentaldecl = new CCodeDeclaration ("const GTypeFundamentalInfo");
147 824 : ctypefundamentaldecl.modifiers = CCodeModifiers.STATIC;
148 824 : ctypefundamentaldecl.add_declarator (new CCodeVariableDeclarator ("g_define_type_fundamental_info", new CCodeConstant ("{ (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }")));
149 824 : type_init.add_statement (ctypefundamentaldecl);
150 : }
151 : }
152 :
153 3169 : type_init.add_statement (get_type_interface_init_declaration ());
154 :
155 : CCodeFunctionCall reg_call;
156 3169 : if (type_symbol is Struct) {
157 441 : reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_type_register_static"));
158 2728 : } else if (type_symbol is Enum) {
159 68 : unowned Enum en = (Enum) type_symbol;
160 68 : if (en.is_flags) {
161 14 : reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_flags_register_static"));
162 : } else {
163 54 : reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_enum_register_static"));
164 : }
165 2660 : } else if (type_symbol is ErrorDomain) {
166 38 : reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_enum_register_static"));
167 2622 : } else if (fundamental) {
168 824 : reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_fundamental"));
169 824 : reg_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("g_type_fundamental_next")));
170 1798 : } else if (!plugin) {
171 1794 : reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_static"));
172 1794 : reg_call.add_argument (new CCodeIdentifier (get_parent_type_name ()));
173 : } else {
174 4 : reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_module_register_type"));
175 4 : reg_call.add_argument (new CCodeIdentifier ("module"));
176 4 : reg_call.add_argument (new CCodeIdentifier (get_parent_type_name ()));
177 : }
178 3169 : reg_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_ccode_name (type_symbol))));
179 3610 : if (type_symbol is Struct) {
180 441 : var st = (Struct) type_symbol;
181 441 : reg_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (get_ccode_dup_function (st)), "GBoxedCopyFunc"));
182 441 : reg_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (get_ccode_free_function (st)), "GBoxedFreeFunc"));
183 2796 : } else if (type_symbol is Enum) {
184 68 : unowned Enum en = (Enum) type_symbol;
185 68 : var clist = new CCodeInitializerList (); /* or during visit time? */
186 :
187 68 : CCodeInitializerList clist_ev = null;
188 466 : foreach (EnumValue ev in en.get_values ()) {
189 199 : clist_ev = new CCodeInitializerList ();
190 199 : clist_ev.append (new CCodeConstant (get_ccode_name (ev)));
191 199 : clist_ev.append (new CCodeConstant ("\"%s\"".printf (get_ccode_name (ev))));
192 199 : clist_ev.append (new CCodeConstant ("\"%s\"".printf (ev.nick)));
193 199 : clist.append (clist_ev);
194 : }
195 :
196 68 : clist_ev = new CCodeInitializerList ();
197 68 : clist_ev.append (new CCodeConstant ("0"));
198 68 : clist_ev.append (new CCodeConstant ("NULL"));
199 68 : clist_ev.append (new CCodeConstant ("NULL"));
200 68 : clist.append (clist_ev);
201 :
202 68 : var enum_decl = new CCodeVariableDeclarator ("values[]", clist);
203 :
204 68 : if (en.is_flags) {
205 14 : cdecl = new CCodeDeclaration ("const GFlagsValue");
206 : } else {
207 54 : cdecl = new CCodeDeclaration ("const GEnumValue");
208 : }
209 :
210 68 : cdecl.add_declarator (enum_decl);
211 68 : cdecl.modifiers = CCodeModifiers.STATIC;
212 :
213 68 : type_init.add_statement (cdecl);
214 :
215 68 : reg_call.add_argument (new CCodeIdentifier ("values"));
216 2698 : } else if (type_symbol is ErrorDomain) {
217 38 : unowned ErrorDomain edomain = (ErrorDomain) type_symbol;
218 38 : var clist = new CCodeInitializerList (); /* or during visit time? */
219 :
220 38 : CCodeInitializerList clist_ec = null;
221 142 : foreach (ErrorCode ec in edomain.get_codes ()) {
222 52 : clist_ec = new CCodeInitializerList ();
223 52 : clist_ec.append (new CCodeConstant (get_ccode_name (ec)));
224 52 : clist_ec.append (new CCodeConstant ("\"%s\"".printf (get_ccode_name (ec))));
225 52 : clist_ec.append (new CCodeConstant ("\"%s\"".printf (ec.nick)));
226 52 : clist.append (clist_ec);
227 : }
228 :
229 38 : clist_ec = new CCodeInitializerList ();
230 38 : clist_ec.append (new CCodeConstant ("0"));
231 38 : clist_ec.append (new CCodeConstant ("NULL"));
232 38 : clist_ec.append (new CCodeConstant ("NULL"));
233 38 : clist.append (clist_ec);
234 :
235 38 : var edomain_decl = new CCodeVariableDeclarator ("values[]", clist);
236 :
237 38 : cdecl = new CCodeDeclaration ("const GEnumValue");
238 38 : cdecl.add_declarator (edomain_decl);
239 38 : cdecl.modifiers = CCodeModifiers.STATIC;
240 :
241 38 : type_init.add_statement (cdecl);
242 :
243 38 : reg_call.add_argument (new CCodeIdentifier ("values"));
244 : } else {
245 2622 : reg_call.add_argument (new CCodeIdentifier ("&g_define_type_info"));
246 2622 : if (fundamental) {
247 824 : reg_call.add_argument (new CCodeIdentifier ("&g_define_type_fundamental_info"));
248 : }
249 2622 : reg_call.add_argument (new CCodeConstant (get_type_flags ()));
250 : }
251 :
252 3169 : var once_call_block = new CCodeBlock ();
253 6334 : if (!plugin) {
254 3165 : var temp_decl = new CCodeDeclaration ("GType");
255 3165 : temp_decl.add_declarator (new CCodeVariableDeclarator (type_id_name, reg_call));
256 3165 : type_init.add_statement (temp_decl);
257 3165 : temp_decl = new CCodeDeclaration ("GType");
258 3165 : temp_decl.add_declarator (new CCodeVariableDeclarator (type_id_name, new CCodeFunctionCall (new CCodeIdentifier (fun_once.name))));
259 3165 : once_call_block.add_statement (temp_decl);
260 : } else {
261 4 : type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (type_id_name), reg_call)));
262 : }
263 :
264 3178 : if (cl != null && cl.has_class_private_fields) {
265 : CCodeFunctionCall add_class_private_call;
266 :
267 9 : add_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_add_class_private"));
268 9 : add_class_private_call.add_argument (new CCodeIdentifier (type_id_name));
269 9 : add_class_private_call.add_argument (new CCodeIdentifier ("sizeof (%sPrivate)".printf (get_ccode_type_name (cl))));
270 9 : type_init.add_statement (new CCodeExpressionStatement (add_class_private_call));
271 : }
272 :
273 3169 : if (!declaration_only) {
274 1095 : get_type_interface_init_statements (context, type_init, plugin);
275 : }
276 :
277 3169 : if (cl != null && (cl.has_private_fields || cl.has_type_parameters ())) {
278 1668 : if (!plugin) {
279 832 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_add_instance_private"));
280 832 : ccall.add_argument (new CCodeIdentifier (type_id_name));
281 832 : ccall.add_argument (new CCodeIdentifier ("sizeof (%sPrivate)".printf (get_ccode_name (cl))));
282 832 : type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_private_offset".printf (get_ccode_name (cl))), ccall)));
283 : } else {
284 4 : type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("%s_private_offset".printf (get_ccode_name (cl))), new CCodeIdentifier ("sizeof (%sPrivate)".printf (get_ccode_name (cl))))));
285 : }
286 : }
287 :
288 6334 : if (!plugin) {
289 : // the condition that guards the type initialisation
290 3165 : var enter = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
291 3165 : enter.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (type_id_name + "__once")));
292 :
293 3165 : var leave = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
294 3165 : leave.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (type_id_name + "__once")));
295 3165 : leave.add_argument (new CCodeIdentifier (type_id_name));
296 3165 : once_call_block.add_statement (new CCodeExpressionStatement (leave));
297 :
298 3165 : var cif = new CCodeIfStatement (enter, once_call_block);
299 3165 : type_block.add_statement (cif);
300 3165 : type_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name + "__once")));
301 :
302 7183 : type_once_block = type_init;
303 3165 : type_once_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
304 : } else {
305 8 : type_block = type_init;
306 4 : type_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
307 : }
308 :
309 3169 : if (!plugin) {
310 3165 : fun_once.block = type_once_block;
311 3165 : definition_fragment.append (fun_once);
312 : }
313 :
314 3169 : fun.block = type_block;
315 3169 : definition_fragment.append (fun);
316 : }
317 :
318 : /**
319 : * Returns the name of the type struct in C code.
320 : *
321 : * @return C struct name
322 : */
323 2622 : public virtual string get_type_struct_name () {
324 0 : assert_not_reached ();
325 : }
326 : /**
327 : * Returns the name of the base_init function in C code.
328 : *
329 : * @return C function name
330 : */
331 2622 : public virtual string get_base_init_func_name () {
332 0 : assert_not_reached ();
333 : }
334 :
335 : /**
336 : * Returns the name of the class_finalize function in C code.
337 : *
338 : * @return C function name
339 : */
340 2622 : public virtual string get_class_finalize_func_name () {
341 0 : assert_not_reached ();
342 : }
343 :
344 : /**
345 : * Returns the name of the base_finalize function in C code.
346 : *
347 : * @return C function name
348 : */
349 4 : public virtual string get_base_finalize_func_name () {
350 0 : assert_not_reached ();
351 : }
352 :
353 : /**
354 : * Returns the name of the class_init function in C code.
355 : *
356 : * @return C function name
357 : */
358 2622 : public virtual string get_class_init_func_name () {
359 0 : assert_not_reached ();
360 : }
361 :
362 : /**
363 : * Returns the size of the instance struct in C code.
364 : *
365 : * @return C instance struct size
366 : */
367 2622 : public virtual string get_instance_struct_size () {
368 0 : assert_not_reached ();
369 : }
370 :
371 : /**
372 : * Returns the name of the instance_init function in C code.
373 : *
374 : * @return C function name
375 : */
376 2622 : public virtual string get_instance_init_func_name () {
377 0 : assert_not_reached ();
378 : }
379 :
380 : /**
381 : * Returns the name of the parent type in C code.
382 : *
383 : * @return C function name
384 : */
385 1798 : public virtual string get_parent_type_name () {
386 0 : assert_not_reached ();
387 : }
388 :
389 :
390 :
391 : /**
392 : * Returns the C-name of the new generated GTypeValueTable init function or null when not available.
393 : *
394 : * @return C function name
395 : */
396 824 : public virtual string? get_gtype_value_table_init_function_name () {
397 0 : return null;
398 : }
399 :
400 : /**
401 : * Returns the C-name of the new generated GTypeValueTable peek pointer function or null when not available.
402 : *
403 : * @return C function name
404 : */
405 824 : public virtual string? get_gtype_value_table_peek_pointer_function_name () {
406 0 : return null;
407 : }
408 :
409 : /**
410 : * Returns the C-name of the new generated GTypeValueTable free function or null when not available.
411 : *
412 : * @return C function name
413 : */
414 824 : public virtual string? get_gtype_value_table_free_function_name () {
415 0 : return null;
416 : }
417 :
418 : /**
419 : * Returns the C-name of the new generated GTypeValueTable copy function or null when not available.
420 : *
421 : * @return C function name
422 : */
423 824 : public virtual string? get_gtype_value_table_copy_function_name () {
424 0 : return null;
425 : }
426 :
427 : /**
428 : * Returns the C-name of the new generated GTypeValueTable lcopy function or null when not available.
429 : *
430 : * @return C function name
431 : */
432 824 : public virtual string? get_gtype_value_table_lcopy_value_function_name () {
433 0 : return null;
434 : }
435 :
436 : /**
437 : * Returns the C-name of the new generated GTypeValueTable collect value function or null when not available.
438 : *
439 : * @return C function name
440 : */
441 824 : public virtual string? get_gtype_value_table_collect_value_function_name () {
442 0 : return null;
443 : }
444 :
445 : /**
446 : * Returns the set of type flags to be applied when registering.
447 : *
448 : * @return type flags
449 : */
450 2622 : public virtual string get_type_flags () {
451 359 : if (CodeContext.get ().require_glib_version (2, 74)) {
452 0 : return "G_TYPE_FLAG_NONE";
453 : } else {
454 359 : return "0";
455 : }
456 : }
457 :
458 : /**
459 : * Returns additional C declarations to setup interfaces.
460 : *
461 : * @return C declarations
462 : */
463 3169 : public virtual CCodeFragment get_type_interface_init_declaration () {
464 906 : return new CCodeFragment ();
465 : }
466 :
467 : /**
468 : * Returns additional C initialization statements to setup interfaces.
469 : */
470 1339 : public virtual void get_type_interface_init_statements (CodeContext context, CCodeBlock block, bool plugin) {
471 : }
472 :
473 851 : public CCodeFragment get_source_declaration () {
474 851 : return source_declaration_fragment;
475 : }
476 :
477 : /**
478 : * Returns the declaration for this type register function in C code.
479 : *
480 : * @return C function declaration fragment
481 : */
482 2068 : public CCodeFragment get_declaration () {
483 2068 : return declaration_fragment;
484 : }
485 :
486 : /**
487 : * Returns the definition for this type register function in C code.
488 : *
489 : * @return C function definition fragment
490 : */
491 1095 : public CCodeFragment get_definition () {
492 1095 : return definition_fragment;
493 : }
494 : }
|