vala: Allow read-only properties
[vala-gnome.git] / codegen / valaccodemethodmodule.vala
blob117e7a21d935dbf29bc0d938cf9805cfbae0c599
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using GLib;
26 /**
27 * The link between a method and generated code.
29 public abstract class Vala.CCodeMethodModule : CCodeStructModule {
31 private bool ellipses_to_valist = false;
33 public override bool method_has_wrapper (Method method) {
34 return (method.get_attribute ("NoWrapper") == null);
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;
42 return type;
45 bool is_gtypeinstance_creation_method (Method m) {
46 bool result = false;
48 var cl = m.parent_symbol as Class;
49 if (m is CreationMethod && cl != null && !cl.is_compact) {
50 result = true;
53 return result;
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 = m.return_type;
58 if (m is CreationMethod) {
59 var cl = m.parent_symbol as Class;
60 if (cl != null) {
61 // object creation methods return the new object in C
62 // in Vala they have no return type
63 creturn_type = new ObjectType (cl);
65 } else if (m.return_type.is_real_non_null_struct_type ()) {
66 // structs are returned via out parameter
67 creturn_type = new VoidType ();
69 cfunc.return_type = get_creturn_type (m, get_ccode_name (creturn_type));
71 generate_type_declaration (m.return_type, decl_space);
73 if (m.return_type.is_real_non_null_struct_type ()) {
74 // structs are returned via out parameter
75 var cparam = new CCodeParameter ("result", get_ccode_name (m.return_type) + "*");
76 cparam_map.set (get_param_pos (-3), cparam);
77 if (carg_map != null) {
78 carg_map.set (get_param_pos (-3), get_result_cexpression ());
80 } else if (get_ccode_array_length (m) && m.return_type is ArrayType) {
81 // return array length if appropriate
82 var array_type = (ArrayType) m.return_type;
83 var array_length_type = get_ccode_array_length_type (m) != null ? get_ccode_array_length_type (m) : "int";
84 array_length_type += "*";
86 for (int dim = 1; dim <= array_type.rank; dim++) {
87 var cparam = new CCodeParameter (get_array_length_cname ("result", dim), array_length_type);
88 cparam_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), cparam);
89 if (carg_map != null) {
90 carg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), get_variable_cexpression (cparam.name));
93 } else if (m.return_type is DelegateType) {
94 // return delegate target if appropriate
95 var deleg_type = (DelegateType) m.return_type;
96 if (deleg_type.delegate_symbol.has_target) {
97 var cparam = new CCodeParameter (get_delegate_target_cname ("result"), "gpointer*");
98 cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), cparam);
99 if (carg_map != null) {
100 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), get_variable_cexpression (cparam.name));
102 if (deleg_type.is_disposable ()) {
103 cparam = new CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
104 cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m) + 0.01), cparam);
105 if (carg_map != null) {
106 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m) + 0.01), get_variable_cexpression (cparam.name));
112 if (m.has_error_type_parameter ()) {
113 foreach (DataType error_type in m.get_error_types ()) {
114 generate_type_declaration (error_type, decl_space);
117 var cparam = new CCodeParameter ("error", "GError**");
118 cparam_map.set (get_param_pos (-1), cparam);
119 if (carg_map != null) {
120 carg_map.set (get_param_pos (-1), new CCodeIdentifier (cparam.name));
125 public void complete_async () {
126 var data_var = new CCodeIdentifier ("_data_");
127 var async_result_expr = new CCodeMemberAccess.pointer (data_var, "_async_result");
129 var finish_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_pointer"));
130 finish_call.add_argument (async_result_expr);
131 finish_call.add_argument (data_var);
132 finish_call.add_argument (new CCodeConstant ("NULL"));
133 ccode.add_expression (finish_call);
135 // Preserve the "complete now" behavior if state != 0, do so by
136 // iterating the GTask's main context till the task is complete.
137 var state = new CCodeMemberAccess.pointer (data_var, "_state_");
138 var zero = new CCodeConstant ("0");
139 var state_is_not_zero = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, state, zero);
140 ccode.open_if (state_is_not_zero);
142 CCodeBinaryExpression task_is_complete;
144 if (context.require_glib_version (2, 44)) {
145 var task_complete = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_completed"));
146 task_complete.add_argument (async_result_expr);
147 task_is_complete = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, task_complete, new CCodeConstant ("TRUE"));
148 } else {
149 var task_complete = new CCodeMemberAccess.pointer (data_var, "_task_complete_");
150 task_is_complete = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, task_complete, new CCodeConstant ("TRUE"));
153 ccode.open_while (task_is_complete);
154 var task_context = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_context"));
155 task_context.add_argument (async_result_expr);
156 var iterate_context = new CCodeFunctionCall (new CCodeIdentifier ("g_main_context_iteration"));
157 iterate_context.add_argument (task_context);
158 iterate_context.add_argument (new CCodeConstant ("TRUE"));
159 ccode.add_expression (iterate_context);
160 ccode.close ();
162 ccode.close ();
164 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
165 unref.add_argument (async_result_expr);
166 ccode.add_expression (unref);
168 ccode.add_return (new CCodeConstant ("FALSE"));
171 public override void generate_method_declaration (Method m, CCodeFile decl_space) {
172 if (m.is_async_callback) {
173 return;
175 if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
176 return;
179 var function = new CCodeFunction (get_ccode_name (m));
181 if (m.is_private_symbol () && !m.external) {
182 function.modifiers |= CCodeModifiers.STATIC;
183 if (m.is_inline) {
184 function.modifiers |= CCodeModifiers.INLINE;
186 } else if (context.hide_internal && m.is_internal_symbol () && !m.external) {
187 function.modifiers |= CCodeModifiers.INTERNAL;
190 if (m.version.deprecated) {
191 function.modifiers |= CCodeModifiers.DEPRECATED;
194 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
195 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
197 var cl = m.parent_symbol as Class;
199 // do not generate _new functions for creation methods of abstract classes
200 if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
201 bool etv_tmp = ellipses_to_valist;
202 ellipses_to_valist = false;
203 generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
204 ellipses_to_valist = etv_tmp;
206 decl_space.add_function_declaration (function);
209 if (is_gtypeinstance_creation_method (m)) {
210 // _construct function
211 function = new CCodeFunction (get_ccode_real_name (m));
213 if (m.is_private_symbol ()) {
214 function.modifiers |= CCodeModifiers.STATIC;
215 } else if (context.hide_internal && m.is_internal_symbol ()) {
216 function.modifiers |= CCodeModifiers.INTERNAL;
219 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
220 bool etv_tmp = ellipses_to_valist;
221 ellipses_to_valist = false;
222 generate_cparameters (m, decl_space, cparam_map, function);
223 ellipses_to_valist = etv_tmp;
225 decl_space.add_function_declaration (function);
227 if (m.is_variadic ()) {
228 // _constructv function
229 function = new CCodeFunction (get_ccode_constructv_name ((CreationMethod) m));
231 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
232 generate_cparameters (m, decl_space, cparam_map, function);
234 decl_space.add_function_declaration (function);
239 void register_plugin_types (Symbol sym, Set<Symbol> registered_types) {
240 var ns = sym as Namespace;
241 var cl = sym as Class;
242 var iface = sym as Interface;
243 if (ns != null) {
244 foreach (var ns_ns in ns.get_namespaces ()) {
245 register_plugin_types (ns_ns, registered_types);
247 foreach (var ns_cl in ns.get_classes ()) {
248 register_plugin_types (ns_cl, registered_types);
250 foreach (var ns_iface in ns.get_interfaces ()) {
251 register_plugin_types (ns_iface, registered_types);
253 } else if (cl != null) {
254 register_plugin_type (cl, registered_types);
255 foreach (var cl_cl in cl.get_classes ()) {
256 register_plugin_types (cl_cl, registered_types);
258 } else if (iface != null) {
259 register_plugin_type (iface, registered_types);
260 foreach (var iface_cl in iface.get_classes ()) {
261 register_plugin_types (iface_cl, registered_types);
266 void register_plugin_type (ObjectTypeSymbol type_symbol, Set<Symbol> registered_types) {
267 if (type_symbol.external_package) {
268 return;
271 if (!registered_types.add (type_symbol)) {
272 // already registered
273 return;
276 var cl = type_symbol as Class;
277 if (cl != null) {
278 if (cl.is_compact) {
279 return;
282 // register base types first
283 foreach (var base_type in cl.get_base_types ()) {
284 register_plugin_type ((ObjectTypeSymbol) base_type.data_type, registered_types);
288 // Add function prototypes for required register-type-calls which are likely external
289 var register_func = new CCodeFunction ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null)), "GType");
290 register_func.add_parameter (new CCodeParameter ("module", "GTypeModule *"));
291 register_func.is_declaration = true;
292 cfile.add_function_declaration (register_func);
294 var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null))));
295 register_call.add_argument (new CCodeIdentifier (module_init_param_name));
296 ccode.add_expression (register_call);
298 var iface = type_symbol as Interface;
299 if (iface != null) {
300 string? dbus_name = GDBusModule.get_dbus_name(type_symbol);
302 if (dbus_name != null) {
303 string proxy_cname = get_ccode_lower_case_prefix (type_symbol) + "proxy";
304 var register_proxy = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_dynamic_type".printf (proxy_cname)));
305 register_proxy.add_argument (new CCodeIdentifier (module_init_param_name));
306 ccode.add_expression (register_proxy);
312 * This function generates the code the given method. If the method is
313 * a constructor, _construct is generated, unless it's variadic, in which
314 * case _constructv is generated (and _construct is generated together
315 * with _new in visit_creation_method).
317 public override void visit_method (Method m) {
318 string real_name = get_ccode_real_name (m);
319 if (m is CreationMethod && m.is_variadic ()) {
320 real_name = get_ccode_constructv_name ((CreationMethod) m);
323 push_context (new EmitContext (m));
324 push_line (m.source_reference);
326 bool in_gobject_creation_method = false;
327 bool in_fundamental_creation_method = false;
329 check_type (m.return_type);
331 bool profile = m.get_attribute ("Profile") != null;
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;
344 var creturn_type = m.return_type;
345 if (m.return_type.is_real_non_null_struct_type ()) {
346 // structs are returned via out parameter
347 creturn_type = new VoidType ();
350 foreach (Parameter param in m.get_parameters ()) {
351 param.accept (this);
354 // do not declare overriding methods and interface implementations
355 if ((m.is_abstract || m.is_virtual
356 || (m.base_method == null && m.base_interface_method == null)) && m.signal_reference == null) {
357 generate_method_declaration (m, cfile);
359 if (!m.is_internal_symbol ()) {
360 generate_method_declaration (m, header_file);
362 if (!m.is_private_symbol ()) {
363 generate_method_declaration (m, internal_header_file);
367 if (profile) {
368 string prefix = "_vala_prof_%s".printf (real_name);
370 cfile.add_include ("stdio.h");
372 var counter = new CCodeIdentifier (prefix + "_counter");
373 var counter_decl = new CCodeDeclaration ("gint");
374 counter_decl.add_declarator (new CCodeVariableDeclarator (counter.name));
375 counter_decl.modifiers = CCodeModifiers.STATIC;
376 cfile.add_type_member_declaration (counter_decl);
378 // nesting level for recursive functions
379 var level = new CCodeIdentifier (prefix + "_level");
380 var level_decl = new CCodeDeclaration ("gint");
381 level_decl.add_declarator (new CCodeVariableDeclarator (level.name));
382 level_decl.modifiers = CCodeModifiers.STATIC;
383 cfile.add_type_member_declaration (level_decl);
385 var timer = new CCodeIdentifier (prefix + "_timer");
386 var timer_decl = new CCodeDeclaration ("GTimer *");
387 timer_decl.add_declarator (new CCodeVariableDeclarator (timer.name));
388 timer_decl.modifiers = CCodeModifiers.STATIC;
389 cfile.add_type_member_declaration (timer_decl);
391 var constructor = new CCodeFunction (prefix + "_init");
392 constructor.modifiers = CCodeModifiers.STATIC | CCodeModifiers.CONSTRUCTOR;
393 cfile.add_function_declaration (constructor);
394 push_function (constructor);
396 ccode.add_assignment (timer, new CCodeFunctionCall (new CCodeIdentifier ("g_timer_new")));
398 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
399 stop_call.add_argument (timer);
400 ccode.add_expression (stop_call);
402 pop_function ();
403 cfile.add_function (constructor);
406 var destructor = new CCodeFunction (prefix + "_exit");
407 destructor.modifiers = CCodeModifiers.STATIC | CCodeModifiers.DESTRUCTOR;
408 cfile.add_function_declaration (destructor);
409 push_function (destructor);
411 var elapsed_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_elapsed"));
412 elapsed_call.add_argument (timer);
413 elapsed_call.add_argument (new CCodeConstant ("NULL"));
415 var print_call = new CCodeFunctionCall (new CCodeIdentifier ("fprintf"));
416 print_call.add_argument (new CCodeIdentifier ("stderr"));
417 print_call.add_argument (new CCodeConstant ("\"%s: %%gs (%%d calls)\\n\"".printf (m.get_full_name ())));
418 print_call.add_argument (elapsed_call);
419 print_call.add_argument (counter);
420 ccode.add_expression (print_call);
422 pop_function ();
423 cfile.add_function (destructor);
426 CCodeFunction function;
427 function = new CCodeFunction (real_name);
429 if (m.is_inline) {
430 function.modifiers |= CCodeModifiers.INLINE;
433 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
435 generate_cparameters (m, cfile, cparam_map, function);
437 // generate *_real_* functions for virtual methods
438 // also generate them for abstract methods of classes to prevent faulty subclassing
439 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
440 if (!m.coroutine) {
441 if (m.base_method != null || m.base_interface_method != null) {
442 // declare *_real_* function
443 function.modifiers |= CCodeModifiers.STATIC;
444 cfile.add_function_declaration (function);
445 } else if (m.is_private_symbol ()) {
446 function.modifiers |= CCodeModifiers.STATIC;
447 } else if (context.hide_internal && m.is_internal_symbol ()) {
448 function.modifiers |= CCodeModifiers.INTERNAL;
450 } else {
451 if (m.body != null) {
452 function = new CCodeFunction (real_name + "_co", "gboolean");
454 // data struct to hold parameters, local variables, and the return value
455 function.add_parameter (new CCodeParameter ("_data_", Symbol.lower_case_to_camel_case (get_ccode_const_name (m)) + "Data*"));
456 function.modifiers |= CCodeModifiers.STATIC;
457 cfile.add_function_declaration (function);
462 if (m.comment != null) {
463 cfile.add_type_member_definition (new CCodeComment (m.comment.content));
466 push_function (function);
468 unowned CCodeBlock? co_switch_block = null;
470 // generate *_real_* functions for virtual methods
471 // also generate them for abstract methods of classes to prevent faulty subclassing
472 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
473 if (m.body != null) {
474 if (m.coroutine) {
475 ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"));
477 // initial coroutine state
478 ccode.add_case (new CCodeConstant ("0"));
479 ccode.add_goto ("_state_0");
481 co_switch_block = ccode.current_block;
483 ccode.close ();
485 // coroutine body
486 ccode.add_label ("_state_0");
489 if (m.closure) {
490 // add variables for parent closure blocks
491 // as closures only have one parameter for the innermost closure block
492 var closure_block = current_closure_block;
493 int block_id = get_block_id (closure_block);
494 while (true) {
495 var parent_closure_block = next_closure_block (closure_block.parent_symbol);
496 if (parent_closure_block == null) {
497 break;
499 int parent_block_id = get_block_id (parent_closure_block);
501 var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id));
502 ccode.add_declaration ("Block%dData*".printf (parent_block_id), new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id)));
503 ccode.add_assignment (new CCodeIdentifier ("_data%d_".printf (parent_block_id)), parent_data);
505 closure_block = parent_closure_block;
506 block_id = parent_block_id;
509 // add self variable for closures
510 // as closures have block data parameter
511 if (m.binding == MemberBinding.INSTANCE) {
512 var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self");
513 ccode.add_declaration (get_ccode_name (get_data_type_for_symbol (current_type_symbol)), new CCodeVariableDeclarator ("self"));
514 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
517 // allow capturing generic type parameters
518 foreach (var type_param in m.get_type_parameters ()) {
519 string func_name;
521 func_name = "%s_type".printf (type_param.name.down ());
522 ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
523 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
525 func_name = "%s_dup_func".printf (type_param.name.down ());
526 ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
527 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
529 func_name = "%s_destroy_func".printf (type_param.name.down ());
530 ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
531 ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
533 } else if (m.parent_symbol is Class && !m.coroutine) {
534 var cl = (Class) m.parent_symbol;
535 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
536 Method base_method;
537 ReferenceType base_expression_type;
538 if (m.overrides) {
539 base_method = m.base_method;
540 base_expression_type = new ObjectType ((Class) base_method.parent_symbol);
541 } else {
542 base_method = m.base_interface_method;
543 base_expression_type = new ObjectType ((Interface) base_method.parent_symbol);
545 var self_target_type = new ObjectType (cl);
546 CCodeExpression cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
548 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
549 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
550 } else if (m.binding == MemberBinding.INSTANCE
551 && !(m is CreationMethod)
552 && m.base_method == null && m.base_interface_method == null) {
553 create_method_type_check_statement (m, creturn_type, cl, true, "self");
557 foreach (Parameter param in m.get_parameters ()) {
558 if (param.ellipsis) {
559 break;
562 if (param.direction != ParameterDirection.OUT) {
563 var t = param.variable_type.data_type;
564 if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) {
565 var cname = get_variable_cname (param.name);
566 if (param.direction == ParameterDirection.REF && !param.variable_type.is_real_struct_type ()) {
567 cname = "*"+cname;
569 create_method_type_check_statement (m, creturn_type, t, !param.variable_type.nullable, cname);
571 } else if (!m.coroutine) {
572 // declare local variable for out parameter to allow assignment even when caller passes NULL
573 var vardecl = new CCodeVariableDeclarator.zero (get_variable_cname ("_vala_%s".printf (param.name)), default_value_for_type (param.variable_type, true));
574 ccode.add_declaration (get_ccode_name (param.variable_type), vardecl);
576 if (param.variable_type is ArrayType) {
577 // create variables to store array dimensions
578 var array_type = (ArrayType) param.variable_type;
580 if (!array_type.fixed_length) {
581 for (int dim = 1; dim <= array_type.rank; dim++) {
582 vardecl = new CCodeVariableDeclarator.zero (get_array_length_cname (get_variable_cname ("_vala_%s".printf (param.name)), dim), new CCodeConstant ("0"));
583 ccode.add_declaration ("int", vardecl);
586 } else if (param.variable_type is DelegateType) {
587 var deleg_type = (DelegateType) param.variable_type;
588 if (deleg_type.delegate_symbol.has_target) {
589 // create variable to store delegate target
590 vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_delegate_target_name (param)), new CCodeConstant ("NULL"));
591 ccode.add_declaration ("void *", vardecl);
593 if (deleg_type.is_disposable ()) {
594 vardecl = new CCodeVariableDeclarator.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_vala_%s".printf (param.name))), new CCodeConstant ("NULL"));
595 ccode.add_declaration ("GDestroyNotify", vardecl);
602 if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
603 var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
604 vardecl.init0 = true;
605 ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
608 if (m is CreationMethod) {
609 if (in_gobject_creation_method) {
610 if (!m.coroutine) {
611 ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
613 } else if (is_gtypeinstance_creation_method (m)) {
614 var cl = (Class) m.parent_symbol;
615 ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
617 if (cl.is_fundamental () && !((CreationMethod) m).chain_up) {
618 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
619 ccall.add_argument (get_variable_cexpression ("object_type"));
620 ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (cl) + "*"));
622 /* type, dup func, and destroy func fields for generic types */
623 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
624 CCodeIdentifier param_name;
625 CCodeAssignment assign;
627 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
629 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
630 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
631 ccode.add_expression (assign);
633 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
634 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
635 ccode.add_expression (assign);
637 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
638 assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
639 ccode.add_expression (assign);
642 } else if (current_type_symbol is Class) {
643 var cl = (Class) m.parent_symbol;
644 if (!m.coroutine) {
645 ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator ("self"));
648 if (!((CreationMethod) m).chain_up) {
649 // TODO implicitly chain up to base class as in add_object_creation
650 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
651 ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
652 ccode.add_assignment (get_this_cexpression (), ccall);
655 if (cl.base_class == null) {
656 var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null))));
657 cinitcall.add_argument (get_this_cexpression ());
658 ccode.add_expression (cinitcall);
660 } else {
661 var st = (Struct) m.parent_symbol;
663 // memset needs string.h
664 cfile.add_include ("string.h");
665 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
666 czero.add_argument (new CCodeIdentifier ("self"));
667 czero.add_argument (new CCodeConstant ("0"));
668 czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (st))));
669 ccode.add_expression (czero);
673 if (context.module_init_method == m && in_plugin) {
674 // GTypeModule-based plug-in, register types
675 register_plugin_types (context.root, new HashSet<Symbol> ());
678 foreach (Expression precondition in m.get_preconditions ()) {
679 create_precondition_statement (m, creturn_type, precondition);
684 if (profile) {
685 string prefix = "_vala_prof_%s".printf (real_name);
687 var level = new CCodeIdentifier (prefix + "_level");
688 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, level)));
690 var counter = new CCodeIdentifier (prefix + "_counter");
691 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, counter));
693 var timer = new CCodeIdentifier (prefix + "_timer");
694 var cont_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_continue"));
695 cont_call.add_argument (timer);
696 ccode.add_expression (cont_call);
698 ccode.close ();
701 if (m.body != null) {
702 m.body.emit (this);
704 if (co_switch_block != null) {
705 // after counting the number of yields for coroutines, append the case statements to the switch
706 var old_block = ccode.current_block;
707 ccode.current_block = co_switch_block;
709 for (int state = 1; state < emit_context.next_coroutine_state; state++) {
710 ccode.add_case (new CCodeConstant (state.to_string ()));
711 ccode.add_goto ("_state_%d".printf (state));
714 // let gcc know that this can't happen
715 ccode.add_default ();
716 ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
718 ccode.current_block = old_block;
719 co_switch_block = null;
723 // we generate the same code if we see a return statement, this handles the case without returns
724 if (profile && m.return_type is VoidType) {
725 string prefix = "_vala_prof_%s".printf (real_name);
727 var level = new CCodeIdentifier (prefix + "_level");
728 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
730 var timer = new CCodeIdentifier (prefix + "_timer");
732 var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
733 stop_call.add_argument (timer);
734 ccode.add_expression (stop_call);
736 ccode.close ();
739 // generate *_real_* functions for virtual methods
740 // also generate them for abstract methods of classes to prevent faulty subclassing
741 if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
742 /* Methods imported from a plain C file don't
743 * have a body, e.g. Vala.Parser.parse_file () */
744 if (m.body != null) {
745 if (current_method_inner_error) {
746 /* always separate error parameter and inner_error local variable
747 * as error may be set to NULL but we're always interested in inner errors
749 if (m.coroutine) {
750 closure_struct.add_field ("GError *", "_inner_error_");
752 // no initialization necessary, closure struct is zeroed
753 } else {
754 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
758 // For non-void return-types GAsyncModule.visit_return_statement () will take care of this
759 if (m.return_type is VoidType && m.coroutine) {
760 // epilogue
761 complete_async ();
764 if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
765 // add dummy return if exit block is known to be unreachable to silence C compiler
766 if (m.return_block != null && m.return_block.get_predecessors ().size == 0) {
767 ccode.add_return (new CCodeIdentifier ("result"));
771 if (m is CreationMethod) {
772 if (current_type_symbol is Class) {
773 creturn_type = new ObjectType (current_class);
774 } else {
775 creturn_type = new VoidType ();
779 if (current_type_symbol is Class && gobject_type != null && current_class.is_subtype_of (gobject_type)
780 && current_class.get_type_parameters ().size > 0
781 && !((CreationMethod) m).chain_up) {
782 var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("__params_it"), new CCodeIdentifier ("__params"));
783 ccode.open_while (ccond);
784 ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeIdentifier ("__params_it")));
785 var cunsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_unset"));
786 cunsetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("__params_it"), "value")));
787 ccode.add_expression (cunsetcall);
788 ccode.close ();
790 var cfreeparams = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
791 cfreeparams.add_argument (new CCodeIdentifier ("__params"));
792 ccode.add_expression (cfreeparams);
795 if (current_type_symbol is Class && !m.coroutine) {
796 CCodeExpression cresult = new CCodeIdentifier ("self");
797 if (get_ccode_type (m) != null) {
798 cresult = new CCodeCastExpression (cresult, get_ccode_type (m));
801 ccode.add_return (cresult);
805 cfile.add_function (ccode);
809 if (m.is_abstract && current_type_symbol is Class) {
810 // generate helpful error message if a sublcass does not implement an abstract method.
811 // This is only meaningful for subclasses implemented in C since the vala compiler would
812 // complain during compile time of such en error.
814 // add critical warning that this method should not have been called
815 var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
816 if (!((Class) current_type_symbol).is_compact) {
817 var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
818 type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
820 var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
821 type_name_call.add_argument (type_from_instance_call);
823 cerrorcall.add_argument (new CCodeConstant ("\"Type `%%s' does not implement abstract method `%s'\"".printf (get_ccode_name (m))));
824 cerrorcall.add_argument (type_name_call);
825 } else {
826 cerrorcall.add_argument (new CCodeConstant ("\"Abstract method `%s' is not implemented\"".printf (get_ccode_name (m))));
829 ccode.add_expression (cerrorcall);
831 // add return statement
832 return_default_value (creturn_type);
834 cfile.add_function (ccode);
837 pop_context ();
839 if ((m.is_abstract || m.is_virtual) && !m.coroutine &&
840 /* If the method is a signal handler, the declaration
841 * is not needed. -- the name should be reserved for the
842 * emitter! */
843 m.signal_reference == null) {
845 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
846 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
848 generate_vfunc (m, creturn_type, cparam_map, carg_map);
851 if (m.entry_point) {
852 // m is possible entry point, add appropriate startup code
853 var cmain = new CCodeFunction ("main", "int");
854 cmain.line = function.line;
855 cmain.add_parameter (new CCodeParameter ("argc", "int"));
856 cmain.add_parameter (new CCodeParameter ("argv", "char **"));
857 push_function (cmain);
859 if (context.profile == Profile.GOBJECT) {
860 if (context.mem_profiler) {
861 var mem_profiler_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_mem_set_vtable"));
862 mem_profiler_init_call.line = cmain.line;
863 mem_profiler_init_call.add_argument (new CCodeConstant ("glib_mem_profiler_table"));
864 ccode.add_expression (mem_profiler_init_call);
868 var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
869 if (m.get_parameters ().size == 1) {
870 main_call.add_argument (new CCodeIdentifier ("argv"));
871 main_call.add_argument (new CCodeIdentifier ("argc"));
873 if (m.return_type is VoidType) {
874 // method returns void, always use 0 as exit code
875 ccode.add_expression (main_call);
876 ccode.add_return (new CCodeConstant ("0"));
877 } else {
878 ccode.add_return (main_call);
880 pop_function ();
881 cfile.add_function (cmain);
884 pop_line ();
887 public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
888 CCodeParameter cparam;
889 if (!param.ellipsis) {
890 string ctypename = get_ccode_name (param.variable_type);
892 generate_type_declaration (param.variable_type, decl_space);
894 // pass non-simple structs always by reference
895 if (param.variable_type.data_type is Struct) {
896 var st = (Struct) param.variable_type.data_type;
897 if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
898 if (st.is_immutable && !param.variable_type.value_owned) {
899 ctypename = "const " + ctypename;
902 if (!param.variable_type.nullable) {
903 ctypename += "*";
908 if (param.direction != ParameterDirection.IN) {
909 ctypename += "*";
912 cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
913 if (param.format_arg) {
914 cparam.modifiers = CCodeModifiers.FORMAT_ARG;
916 } else if (ellipses_to_valist) {
917 cparam = new CCodeParameter ("_vala_va_list", "va_list");
918 } else {
919 cparam = new CCodeParameter.with_ellipsis ();
922 cparam_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis), cparam);
923 if (carg_map != null && !param.ellipsis) {
924 carg_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis), get_variable_cexpression (param.name));
927 return cparam;
930 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) {
931 if (m.closure) {
932 var closure_block = current_closure_block;
933 int block_id = get_block_id (closure_block);
934 var instance_param = new CCodeParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
935 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
936 } else if (m.parent_symbol is Class && m is CreationMethod) {
937 var cl = (Class) m.parent_symbol;
938 if (!cl.is_compact && vcall == null && (direction & 1) == 1) {
939 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
941 } else if ((m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod))
942 && (direction != 2 || get_ccode_finish_instance (m))) {
943 TypeSymbol parent_type = find_parent_type (m);
944 DataType this_type;
945 if (parent_type is Class) {
946 this_type = new ObjectType ((Class) parent_type);
947 } else if (parent_type is Interface) {
948 this_type = new ObjectType ((Interface) parent_type);
949 } else if (parent_type is Struct) {
950 this_type = new StructValueType ((Struct) parent_type);
951 } else if (parent_type is Enum) {
952 this_type = new EnumValueType ((Enum) parent_type);
953 } else {
954 assert_not_reached ();
957 generate_type_declaration (this_type, decl_space);
959 CCodeParameter instance_param = null;
960 if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
961 var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
962 instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
963 } else if (m.overrides) {
964 var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
965 instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
966 } else {
967 if (m.parent_symbol is Struct && !((Struct) m.parent_symbol).is_simple_type ()) {
968 instance_param = new CCodeParameter ("*self", get_ccode_name (this_type));
969 } else {
970 instance_param = new CCodeParameter ("self", get_ccode_name (this_type));
973 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
974 } else if (m.binding == MemberBinding.CLASS) {
975 TypeSymbol parent_type = find_parent_type (m);
976 DataType this_type;
977 this_type = new ClassType ((Class) parent_type);
978 var class_param = new CCodeParameter ("klass", get_ccode_name (this_type));
979 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), class_param);
982 if (is_gtypeinstance_creation_method (m)) {
983 // memory management for generic types
984 int type_param_index = 0;
985 var cl = (Class) m.parent_symbol;
986 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
987 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
988 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
989 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
990 if (carg_map != null) {
991 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
992 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
993 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
995 type_param_index++;
997 } else if (!m.closure && (direction & 1) == 1) {
998 int type_param_index = 0;
999 foreach (var type_param in m.get_type_parameters ()) {
1000 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
1001 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
1002 cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
1003 if (carg_map != null) {
1004 carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
1005 carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
1006 carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
1008 type_param_index++;
1012 var needs_format_arg = m.get_format_arg_index () < 0 && (m.printf_format || m.scanf_format);
1014 CCodeParameter? prev_cparam = null;
1015 foreach (Parameter param in m.get_parameters ()) {
1016 if (param.direction != ParameterDirection.OUT) {
1017 if ((direction & 1) == 0) {
1018 // no in parameters
1019 continue;
1021 } else {
1022 if ((direction & 2) == 0) {
1023 // no out parameters
1024 continue;
1028 var cparam = generate_parameter (param, decl_space, cparam_map, carg_map);
1030 // if there is no explicit FormatArg annotation while this method throws an error
1031 // it is required to mark the parameter located right before ellipsis as format-arg
1032 // to account for the parameter shifting caused by the inserted GError parameter
1033 if (needs_format_arg) {
1034 if (prev_cparam != null && cparam.ellipsis) {
1035 prev_cparam.modifiers |= CCodeModifiers.FORMAT_ARG;
1037 prev_cparam = cparam;
1041 if ((direction & 2) != 0) {
1042 generate_method_result_declaration (m, decl_space, func, cparam_map, carg_map);
1045 // append C parameters in the right order
1046 int last_pos = -1;
1047 int min_pos;
1048 while (true) {
1049 min_pos = -1;
1050 foreach (int pos in cparam_map.get_keys ()) {
1051 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
1052 min_pos = pos;
1055 if (min_pos == -1) {
1056 break;
1058 func.add_parameter (cparam_map.get (min_pos));
1059 if (vdeclarator != null) {
1060 vdeclarator.add_parameter (cparam_map.get (min_pos));
1062 if (vcall != null) {
1063 var arg = carg_map.get (min_pos);
1064 if (arg != null) {
1065 vcall.add_argument (arg);
1068 last_pos = min_pos;
1071 if (m.printf_format) {
1072 func.modifiers |= CCodeModifiers.PRINTF;
1073 } else if (m.scanf_format) {
1074 func.modifiers |= CCodeModifiers.SCANF;
1077 if (m.version.deprecated) {
1078 func.modifiers |= CCodeModifiers.DEPRECATED;
1082 public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) {
1083 push_context (new EmitContext ());
1085 string cname = get_ccode_name (m);
1086 if (suffix == "_finish" && cname.has_suffix ("_async")) {
1087 cname = cname.substring (0, cname.length - "_async".length);
1089 var vfunc = new CCodeFunction (cname + suffix);
1091 CCodeExpression vcast;
1092 if (m.parent_symbol is Interface) {
1093 var iface = (Interface) m.parent_symbol;
1095 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
1096 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self"));
1097 } else {
1098 var cl = (Class) m.parent_symbol;
1099 if (!cl.is_compact) {
1100 vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl))));
1101 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("self"));
1102 } else {
1103 vcast = new CCodeIdentifier ("self");
1107 cname = get_ccode_vfunc_name (m);
1108 if (suffix == "_finish" && cname.has_suffix ("_async")) {
1109 cname = cname.substring (0, cname.length - "_async".length);
1111 var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, cname + suffix));
1112 carg_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeIdentifier ("self"));
1114 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, direction);
1116 push_function (vfunc);
1118 if (context.assert && m.return_type.data_type is Struct && ((Struct) m.return_type.data_type).is_simple_type () && default_value_for_type (m.return_type, false) == null) {
1119 // the type check will use the result variable
1120 var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
1121 vardecl.init0 = true;
1122 ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
1125 // add a typecheck statement for "self"
1126 create_method_type_check_statement (m, return_type, (TypeSymbol) m.parent_symbol, true, "self");
1128 foreach (Expression precondition in m.get_preconditions ()) {
1129 create_precondition_statement (m, return_type, precondition);
1132 if (return_type is VoidType || return_type.is_real_non_null_struct_type ()) {
1133 ccode.add_expression (vcall);
1134 } else if (m.get_postconditions ().size == 0) {
1135 /* pass method return value */
1136 ccode.add_return (vcall);
1137 } else {
1138 /* store method return value for postconditions */
1139 ccode.add_declaration (get_creturn_type (m, get_ccode_name (return_type)), new CCodeVariableDeclarator ("result"));
1140 ccode.add_assignment (new CCodeIdentifier ("result"), vcall);
1143 if (m.get_postconditions ().size > 0) {
1144 foreach (Expression postcondition in m.get_postconditions ()) {
1145 create_postcondition_statement (postcondition);
1148 if (!(return_type is VoidType)) {
1149 ccode.add_return (new CCodeIdentifier ("result"));
1153 if (m.printf_format) {
1154 vfunc.modifiers |= CCodeModifiers.PRINTF;
1155 } else if (m.scanf_format) {
1156 vfunc.modifiers |= CCodeModifiers.SCANF;
1159 if (m.version.deprecated) {
1160 vfunc.modifiers |= CCodeModifiers.DEPRECATED;
1163 cfile.add_function (vfunc);
1165 pop_context ();
1168 private void create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) {
1169 if (!m.coroutine) {
1170 create_type_check_statement (m, return_type, t, non_null, var_name);
1174 private void create_precondition_statement (CodeNode method_node, DataType ret_type, Expression precondition) {
1175 var ccheck = new CCodeFunctionCall ();
1177 precondition.emit (this);
1179 ccheck.add_argument (get_cvalue (precondition));
1181 string message = ((string) precondition.source_reference.begin.pos).substring (0, (int) (precondition.source_reference.end.pos - precondition.source_reference.begin.pos));
1182 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
1183 requires_assert = true;
1185 if (method_node is CreationMethod) {
1186 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1187 ccheck.add_argument (new CCodeConstant ("NULL"));
1188 } else if (method_node is Method && ((Method) method_node).coroutine) {
1189 // _co function
1190 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1191 ccheck.add_argument (new CCodeConstant ("FALSE"));
1192 } else if (ret_type is VoidType) {
1193 /* void function */
1194 ccheck.call = new CCodeIdentifier ("_vala_return_if_fail");
1195 } else {
1196 ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1198 var cdefault = default_value_for_type (ret_type, false);
1199 if (cdefault != null) {
1200 ccheck.add_argument (cdefault);
1201 } else {
1202 return;
1206 ccode.add_expression (ccheck);
1209 private TypeSymbol? find_parent_type (Symbol sym) {
1210 while (sym != null) {
1211 if (sym is TypeSymbol) {
1212 return (TypeSymbol) sym;
1214 sym = sym.parent_symbol;
1216 return null;
1219 public override void visit_creation_method (CreationMethod m) {
1220 push_line (m.source_reference);
1222 ellipses_to_valist = true;
1223 visit_method (m);
1224 ellipses_to_valist = false;
1226 if (m.source_type == SourceFileType.FAST) {
1227 return;
1230 // do not generate _new functions for creation methods of abstract classes
1231 if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
1232 // _new function
1233 create_aux_constructor (m, get_ccode_name (m), false);
1235 // _construct function (if visit_method generated _constructv)
1236 if (m.is_variadic ()) {
1237 create_aux_constructor (m, get_ccode_real_name (m), true);
1241 pop_line ();
1244 private void create_aux_constructor (CreationMethod m, string func_name, bool self_as_first_parameter) {
1245 var vfunc = new CCodeFunction (func_name);
1246 if (m.is_private_symbol ()) {
1247 vfunc.modifiers |= CCodeModifiers.STATIC;
1248 } else if (context.hide_internal && m.is_internal_symbol ()) {
1249 vfunc.modifiers |= CCodeModifiers.INTERNAL;
1252 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
1253 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
1255 push_function (vfunc);
1257 string constructor = (m.is_variadic ()) ? get_ccode_constructv_name (m) : get_ccode_real_name (m);
1258 var vcall = new CCodeFunctionCall (new CCodeIdentifier (constructor));
1260 if (self_as_first_parameter) {
1261 cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
1262 vcall.add_argument (get_variable_cexpression ("object_type"));
1263 } else {
1264 vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
1268 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
1270 if (m.is_variadic ()) {
1271 int last_pos = -1;
1272 int second_last_pos = -1;
1273 foreach (int pos in cparam_map.get_keys ()) {
1274 if (pos > last_pos) {
1275 second_last_pos = last_pos;
1276 last_pos = pos;
1277 } else if (pos > second_last_pos) {
1278 second_last_pos = pos;
1282 var va_start = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1283 va_start.add_argument (new CCodeIdentifier ("_vala_va_list_obj"));
1284 va_start.add_argument (carg_map.get (second_last_pos));
1286 ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_vala_va_list_obj"));
1287 ccode.add_expression (va_start);
1289 vcall.add_argument (new CCodeIdentifier("_vala_va_list_obj"));
1292 ccode.add_return (vcall);
1294 pop_function ();
1296 cfile.add_function (vfunc);
1300 // vim:sw=8 noet