girparser: Add missing source references to classes and structs
[vala-lang.git] / codegen / valaccodemethodcallmodule.vala
blobdd7e499d0394a1f870857f7b4ac766e93fd8e441
1 /* valaccodemethodcallmodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
28 public override void visit_method_call (MethodCall expr) {
29 // the bare function call
30 var ccall = new CCodeFunctionCall (get_cvalue (expr.call));
32 CCodeFunctionCall async_call = null;
34 Method m = null;
35 Delegate deleg = null;
36 List<Parameter> params;
38 var ma = expr.call as MemberAccess;
40 var itype = expr.call.value_type;
41 params = itype.get_parameters ();
43 if (itype is MethodType) {
44 assert (ma != null);
45 m = ((MethodType) itype).method_symbol;
46 if (ma.inner != null && ma.inner.value_type is EnumValueType && ((EnumValueType) ma.inner.value_type).get_to_string_method() == m) {
47 // Enum.VALUE.to_string()
48 var en = (Enum) ma.inner.value_type.data_type;
49 ccall.call = new CCodeIdentifier (generate_enum_tostring_function (en));
51 } else if (itype is SignalType) {
52 var sig_type = (SignalType) itype;
53 if (ma != null && ma.inner is BaseAccess && sig_type.signal_symbol.is_virtual) {
54 m = sig_type.signal_symbol.default_handler;
55 } else {
56 ccall = (CCodeFunctionCall) get_cvalue (expr.call);
58 } else if (itype is ObjectType) {
59 // constructor
60 var cl = (Class) ((ObjectType) itype).type_symbol;
61 m = cl.default_construction_method;
62 generate_method_declaration (m, cfile);
63 ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
64 } else if (itype is StructValueType) {
65 // constructor
66 var st = (Struct) ((StructValueType) itype).type_symbol;
67 m = st.default_construction_method;
68 generate_method_declaration (m, cfile);
69 ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
70 } else if (itype is DelegateType) {
71 deleg = ((DelegateType) itype).delegate_symbol;
74 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
75 var out_arg_map = in_arg_map;
77 if (m != null && m.coroutine) {
78 // async call
80 async_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
81 var finish_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_finish_cname ()));
83 if (ma.inner is BaseAccess) {
84 if (m.base_method != null) {
85 var base_class = (Class) m.base_method.parent_symbol;
86 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
87 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
89 async_call.call = new CCodeMemberAccess.pointer (vcast, m.vfunc_name);
90 finish_call.call = new CCodeMemberAccess.pointer (vcast, m.get_finish_vfunc_name ());
91 } else if (m.base_interface_method != null) {
92 var base_iface = (Interface) m.base_interface_method.parent_symbol;
93 string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
95 async_call.call = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), m.vfunc_name);
96 finish_call.call = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), m.get_finish_vfunc_name ());
100 if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
101 // no finish call
102 ccall = async_call;
103 params = m.get_async_begin_parameters ();
104 } else if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
105 // no async call
106 ccall = finish_call;
107 params = m.get_async_end_parameters ();
108 } else if (!expr.is_yield_expression) {
109 // same as .begin, backwards compatible to bindings without async methods
110 ccall = async_call;
111 params = m.get_async_begin_parameters ();
112 } else {
113 ccall = finish_call;
115 // output arguments used separately
116 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
117 // pass GAsyncResult stored in closure to finish function
118 out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_res_"));
122 if (m is CreationMethod && m.parent_symbol is Class) {
123 if (context.profile == Profile.GOBJECT) {
124 if (!((Class) m.parent_symbol).is_compact) {
125 ccall.add_argument (new CCodeIdentifier ("object_type"));
127 } else {
128 ccall.add_argument (new CCodeIdentifier ("self"));
131 if (!current_class.is_compact) {
132 if (current_class != m.parent_symbol) {
133 // chain up to base class
134 foreach (DataType base_type in current_class.get_base_types ()) {
135 if (base_type.data_type is Class) {
136 add_generic_type_arguments (in_arg_map, base_type.get_type_arguments (), expr, true);
137 break;
140 } else {
141 // chain up to other constructor in same class
142 int type_param_index = 0;
143 var cl = (Class) m.parent_symbol;
144 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
145 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
146 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
147 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
148 type_param_index++;
152 } else if (m is CreationMethod && m.parent_symbol is Struct) {
153 ccall.add_argument (new CCodeIdentifier ("self"));
154 } else if (m != null && m.get_type_parameters ().size > 0 && !m.has_generic_type_parameter && !m.simple_generics) {
155 // generic method
156 add_generic_type_arguments (in_arg_map, ma.get_type_arguments (), expr);
159 // the complete call expression, might include casts, comma expressions, and/or assignments
160 CCodeExpression ccall_expr = ccall;
162 if (m is ArrayResizeMethod) {
163 var array_type = (ArrayType) ma.inner.value_type;
164 in_arg_map.set (get_param_pos (0), new CCodeIdentifier (array_type.element_type.get_cname ()));
165 } else if (m is ArrayMoveMethod) {
166 requires_array_move = true;
169 CCodeExpression instance = null;
170 if (m != null && m.is_async_callback) {
171 if (current_method.closure) {
172 var block = ((Method) m.parent_symbol).body;
173 instance = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_");
174 } else {
175 instance = new CCodeIdentifier ("data");
178 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
179 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
180 } else if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
181 instance = get_cvalue (ma.inner);
183 if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) {
184 var inner_ma = (MemberAccess) ma.inner;
185 instance = get_cvalue (inner_ma.inner);
188 var st = m.parent_symbol as Struct;
189 if (st != null && !st.is_simple_type ()) {
190 // we need to pass struct instance by reference
191 var unary = instance as CCodeUnaryExpression;
192 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
193 // *expr => expr
194 instance = unary.inner;
195 } else if (instance is CCodeIdentifier || instance is CCodeMemberAccess) {
196 instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance);
197 } else {
198 // if instance is e.g. a function call, we can't take the address of the expression
199 // (tmp = expr, &tmp)
200 var ccomma = new CCodeCommaExpression ();
202 var temp_var = get_temp_variable (ma.inner.target_type, true, null, false);
203 emit_temp_var (temp_var);
204 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), instance));
205 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
207 instance = ccomma;
211 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
212 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
213 } else if (m != null && m.binding == MemberBinding.CLASS) {
214 var cl = (Class) m.parent_symbol;
215 var cast = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null) + "_CLASS"));
217 CCodeExpression klass;
218 if (ma.inner == null) {
219 if (in_static_or_class_context) {
220 // Accessing the method from a static or class constructor
221 klass = new CCodeIdentifier ("klass");
222 } else {
223 // Accessing the method from within an instance method
224 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
225 k.add_argument (new CCodeIdentifier ("self"));
226 klass = k;
228 } else {
229 // Accessing the method of an instance
230 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
231 k.add_argument (get_cvalue (ma.inner));
232 klass = k;
235 cast.add_argument (klass);
236 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), cast);
237 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), cast);
240 if (m != null && m.has_generic_type_parameter) {
241 // insert type argument for macros
242 if (m.get_type_parameters ().size > 0) {
243 // generic method
244 int type_param_index = 0;
245 foreach (var type_arg in ma.get_type_arguments ()) {
246 in_arg_map.set (get_param_pos (m.generic_type_parameter_position + 0.01 * type_param_index), new CCodeIdentifier (type_arg.get_cname ()));
247 type_param_index++;
249 } else {
250 // method in generic type
251 int type_param_index = 0;
252 foreach (var type_arg in ma.inner.value_type.get_type_arguments ()) {
253 in_arg_map.set (get_param_pos (m.generic_type_parameter_position + 0.01 * type_param_index), new CCodeIdentifier (type_arg.get_cname ()));
254 type_param_index++;
259 if (m is ArrayMoveMethod) {
260 var array_type = (ArrayType) ma.inner.value_type;
261 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
262 csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
263 in_arg_map.set (get_param_pos (0.1), csizeof);
264 } else if (m is DynamicMethod) {
265 m.clear_parameters ();
266 int param_nr = 1;
267 foreach (Expression arg in expr.get_argument_list ()) {
268 var unary = arg as UnaryExpression;
269 if (unary != null && unary.operator == UnaryOperator.OUT) {
270 // out argument
271 var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
272 param.direction = ParameterDirection.OUT;
273 m.add_parameter (param);
274 } else if (unary != null && unary.operator == UnaryOperator.REF) {
275 // ref argument
276 var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
277 param.direction = ParameterDirection.REF;
278 m.add_parameter (param);
279 } else {
280 // in argument
281 m.add_parameter (new Parameter ("param%d".printf (param_nr), arg.value_type));
283 param_nr++;
285 foreach (Parameter param in m.get_parameters ()) {
286 param.accept (this);
288 generate_dynamic_method_wrapper ((DynamicMethod) m);
289 } else if (m is CreationMethod && context.profile == Profile.GOBJECT && m.parent_symbol is Class) {
290 ccall_expr = new CCodeAssignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, current_class.get_cname () + "*"));
292 if (current_method.body.captured) {
293 // capture self after setting it
294 var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), expr.source_reference));
295 ref_call.add_argument (ccall_expr);
297 ccall_expr = new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method.body))), "self"), ref_call);
300 if (!current_class.is_compact && current_class.get_type_parameters ().size > 0) {
301 var ccomma = new CCodeCommaExpression ();
302 ccomma.append_expression (ccall_expr);
304 /* type, dup func, and destroy func fields for generic types */
305 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
306 CCodeIdentifier param_name;
308 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
310 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
311 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
313 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
314 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
316 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
317 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
320 ccall_expr = ccomma;
324 bool ellipsis = false;
326 int i = 1;
327 int arg_pos;
328 Iterator<Parameter> params_it = params.iterator ();
329 foreach (Expression arg in expr.get_argument_list ()) {
330 CCodeExpression cexpr = get_cvalue (arg);
332 var carg_map = in_arg_map;
334 if (params_it.next ()) {
335 var param = params_it.get ();
336 ellipsis = param.params_array || param.ellipsis;
337 if (!ellipsis) {
338 if (param.direction == ParameterDirection.OUT) {
339 carg_map = out_arg_map;
342 var unary = arg as UnaryExpression;
343 if (unary == null || unary.operator != UnaryOperator.OUT) {
344 if (!param.no_array_length && param.variable_type is ArrayType) {
345 var array_type = (ArrayType) param.variable_type;
346 for (int dim = 1; dim <= array_type.rank; dim++) {
347 CCodeExpression? array_length_expr = null;
348 if (param.array_length_type != null) {
349 array_length_expr = new CCodeCastExpression (get_array_length_cexpression (arg, dim), param.array_length_type);
350 } else {
351 array_length_expr = get_array_length_cexpression (arg, dim);
353 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), array_length_expr);
355 } else if (param.variable_type is DelegateType) {
356 var deleg_type = (DelegateType) param.variable_type;
357 var d = deleg_type.delegate_symbol;
358 if (d.has_target) {
359 CCodeExpression delegate_target_destroy_notify;
360 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
361 assert (delegate_target != null);
362 if (param.ctype == "GClosure*") {
363 // one single GClosure parameter
364 var closure_new = new CCodeFunctionCall (new CCodeIdentifier ("g_cclosure_new"));
365 closure_new.add_argument (new CCodeCastExpression (cexpr, "GCallback"));
366 closure_new.add_argument (delegate_target);
367 closure_new.add_argument (delegate_target_destroy_notify);
368 cexpr = new CCodeConditionalExpression (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cexpr, new CCodeIdentifier ("NULL")), new CCodeIdentifier ("NULL"), closure_new);
369 } else {
370 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
371 if (deleg_type.value_owned) {
372 assert (delegate_target_destroy_notify != null);
373 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), delegate_target_destroy_notify);
377 } else if (param.variable_type is MethodType) {
378 // callbacks in dynamic method calls
379 CCodeExpression delegate_target_destroy_notify;
380 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), get_delegate_target_cexpression (arg, out delegate_target_destroy_notify));
381 } else if (param.variable_type is GenericType) {
382 if (m != null && m.simple_generics) {
383 var generic_type = (GenericType) param.variable_type;
384 int type_param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
385 var type_arg = ma.get_type_arguments ().get (type_param_index);
386 if (requires_copy (type_arg)) {
387 carg_map.set (get_param_pos (param.cdestroy_notify_parameter_position), get_destroy_func_expression (type_arg));
388 } else {
389 carg_map.set (get_param_pos (param.cdestroy_notify_parameter_position), new CCodeConstant ("NULL"));
394 cexpr = handle_struct_argument (param, arg, cexpr);
395 } else {
396 arg.target_value = null;
398 var temp_var = get_temp_variable (param.variable_type, param.variable_type.value_owned);
399 emit_temp_var (temp_var);
400 set_cvalue (arg, get_variable_cexpression (temp_var.name));
402 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
404 if (!param.no_array_length && param.variable_type is ArrayType) {
405 var array_type = (ArrayType) param.variable_type;
406 var array_length_type = int_type;
407 if (param.array_length_type != null) {
408 array_length_type = new CType (param.array_length_type);
410 for (int dim = 1; dim <= array_type.rank; dim++) {
411 var temp_array_length = get_temp_variable (array_length_type);
412 emit_temp_var (temp_array_length);
413 append_array_size (arg, get_variable_cexpression (temp_array_length.name));
414 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_sizes (arg).get (dim - 1)));
416 } else if (param.variable_type is DelegateType) {
417 var deleg_type = (DelegateType) param.variable_type;
418 var d = deleg_type.delegate_symbol;
419 if (d.has_target) {
420 temp_var = get_temp_variable (new PointerType (new VoidType ()));
421 emit_temp_var (temp_var);
422 set_delegate_target (arg, get_variable_cexpression (temp_var.name));
423 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target (arg)));
424 if (deleg_type.value_owned) {
425 temp_var = get_temp_variable (new DelegateType ((Delegate) context.root.scope.lookup ("GLib").scope.lookup ("DestroyNotify")));
426 emit_temp_var (temp_var);
427 set_delegate_target_destroy_notify (arg, get_variable_cexpression (temp_var.name));
428 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_destroy_notify (arg)));
434 if (param.ctype != null) {
435 cexpr = new CCodeCastExpression (cexpr, param.ctype);
437 } else {
438 cexpr = handle_struct_argument (null, arg, cexpr);
440 arg_pos = get_param_pos (param.cparameter_position, ellipsis);
441 } else {
442 // default argument position
443 cexpr = handle_struct_argument (null, arg, cexpr);
444 arg_pos = get_param_pos (i, ellipsis);
447 carg_map.set (arg_pos, cexpr);
449 if (arg is NamedArgument && ellipsis) {
450 var named_arg = (NamedArgument) arg;
451 string name = string.joinv ("-", named_arg.name.split ("_"));
452 carg_map.set (get_param_pos (i - 0.1, ellipsis), new CCodeConstant ("\"%s\"".printf (name)));
455 i++;
457 if (params_it.next ()) {
458 var param = params_it.get ();
460 /* if there are more parameters than arguments,
461 * the additional parameter is an ellipsis parameter
462 * otherwise there is a bug in the semantic analyzer
464 assert (param.params_array || param.ellipsis);
465 ellipsis = true;
468 /* add length argument for methods returning arrays */
469 if (m != null && m.return_type is ArrayType && async_call != ccall) {
470 var array_type = (ArrayType) m.return_type;
471 for (int dim = 1; dim <= array_type.rank; dim++) {
472 if (m.array_null_terminated) {
473 // handle calls to methods returning null-terminated arrays
474 var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
475 var temp_ref = get_variable_cexpression (temp_var.name);
477 emit_temp_var (temp_var);
479 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
481 requires_array_length = true;
482 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
483 len_call.add_argument (temp_ref);
485 append_array_size (expr, len_call);
486 } else if (!m.no_array_length) {
487 LocalVariable temp_var;
489 if (m.array_length_type == null) {
490 temp_var = get_temp_variable (int_type);
491 } else {
492 temp_var = get_temp_variable (new CType (m.array_length_type));
494 var temp_ref = get_variable_cexpression (temp_var.name);
496 emit_temp_var (temp_var);
498 out_arg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
500 append_array_size (expr, temp_ref);
501 } else {
502 append_array_size (expr, new CCodeConstant ("-1"));
505 } else if (m != null && m.return_type is DelegateType && async_call != ccall) {
506 var deleg_type = (DelegateType) m.return_type;
507 var d = deleg_type.delegate_symbol;
508 if (d.has_target) {
509 var temp_var = get_temp_variable (new PointerType (new VoidType ()));
510 var temp_ref = get_variable_cexpression (temp_var.name);
512 emit_temp_var (temp_var);
514 out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
516 set_delegate_target (expr, temp_ref);
518 if (deleg_type.value_owned) {
519 temp_var = get_temp_variable (new DelegateType ((Delegate) context.root.scope.lookup ("GLib").scope.lookup ("DestroyNotify")));
520 temp_ref = get_variable_cexpression (temp_var.name);
522 emit_temp_var (temp_var);
524 out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
526 set_delegate_target_destroy_notify (expr, temp_ref);
531 // add length argument for delegates returning arrays
532 // TODO: avoid code duplication with methods returning arrays, see above
533 if (deleg != null && deleg.return_type is ArrayType) {
534 var array_type = (ArrayType) deleg.return_type;
535 for (int dim = 1; dim <= array_type.rank; dim++) {
536 if (deleg.array_null_terminated) {
537 // handle calls to methods returning null-terminated arrays
538 var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
539 var temp_ref = get_variable_cexpression (temp_var.name);
541 emit_temp_var (temp_var);
543 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
545 requires_array_length = true;
546 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
547 len_call.add_argument (temp_ref);
549 append_array_size (expr, len_call);
550 } else if (!deleg.no_array_length) {
551 var temp_var = get_temp_variable (int_type);
552 var temp_ref = get_variable_cexpression (temp_var.name);
554 emit_temp_var (temp_var);
556 out_arg_map.set (get_param_pos (deleg.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
558 append_array_size (expr, temp_ref);
559 } else {
560 append_array_size (expr, new CCodeConstant ("-1"));
563 } else if (deleg != null && deleg.return_type is DelegateType) {
564 var deleg_type = (DelegateType) deleg.return_type;
565 var d = deleg_type.delegate_symbol;
566 if (d.has_target) {
567 var temp_var = get_temp_variable (new PointerType (new VoidType ()));
568 var temp_ref = get_variable_cexpression (temp_var.name);
570 emit_temp_var (temp_var);
572 out_arg_map.set (get_param_pos (deleg.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
574 set_delegate_target (expr, temp_ref);
578 if (m != null && m.coroutine) {
579 if (expr.is_yield_expression) {
580 // asynchronous call
581 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (current_method.get_cname () + "_ready"));
582 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("data"));
586 if (expr.tree_can_fail) {
587 // method can fail
588 current_method_inner_error = true;
589 // add &inner_error before the ellipsis arguments
590 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
593 if (ellipsis) {
594 /* ensure variable argument list ends with NULL
595 * except when using printf-style arguments */
596 if (m == null) {
597 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (Method.DEFAULT_SENTINEL));
598 } else if (!m.printf_format && !m.scanf_format && m.sentinel != "") {
599 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (m.sentinel));
603 if (itype is DelegateType) {
604 var deleg_type = (DelegateType) itype;
605 var d = deleg_type.delegate_symbol;
606 if (d.has_target) {
607 CCodeExpression delegate_target_destroy_notify;
608 in_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
609 out_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
613 // structs are returned via out parameter
614 bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type ();
616 // pass address for the return value of non-void signals without emitter functions
617 if (itype is SignalType && !(itype.get_return_type () is VoidType)) {
618 var sig = ((SignalType) itype).signal_symbol;
620 if (ma != null && ma.inner is BaseAccess && sig.is_virtual) {
621 // normal return value for base access
622 } else if (!sig.has_emitter) {
623 return_result_via_out_param = true;
627 if (return_result_via_out_param) {
628 var temp_var = get_temp_variable (itype.get_return_type ());
629 var temp_ref = get_variable_cexpression (temp_var.name);
631 emit_temp_var (temp_var);
633 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
635 var ccomma = new CCodeCommaExpression ();
636 ccomma.append_expression ((CCodeExpression) ccall_expr);
637 ccomma.append_expression ((CCodeExpression) temp_ref);
639 ccall_expr = ccomma;
642 // append C arguments in the right order
644 int last_pos;
645 int min_pos;
647 if (async_call != ccall) {
648 // don't append out arguments for .begin() calls
649 last_pos = -1;
650 while (true) {
651 min_pos = -1;
652 foreach (int pos in out_arg_map.get_keys ()) {
653 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
654 min_pos = pos;
657 if (min_pos == -1) {
658 break;
660 ccall.add_argument (out_arg_map.get (min_pos));
661 last_pos = min_pos;
665 if (async_call != null) {
666 last_pos = -1;
667 while (true) {
668 min_pos = -1;
669 foreach (int pos in in_arg_map.get_keys ()) {
670 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
671 min_pos = pos;
674 if (min_pos == -1) {
675 break;
677 async_call.add_argument (in_arg_map.get (min_pos));
678 last_pos = min_pos;
682 if (m != null && m.binding == MemberBinding.INSTANCE && m.returns_modified_pointer) {
683 ccall_expr = new CCodeAssignment (instance, ccall_expr);
686 if (expr.is_yield_expression) {
687 // set state before calling async function to support immediate callbacks
688 int state = next_coroutine_state++;
690 ccode.add_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_state_"), new CCodeConstant (state.to_string ())));
691 ccode.add_expression (async_call);
692 ccode.add_return (new CCodeConstant ("FALSE"));
693 ccode.add_label ("_state_%d".printf (state));
696 if (m is ArrayResizeMethod) {
697 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
698 Iterator<Expression> arg_it = expr.get_argument_list ().iterator ();
699 arg_it.next ();
700 var new_size = get_cvalue (arg_it.get ());
702 var temp_decl = get_temp_variable (int_type);
703 var temp_ref = get_variable_cexpression (temp_decl.name);
705 emit_temp_var (temp_decl);
707 /* memset needs string.h */
708 cfile.add_include ("string.h");
710 var clen = get_array_length_cexpression (ma.inner, 1);
711 var celems = get_cvalue (ma.inner);
712 var array_type = (ArrayType) ma.inner.value_type;
713 var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (array_type.element_type.get_cname ()));
714 var cdelta = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen);
715 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
717 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
718 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
719 czero.add_argument (new CCodeConstant ("0"));
720 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
722 var ccomma = new CCodeCommaExpression ();
723 ccomma.append_expression (new CCodeAssignment (temp_ref, new_size));
724 ccomma.append_expression (ccall_expr);
725 ccomma.append_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
726 ccomma.append_expression (new CCodeAssignment (get_array_length_cexpression (ma.inner, 1), temp_ref));
728 var array_var = ma.inner.symbol_reference;
729 var array_local = array_var as LocalVariable;
730 if (array_var != null && array_var.is_internal_symbol ()
731 && ((array_var is LocalVariable && !array_local.captured) || array_var is Field)) {
732 ccomma.append_expression (new CCodeAssignment (get_array_size_cvalue (ma.inner.target_value), temp_ref));
735 set_cvalue (expr, ccomma);
737 return;
740 if (expr.parent_node is ExpressionStatement && !expr.value_type.is_disposable ()) {
741 ccode.add_expression (ccall_expr);
742 } else {
743 var result_type = itype.get_return_type ();
745 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
746 var st = expr.formal_value_type.type_parameter.parent_symbol.parent_symbol as Struct;
747 if (expr.formal_value_type.type_parameter.parent_symbol == garray_type ||
748 (st != null && st.get_cname () == "va_list")) {
749 // GArray and va_list don't use pointer-based generics
750 // above logic copied from visit_expression ()
751 // TODO avoid code duplication
752 result_type = expr.value_type;
756 var temp_var = get_temp_variable (result_type, result_type.value_owned);
757 var temp_ref = get_variable_cexpression (temp_var.name);
759 emit_temp_var (temp_var);
761 ccode.add_expression (new CCodeAssignment (temp_ref, ccall_expr));
762 set_cvalue (expr, temp_ref);
765 params_it = params.iterator ();
766 foreach (Expression arg in expr.get_argument_list ()) {
767 if (params_it.next ()) {
768 var param = params_it.get ();
769 if (param.params_array || param.ellipsis) {
770 // ignore ellipsis arguments as we currently don't use temporary variables for them
771 break;
775 var unary = arg as UnaryExpression;
776 if (unary == null || unary.operator != UnaryOperator.OUT) {
777 continue;
780 if (requires_destroy (arg.value_type)) {
781 // unref old value
782 ccode.add_expression (get_unref_expression (get_cvalue (unary.inner), unary.inner.value_type, unary.inner));
785 // assign new value
786 ccode.add_expression (new CCodeAssignment (get_cvalue (unary.inner), transform_expression (get_cvalue (unary), unary.target_type, unary.inner.value_type, arg)));
788 var array_type = arg.value_type as ArrayType;
789 if (array_type != null) {
790 for (int dim = 1; dim <= array_type.rank; dim++) {
791 ccode.add_expression (new CCodeAssignment (get_array_sizes (unary.inner).get (dim - 1), get_array_sizes (unary).get (dim - 1)));
795 var delegate_type = arg.value_type as DelegateType;
796 if (delegate_type != null) {
797 ccode.add_expression (new CCodeAssignment (get_delegate_target (unary.inner), get_delegate_target (unary)));
802 private string generate_enum_tostring_function (Enum en) {
803 var to_string_func = "_%s_to_string".printf (en.get_lower_case_cname ());
805 if (!add_wrapper (to_string_func)) {
806 // wrapper already defined
807 return to_string_func;
809 // declaration
811 var function = new CCodeFunction (to_string_func, "const char*");
812 function.modifiers = CCodeModifiers.STATIC;
814 function.add_parameter (new CCodeParameter ("value", en.get_cname ()));
816 // definition
817 push_context (new EmitContext ());
818 push_function (function);
820 ccode.open_switch (new CCodeConstant ("value"));
821 foreach (var enum_value in en.get_values ()) {
822 ccode.add_case (new CCodeIdentifier (enum_value.get_cname ()));
823 ccode.add_return (new CCodeConstant ("\""+enum_value.get_cname ()+"\""));
825 ccode.close ();
826 ccode.add_return (new CCodeConstant ("NULL"));
828 // append to file
829 cfile.add_function_declaration (function);
830 cfile.add_function (function);
832 pop_context ();
834 return to_string_func;