1/* valaccodemethodmodule.vala 2 * 3 * Copyright (C) 2007-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 * Raffaele Sandrini <raffaele@sandrini.ch> 22 */ 23 24using GLib; 25 26/** 27 * The link between a method and generated code. 28 */ 29public abstract class Vala.CCodeMethodModule : CCodeStructModule { 30 31 private bool ellipses_to_valist = false; 32 33 public override bool method_has_wrapper (Method method) { 34 return (method.get_attribute ("NoWrapper") == null); 35 } 36 37 string get_creturn_type (Method m, string default_value) { 38 string type = get_ccode_type (m); 39 if (type == null) { 40 return default_value; 41 } 42 return type; 43 } 44 45 bool is_gtypeinstance_creation_method (Method m) { 46 bool result = false; 47 48 var cl = m.parent_symbol as Class; 49 if (m is CreationMethod && cl != null && !cl.is_compact) { 50 result = true; 51 } 52 53 return result; 54 } 55 56 public virtual void generate_method_result_declaration (Method m, CCodeFile decl_space, CCodeFunction cfunc, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) { 57 var creturn_type = get_callable_creturn_type (m); 58 cfunc.return_type = get_creturn_type (m, get_ccode_name (creturn_type)); 59 60 generate_type_declaration (m.return_type, decl_space); 61 62 if (m.return_type.is_real_non_null_struct_type ()) { 63 // structs are returned via out parameter 64 var cparam = new CCodeParameter ("result", get_ccode_name (m.return_type) + "*"); 65 cparam_map.set (get_param_pos (-3), cparam); 66 if (carg_map != null) { 67 carg_map.set (get_param_pos (-3), get_cexpression ("result")); 68 } 69 } else if (get_ccode_array_length (m) && m.return_type is ArrayType) { 70 // return array length if appropriate 71 var array_type = (ArrayType) m.return_type; 72 var length_ctype = get_ccode_array_length_type (m) + "*"; 73 74 for (int dim = 1; dim <= array_type.rank; dim++) { 75 var cparam = new CCodeParameter (get_array_length_cname ("result", dim), length_ctype); 76 cparam_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), cparam); 77 if (carg_map != null) { 78 carg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), get_cexpression (cparam.name)); 79 } 80 } 81 } else if (get_ccode_delegate_target (m) && m.return_type is DelegateType) { 82 // return delegate target if appropriate 83 var deleg_type = (DelegateType) m.return_type; 84 if (deleg_type.delegate_symbol.has_target) { 85 var cparam = new CCodeParameter (get_delegate_target_cname ("result"), get_ccode_name (delegate_target_type) + "*"); 86 cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), cparam); 87 if (carg_map != null) { 88 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), get_cexpression (cparam.name)); 89 } 90 if (deleg_type.is_disposable ()) { 91 cparam = new CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), get_ccode_name (delegate_target_destroy_type) + "*"); 92 cparam_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), cparam); 93 if (carg_map != null) { 94 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), get_cexpression (cparam.name)); 95 } 96 } 97 } 98 } 99 100 if (m.has_error_type_parameter ()) { 101 var error_types = new ArrayList<DataType> (); 102 m.get_error_types (error_types); 103 foreach (DataType error_type in error_types) { 104 generate_type_declaration (error_type, decl_space); 105 } 106 107 var cparam = new CCodeParameter ("error", "GError**"); 108 cparam_map.set (get_param_pos (get_ccode_error_pos (m)), cparam); 109 if (carg_map != null) { 110 carg_map.set (get_param_pos (get_ccode_error_pos (m)), new CCodeIdentifier (cparam.name)); 111 } 112 } 113 } 114 115 public void complete_async () { 116 var data_var = new CCodeIdentifier ("_data_"); 117 var async_result_expr = new CCodeMemberAccess.pointer (data_var, "_async_result"); 118 119 var finish_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_pointer")); 120 finish_call.add_argument (async_result_expr); 121 finish_call.add_argument (data_var); 122 finish_call.add_argument (new CCodeConstant ("NULL")); 123 ccode.add_expression (finish_call); 124 125 // Preserve the "complete now" behavior if state != 0, do so by 126 // iterating the GTask's main context till the task is complete. 127 var state = new CCodeMemberAccess.pointer (data_var, "_state_"); 128 var zero = new CCodeConstant ("0"); 129 var state_is_not_zero = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, state, zero); 130 ccode.open_if (state_is_not_zero); 131 132 CCodeExpression task_is_complete; 133 134 var task_complete = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_completed")); 135 task_complete.add_argument (async_result_expr); 136 task_is_complete = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, task_complete); 137 138 ccode.open_while (task_is_complete); 139 var task_context = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_context")); 140 task_context.add_argument (async_result_expr); 141 var iterate_context = new CCodeFunctionCall (new CCodeIdentifier ("g_main_context_iteration")); 142 iterate_context.add_argument (task_context); 143 iterate_context.add_argument (new CCodeConstant ("TRUE")); 144 ccode.add_expression (iterate_context); 145 ccode.close (); 146 147 ccode.close (); 148 149 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref")); 150 unref.add_argument (async_result_expr); 151 ccode.add_expression (unref); 152 153 ccode.add_return (new CCodeConstant ("FALSE")); 154 } 155 156 public override bool generate_method_declaration (Method m, CCodeFile decl_space) { 157 if (m.is_async_callback) { 158 return false; 159 } 160 if ((m.is_abstract || m.is_virtual) && get_ccode_no_wrapper (m)) { 161 return false; 162 } 163 if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) { 164 return false; 165 } 166 167 generate_type_declaration (new MethodType (m), decl_space); 168 169 var function = new CCodeFunction (get_ccode_name (m)); 170 171 if (m.is_private_symbol () && !m.external) { 172 function.modifiers |= CCodeModifiers.STATIC; 173 if (m.is_inline) { 174 function.modifiers |= CCodeModifiers.INLINE; 175 } 176 } else if (context.hide_internal && m.is_internal_symbol () && !m.external) { 177 function.modifiers |= CCodeModifiers.INTERNAL; 178 } 179 180 if (m.entry_point) { 181 function.modifiers |= CCodeModifiers.STATIC; 182 } 183 184 if (m.version.deprecated) { 185 if (context.profile == Profile.GOBJECT) { 186 decl_space.add_include ("glib.h"); 187 } 188 function.modifiers |= CCodeModifiers.DEPRECATED; 189 } 190 191 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal); 192 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal); 193 194 var cl = m.parent_symbol as Class; 195 196 // do not generate _new functions for creation methods of abstract classes 197 if (!(m is CreationMethod && cl != null && cl.is_abstract && !cl.is_compact)) { 198 bool etv_tmp = ellipses_to_valist; 199 ellipses_to_valist = false; 200 generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake"))); 201 ellipses_to_valist = etv_tmp; 202 203 decl_space.add_function_declaration (function); 204 } 205 206 if (is_gtypeinstance_creation_method (m)) { 207 // _construct function 208 function = new CCodeFunction (get_ccode_real_name (m)); 209 210 if (m.is_private_symbol ()) { 211 function.modifiers |= CCodeModifiers.STATIC; 212 } else if (context.hide_internal && m.is_internal_symbol ()) { 213 function.modifiers |= CCodeModifiers.INTERNAL; 214 } 215 216 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal); 217 bool etv_tmp = ellipses_to_valist; 218 ellipses_to_valist = false; 219 generate_cparameters (m, decl_space, cparam_map, function); 220 ellipses_to_valist = etv_tmp; 221 222 decl_space.add_function_declaration (function); 223 224 if (m.is_variadic ()) { 225 // _constructv function 226 function = new CCodeFunction (get_ccode_constructv_name ((CreationMethod) m)); 227 228 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal); 229 generate_cparameters (m, decl_space, cparam_map, function); 230 231 decl_space.add_function_declaration (function); 232 } 233 } 234 235 return true; 236 } 237 238 void register_plugin_types (Symbol sym, Set<Symbol> registered_types) { 239 var ns = sym as Namespace; 240 var cl = sym as Class; 241 var iface = sym as Interface; 242 if (ns != null) { 243 foreach (var ns_ns in ns.get_namespaces ()) { 244 register_plugin_types (ns_ns, registered_types); 245 } 246 foreach (var ns_cl in ns.get_classes ()) { 247 register_plugin_types (ns_cl, registered_types); 248 } 249 foreach (var ns_iface in ns.get_interfaces ()) { 250 register_plugin_types (ns_iface, registered_types); 251 } 252 } else if (cl != null) { 253 register_plugin_type (cl, registered_types); 254 foreach (var cl_cl in cl.get_classes ()) { 255 register_plugin_types (cl_cl, registered_types); 256 } 257 } else if (iface != null) { 258 register_plugin_type (iface, registered_types); 259 foreach (var iface_cl in iface.get_classes ()) { 260 register_plugin_types (iface_cl, registered_types); 261 } 262 } 263 } 264 265 void register_plugin_type (ObjectTypeSymbol type_symbol, Set<Symbol> registered_types) { 266 if (type_symbol.external_package) { 267 return; 268 } 269 270 if (!registered_types.add (type_symbol)) { 271 // already registered 272 return; 273 } 274 275 var cl = type_symbol as Class; 276 if (cl != null) { 277 if (cl.is_compact) { 278 return; 279 } 280 281 // register base types first 282 foreach (var base_type in cl.get_base_types ()) { 283 register_plugin_type ((ObjectTypeSymbol) base_type.type_symbol, registered_types); 284 } 285 } 286 287 // Add function prototypes for required register-type-calls which are likely external 288 if (type_symbol.source_reference.file != cfile.file) { 289 // TODO Duplicated source with TypeRegisterFunction.init_from_type() 290 var register_func = new CCodeFunction ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null)), "GType"); 291 register_func.add_parameter (new CCodeParameter ("module", "GTypeModule *")); 292 register_func.is_declaration = true; 293 cfile.add_function_declaration (register_func); 294 } 295 296 var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null)))); 297 register_call.add_argument (new CCodeIdentifier (module_init_param_name)); 298 ccode.add_expression (register_call); 299 300 var iface = type_symbol as Interface; 301 if (iface != null) { 302 string? dbus_name = GDBusModule.get_dbus_name(type_symbol); 303 304 if (dbus_name != null) { 305 string proxy_cname = get_ccode_lower_case_prefix (type_symbol) + "proxy"; 306 var register_proxy = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_dynamic_type".printf (proxy_cname))); 307 register_proxy.add_argument (new CCodeIdentifier (module_init_param_name)); 308 ccode.add_expression (register_proxy); 309 } 310 } 311 } 312 313 /** 314 * This function generates the code the given method. If the method is 315 * a constructor, _construct is generated, unless it's variadic, in which 316 * case _constructv is generated (and _construct is generated together 317 * with _new in visit_creation_method). 318 */ 319 public override void visit_method (Method m) { 320 string real_name = get_ccode_real_name (m); 321 if (m is CreationMethod && m.is_variadic ()) { 322 real_name = get_ccode_constructv_name ((CreationMethod) m); 323 } 324 325 push_context (new EmitContext (m)); 326 push_line (m.source_reference); 327 328 bool in_gobject_creation_method = false; 329 bool in_fundamental_creation_method = false; 330 331 bool profile = m.get_attribute ("Profile") != null; 332 333 if (m is CreationMethod) { 334 var cl = current_type_symbol as Class; 335 if (cl != null && !cl.is_compact) { 336 if (cl.base_class == null) { 337 in_fundamental_creation_method = true; 338 } else if (gobject_type != null && cl.is_subtype_of (gobject_type)) { 339 in_gobject_creation_method = true; 340 } 341 } 342 } 343 344 var creturn_type = get_callable_creturn_type (m); 345 346 foreach (Parameter param in m.get_parameters ()) { 347 param.accept (this); 348 } 349 350 // do not declare overriding methods and interface implementations 351 if ((m.is_abstract || m.is_virtual 352 || (m.base_method == null && m.base_interface_method == null)) 353 && m.signal_reference == null) { 354 generate_method_declaration (m, cfile); 355 356 if (!m.is_internal_symbol ()) { 357 generate_method_declaration (m, header_file); 358 } 359 if (!m.is_private_symbol ()) { 360 generate_method_declaration (m, internal_header_file); 361 } 362 } 363 364 if (profile) { 365 string prefix = "_vala_prof_%s".printf (real_name); 366 367 cfile.add_include ("stdio.h"); 368 369 var counter = new CCodeIdentifier (prefix + "_counter"); 370 var counter_decl = new CCodeDeclaration (get_ccode_name (int_type)); 371 counter_decl.add_declarator (new CCodeVariableDeclarator (counter.name)); 372 counter_decl.modifiers = CCodeModifiers.STATIC; 373 cfile.add_type_member_declaration (counter_decl); 374 375 // nesting level for recursive functions 376 var level = new CCodeIdentifier (prefix + "_level"); 377 var level_decl = new CCodeDeclaration (get_ccode_name (int_type)); 378 level_decl.add_declarator (new CCodeVariableDeclarator (level.name)); 379 level_decl.modifiers = CCodeModifiers.STATIC; 380 cfile.add_type_member_declaration (level_decl); 381 382 var timer = new CCodeIdentifier (prefix + "_timer"); 383 var timer_decl = new CCodeDeclaration ("GTimer *"); 384 timer_decl.add_declarator (new CCodeVariableDeclarator (timer.name)); 385 timer_decl.modifiers = CCodeModifiers.STATIC; 386 cfile.add_type_member_declaration (timer_decl); 387 388 var constructor = new CCodeFunction (prefix + "_init"); 389 constructor.modifiers = CCodeModifiers.STATIC | CCodeModifiers.CONSTRUCTOR; 390 cfile.add_function_declaration (constructor); 391 push_function (constructor); 392 393 ccode.add_assignment (timer, new CCodeFunctionCall (new CCodeIdentifier ("g_timer_new"))); 394 395 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop")); 396 stop_call.add_argument (timer); 397 ccode.add_expression (stop_call); 398 399 pop_function (); 400 cfile.add_function (constructor); 401 402 403 var destructor = new CCodeFunction (prefix + "_exit"); 404 destructor.modifiers = CCodeModifiers.STATIC | CCodeModifiers.DESTRUCTOR; 405 cfile.add_function_declaration (destructor); 406 push_function (destructor); 407 408 var elapsed_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_elapsed")); 409 elapsed_call.add_argument (timer); 410 elapsed_call.add_argument (new CCodeConstant ("NULL")); 411 412 var print_call = new CCodeFunctionCall (new CCodeIdentifier ("fprintf")); 413 print_call.add_argument (new CCodeIdentifier ("stderr")); 414 print_call.add_argument (new CCodeConstant ("\"%s: %%gs (%%d calls)\\n\"".printf (m.get_full_name ()))); 415 print_call.add_argument (elapsed_call); 416 print_call.add_argument (counter); 417 ccode.add_expression (print_call); 418 419 pop_function (); 420 cfile.add_function (destructor); 421 } 422 423 CCodeFunction function; 424 function = new CCodeFunction (real_name); 425 426 if (m.is_inline) { 427 function.modifiers |= CCodeModifiers.INLINE; 428 } 429 430 if (m.entry_point) { 431 function.modifiers |= CCodeModifiers.STATIC; 432 } 433 434 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal); 435 436 generate_cparameters (m, cfile, cparam_map, function); 437 438 // generate *_real_* functions for virtual methods 439 // also generate them for abstract methods of classes to prevent faulty subclassing 440 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) { 441 if (!m.coroutine) { 442 if (m.base_method != null || m.base_interface_method != null) { 443 // declare *_real_* function 444 function.modifiers |= CCodeModifiers.STATIC; 445 cfile.add_function_declaration (function); 446 } else if (m.is_private_symbol ()) { 447 function.modifiers |= CCodeModifiers.STATIC; 448 } else if (context.hide_internal && m.is_internal_symbol ()) { 449 function.modifiers |= CCodeModifiers.INTERNAL; 450 } 451 } else { 452 if (m.body != null) { 453 function = new CCodeFunction (real_name + "_co", get_ccode_name (bool_type)); 454 455 // data struct to hold parameters, local variables, and the return value 456 function.add_parameter (new CCodeParameter ("_data_", Symbol.lower_case_to_camel_case (get_ccode_const_name (m)) + "Data*")); 457 function.modifiers |= CCodeModifiers.STATIC; 458 cfile.add_function_declaration (function); 459 } 460 } 461 } 462 463 if (m.comment != null) { 464 cfile.add_type_member_definition (new CCodeComment (m.comment.content)); 465 } 466 467 push_function (function); 468 469 unowned CCodeBlock? co_switch_block = null; 470 471 // generate *_real_* functions for virtual methods 472 // also generate them for abstract methods of classes to prevent faulty subclassing 473 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) { 474 if (m.body != null) { 475 if (m.coroutine) { 476 ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_")); 477 478 // initial coroutine state 479 ccode.add_case (new CCodeConstant ("0")); 480 ccode.add_goto ("_state_0"); 481 482 co_switch_block = ccode.current_block; 483 484 ccode.close (); 485 486 // coroutine body 487 ccode.add_label ("_state_0"); 488 } 489 490 if (m.closure) { 491 // add variables for parent closure blocks 492 // as closures only have one parameter for the innermost closure block 493 var closure_block = current_closure_block; 494 int block_id = get_block_id (closure_block); 495 while (true) { 496 var parent_closure_block = next_closure_block (closure_block.parent_symbol); 497 if (parent_closure_block == null) { 498 break; 499 } 500 int parent_block_id = get_block_id (parent_closure_block); 501 502 var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id)); 503 ccode.add_declaration ("Block%dData*".printf (parent_block_id), new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id))); 504 ccode.add_assignment (new CCodeIdentifier ("_data%d_".printf (parent_block_id)), parent_data); 505 506 closure_block = parent_closure_block; 507 block_id = parent_block_id; 508 } 509 510 // add self variable for closures 511 // as closures have block data parameter 512 if (m.binding == MemberBinding.INSTANCE) { 513 var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self"); 514 ccode.add_declaration (get_ccode_name (SemanticAnalyzer.get_data_type_for_symbol (current_type_symbol)), new CCodeVariableDeclarator ("self")); 515 ccode.add_assignment (new CCodeIdentifier ("self"), cself); 516 } 517 518 // allow capturing generic type parameters 519 foreach (var type_param in m.get_type_parameters ()) { 520 string func_name; 521 522 func_name = "%s_type".printf (type_param.name.ascii_down ()); 523 ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name)); 524 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)); 525 526 func_name = "%s_dup_func".printf (type_param.name.ascii_down ()); 527 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name)); 528 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)); 529 530 func_name = "%s_destroy_func".printf (type_param.name.ascii_down ()); 531 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name)); 532 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name)); 533 } 534 } else if (m.parent_symbol is Class && !m.coroutine) { 535 var cl = (Class) m.parent_symbol; 536 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) { 537 Method base_method; 538 ReferenceType base_expression_type; 539 if (m.overrides && m.base_method != null) { 540 base_method = m.base_method; 541 base_expression_type = new ObjectType ((Class) base_method.parent_symbol); 542 } else { 543 base_method = m.base_interface_method; 544 base_expression_type = new ObjectType ((Interface) base_method.parent_symbol); 545 } 546 var self_target_type = new ObjectType (cl); 547 CCodeExpression cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m)); 548 549 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self")); 550 ccode.add_assignment (new CCodeIdentifier ("self"), cself); 551 } else if (m.binding == MemberBinding.INSTANCE 552 && !(m is CreationMethod) 553 && m.base_method == null && m.base_interface_method == null) { 554 create_method_type_check_statement (m, creturn_type, cl, true, "self"); 555 } 556 } 557 558 foreach (Parameter param in m.get_parameters ()) { 559 if (param.ellipsis || param.params_array) { 560 if (param.params_array) { 561 append_params_array (m); 562 } 563 break; 564 } 565 566 if (param.direction != ParameterDirection.OUT) { 567 unowned TypeSymbol? t = param.variable_type.type_symbol; 568 if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) { 569 var cname = get_ccode_name (param); 570 if (param.direction == ParameterDirection.REF && !param.variable_type.is_real_struct_type ()) { 571 cname = "*"+cname; 572 } 573 create_method_type_check_statement (m, creturn_type, t, !param.variable_type.nullable, cname); 574 } 575 } else if (!m.coroutine) { 576 // declare local variable for out parameter to allow assignment even when caller passes NULL 577 var vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_name (param)), default_value_for_type (param.variable_type, true), get_ccode_declarator_suffix (param.variable_type)); 578 ccode.add_declaration (get_ccode_name (param.variable_type), vardecl); 579 580 if (param.variable_type is ArrayType) { 581 // create variables to store array dimensions 582 var array_type = (ArrayType) param.variable_type; 583 584 if (!array_type.fixed_length) { 585 var length_ctype = get_ccode_array_length_type (param); 586 for (int dim = 1; dim <= array_type.rank; dim++) { 587 vardecl = new CCodeVariableDeclarator.zero (get_array_length_cname ("_vala_%s".printf (get_ccode_name (param)), dim), new CCodeConstant ("0")); 588 ccode.add_declaration (length_ctype, vardecl); 589 } 590 } 591 } else if (param.variable_type is DelegateType) { 592 var deleg_type = (DelegateType) param.variable_type; 593 if (deleg_type.delegate_symbol.has_target) { 594 // create variable to store delegate target 595 vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_delegate_target_name (param)), new CCodeConstant ("NULL")); 596 ccode.add_declaration (get_ccode_name (delegate_target_type), vardecl); 597 598 if (deleg_type.is_disposable ()) { 599 vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_delegate_target_destroy_notify_name (param)), new CCodeConstant ("NULL")); 600 ccode.add_declaration (get_ccode_name (delegate_target_destroy_type), vardecl); 601 } 602 } 603 } 604 } 605 } 606 607 if (m is CreationMethod) { 608 if (in_gobject_creation_method) { 609 if (!m.coroutine) { 610 ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL"))); 611 } 612 } else if (is_gtypeinstance_creation_method (m)) { 613 var cl = (Class) m.parent_symbol; 614 ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL"))); 615 616 if (cl.is_fundamental () && !((CreationMethod) m).chain_up) { 617 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance")); 618 ccall.add_argument (get_variable_cexpression ("object_type")); 619 ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (cl) + "*")); 620 621 /* type, dup func, and destroy func fields for generic types */ 622 foreach (TypeParameter type_param in current_class.get_type_parameters ()) { 623 CCodeIdentifier param_name; 624 CCodeAssignment assign; 625 626 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"); 627 628 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.ascii_down ())); 629 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name); 630 ccode.add_expression (assign); 631 632 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.ascii_down ())); 633 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name); 634 ccode.add_expression (assign); 635 636 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.ascii_down ())); 637 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name); 638 ccode.add_expression (assign); 639 } 640 } 641 } else if (current_type_symbol is Class) { 642 var cl = (Class) m.parent_symbol; 643 if (!m.coroutine) { 644 ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator ("self")); 645 } 646 647 if (!((CreationMethod) m).chain_up) { 648 // TODO implicitly chain up to base class as in add_object_creation 649 // g_slice_new0 needs glib.h 650 cfile.add_include ("glib.h"); 651 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0")); 652 ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl))); 653 ccode.add_assignment (get_this_cexpression (), ccall); 654 } 655 656 if (cl.base_class == null && !(((CreationMethod) m).chain_up && cl.is_compact)) { 657 var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null)))); 658 cinitcall.add_argument (get_this_cexpression ()); 659 if (!cl.is_compact) { 660 cinitcall.add_argument (new CCodeConstant ("NULL")); 661 } 662 ccode.add_expression (cinitcall); 663 } 664 } else if (m.parent_symbol is Struct) { 665 unowned Struct st = (Struct) m.parent_symbol; 666 if (st.is_simple_type ()) { 667 var vardecl = new CCodeVariableDeclarator ("self", default_value_for_type (creturn_type, true)); 668 vardecl.init0 = true; 669 ccode.add_declaration (get_ccode_name (creturn_type), vardecl); 670 } else { 671 // memset needs string.h 672 cfile.add_include ("string.h"); 673 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset")); 674 czero.add_argument (new CCodeIdentifier ("self")); 675 czero.add_argument (new CCodeConstant ("0")); 676 czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (st)))); 677 ccode.add_expression (czero); 678 } 679 } else { 680 Report.error (m.source_reference, "internal: creation method not supported in `%s'".printf (m.parent_symbol.get_full_name ())); 681 } 682 } 683 684 if (context.module_init_method == m && in_plugin) { 685 // GTypeModule-based plug-in, register types 686 register_plugin_types (context.root, new HashSet<Symbol> ()); 687 } 688 689 foreach (Expression precondition in m.get_preconditions ()) { 690 create_precondition_statement (m, creturn_type, precondition); 691 } 692 } 693 } 694 695 if (profile) { 696 string prefix = "_vala_prof_%s".printf (real_name); 697 698 var level = new CCodeIdentifier (prefix + "_level"); 699 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, level))); 700 701 var counter = new CCodeIdentifier (prefix + "_counter"); 702 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, counter)); 703 704 var timer = new CCodeIdentifier (prefix + "_timer"); 705 var cont_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_continue")); 706 cont_call.add_argument (timer); 707 ccode.add_expression (cont_call); 708 709 ccode.close (); 710 } 711 712 if (m.body != null) { 713 m.body.emit (this); 714 715 if (co_switch_block != null) { 716 // after counting the number of yields for coroutines, append the case statements to the switch 717 var old_block = ccode.current_block; 718 ccode.current_block = co_switch_block; 719 720 for (int state = 1; state < emit_context.next_coroutine_state; state++) { 721 ccode.add_case (new CCodeConstant (state.to_string ())); 722 ccode.add_goto ("_state_%d".printf (state)); 723 } 724 725 // let gcc know that this can't happen 726 ccode.add_default (); 727 ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached"))); 728 729 ccode.current_block = old_block; 730 co_switch_block = null; 731 } 732 } 733 734 // we generate the same code if we see a return statement, this handles the case without returns 735 if (profile && m.return_type is VoidType) { 736 string prefix = "_vala_prof_%s".printf (real_name); 737 738 var level = new CCodeIdentifier (prefix + "_level"); 739 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level))); 740 741 var timer = new CCodeIdentifier (prefix + "_timer"); 742 743 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop")); 744 stop_call.add_argument (timer); 745 ccode.add_expression (stop_call); 746 747 ccode.close (); 748 } 749 750 // generate *_real_* functions for virtual methods 751 // also generate them for abstract methods of classes to prevent faulty subclassing 752 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) { 753 /* Methods imported from a plain C file don't 754 * have a body, e.g. Vala.Parser.parse_file () */ 755 if (m.body != null) { 756 if (current_method_inner_error) { 757 cfile.add_include ("glib.h"); 758 /* always separate error parameter and inner_error local variable 759 * as error may be set to NULL but we're always interested in inner errors 760 */ 761 if (m.coroutine) { 762 // no initialization necessary, closure struct is zeroed 763 closure_struct.add_field ("GError*", "_inner_error%d_".printf (current_inner_error_id)); 764 } else { 765 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL"))); 766 } 767 } 768 769 // For non-void return-types GAsyncModule.visit_return_statement () will take care of this 770 if (m.return_type is VoidType && m.coroutine) { 771 // epilogue 772 complete_async (); 773 } 774 775 if (m is CreationMethod) { 776 if (current_type_symbol is Class && !m.coroutine) { 777 CCodeExpression cresult = new CCodeIdentifier ("self"); 778 if (get_ccode_type (m) != null) { 779 cresult = new CCodeCastExpression (cresult, get_ccode_type (m)); 780 } 781 782 ccode.add_return (cresult); 783 } else if (current_type_symbol is Struct && ((Struct) current_type_symbol).is_simple_type ()) { 784 // constructors return simple type structs by value 785 ccode.add_return (new CCodeIdentifier ("self")); 786 } 787 } 788 789 cfile.add_function (ccode); 790 } 791 } 792 793 if (m.is_abstract && current_type_symbol is Class) { 794 // generate helpful error message if a sublcass does not implement an abstract method. 795 // This is only meaningful for subclasses implemented in C since the vala compiler would 796 // complain during compile time of such en error. 797 798 // add critical warning that this method should not have been called 799 var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical")); 800 if (!((Class) current_type_symbol).is_compact) { 801 var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE")); 802 type_from_instance_call.add_argument (new CCodeIdentifier ("self")); 803 804 var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name")); 805 type_name_call.add_argument (type_from_instance_call); 806 807 cerrorcall.add_argument (new CCodeConstant ("\"Type `%%s' does not implement abstract method `%s'\"".printf (get_ccode_name (m)))); 808 cerrorcall.add_argument (type_name_call); 809 } else { 810 cerrorcall.add_argument (new CCodeConstant ("\"Abstract method `%s' is not implemented\"".printf (get_ccode_name (m)))); 811 } 812 813 ccode.add_expression (cerrorcall); 814 815 // add return statement 816 return_default_value (creturn_type); 817 818 cfile.add_function (ccode); 819 } 820 821 if (current_method_return && !(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) { 822 var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true)); 823 vardecl.init0 = true; 824 ccode.add_declaration (get_ccode_name (m.return_type), vardecl); 825 } 826 827 pop_context (); 828 829 if ((m.is_abstract || m.is_virtual) && !m.coroutine 830 && !get_ccode_no_wrapper (m) 831 // If the method is a signal handler, the declaration is not needed. 832 // the name should be reserved for the emitter! 833 && m.signal_reference == null) { 834 835 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal); 836 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal); 837 838 generate_vfunc (m, creturn_type, cparam_map, carg_map); 839 } 840 841 if (m.entry_point) { 842 // m is possible entry point, add appropriate startup code 843 var cmain = new CCodeFunction ("main", "int"); 844 cmain.line = function.line; 845 cmain.add_parameter (new CCodeParameter ("argc", "int")); 846 cmain.add_parameter (new CCodeParameter ("argv", "char **")); 847 push_function (cmain); 848 849 if (context.profile == Profile.GOBJECT) { 850 if (context.mem_profiler) { 851 var mem_profiler_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_mem_set_vtable")); 852 mem_profiler_init_call.line = cmain.line; 853 mem_profiler_init_call.add_argument (new CCodeConstant ("glib_mem_profiler_table")); 854 ccode.add_expression (mem_profiler_init_call); 855 } 856 } 857 858 var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name)); 859 if (m.get_parameters ().size == 1) { 860 main_call.add_argument (new CCodeIdentifier ("argv")); 861 main_call.add_argument (new CCodeIdentifier ("argc")); 862 } 863 if (m.return_type is VoidType) { 864 // method returns void, always use 0 as exit code 865 ccode.add_expression (main_call); 866 ccode.add_return (new CCodeConstant ("0")); 867 } else { 868 ccode.add_return (main_call); 869 } 870 pop_function (); 871 cfile.add_function (cmain); 872 } 873 874 pop_line (); 875 } 876 877 public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) { 878 CCodeParameter cparam; 879 if (!param.ellipsis && !param.params_array) { 880 string ctypename = get_ccode_name (param.variable_type); 881 882 generate_type_declaration (param.variable_type, decl_space); 883 884 // pass non-simple structs always by reference 885 unowned Struct? st = param.variable_type.type_symbol as Struct; 886 if (st != null) { 887 if (!st.is_simple_type () && param.direction == ParameterDirection.IN) { 888 if (st.is_immutable && !param.variable_type.value_owned) { 889 ctypename = "const " + ctypename; 890 } 891 892 if (!param.variable_type.nullable) { 893 ctypename += "*"; 894 } 895 } 896 } 897 898 if (param.direction != ParameterDirection.IN) { 899 ctypename += "*"; 900 } 901 902 cparam = new CCodeParameter (get_ccode_name (param), ctypename); 903 if (param.format_arg) { 904 cparam.modifiers = CCodeModifiers.FORMAT_ARG; 905 } 906 } else { 907 var va_list_name = "_vala_va_list"; 908 909 // Add _first_* parameter for the params array parameter 910 if (param.params_array) { 911 var param_type = ((ArrayType) param.variable_type).element_type; 912 string ctypename = get_ccode_name (param_type); 913 914 generate_type_declaration (param_type, decl_space); 915 916 // pass non-simple structs always by reference 917 if (param_type.type_symbol is Struct) { 918 var st = (Struct) param_type.type_symbol; 919 if (!st.is_simple_type () && param.direction == ParameterDirection.IN) { 920 if (st.is_immutable && !param.variable_type.value_owned) { 921 ctypename = "const " + ctypename; 922 } 923 924 if (!param_type.nullable) { 925 ctypename += "*"; 926 } 927 } 928 } 929 930 cparam = new CCodeParameter ("_first_%s".printf (get_ccode_name (param)), ctypename); 931 cparam_map.set (get_param_pos (get_ccode_pos (param) - 0.1, true), cparam); 932 933 va_list_name = "_va_list_%s".printf (get_ccode_name (param)); 934 } 935 936 if (ellipses_to_valist) { 937 cparam = new CCodeParameter (va_list_name, "va_list"); 938 } else { 939 cparam = new CCodeParameter.with_ellipsis (); 940 } 941 } 942 943 cparam_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis || param.params_array), cparam); 944 if (carg_map != null && !param.ellipsis && !param.params_array) { 945 carg_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis || param.params_array), get_parameter_cexpression (param)); 946 } 947 948 return cparam; 949 } 950 951 public override void generate_cparameters (Method m, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) { 952 if (m.closure) { 953 var closure_block = current_closure_block; 954 int block_id = get_block_id (closure_block); 955 var instance_param = new CCodeParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id)); 956 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param); 957 } else if (m.parent_symbol is Class && m is CreationMethod) { 958 var cl = (Class) m.parent_symbol; 959 if (!cl.is_compact && vcall == null && (direction & 1) == 1) { 960 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType")); 961 } 962 } else if (m.binding == MemberBinding.INSTANCE && (direction != 2 || get_ccode_finish_instance (m))) { 963 var this_type = SemanticAnalyzer.get_this_type (m); 964 965 generate_type_declaration (this_type, decl_space); 966 967 CCodeParameter instance_param = null; 968 if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) { 969 var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol); 970 instance_param = new CCodeParameter ("base", get_ccode_name (base_type)); 971 } else if (m.overrides) { 972 var base_type = new ObjectType ((Class) m.base_method.parent_symbol); 973 instance_param = new CCodeParameter ("base", get_ccode_name (base_type)); 974 } else { 975 unowned Struct? st = m.parent_symbol as Struct; 976 if (st != null && !st.is_simple_type ()) { 977 instance_param = new CCodeParameter ("*self", get_ccode_name (this_type)); 978 } else if (st != null && st.is_simple_type () && m is CreationMethod) { 979 // constructors return simple type structs by value 980 } else { 981 instance_param = new CCodeParameter ("self", get_ccode_name (this_type)); 982 } 983 } 984 if (instance_param != null) { 985 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param); 986 } 987 } else if (m.binding == MemberBinding.CLASS) { 988 var this_type = SemanticAnalyzer.get_this_type (m); 989 var class_param = new CCodeParameter ("klass", get_ccode_name (this_type)); 990 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), class_param); 991 } 992 993 if (is_gtypeinstance_creation_method (m) && (direction & 1) == 1) { 994 // memory management for generic types 995 int type_param_index = 0; 996 var cl = (Class) m.parent_symbol; 997 foreach (TypeParameter type_param in cl.get_type_parameters ()) { 998 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.ascii_down ()), "GType")); 999 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.ascii_down ()), "GBoxedCopyFunc")); 1000 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.ascii_down ()), "GDestroyNotify")); 1001 if (carg_map != null) { 1002 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.ascii_down ()))); 1003 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.ascii_down ()))); 1004 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.ascii_down ()))); 1005 } 1006 type_param_index++; 1007 } 1008 } else if (!m.closure && (direction & 1) == 1) { 1009 int type_param_index = 0; 1010 foreach (var type_param in m.get_type_parameters ()) { 1011 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.ascii_down ()), "GType")); 1012 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.ascii_down ()), "GBoxedCopyFunc")); 1013 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.ascii_down ()), "GDestroyNotify")); 1014 if (carg_map != null) { 1015 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.ascii_down ()))); 1016 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.ascii_down ()))); 1017 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.ascii_down ()))); 1018 } 1019 type_param_index++; 1020 } 1021 } 1022 1023 var needs_format_arg = m.get_format_arg_index () < 0 && (m.printf_format || m.scanf_format); 1024 1025 CCodeParameter? prev_cparam = null; 1026 foreach (Parameter param in m.get_parameters ()) { 1027 if (param.direction != ParameterDirection.OUT) { 1028 if ((direction & 1) == 0) { 1029 // no in parameters 1030 continue; 1031 } 1032 } else { 1033 if ((direction & 2) == 0) { 1034 // no out parameters 1035 continue; 1036 } 1037 } 1038 1039 var cparam = generate_parameter (param, decl_space, cparam_map, carg_map); 1040 1041 // if there is no explicit FormatArg annotation while this method throws an error 1042 // it is required to mark the parameter located right before ellipsis as format-arg 1043 // to account for the parameter shifting caused by the inserted GError parameter 1044 if (needs_format_arg) { 1045 if (prev_cparam != null && cparam.ellipsis) { 1046 prev_cparam.modifiers |= CCodeModifiers.FORMAT_ARG; 1047 } 1048 prev_cparam = cparam; 1049 } 1050 } 1051 1052 if ((direction & 2) != 0) { 1053 generate_method_result_declaration (m, decl_space, func, cparam_map, carg_map); 1054 } 1055 1056 // append C parameters in the right order 1057 int last_pos = -1; 1058 int min_pos; 1059 while (true) { 1060 min_pos = -1; 1061 foreach (int pos in cparam_map.get_keys ()) { 1062 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) { 1063 min_pos = pos; 1064 } 1065 } 1066 if (min_pos == -1) { 1067 break; 1068 } 1069 func.add_parameter (cparam_map.get (min_pos)); 1070 if (vdeclarator != null) { 1071 vdeclarator.add_parameter (cparam_map.get (min_pos)); 1072 } 1073 if (vcall != null) { 1074 var arg = carg_map.get (min_pos); 1075 if (arg != null) { 1076 vcall.add_argument (arg); 1077 } 1078 } 1079 last_pos = min_pos; 1080 } 1081 1082 if (m.printf_format) { 1083 func.modifiers |= CCodeModifiers.PRINTF; 1084 } else if (m.scanf_format) { 1085 func.modifiers |= CCodeModifiers.SCANF; 1086 } 1087 1088 if (m.version.deprecated) { 1089 func.modifiers |= CCodeModifiers.DEPRECATED; 1090 } 1091 } 1092 1093 public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) { 1094 push_context (new EmitContext ()); 1095 1096 CCodeFunction vfunc; 1097 if (suffix == "_finish") { 1098 vfunc = new CCodeFunction (get_ccode_finish_name (m)); 1099 } else { 1100 vfunc = new CCodeFunction (get_ccode_name (m)); 1101 } 1102 1103 CCodeExpression vcast; 1104 if (m.parent_symbol is Interface) { 1105 var iface = (Interface) m.parent_symbol; 1106 1107 vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface))); 1108 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self")); 1109 } else { 1110 var cl = (Class) m.parent_symbol; 1111 if (!cl.is_compact) { 1112 vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl))); 1113 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self")); 1114 } else { 1115 vcast = new CCodeIdentifier ("self"); 1116 } 1117 } 1118 1119 CCodeFunctionCall vcall; 1120 if (suffix == "_finish") { 1121 vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m))); 1122 } else { 1123 vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m))); 1124 } 1125 1126 carg_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeIdentifier ("self")); 1127 1128 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, direction); 1129 1130 push_function (vfunc); 1131 1132 if (context.assert && m.return_type.type_symbol is Struct && ((Struct) m.return_type.type_symbol).is_simple_type () && default_value_for_type (m.return_type, false) == null) { 1133 // the type check will use the result variable 1134 var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true)); 1135 vardecl.init0 = true; 1136 ccode.add_declaration (get_ccode_name (m.return_type), vardecl); 1137 } 1138 1139 // add a typecheck statement for "self" 1140 create_method_type_check_statement (m, return_type, (TypeSymbol) m.parent_symbol, true, "self"); 1141 1142 foreach (Expression precondition in m.get_preconditions ()) { 1143 create_precondition_statement (m, return_type, precondition); 1144 } 1145 1146 if (return_type is VoidType || return_type.is_real_non_null_struct_type ()) { 1147 ccode.add_expression (vcall); 1148 } else if (m.get_postconditions ().size == 0) { 1149 /* pass method return value */ 1150 ccode.add_return (vcall); 1151 } else { 1152 /* store method return value for postconditions */ 1153 ccode.add_declaration (get_creturn_type (m, get_ccode_name (return_type)), new CCodeVariableDeclarator ("result")); 1154 ccode.add_assignment (new CCodeIdentifier ("result"), vcall); 1155 } 1156 1157 if (m.get_postconditions ().size > 0) { 1158 foreach (Expression postcondition in m.get_postconditions ()) { 1159 create_postcondition_statement (postcondition); 1160 } 1161 1162 if (!(return_type is VoidType)) { 1163 ccode.add_return (new CCodeIdentifier ("result")); 1164 } 1165 } 1166 1167 if (m.printf_format) { 1168 vfunc.modifiers |= CCodeModifiers.PRINTF; 1169 } else if (m.scanf_format) { 1170 vfunc.modifiers |= CCodeModifiers.SCANF; 1171 } 1172 1173 if (m.version.deprecated) { 1174 vfunc.modifiers |= CCodeModifiers.DEPRECATED; 1175 } 1176 1177 cfile.add_function (vfunc); 1178 1179 pop_context (); 1180 } 1181 1182 private void create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) { 1183 if (!m.coroutine) { 1184 create_type_check_statement (m, return_type, t, non_null, var_name); 1185 } 1186 } 1187 1188 private void create_precondition_statement (Method m, DataType ret_type, Expression precondition) { 1189 is_in_method_precondition = true; 1190 1191 var ccheck = new CCodeFunctionCall (); 1192 1193 precondition.emit (this); 1194 1195 ccheck.add_argument (get_cvalue (precondition)); 1196 1197 string message = ((string) precondition.source_reference.begin.pos).substring (0, (int) (precondition.source_reference.end.pos - precondition.source_reference.begin.pos)); 1198 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape ("")))); 1199 requires_assert = true; 1200 1201 if (m is CreationMethod) { 1202 if (m.parent_symbol is Class) { 1203 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail"); 1204 ccheck.add_argument (new CCodeConstant ("NULL")); 1205 } else { 1206 // creation method of struct 1207 ccheck.call = new CCodeIdentifier ("_vala_return_if_fail"); 1208 } 1209 } else if (m.coroutine) { 1210 // _co function 1211 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail"); 1212 ccheck.add_argument (new CCodeConstant ("FALSE")); 1213 } else if (ret_type is VoidType) { 1214 /* void function */ 1215 ccheck.call = new CCodeIdentifier ("_vala_return_if_fail"); 1216 } else { 1217 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail"); 1218 1219 var cdefault = default_value_for_type (ret_type, false); 1220 if (cdefault != null) { 1221 ccheck.add_argument (cdefault); 1222 } else { 1223 return; 1224 } 1225 } 1226 1227 ccode.add_expression (ccheck); 1228 1229 current_method_return = true; 1230 is_in_method_precondition = false; 1231 } 1232 1233 public override void visit_creation_method (CreationMethod m) { 1234 push_line (m.source_reference); 1235 1236 ellipses_to_valist = true; 1237 visit_method (m); 1238 ellipses_to_valist = false; 1239 1240 if (m.source_type == SourceFileType.FAST) { 1241 pop_line (); 1242 return; 1243 } 1244 1245 // do not generate _new functions for creation methods of abstract classes 1246 if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) { 1247 // _new function 1248 create_aux_constructor (m, get_ccode_name (m), false); 1249 1250 // _construct function (if visit_method generated _constructv) 1251 if (m.is_variadic ()) { 1252 create_aux_constructor (m, get_ccode_real_name (m), true); 1253 } 1254 } 1255 1256 pop_line (); 1257 } 1258 1259 private void create_aux_constructor (CreationMethod m, string func_name, bool self_as_first_parameter) { 1260 var vfunc = new CCodeFunction (func_name); 1261 if (m.is_private_symbol ()) { 1262 vfunc.modifiers |= CCodeModifiers.STATIC; 1263 } else if (context.hide_internal && m.is_internal_symbol ()) { 1264 vfunc.modifiers |= CCodeModifiers.INTERNAL; 1265 } 1266 1267 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal); 1268 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal); 1269 1270 push_function (vfunc); 1271 1272 string constructor = (m.is_variadic ()) ? get_ccode_constructv_name (m) : get_ccode_real_name (m); 1273 var vcall = new CCodeFunctionCall (new CCodeIdentifier (constructor)); 1274 1275 if (self_as_first_parameter) { 1276 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType")); 1277 vcall.add_argument (get_variable_cexpression ("object_type")); 1278 } else { 1279 vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class))); 1280 } 1281 1282 1283 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall); 1284 1285 if (m.is_variadic ()) { 1286 int last_pos = -1; 1287 int second_last_pos = -1; 1288 foreach (int pos in cparam_map.get_keys ()) { 1289 if (pos > last_pos) { 1290 second_last_pos = last_pos; 1291 last_pos = pos; 1292 } else if (pos > second_last_pos) { 1293 second_last_pos = pos; 1294 } 1295 } 1296 1297 var carg = carg_map.get (second_last_pos); 1298 if (carg == null) { 1299 // params arrays have an implicit first argument, refer to the cparameter name 1300 carg = new CCodeIdentifier (cparam_map.get (second_last_pos).name); 1301 vcall.add_argument (carg); 1302 } 1303 1304 var va_start = new CCodeFunctionCall (new CCodeIdentifier ("va_start")); 1305 va_start.add_argument (new CCodeIdentifier ("_vala_va_list_obj")); 1306 va_start.add_argument (carg); 1307 1308 ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_vala_va_list_obj")); 1309 ccode.add_expression (va_start); 1310 1311 vcall.add_argument (new CCodeIdentifier("_vala_va_list_obj")); 1312 } 1313 1314 ccode.add_return (vcall); 1315 1316 pop_function (); 1317 1318 cfile.add_function (vfunc); 1319 } 1320} 1321 1322// vim:sw=8 noet 1323