1 /* valaccodemethodmodule.vala
3 * Copyright (C) 2007-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
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
27 * The link between a method and generated code.
29 public abstract class Vala.CCodeMethodModule : CCodeStructModule {
31 private bool ellipses_to_valist = false;
33 string get_creturn_type (Method m, string default_value) {
34 string type = get_ccode_type (m);
41 bool is_gtypeinstance_creation_method (Method m) {
44 var cl = m.parent_symbol as Class;
45 if (m is CreationMethod && cl != null && !cl.is_compact) {
52 public virtual void generate_method_result_declaration (Method m, CCodeFile decl_space, CCodeFunction cfunc, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
53 var creturn_type = get_callable_creturn_type (m);
54 cfunc.return_type = get_creturn_type (m, get_ccode_name (creturn_type));
56 generate_type_declaration (m.return_type, decl_space);
58 if (m.return_type.is_real_non_null_struct_type ()) {
59 // structs are returned via out parameter
60 var cparam = new CCodeParameter ("result", get_ccode_name (m.return_type) + "*");
61 cparam_map.set (get_param_pos (-3), cparam);
62 if (carg_map != null) {
63 carg_map.set (get_param_pos (-3), get_cexpression ("result"));
65 } else if (get_ccode_array_length (m) && m.return_type is ArrayType) {
66 // return array length if appropriate
67 var array_type = (ArrayType) m.return_type;
68 var length_ctype = get_ccode_array_length_type (m) + "*";
70 for (int dim = 1; dim <= array_type.rank; dim++) {
71 var cparam = new CCodeParameter (get_array_length_cname ("result", dim), length_ctype);
72 cparam_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), cparam);
73 if (carg_map != null) {
74 carg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), get_cexpression (cparam.name));
77 } else if (get_ccode_delegate_target (m) && m.return_type is DelegateType) {
78 // return delegate target if appropriate
79 var deleg_type = (DelegateType) m.return_type;
80 if (deleg_type.delegate_symbol.has_target) {
81 var cparam = new CCodeParameter (get_delegate_target_cname ("result"), get_ccode_name (delegate_target_type) + "*");
82 cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), cparam);
83 if (carg_map != null) {
84 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), get_cexpression (cparam.name));
86 if (deleg_type.is_disposable ()) {
87 cparam = new CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), get_ccode_name (delegate_target_destroy_type) + "*");
88 cparam_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), cparam);
89 if (carg_map != null) {
90 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), get_cexpression (cparam.name));
96 if (m.has_error_type_parameter ()) {
97 var error_types = new ArrayList<DataType> ();
98 m.get_error_types (error_types);
99 foreach (DataType error_type in error_types) {
100 generate_type_declaration (error_type, decl_space);
103 var cparam = new CCodeParameter ("error", "GError**");
104 cparam_map.set (get_param_pos (get_ccode_error_pos (m)), cparam);
105 if (carg_map != null) {
106 carg_map.set (get_param_pos (get_ccode_error_pos (m)), new CCodeIdentifier (cparam.name));
111 public void complete_async () {
112 var data_var = new CCodeIdentifier ("_data_");
113 var async_result_expr = new CCodeMemberAccess.pointer (data_var, "_async_result");
115 var finish_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_pointer"));
116 finish_call.add_argument (async_result_expr);
117 finish_call.add_argument (data_var);
118 finish_call.add_argument (new CCodeConstant ("NULL"));
119 ccode.add_expression (finish_call);
121 // Preserve the "complete now" behavior if state != 0, do so by
122 // iterating the GTask's main context till the task is complete.
123 var state = new CCodeMemberAccess.pointer (data_var, "_state_");
124 var zero = new CCodeConstant ("0");
125 var state_is_not_zero = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, state, zero);
126 ccode.open_if (state_is_not_zero);
128 CCodeExpression task_is_complete;
130 var task_complete = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_completed"));
131 task_complete.add_argument (async_result_expr);
132 task_is_complete = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, task_complete);
134 ccode.open_while (task_is_complete);
135 var task_context = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_context"));
136 task_context.add_argument (async_result_expr);
137 var iterate_context = new CCodeFunctionCall (new CCodeIdentifier ("g_main_context_iteration"));
138 iterate_context.add_argument (task_context);
139 iterate_context.add_argument (new CCodeConstant ("TRUE"));
140 ccode.add_expression (iterate_context);
145 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
146 unref.add_argument (async_result_expr);
147 ccode.add_expression (unref);
149 ccode.add_return (new CCodeConstant ("FALSE"));
152 public override bool generate_method_declaration (Method m, CCodeFile decl_space) {
153 if (m.is_async_callback) {
156 if ((m.is_abstract || m.is_virtual) && get_ccode_no_wrapper (m)) {
159 if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
163 generate_type_declaration (new MethodType (m), decl_space);
165 var function = new CCodeFunction (get_ccode_name (m));
167 if (m.is_private_symbol () && !m.external) {
168 function.modifiers |= CCodeModifiers.STATIC;
170 function.modifiers |= CCodeModifiers.INLINE;
172 } else if (context.hide_internal && m.is_internal_symbol () && !m.external) {
173 function.modifiers |= CCodeModifiers.INTERNAL;
174 } else if (!m.entry_point && !m.external) {
175 function.modifiers |= CCodeModifiers.EXTERN;
176 requires_vala_extern = true;
180 function.modifiers |= CCodeModifiers.STATIC;
183 if (m.version.deprecated) {
184 if (context.profile == Profile.GOBJECT) {
185 decl_space.add_include ("glib.h");
187 function.modifiers |= CCodeModifiers.DEPRECATED;
190 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
191 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
193 var cl = m.parent_symbol as Class;
195 // do not generate _new functions for creation methods of abstract classes
196 if (!(m is CreationMethod && cl != null && cl.is_abstract && !cl.is_compact)) {
197 bool etv_tmp = ellipses_to_valist;
198 ellipses_to_valist = false;
199 generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
200 ellipses_to_valist = etv_tmp;
202 decl_space.add_function_declaration (function);
205 if (is_gtypeinstance_creation_method (m)) {
206 // _construct function
207 function = new CCodeFunction (get_ccode_real_name (m));
209 if (m.is_private_symbol ()) {
210 function.modifiers |= CCodeModifiers.STATIC;
211 } else if (context.hide_internal && m.is_internal_symbol ()) {
212 function.modifiers |= CCodeModifiers.INTERNAL;
214 function.modifiers |= CCodeModifiers.EXTERN;
215 requires_vala_extern = true;
218 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
219 bool etv_tmp = ellipses_to_valist;
220 ellipses_to_valist = false;
221 generate_cparameters (m, decl_space, cparam_map, function);
222 ellipses_to_valist = etv_tmp;
224 decl_space.add_function_declaration (function);
226 if (m.is_variadic ()) {
227 // _constructv function
228 function = new CCodeFunction (get_ccode_constructv_name ((CreationMethod) m));
230 if (!m.is_private_symbol ()) {
231 function.modifiers |= CCodeModifiers.EXTERN;
232 requires_vala_extern = true;
235 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
236 generate_cparameters (m, decl_space, cparam_map, function);
238 decl_space.add_function_declaration (function);
245 void register_plugin_types (Symbol sym, Set<Symbol> registered_types) {
246 var ns = sym as Namespace;
247 var cl = sym as Class;
248 var iface = sym as Interface;
250 foreach (var ns_ns in ns.get_namespaces ()) {
251 register_plugin_types (ns_ns, registered_types);
253 foreach (var ns_cl in ns.get_classes ()) {
254 register_plugin_types (ns_cl, registered_types);
256 foreach (var ns_iface in ns.get_interfaces ()) {
257 register_plugin_types (ns_iface, registered_types);
259 } else if (cl != null) {
260 register_plugin_type (cl, registered_types);
261 foreach (var cl_cl in cl.get_classes ()) {
262 register_plugin_types (cl_cl, registered_types);
264 } else if (iface != null) {
265 register_plugin_type (iface, registered_types);
266 foreach (var iface_cl in iface.get_classes ()) {
267 register_plugin_types (iface_cl, registered_types);
272 void register_plugin_type (ObjectTypeSymbol type_symbol, Set<Symbol> registered_types) {
273 if (type_symbol.external_package) {
277 if (!registered_types.add (type_symbol)) {
278 // already registered
282 var cl = type_symbol as Class;
288 // register base types first
289 foreach (var base_type in cl.get_base_types ()) {
290 register_plugin_type ((ObjectTypeSymbol) base_type.type_symbol, registered_types);
294 // Add function prototypes for required register-type-calls which are likely external
295 if (type_symbol.source_reference.file != cfile.file) {
296 // TODO Duplicated source with TypeRegisterFunction.init_from_type()
297 var register_func = new CCodeFunction ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null)), "GType");
298 register_func.add_parameter (new CCodeParameter ("module", "GTypeModule *"));
299 register_func.is_declaration = true;
300 cfile.add_function_declaration (register_func);
303 var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null))));
304 register_call.add_argument (new CCodeIdentifier (module_init_param_name));
305 ccode.add_expression (register_call);
307 var iface = type_symbol as Interface;
309 string? dbus_name = GDBusModule.get_dbus_name(type_symbol);
311 if (dbus_name != null) {
312 string proxy_cname = get_ccode_lower_case_prefix (type_symbol) + "proxy";
313 var register_proxy = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_dynamic_type".printf (proxy_cname)));
314 register_proxy.add_argument (new CCodeIdentifier (module_init_param_name));
315 ccode.add_expression (register_proxy);
321 * This function generates the code the given method. If the method is
322 * a constructor, _construct is generated, unless it's variadic, in which
323 * case _constructv is generated (and _construct is generated together
324 * with _new in visit_creation_method).
326 public override void visit_method (Method m) {
327 push_context (new EmitContext (m));
328 push_line (m.source_reference);
330 bool in_gobject_creation_method = false;
331 bool in_fundamental_creation_method = false;
333 bool profile = m.get_attribute ("Profile") != null;
335 string real_name = get_ccode_real_name (m);
337 if (m is CreationMethod) {
338 unowned Class? cl = m.parent_symbol as Class;
339 if (cl != null && !cl.is_compact) {
340 if (cl.base_class == null) {
341 in_fundamental_creation_method = true;
342 } else if (gobject_type != null && cl.is_subtype_of (gobject_type)) {
343 in_gobject_creation_method = true;
346 if (cl != null && !cl.is_compact && m.is_variadic ()) {
347 real_name = get_ccode_constructv_name ((CreationMethod) m);
351 var creturn_type = get_callable_creturn_type (m);
353 foreach (Parameter param in m.get_parameters ()) {
357 // do not declare overriding methods and interface implementations
358 if ((m.is_abstract || m.is_virtual
359 || (m.base_method == null && m.base_interface_method == null))
360 && m.signal_reference == null) {
361 generate_method_declaration (m, cfile);
363 if (!m.is_internal_symbol ()) {
364 generate_method_declaration (m, header_file);
366 if (!m.is_private_symbol ()) {
367 generate_method_declaration (m, internal_header_file);
372 string prefix = "_vala_prof_%s".printf (real_name);
374 cfile.add_include ("stdio.h");
376 var counter = new CCodeIdentifier (prefix + "_counter");
377 var counter_decl = new CCodeDeclaration (get_ccode_name (int_type));
378 counter_decl.add_declarator (new CCodeVariableDeclarator (counter.name));
379 counter_decl.modifiers = CCodeModifiers.STATIC;
380 cfile.add_type_member_declaration (counter_decl);
382 // nesting level for recursive functions
383 var level = new CCodeIdentifier (prefix + "_level");
384 var level_decl = new CCodeDeclaration (get_ccode_name (int_type));
385 level_decl.add_declarator (new CCodeVariableDeclarator (level.name));
386 level_decl.modifiers = CCodeModifiers.STATIC;
387 cfile.add_type_member_declaration (level_decl);
389 var timer = new CCodeIdentifier (prefix + "_timer");
390 var timer_decl = new CCodeDeclaration ("GTimer *");
391 timer_decl.add_declarator (new CCodeVariableDeclarator (timer.name));
392 timer_decl.modifiers = CCodeModifiers.STATIC;
393 cfile.add_type_member_declaration (timer_decl);
395 var constructor = new CCodeFunction (prefix + "_init");
396 constructor.modifiers = CCodeModifiers.STATIC | CCodeModifiers.CONSTRUCTOR;
397 cfile.add_function_declaration (constructor);
398 push_function (constructor);
400 ccode.add_assignment (timer, new CCodeFunctionCall (new CCodeIdentifier ("g_timer_new")));
402 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
403 stop_call.add_argument (timer);
404 ccode.add_expression (stop_call);
407 cfile.add_function (constructor);
410 var destructor = new CCodeFunction (prefix + "_exit");
411 destructor.modifiers = CCodeModifiers.STATIC | CCodeModifiers.DESTRUCTOR;
412 cfile.add_function_declaration (destructor);
413 push_function (destructor);
415 var elapsed_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_elapsed"));
416 elapsed_call.add_argument (timer);
417 elapsed_call.add_argument (new CCodeConstant ("NULL"));
419 var print_call = new CCodeFunctionCall (new CCodeIdentifier ("fprintf"));
420 print_call.add_argument (new CCodeIdentifier ("stderr"));
421 print_call.add_argument (new CCodeConstant ("\"%s: %%gs (%%d calls)\\n\"".printf (m.get_full_name ())));
422 print_call.add_argument (elapsed_call);
423 print_call.add_argument (counter);
424 ccode.add_expression (print_call);
427 cfile.add_function (destructor);
430 CCodeFunction function;
431 function = new CCodeFunction (real_name);
434 function.modifiers |= CCodeModifiers.INLINE;
438 function.modifiers |= CCodeModifiers.STATIC;
441 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
443 generate_cparameters (m, cfile, cparam_map, function);
445 // generate *_real_* functions for virtual methods
446 // also generate them for abstract methods of classes to prevent faulty subclassing
447 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
449 if (m.base_method != null || m.base_interface_method != null) {
450 // declare *_real_* function
451 function.modifiers |= CCodeModifiers.STATIC;
452 cfile.add_function_declaration (function);
453 } else if (m.is_private_symbol ()) {
454 function.modifiers |= CCodeModifiers.STATIC;
455 } else if (context.hide_internal && m.is_internal_symbol ()) {
456 function.modifiers |= CCodeModifiers.INTERNAL;
459 if (m.body != null) {
460 function = new CCodeFunction (real_name + "_co", get_ccode_name (bool_type));
462 // data struct to hold parameters, local variables, and the return value
463 function.add_parameter (new CCodeParameter ("_data_", Symbol.lower_case_to_camel_case (get_ccode_const_name (m)) + "Data*"));
464 function.modifiers |= CCodeModifiers.STATIC;
465 cfile.add_function_declaration (function);
470 if (m.comment != null) {
471 cfile.add_type_member_definition (new CCodeComment (m.comment.content));
474 push_function (function);
476 unowned CCodeBlock? co_switch_block = null;
478 // generate *_real_* functions for virtual methods
479 // also generate them for abstract methods of classes to prevent faulty subclassing
480 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
481 if (m.body != null) {
483 ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"));
485 // initial coroutine state
486 ccode.add_case (new CCodeConstant ("0"));
487 ccode.add_goto ("_state_0");
489 co_switch_block = ccode.current_block;
494 ccode.add_label ("_state_0");
498 // add variables for parent closure blocks
499 // as closures only have one parameter for the innermost closure block
500 var closure_block = current_closure_block;
501 int block_id = get_block_id (closure_block);
503 var parent_closure_block = next_closure_block (closure_block.parent_symbol);
504 if (parent_closure_block == null) {
507 int parent_block_id = get_block_id (parent_closure_block);
509 var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id));
510 ccode.add_declaration ("Block%dData*".printf (parent_block_id), new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id)));
511 ccode.add_assignment (new CCodeIdentifier ("_data%d_".printf (parent_block_id)), parent_data);
513 closure_block = parent_closure_block;
514 block_id = parent_block_id;
517 // add self variable for closures
518 // as closures have block data parameter
519 if (m.binding == MemberBinding.INSTANCE) {
520 var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self");
521 ccode.add_declaration (get_ccode_name (SemanticAnalyzer.get_data_type_for_symbol (current_type_symbol)), new CCodeVariableDeclarator ("self"));
522 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
525 // allow capturing generic type parameters
526 var data_var = get_variable_cexpression ("_data%d_".printf (block_id));
527 foreach (var type_param in m.get_type_parameters ()) {
528 var type = get_ccode_type_id (type_param);
529 var dup_func = get_ccode_copy_function (type_param);
530 var destroy_func = get_ccode_destroy_function (type_param);
531 ccode.add_declaration ("GType", new CCodeVariableDeclarator (type));
532 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (dup_func));
533 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (destroy_func));
534 ccode.add_assignment (new CCodeIdentifier (type), new CCodeMemberAccess.pointer (data_var, type));
535 ccode.add_assignment (new CCodeIdentifier (dup_func), new CCodeMemberAccess.pointer (data_var, dup_func));
536 ccode.add_assignment (new CCodeIdentifier (destroy_func), new CCodeMemberAccess.pointer (data_var, destroy_func));
538 } else if (m.parent_symbol is Class && !m.coroutine) {
539 var cl = (Class) m.parent_symbol;
540 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
542 ReferenceType base_expression_type;
543 if (m.overrides && m.base_method != null) {
544 base_method = m.base_method;
545 base_expression_type = new ObjectType ((Class) base_method.parent_symbol);
547 base_method = m.base_interface_method;
548 base_expression_type = new ObjectType ((Interface) base_method.parent_symbol);
550 var self_target_type = new ObjectType (cl);
551 CCodeExpression cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
553 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
554 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
555 } else if (m.binding == MemberBinding.INSTANCE
556 && !(m is CreationMethod)
557 && m.base_method == null && m.base_interface_method == null) {
558 create_method_type_check_statement (m, creturn_type, cl, true, "self");
562 foreach (Parameter param in m.get_parameters ()) {
563 if (param.ellipsis || param.params_array) {
564 if (param.params_array) {
565 append_params_array (m);
570 if (param.direction != ParameterDirection.OUT) {
571 unowned TypeSymbol? t = param.variable_type.type_symbol;
572 if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) {
573 var cname = get_ccode_name (param);
574 if (param.direction == ParameterDirection.REF && !param.variable_type.is_real_struct_type ()) {
577 create_method_type_check_statement (m, creturn_type, t, !param.variable_type.nullable, cname);
579 } else if (!m.coroutine) {
580 // declare local variable for out parameter to allow assignment even when caller passes NULL
581 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));
582 ccode.add_declaration (get_ccode_name (param.variable_type), vardecl);
584 if (param.variable_type is ArrayType) {
585 // create variables to store array dimensions
586 var array_type = (ArrayType) param.variable_type;
588 if (!array_type.fixed_length) {
589 var length_ctype = get_ccode_array_length_type (param);
590 for (int dim = 1; dim <= array_type.rank; dim++) {
591 vardecl = new CCodeVariableDeclarator.zero (get_array_length_cname ("_vala_%s".printf (get_ccode_name (param)), dim), new CCodeConstant ("0"));
592 ccode.add_declaration (length_ctype, vardecl);
595 } else if (param.variable_type is DelegateType) {
596 var deleg_type = (DelegateType) param.variable_type;
597 if (deleg_type.delegate_symbol.has_target) {
598 // create variable to store delegate target
599 vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_delegate_target_name (param)), new CCodeConstant ("NULL"));
600 ccode.add_declaration (get_ccode_name (delegate_target_type), vardecl);
602 if (deleg_type.is_disposable ()) {
603 vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_delegate_target_destroy_notify_name (param)), new CCodeConstant ("NULL"));
604 ccode.add_declaration (get_ccode_name (delegate_target_destroy_type), vardecl);
611 if (m is CreationMethod) {
612 if (in_gobject_creation_method) {
614 ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
616 } else if (is_gtypeinstance_creation_method (m)) {
617 var cl = (Class) m.parent_symbol;
618 ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
620 if (cl.is_fundamental () && !((CreationMethod) m).chain_up) {
621 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
622 ccall.add_argument (get_variable_cexpression ("object_type"));
623 ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (cl) + "*"));
625 /* type, dup func, and destroy func fields for generic types */
626 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
627 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
628 var type = get_ccode_type_id (type_param);
629 var dup_func = get_ccode_copy_function (type_param);
630 var destroy_func = get_ccode_destroy_function (type_param);
631 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, type), new CCodeIdentifier (type));
632 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, dup_func), new CCodeIdentifier (dup_func));
633 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, destroy_func), new CCodeIdentifier (destroy_func));
636 } else if (current_type_symbol is Class) {
637 var cl = (Class) m.parent_symbol;
639 ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator ("self"));
642 if (!((CreationMethod) m).chain_up) {
643 // TODO implicitly chain up to base class as in add_object_creation
644 // g_slice_new0 needs glib.h
645 cfile.add_include ("glib.h");
646 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
647 ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
648 ccode.add_assignment (get_this_cexpression (), ccall);
651 if (cl.base_class == null && !(((CreationMethod) m).chain_up && cl.is_compact)) {
652 var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null))));
653 cinitcall.add_argument (get_this_cexpression ());
654 if (!cl.is_compact) {
655 cinitcall.add_argument (new CCodeConstant ("NULL"));
657 ccode.add_expression (cinitcall);
659 } else if (m.parent_symbol is Struct) {
660 unowned Struct st = (Struct) m.parent_symbol;
661 if (st.is_simple_type ()) {
662 var vardecl = new CCodeVariableDeclarator ("self", default_value_for_type (creturn_type, true));
663 vardecl.init0 = true;
664 ccode.add_declaration (get_ccode_name (creturn_type), vardecl);
665 } else if (!((CreationMethod) m).chain_up) {
666 // memset needs string.h
667 cfile.add_include ("string.h");
668 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
669 czero.add_argument (new CCodeIdentifier ("self"));
670 czero.add_argument (new CCodeConstant ("0"));
671 czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (st))));
672 ccode.add_expression (czero);
675 Report.error (m.source_reference, "internal: creation method not supported in `%s'", m.parent_symbol.get_full_name ());
679 if (context.module_init_method == m && in_plugin) {
680 // GTypeModule-based plug-in, register types
681 register_plugin_types (context.root, new HashSet<Symbol> ());
684 foreach (Expression precondition in m.get_preconditions ()) {
685 create_precondition_statement (m, creturn_type, precondition);
691 string prefix = "_vala_prof_%s".printf (real_name);
693 var level = new CCodeIdentifier (prefix + "_level");
694 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, level)));
696 var counter = new CCodeIdentifier (prefix + "_counter");
697 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, counter));
699 var timer = new CCodeIdentifier (prefix + "_timer");
700 var cont_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_continue"));
701 cont_call.add_argument (timer);
702 ccode.add_expression (cont_call);
707 if (m.body != null) {
710 if (co_switch_block != null) {
711 // after counting the number of yields for coroutines, append the case statements to the switch
712 var old_block = ccode.current_block;
713 ccode.current_block = co_switch_block;
715 for (int state = 1; state < emit_context.next_coroutine_state; state++) {
716 ccode.add_case (new CCodeConstant (state.to_string ()));
717 ccode.add_goto ("_state_%d".printf (state));
720 // let gcc know that this can't happen
721 ccode.add_default ();
722 ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
724 ccode.current_block = old_block;
725 co_switch_block = null;
729 // we generate the same code if we see a return statement, this handles the case without returns
730 if (profile && m.return_type is VoidType) {
731 string prefix = "_vala_prof_%s".printf (real_name);
733 var level = new CCodeIdentifier (prefix + "_level");
734 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
736 var timer = new CCodeIdentifier (prefix + "_timer");
738 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
739 stop_call.add_argument (timer);
740 ccode.add_expression (stop_call);
745 // generate *_real_* functions for virtual methods
746 // also generate them for abstract methods of classes to prevent faulty subclassing
747 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
748 /* Methods imported from a plain C file don't
749 * have a body, e.g. Vala.Parser.parse_file () */
750 if (m.body != null) {
751 if (current_method_inner_error) {
752 cfile.add_include ("glib.h");
753 /* always separate error parameter and inner_error local variable
754 * as error may be set to NULL but we're always interested in inner errors
757 // no initialization necessary, closure struct is zeroed
758 closure_struct.add_field ("GError*", "_inner_error%d_".printf (current_inner_error_id));
760 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
764 // For non-void return-types GAsyncModule.visit_return_statement () will take care of this
765 if (m.return_type is VoidType && m.coroutine) {
770 if (m is CreationMethod) {
771 if (current_type_symbol is Class && !m.coroutine) {
772 CCodeExpression cresult = new CCodeIdentifier ("self");
773 if (get_ccode_type (m) != null) {
774 cresult = new CCodeCastExpression (cresult, get_ccode_type (m));
777 ccode.add_return (cresult);
778 } else if (current_type_symbol is Struct && ((Struct) current_type_symbol).is_simple_type ()) {
779 // constructors return simple type structs by value
780 ccode.add_return (new CCodeIdentifier ("self"));
784 cfile.add_function (ccode);
788 if (m.is_abstract && current_type_symbol is Class) {
789 // generate helpful error message if a sublcass does not implement an abstract method.
790 // This is only meaningful for subclasses implemented in C since the vala compiler would
791 // complain during compile time of such en error.
793 // add critical warning that this method should not have been called
794 var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
795 if (!((Class) current_type_symbol).is_compact) {
796 var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
797 type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
799 var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
800 type_name_call.add_argument (type_from_instance_call);
802 cerrorcall.add_argument (new CCodeConstant ("\"Type `%%s' does not implement abstract method `%s'\"".printf (get_ccode_name (m))));
803 cerrorcall.add_argument (type_name_call);
805 cerrorcall.add_argument (new CCodeConstant ("\"Abstract method `%s' is not implemented\"".printf (get_ccode_name (m))));
808 ccode.add_expression (cerrorcall);
810 // add return statement
811 return_default_value (creturn_type);
813 cfile.add_function (ccode);
816 if (current_method_return && !(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
817 CCodeVariableDeclarator vardecl;
819 vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
820 vardecl.init0 = true;
822 vardecl = new CCodeVariableDeclarator ("result");
824 ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
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) {
835 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
836 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
838 generate_vfunc (m, creturn_type, cparam_map, carg_map);
842 // m is possible entry point, add appropriate startup code
845 // add callback for async main
846 var asyncmain_callback = new CCodeFunction (real_name + "_callback");
847 asyncmain_callback.add_parameter (new CCodeParameter ("source_object", "GObject*"));
848 asyncmain_callback.add_parameter (new CCodeParameter ("res", "GAsyncResult*"));
849 asyncmain_callback.add_parameter (new CCodeParameter ("user_data", "gpointer"));
850 asyncmain_callback.modifiers |= CCodeModifiers.STATIC;
852 push_function (asyncmain_callback);
853 ccode.add_declaration ("GMainLoop*", new CCodeVariableDeclarator.zero ("loop", new CCodeIdentifier ("user_data")));
855 // get the return value
856 var finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_real_name (m)));
857 finish_call.add_argument (new CCodeIdentifier ("res"));
858 if (m.return_type is VoidType) {
859 ccode.add_expression (finish_call);
861 // save the return value
862 var asyncmain_result = new CCodeIdentifier (real_name + "_result");
863 var asyncmain_result_decl = new CCodeDeclaration (get_ccode_name (int_type));
864 asyncmain_result_decl.add_declarator (new CCodeVariableDeclarator (asyncmain_result.name));
865 asyncmain_result_decl.modifiers = CCodeModifiers.STATIC;
866 cfile.add_type_member_declaration (asyncmain_result_decl);
867 ccode.add_assignment (asyncmain_result, finish_call);
870 // quit the main loop
871 var loop_quit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_main_loop_quit"));
872 loop_quit_call.add_argument (new CCodeIdentifier ("loop"));
873 ccode.add_expression (loop_quit_call);
876 cfile.add_function (asyncmain_callback);
879 var cmain = new CCodeFunction ("main", "int");
880 cmain.line = function.line;
881 cmain.add_parameter (new CCodeParameter ("argc", "int"));
882 cmain.add_parameter (new CCodeParameter ("argv", "char **"));
883 push_function (cmain);
885 if (context.profile == Profile.GOBJECT) {
886 if (context.mem_profiler) {
887 var mem_profiler_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_mem_set_vtable"));
888 mem_profiler_init_call.line = cmain.line;
889 mem_profiler_init_call.add_argument (new CCodeConstant ("glib_mem_profiler_table"));
890 ccode.add_expression (mem_profiler_init_call);
894 var main_call = new CCodeFunctionCall (new CCodeIdentifier (m.coroutine ? real_name : function.name));
895 if (m.get_parameters ().size == 1) {
896 main_call.add_argument (new CCodeIdentifier ("argv"));
897 main_call.add_argument (new CCodeIdentifier ("argc"));
901 // main method is asynchronous, so we have to setup GMainLoop and run it
902 var main_loop_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_main_loop_new"));
903 main_loop_new_call.add_argument (new CCodeConstantIdentifier ("NULL"));
904 main_loop_new_call.add_argument (new CCodeConstantIdentifier ("FALSE"));
905 ccode.add_declaration ("GMainLoop*", new CCodeVariableDeclarator.zero ("loop", main_loop_new_call));
907 // add some more arguments to main_call
908 main_call.add_argument (new CCodeIdentifier (real_name + "_callback"));
909 main_call.add_argument (new CCodeIdentifier ("loop"));
910 ccode.add_expression (main_call);
912 var main_loop_run_call = new CCodeFunctionCall (new CCodeIdentifier ("g_main_loop_run"));
913 main_loop_run_call.add_argument (new CCodeIdentifier ("loop"));
914 ccode.add_expression (main_loop_run_call);
916 var main_loop_unref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_main_loop_unref"));
917 main_loop_unref_call.add_argument (new CCodeIdentifier ("loop"));
918 ccode.add_expression (main_loop_unref_call);
920 if (m.return_type is VoidType) {
921 // method returns void, always use 0 as exit code
922 ccode.add_return (new CCodeConstant ("0"));
924 // get the saved return value
925 ccode.add_return (new CCodeIdentifier (real_name + "_result"));
928 if (m.return_type is VoidType) {
929 // method returns void, always use 0 as exit code
930 ccode.add_expression (main_call);
931 ccode.add_return (new CCodeConstant ("0"));
933 ccode.add_return (main_call);
937 cfile.add_function (cmain);
943 public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
944 CCodeParameter cparam;
945 if (!param.ellipsis && !param.params_array) {
946 generate_type_declaration (param.variable_type, decl_space);
948 string? ctypename = get_ccode_type (param);
949 if (ctypename == null) {
950 ctypename = get_ccode_name (param.variable_type);
952 // pass non-simple structs always by reference
953 unowned Struct? st = param.variable_type.type_symbol as Struct;
955 if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
956 if (st.is_immutable && !param.variable_type.value_owned) {
957 ctypename = "const " + ctypename;
960 if (!param.variable_type.nullable) {
966 if (param.direction != ParameterDirection.IN) {
971 cparam = new CCodeParameter (get_ccode_name (param), ctypename);
972 if (param.format_arg) {
973 cparam.modifiers = CCodeModifiers.FORMAT_ARG;
976 var va_list_name = "_vala_va_list";
978 // Add _first_* parameter for the params array parameter
979 if (param.params_array) {
980 var param_type = ((ArrayType) param.variable_type).element_type;
981 string ctypename = get_ccode_name (param_type);
983 generate_type_declaration (param_type, decl_space);
985 // pass non-simple structs always by reference
986 if (param_type.type_symbol is Struct) {
987 var st = (Struct) param_type.type_symbol;
988 if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
989 if (st.is_immutable && !param.variable_type.value_owned) {
990 ctypename = "const " + ctypename;
993 if (!param_type.nullable) {
999 cparam = new CCodeParameter ("_first_%s".printf (get_ccode_name (param)), ctypename);
1000 cparam_map.set (get_param_pos (get_ccode_pos (param) - 0.1, true), cparam);
1002 va_list_name = "_va_list_%s".printf (get_ccode_name (param));
1005 if (ellipses_to_valist) {
1006 cparam = new CCodeParameter (va_list_name, "va_list");
1008 cparam = new CCodeParameter.with_ellipsis ();
1012 cparam_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis || param.params_array), cparam);
1013 if (carg_map != null && !param.ellipsis && !param.params_array) {
1014 carg_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis || param.params_array), get_parameter_cexpression (param));
1020 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) {
1022 var closure_block = current_closure_block;
1023 int block_id = get_block_id (closure_block);
1024 var instance_param = new CCodeParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
1025 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
1026 } else if (m.parent_symbol is Class && m is CreationMethod) {
1027 var cl = (Class) m.parent_symbol;
1028 if (!cl.is_compact && vcall == null && (direction & 1) == 1) {
1029 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
1031 } else if (m.binding == MemberBinding.INSTANCE && (direction != 2 || get_ccode_finish_instance (m))) {
1032 var this_type = SemanticAnalyzer.get_this_type (m);
1034 generate_type_declaration (this_type, decl_space);
1036 CCodeParameter instance_param = null;
1037 if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
1038 var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
1039 instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
1040 } else if (m.overrides) {
1041 var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
1042 instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
1044 unowned Struct? st = m.parent_symbol as Struct;
1045 if (st != null && !st.is_simple_type ()) {
1046 instance_param = new CCodeParameter ("*self", get_ccode_name (this_type));
1047 } else if (st != null && st.is_simple_type () && m is CreationMethod) {
1048 // constructors return simple type structs by value
1050 instance_param = new CCodeParameter ("self", get_ccode_name (this_type));
1053 if (instance_param != null) {
1054 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
1056 } else if (m.binding == MemberBinding.CLASS) {
1057 var this_type = SemanticAnalyzer.get_this_type (m);
1058 var class_param = new CCodeParameter ("klass", get_ccode_name (this_type));
1059 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), class_param);
1062 // memory management for generic types
1063 List<TypeParameter>? type_parameters = null;
1064 if (is_gtypeinstance_creation_method (m) && (direction & 1) == 1) {
1065 type_parameters = ((Class) m.parent_symbol).get_type_parameters ();
1066 } else if (!m.closure && (direction & 1) == 1) {
1067 type_parameters = m.get_type_parameters ();
1069 if (type_parameters != null) {
1070 int type_param_index = 0;
1071 foreach (var type_param in type_parameters) {
1072 var type = get_ccode_type_id (type_param);
1073 var dup_func = get_ccode_copy_function (type_param);
1074 var destroy_func = get_ccode_destroy_function (type_param);
1075 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter (type, "GType"));
1076 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter (dup_func, "GBoxedCopyFunc"));
1077 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter (destroy_func, "GDestroyNotify"));
1078 if (carg_map != null) {
1079 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier (type));
1080 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (dup_func));
1081 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier (destroy_func));
1087 var needs_format_arg = m.get_format_arg_index () < 0 && (m.printf_format || m.scanf_format);
1089 CCodeParameter? prev_cparam = null;
1090 foreach (Parameter param in m.get_parameters ()) {
1091 if (param.direction != ParameterDirection.OUT) {
1092 if ((direction & 1) == 0) {
1097 if ((direction & 2) == 0) {
1098 // no out parameters
1103 var cparam = generate_parameter (param, decl_space, cparam_map, carg_map);
1105 // if there is no explicit FormatArg annotation while this method throws an error
1106 // it is required to mark the parameter located right before ellipsis as format-arg
1107 // to account for the parameter shifting caused by the inserted GError parameter
1108 if (needs_format_arg) {
1109 if (prev_cparam != null && cparam.ellipsis) {
1110 prev_cparam.modifiers |= CCodeModifiers.FORMAT_ARG;
1112 prev_cparam = cparam;
1116 if ((direction & 2) != 0) {
1117 generate_method_result_declaration (m, decl_space, func, cparam_map, carg_map);
1120 // append C parameters in the right order
1125 foreach (int pos in cparam_map.get_keys ()) {
1126 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
1130 if (min_pos == -1) {
1133 func.add_parameter (cparam_map.get (min_pos));
1134 if (vdeclarator != null) {
1135 vdeclarator.add_parameter (cparam_map.get (min_pos));
1137 if (vcall != null) {
1138 var arg = carg_map.get (min_pos);
1140 vcall.add_argument (arg);
1146 if (m.printf_format) {
1147 func.modifiers |= CCodeModifiers.PRINTF;
1148 } else if (m.scanf_format) {
1149 func.modifiers |= CCodeModifiers.SCANF;
1152 if (m.version.deprecated) {
1153 func.modifiers |= CCodeModifiers.DEPRECATED;
1157 public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) {
1158 push_context (new EmitContext ());
1160 CCodeFunction vfunc;
1161 if (suffix == "_finish") {
1162 vfunc = new CCodeFunction (get_ccode_finish_name (m));
1164 vfunc = new CCodeFunction (get_ccode_name (m));
1167 CCodeExpression vcast;
1168 if (m.parent_symbol is Interface) {
1169 vcast = new CCodeIdentifier ("_iface_");
1171 var cl = (Class) m.parent_symbol;
1172 if (!cl.is_compact) {
1173 vcast = new CCodeIdentifier ("_klass_");
1175 vcast = new CCodeIdentifier ("self");
1179 CCodeFunctionCall vcall;
1180 if (suffix == "_finish") {
1181 vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m)));
1183 vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m)));
1186 carg_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeIdentifier ("self"));
1188 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, direction);
1190 push_function (vfunc);
1192 if (m.return_type.is_non_null_simple_type () && default_value_for_type (m.return_type, false) == null) {
1193 // the type check will use the result variable
1194 CCodeVariableDeclarator vardecl;
1195 if (m.is_abstract) {
1196 vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
1197 vardecl.init0 = true;
1199 vardecl = new CCodeVariableDeclarator ("result");
1201 ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
1204 // add a typecheck statement for "self"
1205 create_method_type_check_statement (m, return_type, (TypeSymbol) m.parent_symbol, true, "self");
1207 foreach (Expression precondition in m.get_preconditions ()) {
1208 create_precondition_statement (m, return_type, precondition);
1211 if (m.parent_symbol is Interface) {
1212 var iface = (Interface) m.parent_symbol;
1214 var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
1215 ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1216 ccode.add_declaration ("%s*".printf (get_ccode_type_name (iface)), new CCodeVariableDeclarator ("_iface_"));
1217 ccode.add_assignment (vcast, vcastcall);
1219 var cl = (Class) m.parent_symbol;
1220 if (!cl.is_compact) {
1221 var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
1222 ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1223 ccode.add_declaration ("%s*".printf (get_ccode_type_name (cl)), new CCodeVariableDeclarator ("_klass_"));
1224 ccode.add_assignment (vcast, vcastcall);
1228 // check if vfunc pointer is properly set
1229 ccode.open_if (vcall.call);
1231 if (return_type is VoidType || return_type.is_real_non_null_struct_type ()) {
1232 ccode.add_expression (vcall);
1233 } else if (m.get_postconditions ().size == 0) {
1234 /* pass method return value */
1235 ccode.add_return (vcall);
1237 /* store method return value for postconditions */
1238 ccode.add_declaration (get_creturn_type (m, get_ccode_name (return_type)), new CCodeVariableDeclarator ("result"));
1239 ccode.add_assignment (new CCodeIdentifier ("result"), vcall);
1242 if (m.get_postconditions ().size > 0) {
1243 foreach (Expression postcondition in m.get_postconditions ()) {
1244 create_postcondition_statement (postcondition);
1247 if (!(return_type is VoidType)) {
1248 ccode.add_return (new CCodeIdentifier ("result"));
1254 if (m.return_type.is_non_null_simple_type () && default_value_for_type (m.return_type, false) == null) {
1255 ccode.add_return (new CCodeIdentifier ("result"));
1256 } else if (!(return_type is VoidType)) {
1257 ccode.add_return (default_value_for_type (return_type, false, true));
1260 if (m.printf_format) {
1261 vfunc.modifiers |= CCodeModifiers.PRINTF;
1262 } else if (m.scanf_format) {
1263 vfunc.modifiers |= CCodeModifiers.SCANF;
1266 if (m.version.deprecated) {
1267 vfunc.modifiers |= CCodeModifiers.DEPRECATED;
1270 cfile.add_function (vfunc);
1275 private void create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) {
1277 create_type_check_statement (m, return_type, t, non_null, var_name);
1281 private void create_precondition_statement (Method m, DataType ret_type, Expression precondition) {
1282 is_in_method_precondition = true;
1284 var ccheck = new CCodeFunctionCall ();
1286 precondition.emit (this);
1288 ccheck.add_argument (get_cvalue (precondition));
1290 string message = ((string) precondition.source_reference.begin.pos).substring (0, (int) (precondition.source_reference.end.pos - precondition.source_reference.begin.pos));
1291 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
1292 requires_assert = true;
1294 if (m is CreationMethod) {
1295 if (m.parent_symbol is Class) {
1296 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1297 ccheck.add_argument (new CCodeConstant ("NULL"));
1299 // creation method of struct
1300 ccheck.call = new CCodeIdentifier ("_vala_return_if_fail");
1302 } else if (m.coroutine) {
1304 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1305 ccheck.add_argument (new CCodeConstant ("FALSE"));
1306 } else if (ret_type is VoidType) {
1308 ccheck.call = new CCodeIdentifier ("_vala_return_if_fail");
1310 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1312 var cdefault = default_value_for_type (ret_type, false);
1313 if (cdefault != null) {
1314 ccheck.add_argument (cdefault);
1320 ccode.add_expression (ccheck);
1322 current_method_return = true;
1323 is_in_method_precondition = false;
1326 public override void visit_creation_method (CreationMethod m) {
1327 push_line (m.source_reference);
1329 unowned Class? cl = m.parent_symbol as Class;
1330 if (cl != null && !cl.is_compact) {
1331 ellipses_to_valist = true;
1333 ellipses_to_valist = false;
1336 ellipses_to_valist = false;
1338 if ((!m.external && m.external_package) || m.source_type == SourceFileType.FAST) {
1343 // do not generate _new functions for creation methods of abstract classes
1344 if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
1346 create_aux_constructor (m, get_ccode_name (m), false);
1348 // _construct function (if visit_method generated _constructv)
1349 if (m.is_variadic ()) {
1350 create_aux_constructor (m, get_ccode_real_name (m), true);
1357 private void create_aux_constructor (CreationMethod m, string func_name, bool self_as_first_parameter) {
1358 var vfunc = new CCodeFunction (func_name);
1359 if (m.is_private_symbol ()) {
1360 vfunc.modifiers |= CCodeModifiers.STATIC;
1361 } else if (context.hide_internal && m.is_internal_symbol ()) {
1362 vfunc.modifiers |= CCodeModifiers.INTERNAL;
1365 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
1366 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
1368 push_function (vfunc);
1370 string constructor = (m.is_variadic ()) ? get_ccode_constructv_name (m) : get_ccode_real_name (m);
1371 var vcall = new CCodeFunctionCall (new CCodeIdentifier (constructor));
1373 if (self_as_first_parameter) {
1374 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
1375 vcall.add_argument (get_variable_cexpression ("object_type"));
1377 vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
1381 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
1383 if (m.is_variadic ()) {
1385 int second_last_pos = -1;
1386 foreach (int pos in cparam_map.get_keys ()) {
1387 if (pos > last_pos) {
1388 second_last_pos = last_pos;
1390 } else if (pos > second_last_pos) {
1391 second_last_pos = pos;
1395 var carg = carg_map.get (second_last_pos);
1397 // params arrays have an implicit first argument, refer to the cparameter name
1398 carg = new CCodeIdentifier (cparam_map.get (second_last_pos).name);
1399 vcall.add_argument (carg);
1402 var vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1403 vastart.add_argument (new CCodeIdentifier ("_vala_va_list_obj"));
1404 vastart.add_argument (carg);
1406 ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_vala_va_list_obj"));
1407 ccode.add_expression (vastart);
1409 vcall.add_argument (new CCodeIdentifier("_vala_va_list_obj"));
1412 ccode.add_return (vcall);
1416 cfile.add_function (vfunc);