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