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