codegen: Fix array size variable on assignment
[vala-lang.git] / codegen / valaccodemethodcallmodule.vala
blobf7abf5ebd9a32714a3ee1af1d285bb9dadc1747f
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 var temp_var = get_temp_variable (ma.inner.target_type, true, null, false);
200 emit_temp_var (temp_var);
201 ccode.add_assignment (get_variable_cexpression (temp_var.name), instance);
202 instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name));
206 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
207 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
208 } else if (m != null && m.binding == MemberBinding.CLASS) {
209 var cl = (Class) m.parent_symbol;
210 var cast = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null) + "_CLASS"));
212 CCodeExpression klass;
213 if (ma.inner == null) {
214 if (in_static_or_class_context) {
215 // Accessing the method from a static or class constructor
216 klass = new CCodeIdentifier ("klass");
217 } else {
218 // Accessing the method from within an instance method
219 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
220 k.add_argument (new CCodeIdentifier ("self"));
221 klass = k;
223 } else {
224 // Accessing the method of an instance
225 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
226 k.add_argument (get_cvalue (ma.inner));
227 klass = k;
230 cast.add_argument (klass);
231 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), cast);
232 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), cast);
235 if (m != null && m.has_generic_type_parameter) {
236 // insert type argument for macros
237 if (m.get_type_parameters ().size > 0) {
238 // generic method
239 int type_param_index = 0;
240 foreach (var type_arg in ma.get_type_arguments ()) {
241 in_arg_map.set (get_param_pos (m.generic_type_parameter_position + 0.01 * type_param_index), new CCodeIdentifier (type_arg.get_cname ()));
242 type_param_index++;
244 } else {
245 // method in generic type
246 int type_param_index = 0;
247 foreach (var type_arg in ma.inner.value_type.get_type_arguments ()) {
248 in_arg_map.set (get_param_pos (m.generic_type_parameter_position + 0.01 * type_param_index), new CCodeIdentifier (type_arg.get_cname ()));
249 type_param_index++;
254 if (m is ArrayMoveMethod) {
255 var array_type = (ArrayType) ma.inner.value_type;
256 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
257 csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
258 in_arg_map.set (get_param_pos (0.1), csizeof);
259 } else if (m is DynamicMethod) {
260 m.clear_parameters ();
261 int param_nr = 1;
262 foreach (Expression arg in expr.get_argument_list ()) {
263 var unary = arg as UnaryExpression;
264 if (unary != null && unary.operator == UnaryOperator.OUT) {
265 // out argument
266 var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
267 param.direction = ParameterDirection.OUT;
268 m.add_parameter (param);
269 } else if (unary != null && unary.operator == UnaryOperator.REF) {
270 // ref argument
271 var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
272 param.direction = ParameterDirection.REF;
273 m.add_parameter (param);
274 } else {
275 // in argument
276 m.add_parameter (new Parameter ("param%d".printf (param_nr), arg.value_type));
278 param_nr++;
280 foreach (Parameter param in m.get_parameters ()) {
281 param.accept (this);
283 generate_dynamic_method_wrapper ((DynamicMethod) m);
284 } else if (m is CreationMethod && context.profile == Profile.GOBJECT && m.parent_symbol is Class) {
285 ccode.add_assignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, current_class.get_cname () + "*"));
287 if (current_method.body.captured) {
288 // capture self after setting it
289 var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), expr.source_reference));
290 ref_call.add_argument (new CCodeIdentifier ("self"));
292 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method.body))), "self"), ref_call);
295 if (!current_class.is_compact && current_class.get_type_parameters ().size > 0) {
296 /* type, dup func, and destroy func fields for generic types */
297 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
298 CCodeIdentifier param_name;
300 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
302 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
303 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
305 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
306 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
308 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
309 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
312 // object chainup can't be used as expression
313 ccall_expr = null;
316 bool ellipsis = false;
318 int i = 1;
319 int arg_pos;
320 Iterator<Parameter> params_it = params.iterator ();
321 foreach (Expression arg in expr.get_argument_list ()) {
322 CCodeExpression cexpr = get_cvalue (arg);
324 var carg_map = in_arg_map;
326 if (params_it.next ()) {
327 var param = params_it.get ();
328 ellipsis = param.params_array || param.ellipsis;
329 if (!ellipsis) {
330 if (param.direction == ParameterDirection.OUT) {
331 carg_map = out_arg_map;
334 var unary = arg as UnaryExpression;
335 if (unary == null || unary.operator != UnaryOperator.OUT) {
336 if (!param.no_array_length && param.variable_type is ArrayType) {
337 var array_type = (ArrayType) param.variable_type;
338 for (int dim = 1; dim <= array_type.rank; dim++) {
339 CCodeExpression? array_length_expr = null;
340 if (param.array_length_type != null) {
341 array_length_expr = new CCodeCastExpression (get_array_length_cexpression (arg, dim), param.array_length_type);
342 } else {
343 array_length_expr = get_array_length_cexpression (arg, dim);
345 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), array_length_expr);
347 } else if (param.variable_type is DelegateType) {
348 var deleg_type = (DelegateType) param.variable_type;
349 var d = deleg_type.delegate_symbol;
350 if (d.has_target) {
351 CCodeExpression delegate_target_destroy_notify;
352 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
353 assert (delegate_target != null);
354 if (param.ctype == "GClosure*") {
355 // one single GClosure parameter
356 var closure_new = new CCodeFunctionCall (new CCodeIdentifier ("g_cclosure_new"));
357 closure_new.add_argument (new CCodeCastExpression (cexpr, "GCallback"));
358 closure_new.add_argument (delegate_target);
359 closure_new.add_argument (delegate_target_destroy_notify);
360 cexpr = new CCodeConditionalExpression (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cexpr, new CCodeIdentifier ("NULL")), new CCodeIdentifier ("NULL"), closure_new);
361 } else {
362 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
363 if (deleg_type.value_owned) {
364 assert (delegate_target_destroy_notify != null);
365 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), delegate_target_destroy_notify);
369 } else if (param.variable_type is MethodType) {
370 // callbacks in dynamic method calls
371 CCodeExpression delegate_target_destroy_notify;
372 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), get_delegate_target_cexpression (arg, out delegate_target_destroy_notify));
373 } else if (param.variable_type is GenericType) {
374 if (m != null && m.simple_generics) {
375 var generic_type = (GenericType) param.variable_type;
376 int type_param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
377 var type_arg = ma.get_type_arguments ().get (type_param_index);
378 if (param.variable_type.value_owned) {
379 if (requires_copy (type_arg)) {
380 carg_map.set (get_param_pos (param.cdestroy_notify_parameter_position), get_destroy_func_expression (type_arg));
381 } else {
382 carg_map.set (get_param_pos (param.cdestroy_notify_parameter_position), new CCodeConstant ("NULL"));
388 cexpr = handle_struct_argument (param, arg, cexpr);
389 } else {
390 arg.target_value = null;
392 var temp_var = get_temp_variable (param.variable_type, param.variable_type.value_owned);
393 emit_temp_var (temp_var);
394 set_cvalue (arg, get_variable_cexpression (temp_var.name));
396 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
398 if (!param.no_array_length && param.variable_type is ArrayType) {
399 var array_type = (ArrayType) param.variable_type;
400 var array_length_type = int_type;
401 if (param.array_length_type != null) {
402 array_length_type = new CType (param.array_length_type);
404 for (int dim = 1; dim <= array_type.rank; dim++) {
405 var temp_array_length = get_temp_variable (array_length_type);
406 emit_temp_var (temp_array_length);
407 append_array_length (arg, get_variable_cexpression (temp_array_length.name));
408 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_lengths (arg).get (dim - 1)));
410 } else if (param.variable_type is DelegateType) {
411 var deleg_type = (DelegateType) param.variable_type;
412 var d = deleg_type.delegate_symbol;
413 if (d.has_target) {
414 temp_var = get_temp_variable (new PointerType (new VoidType ()));
415 emit_temp_var (temp_var);
416 set_delegate_target (arg, get_variable_cexpression (temp_var.name));
417 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target (arg)));
418 if (deleg_type.value_owned) {
419 temp_var = get_temp_variable (gdestroynotify_type);
420 emit_temp_var (temp_var);
421 set_delegate_target_destroy_notify (arg, get_variable_cexpression (temp_var.name));
422 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_destroy_notify (arg)));
428 if (param.ctype != null) {
429 cexpr = new CCodeCastExpression (cexpr, param.ctype);
431 } else {
432 cexpr = handle_struct_argument (null, arg, cexpr);
434 arg_pos = get_param_pos (param.cparameter_position, ellipsis);
435 } else {
436 // default argument position
437 cexpr = handle_struct_argument (null, arg, cexpr);
438 arg_pos = get_param_pos (i, ellipsis);
441 carg_map.set (arg_pos, cexpr);
443 if (arg is NamedArgument && ellipsis) {
444 var named_arg = (NamedArgument) arg;
445 string name = string.joinv ("-", named_arg.name.split ("_"));
446 carg_map.set (get_param_pos (i - 0.1, ellipsis), new CCodeConstant ("\"%s\"".printf (name)));
449 i++;
451 if (params_it.next ()) {
452 var param = params_it.get ();
454 /* if there are more parameters than arguments,
455 * the additional parameter is an ellipsis parameter
456 * otherwise there is a bug in the semantic analyzer
458 assert (param.params_array || param.ellipsis);
459 ellipsis = true;
462 /* add length argument for methods returning arrays */
463 if (m != null && m.return_type is ArrayType && async_call != ccall) {
464 var array_type = (ArrayType) m.return_type;
465 for (int dim = 1; dim <= array_type.rank; dim++) {
466 if (m.array_null_terminated) {
467 // handle calls to methods returning null-terminated arrays
468 var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
469 var temp_ref = get_variable_cexpression (temp_var.name);
471 emit_temp_var (temp_var);
473 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
475 requires_array_length = true;
476 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
477 len_call.add_argument (temp_ref);
479 append_array_length (expr, len_call);
480 } else if (!m.no_array_length) {
481 LocalVariable temp_var;
483 if (m.array_length_type == null) {
484 temp_var = get_temp_variable (int_type);
485 } else {
486 temp_var = get_temp_variable (new CType (m.array_length_type));
488 var temp_ref = get_variable_cexpression (temp_var.name);
490 emit_temp_var (temp_var);
492 out_arg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
494 append_array_length (expr, temp_ref);
495 } else {
496 append_array_length (expr, new CCodeConstant ("-1"));
499 } else if (m != null && m.return_type is DelegateType && async_call != ccall) {
500 var deleg_type = (DelegateType) m.return_type;
501 var d = deleg_type.delegate_symbol;
502 if (d.has_target) {
503 var temp_var = get_temp_variable (new PointerType (new VoidType ()));
504 var temp_ref = get_variable_cexpression (temp_var.name);
506 emit_temp_var (temp_var);
508 out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
510 set_delegate_target (expr, temp_ref);
512 if (deleg_type.value_owned) {
513 temp_var = get_temp_variable (gdestroynotify_type);
514 temp_ref = get_variable_cexpression (temp_var.name);
516 emit_temp_var (temp_var);
518 out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
520 set_delegate_target_destroy_notify (expr, temp_ref);
525 // add length argument for delegates returning arrays
526 // TODO: avoid code duplication with methods returning arrays, see above
527 if (deleg != null && deleg.return_type is ArrayType) {
528 var array_type = (ArrayType) deleg.return_type;
529 for (int dim = 1; dim <= array_type.rank; dim++) {
530 if (deleg.array_null_terminated) {
531 // handle calls to methods returning null-terminated arrays
532 var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
533 var temp_ref = get_variable_cexpression (temp_var.name);
535 emit_temp_var (temp_var);
537 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
539 requires_array_length = true;
540 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
541 len_call.add_argument (temp_ref);
543 append_array_length (expr, len_call);
544 } else if (!deleg.no_array_length) {
545 var temp_var = get_temp_variable (int_type);
546 var temp_ref = get_variable_cexpression (temp_var.name);
548 emit_temp_var (temp_var);
550 out_arg_map.set (get_param_pos (deleg.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
552 append_array_length (expr, temp_ref);
553 } else {
554 append_array_length (expr, new CCodeConstant ("-1"));
557 } else if (deleg != null && deleg.return_type is DelegateType) {
558 var deleg_type = (DelegateType) deleg.return_type;
559 var d = deleg_type.delegate_symbol;
560 if (d.has_target) {
561 var temp_var = get_temp_variable (new PointerType (new VoidType ()));
562 var temp_ref = get_variable_cexpression (temp_var.name);
564 emit_temp_var (temp_var);
566 out_arg_map.set (get_param_pos (deleg.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
568 set_delegate_target (expr, temp_ref);
572 if (m != null && m.coroutine) {
573 if (expr.is_yield_expression) {
574 // asynchronous call
575 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
576 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("data"));
580 if (expr.tree_can_fail) {
581 // method can fail
582 current_method_inner_error = true;
583 // add &inner_error before the ellipsis arguments
584 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
587 if (ellipsis) {
588 /* ensure variable argument list ends with NULL
589 * except when using printf-style arguments */
590 if (m == null) {
591 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (Method.DEFAULT_SENTINEL));
592 } else if (!m.printf_format && !m.scanf_format && m.sentinel != "") {
593 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (m.sentinel));
597 if (itype is DelegateType) {
598 var deleg_type = (DelegateType) itype;
599 var d = deleg_type.delegate_symbol;
600 if (d.has_target) {
601 CCodeExpression delegate_target_destroy_notify;
602 in_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
603 out_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
607 // structs are returned via out parameter
608 bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type ();
610 // pass address for the return value of non-void signals without emitter functions
611 if (itype is SignalType && !(itype.get_return_type () is VoidType)) {
612 var sig = ((SignalType) itype).signal_symbol;
614 if (ma != null && ma.inner is BaseAccess && sig.is_virtual) {
615 // normal return value for base access
616 } else if (!sig.has_emitter) {
617 return_result_via_out_param = true;
621 CCodeExpression out_param_ref = null;
623 if (return_result_via_out_param) {
624 var out_param_var = get_temp_variable (itype.get_return_type ());
625 out_param_ref = get_variable_cexpression (out_param_var.name);
626 emit_temp_var (out_param_var);
627 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, out_param_ref));
630 // append C arguments in the right order
632 int last_pos;
633 int min_pos;
635 if (async_call != ccall) {
636 // don't append out arguments for .begin() calls
637 last_pos = -1;
638 while (true) {
639 min_pos = -1;
640 foreach (int pos in out_arg_map.get_keys ()) {
641 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
642 min_pos = pos;
645 if (min_pos == -1) {
646 break;
648 ccall.add_argument (out_arg_map.get (min_pos));
649 last_pos = min_pos;
653 if (async_call != null) {
654 last_pos = -1;
655 while (true) {
656 min_pos = -1;
657 foreach (int pos in in_arg_map.get_keys ()) {
658 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
659 min_pos = pos;
662 if (min_pos == -1) {
663 break;
665 async_call.add_argument (in_arg_map.get (min_pos));
666 last_pos = min_pos;
670 if (expr.is_yield_expression) {
671 // set state before calling async function to support immediate callbacks
672 int state = next_coroutine_state++;
674 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_state_"), new CCodeConstant (state.to_string ()));
675 ccode.add_expression (async_call);
676 ccode.add_return (new CCodeConstant ("FALSE"));
677 ccode.add_label ("_state_%d".printf (state));
680 if (return_result_via_out_param) {
681 ccode.add_expression (ccall_expr);
682 ccall_expr = out_param_ref;
685 if (m != null && m.binding == MemberBinding.INSTANCE && m.returns_modified_pointer) {
686 ccall_expr = new CCodeAssignment (instance, ccall_expr);
689 if (m is ArrayResizeMethod) {
690 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
691 Iterator<Expression> arg_it = expr.get_argument_list ().iterator ();
692 arg_it.next ();
693 var new_size = get_cvalue (arg_it.get ());
695 var temp_decl = get_temp_variable (int_type);
696 var temp_ref = get_variable_cexpression (temp_decl.name);
698 emit_temp_var (temp_decl);
700 /* memset needs string.h */
701 cfile.add_include ("string.h");
703 var clen = get_array_length_cexpression (ma.inner, 1);
704 var celems = get_cvalue (ma.inner);
705 var array_type = (ArrayType) ma.inner.value_type;
706 var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (array_type.element_type.get_cname ()));
707 var cdelta = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen);
708 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
710 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
711 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
712 czero.add_argument (new CCodeConstant ("0"));
713 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
715 ccode.add_assignment (temp_ref, new_size);
716 ccode.add_expression (ccall_expr);
717 ccode.add_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
718 ccode.add_assignment (get_array_length_cexpression (ma.inner, 1), temp_ref);
720 var array_var = ma.inner.symbol_reference;
721 var array_local = array_var as LocalVariable;
722 if (array_var != null && array_var.is_internal_symbol ()
723 && ((array_var is LocalVariable && !array_local.captured) || array_var is Field)) {
724 ccode.add_assignment (get_array_size_cvalue (ma.inner.target_value), temp_ref);
727 return;
730 if (expr.parent_node is ExpressionStatement && !expr.value_type.is_disposable ()) {
731 if (ccall_expr != null) {
732 ccode.add_expression (ccall_expr);
734 } else {
735 var result_type = itype.get_return_type ();
737 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
738 var st = expr.formal_value_type.type_parameter.parent_symbol.parent_symbol as Struct;
739 if (expr.formal_value_type.type_parameter.parent_symbol == garray_type ||
740 (st != null && st.get_cname () == "va_list")) {
741 // GArray and va_list don't use pointer-based generics
742 // above logic copied from visit_expression ()
743 // TODO avoid code duplication
744 result_type = expr.value_type;
748 var temp_var = get_temp_variable (result_type, result_type.value_owned);
749 var temp_ref = get_variable_cexpression (temp_var.name);
751 emit_temp_var (temp_var);
753 ccode.add_assignment (temp_ref, ccall_expr);
754 set_cvalue (expr, temp_ref);
757 params_it = params.iterator ();
758 foreach (Expression arg in expr.get_argument_list ()) {
759 if (params_it.next ()) {
760 var param = params_it.get ();
761 if (param.params_array || param.ellipsis) {
762 // ignore ellipsis arguments as we currently don't use temporary variables for them
763 break;
767 var unary = arg as UnaryExpression;
768 if (unary == null || unary.operator != UnaryOperator.OUT) {
769 continue;
772 if (requires_destroy (arg.value_type)) {
773 // unref old value
774 ccode.add_expression (get_unref_expression (get_cvalue (unary.inner), unary.inner.value_type, unary.inner));
777 // assign new value
778 ccode.add_assignment (get_cvalue (unary.inner), transform_expression (get_cvalue (unary), unary.target_type, unary.inner.value_type, arg));
780 var array_type = arg.value_type as ArrayType;
781 if (array_type != null) {
782 for (int dim = 1; dim <= array_type.rank; dim++) {
783 ccode.add_assignment (get_array_lengths (unary.inner).get (dim - 1), get_array_lengths (unary).get (dim - 1));
787 var delegate_type = arg.value_type as DelegateType;
788 if (delegate_type != null) {
789 ccode.add_assignment (get_delegate_target (unary.inner), get_delegate_target (unary));
794 private string generate_enum_tostring_function (Enum en) {
795 var to_string_func = "_%s_to_string".printf (en.get_lower_case_cname ());
797 if (!add_wrapper (to_string_func)) {
798 // wrapper already defined
799 return to_string_func;
801 // declaration
803 var function = new CCodeFunction (to_string_func, "const char*");
804 function.modifiers = CCodeModifiers.STATIC;
806 function.add_parameter (new CCodeParameter ("value", en.get_cname ()));
808 // definition
809 push_context (new EmitContext ());
810 push_function (function);
812 ccode.open_switch (new CCodeConstant ("value"));
813 foreach (var enum_value in en.get_values ()) {
814 ccode.add_case (new CCodeIdentifier (enum_value.get_cname ()));
815 ccode.add_return (new CCodeConstant ("\""+enum_value.get_cname ()+"\""));
817 ccode.close ();
818 ccode.add_return (new CCodeConstant ("NULL"));
820 // append to file
821 cfile.add_function_declaration (function);
822 cfile.add_function (function);
824 pop_context ();
826 return to_string_func;