codegen: Fix array size variable on assignment
[vala-lang.git] / codegen / valatyperegisterfunction.vala
blobe3f38ad0f80b43e7651b76c9681a243cbf1f61f7
1 /* valatyperegisterfunction.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * C function to register a type at runtime.
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 ();
33 public CodeContext context { get; set; }
35 /**
36 * Constructs the C function from the specified type.
38 public void init_from_type (bool plugin, bool declaration_only) {
39 bool use_thread_safe = !plugin;
41 bool fundamental = false;
42 Class cl = get_type_declaration () as Class;
43 if (cl != null && !cl.is_compact && cl.base_class == null) {
44 fundamental = true;
47 string type_id_name = "%s_type_id".printf (get_type_declaration ().get_lower_case_cname (null));
49 var type_block = new CCodeBlock ();
50 CCodeDeclaration cdecl;
51 if (use_thread_safe) {
52 cdecl = new CCodeDeclaration ("gsize");
53 cdecl.add_declarator (new CCodeVariableDeclarator (type_id_name + "__volatile", new CCodeConstant ("0")));
54 } else {
55 cdecl = new CCodeDeclaration ("GType");
56 cdecl.add_declarator (new CCodeVariableDeclarator (type_id_name, new CCodeConstant ("0")));
58 cdecl.modifiers = CCodeModifiers.STATIC;
59 if (use_thread_safe) {
60 cdecl.modifiers |= CCodeModifiers.VOLATILE;
62 if (!plugin) {
63 type_block.add_statement (cdecl);
64 } else {
65 source_declaration_fragment.append (cdecl);
68 CCodeFunction fun;
69 if (!plugin) {
70 fun = new CCodeFunction ("%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
71 fun.attributes = "G_GNUC_CONST";
73 /* Function will not be prototyped anyway */
74 if (get_accessibility () == SymbolAccessibility.PRIVATE) {
75 fun.modifiers = CCodeModifiers.STATIC;
76 // avoid C warning as this function is not always used
77 fun.attributes += " G_GNUC_UNUSED";
79 } else {
80 fun = new CCodeFunction ("%s_register_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
81 fun.add_parameter (new CCodeParameter ("module", "GTypeModule *"));
83 var get_fun = new CCodeFunction ("%s_get_type".printf (get_type_declaration ().get_lower_case_cname (null)), "GType");
84 get_fun.attributes = "G_GNUC_CONST";
86 get_fun.is_declaration = true;
87 declaration_fragment.append (get_fun.copy ());
88 get_fun.is_declaration = false;
90 get_fun.block = new CCodeBlock ();
91 get_fun.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
93 definition_fragment.append (get_fun);
96 string type_value_table_decl_name = null;
97 var type_init = new CCodeBlock ();
99 if (fundamental) {
100 var cgtypetabledecl = new CCodeDeclaration ("const GTypeValueTable");
101 cgtypetabledecl.modifiers = CCodeModifiers.STATIC;
103 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 ()))));
104 type_value_table_decl_name = "&g_define_type_value_table";
105 type_init.add_statement ( cgtypetabledecl );
107 else {
108 type_value_table_decl_name = "NULL";
112 if (get_type_declaration () is ObjectTypeSymbol) {
113 var ctypedecl = new CCodeDeclaration ("const GTypeInfo");
114 ctypedecl.modifiers = CCodeModifiers.STATIC;
115 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))));
116 type_init.add_statement (ctypedecl);
117 if (fundamental) {
118 var ctypefundamentaldecl = new CCodeDeclaration ("const GTypeFundamentalInfo");
119 ctypefundamentaldecl.modifiers = CCodeModifiers.STATIC;
120 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) }")));
121 type_init.add_statement (ctypefundamentaldecl);
125 type_init.add_statement (get_type_interface_init_declaration ());
127 if (cl != null && cl.has_class_private_fields && !context.require_glib_version (2, 24)) {
128 CCodeFunctionCall quark_reg_call;
130 if (plugin) {
131 quark_reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
132 } else {
133 quark_reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
136 quark_reg_call.add_argument (new CCodeConstant ("\"Vala%sClassPrivate\"".printf (get_type_declaration ().get_cname ())));
138 type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_vala_%s_class_private_quark".printf (get_type_declaration ().get_lower_case_cname ())), quark_reg_call)));
141 CCodeFunctionCall reg_call;
142 if (get_type_declaration () is Struct) {
143 reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_boxed_type_register_static"));
144 } else if (get_type_declaration () is Enum) {
145 var en = get_type_declaration () as Enum;
146 if (en.is_flags) {
147 reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_flags_register_static"));
148 } else {
149 reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_enum_register_static"));
151 } else if (fundamental) {
152 reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_fundamental"));
153 reg_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("g_type_fundamental_next")));
154 } else if (!plugin) {
155 reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_register_static"));
156 reg_call.add_argument (new CCodeIdentifier (get_parent_type_name ()));
157 } else {
158 reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_module_register_type"));
159 reg_call.add_argument (new CCodeIdentifier ("module"));
160 reg_call.add_argument (new CCodeIdentifier (get_parent_type_name ()));
162 reg_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_declaration ().get_cname ())));
163 if (get_type_declaration () is Struct) {
164 var st = (Struct) get_type_declaration ();
165 reg_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (st.get_dup_function ()), "GBoxedCopyFunc"));
166 reg_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (st.get_free_function ()), "GBoxedFreeFunc"));
167 } else if (get_type_declaration () is Enum) {
168 var en = get_type_declaration () as Enum;
169 var clist = new CCodeInitializerList (); /* or during visit time? */
171 CCodeInitializerList clist_ev = null;
172 foreach (EnumValue ev in en.get_values ()) {
173 clist_ev = new CCodeInitializerList ();
174 clist_ev.append (new CCodeConstant (ev.get_cname ()));
175 clist_ev.append (new CCodeIdentifier ("\"%s\"".printf (ev.get_cname ())));
176 clist_ev.append (ev.get_canonical_cconstant ());
177 clist.append (clist_ev);
180 clist_ev = new CCodeInitializerList ();
181 clist_ev.append (new CCodeConstant ("0"));
182 clist_ev.append (new CCodeConstant ("NULL"));
183 clist_ev.append (new CCodeConstant ("NULL"));
184 clist.append (clist_ev);
186 var enum_decl = new CCodeVariableDeclarator ("values[]", clist);
188 if (en.is_flags) {
189 cdecl = new CCodeDeclaration ("const GFlagsValue");
190 } else {
191 cdecl = new CCodeDeclaration ("const GEnumValue");
194 cdecl.add_declarator (enum_decl);
195 cdecl.modifiers = CCodeModifiers.STATIC;
197 type_init.add_statement (cdecl);
199 reg_call.add_argument (new CCodeIdentifier ("values"));
200 } else {
201 reg_call.add_argument (new CCodeIdentifier ("&g_define_type_info"));
202 if (fundamental) {
203 reg_call.add_argument (new CCodeIdentifier ("&g_define_type_fundamental_info"));
205 reg_call.add_argument (new CCodeConstant (get_type_flags ()));
208 if (use_thread_safe && !plugin) {
209 var temp_decl = new CCodeDeclaration ("GType");
210 temp_decl.add_declarator (new CCodeVariableDeclarator (type_id_name, reg_call));
211 type_init.add_statement (temp_decl);
212 } else {
213 type_init.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (type_id_name), reg_call)));
216 if (cl != null && cl.has_class_private_fields && context.require_glib_version (2, 24)) {
217 CCodeFunctionCall add_class_private_call;
219 add_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_add_class_private"));
220 add_class_private_call.add_argument (new CCodeIdentifier (type_id_name));
221 add_class_private_call.add_argument (new CCodeIdentifier ("sizeof (%sClassPrivate)".printf (get_type_declaration ().get_cname ())));
222 type_init.add_statement (new CCodeExpressionStatement (add_class_private_call));
225 if (!declaration_only) {
226 get_type_interface_init_statements (type_init, plugin);
229 if (!plugin) {
230 CCodeExpression condition; // the condition that guards the type initialisation
231 if (use_thread_safe) {
232 var enter = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
233 enter.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (type_id_name + "__volatile")));
234 condition = enter;
236 var leave = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
237 leave.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (type_id_name + "__volatile")));
238 leave.add_argument (new CCodeIdentifier (type_id_name));
239 type_init.add_statement (new CCodeExpressionStatement (leave));
240 } else {
241 var id = new CCodeIdentifier (type_id_name);
242 var zero = new CCodeConstant ("0");
243 condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, id, zero);
246 CCodeExpression cond;
247 if (use_thread_safe) {
248 cond = condition;
249 } else {
250 cond = new CCodeFunctionCall (new CCodeIdentifier ("G_UNLIKELY"));
251 (cond as CCodeFunctionCall).add_argument (condition);
253 var cif = new CCodeIfStatement (cond, type_init);
254 type_block.add_statement (cif);
255 } else {
256 type_block = type_init;
259 if (use_thread_safe) {
260 type_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name + "__volatile")));
261 } else {
262 type_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier (type_id_name)));
265 fun.is_declaration = true;
266 declaration_fragment.append (fun.copy ());
267 fun.is_declaration = false;
269 fun.block = type_block;
271 definition_fragment.append (fun);
275 * Returns the data type to be registered.
277 * @return type to be registered
279 public abstract TypeSymbol get_type_declaration ();
282 * Returns the name of the type struct in C code.
284 * @return C struct name
286 public virtual string get_type_struct_name () {
287 assert_not_reached ();
290 * Returns the name of the base_init function in C code.
292 * @return C function name
294 public virtual string get_base_init_func_name () {
295 assert_not_reached ();
299 * Returns the name of the class_finalize function in C code.
301 * @return C function name
303 public virtual string get_class_finalize_func_name () {
304 assert_not_reached ();
308 * Returns the name of the base_finalize function in C code.
310 * @return C function name
312 public virtual string get_base_finalize_func_name () {
313 assert_not_reached ();
317 * Returns the name of the class_init function in C code.
319 * @return C function name
321 public virtual string get_class_init_func_name () {
322 assert_not_reached ();
326 * Returns the size of the instance struct in C code.
328 * @return C instance struct size
330 public virtual string get_instance_struct_size () {
331 assert_not_reached ();
335 * Returns the name of the instance_init function in C code.
337 * @return C function name
339 public virtual string get_instance_init_func_name () {
340 assert_not_reached ();
344 * Returns the name of the parent type in C code.
346 * @return C function name
348 public virtual string get_parent_type_name () {
349 assert_not_reached ();
355 * Returns the C-name of the new generated GTypeValueTable init function or null when not available.
357 * @return C function name
359 public virtual string? get_gtype_value_table_init_function_name () {
360 return null;
364 * Returns the C-name of the new generated GTypeValueTable peek pointer function or null when not available.
366 * @return C function name
368 public virtual string? get_gtype_value_table_peek_pointer_function_name () {
369 return null;
373 * Returns the C-name of the new generated GTypeValueTable free function or null when not available.
375 * @return C function name
377 public virtual string? get_gtype_value_table_free_function_name () {
378 return null;
382 * Returns the C-name of the new generated GTypeValueTable copy function or null when not available.
384 * @return C function name
386 public virtual string? get_gtype_value_table_copy_function_name () {
387 return null;
391 * Returns the C-name of the new generated GTypeValueTable lcopy function or null when not available.
393 * @return C function name
395 public virtual string? get_gtype_value_table_lcopy_value_function_name () {
396 return null;
400 * Returns the C-name of the new generated GTypeValueTable collect value function or null when not available.
402 * @return C function name
404 public virtual string? get_gtype_value_table_collect_value_function_name () {
405 return null;
409 * Returns the set of type flags to be applied when registering.
411 * @return type flags
413 public virtual string get_type_flags () {
414 return "0";
418 * Returns additional C declarations to setup interfaces.
420 * @return C declarations
422 public virtual CCodeFragment get_type_interface_init_declaration () {
423 return new CCodeFragment ();
427 * Returns additional C initialization statements to setup interfaces.
429 * @return C statements
431 public virtual void get_type_interface_init_statements (CCodeBlock block, bool plugin) {
434 public CCodeFragment get_source_declaration () {
435 return source_declaration_fragment;
439 * Returns the declaration for this type register function in C code.
441 * @return C function declaration fragment
443 public CCodeFragment get_declaration () {
444 return declaration_fragment;
448 * Returns the definition for this type register function in C code.
450 * @return C function definition fragment
452 public CCodeFragment get_definition () {
453 return definition_fragment;
457 * Returns the accessibility for this type.
459 public abstract SymbolAccessibility get_accessibility ();