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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
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 ((CCodeExpression
) expr
.call
.ccodenode
);
32 CCodeFunctionCall async_call
= null;
35 Delegate deleg
= null;
36 List
<FormalParameter
> 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
) {
45 m
= ((MethodType
) itype
).method_symbol
;
46 } else if (itype is SignalType
) {
47 var sig_type
= (SignalType
) itype
;
48 if (ma
!= null && ma
.inner is BaseAccess
&& sig_type
.signal_symbol
.is_virtual
) {
49 m
= sig_type
.signal_symbol
.default_handler
;
51 ccall
= (CCodeFunctionCall
) expr
.call
.ccodenode
;
53 } else if (itype is ObjectType
) {
55 var cl
= (Class
) ((ObjectType
) itype
).type_symbol
;
56 m
= cl
.default_construction_method
;
57 generate_method_declaration (m
, cfile
);
58 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
59 } else if (itype is StructValueType
) {
61 var st
= (Struct
) ((StructValueType
) itype
).type_symbol
;
62 m
= st
.default_construction_method
;
63 generate_method_declaration (m
, cfile
);
64 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
65 } else if (itype is DelegateType
) {
66 deleg
= ((DelegateType
) itype
).delegate_symbol
;
69 var in_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
70 var out_arg_map
= in_arg_map
;
72 if (m
!= null && m
.coroutine
) {
75 async_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_cname ()));
76 var finish_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_finish_cname ()));
78 if (ma
.inner is BaseAccess
) {
79 if (m
.base_method
!= null) {
80 var base_class
= (Class
) m
.base_method
.parent_symbol
;
81 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
82 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
84 async_call
.call
= new CCodeMemberAccess
.pointer (vcast
, m
.vfunc_name
);
85 finish_call
.call
= new CCodeMemberAccess
.pointer (vcast
, m
.get_finish_vfunc_name ());
86 } else if (m
.base_interface_method
!= null) {
87 var base_iface
= (Interface
) m
.base_interface_method
.parent_symbol
;
88 string parent_iface_var
= "%s_%s_parent_iface".printf (current_class
.get_lower_case_cname (null), base_iface
.get_lower_case_cname (null));
90 async_call
.call
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), m
.vfunc_name
);
91 finish_call
.call
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), m
.get_finish_vfunc_name ());
95 if (ma
.member_name
== "begin" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
98 params
= m
.get_async_begin_parameters ();
99 } else if (ma
.member_name
== "end" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
102 params
= m
.get_async_end_parameters ();
103 } else if (!expr
.is_yield_expression
) {
104 // same as .begin, backwards compatible to bindings without async methods
106 params
= m
.get_async_begin_parameters ();
110 // output arguments used separately
111 out_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
112 // pass GAsyncResult stored in closure to finish function
113 out_arg_map
.set (get_param_pos (0.1), new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_res_"));
117 if (m is CreationMethod
&& m
.parent_symbol is Class
) {
118 if (context
.profile
== Profile
.GOBJECT
) {
119 if (!((Class
) m
.parent_symbol
).is_compact
) {
120 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
123 ccall
.add_argument (new
CCodeIdentifier ("self"));
126 if (!current_class
.is_compact
) {
127 if (current_class
!= m
.parent_symbol
) {
128 // chain up to base class
129 foreach (DataType base_type
in current_class
.get_base_types ()) {
130 if (base_type
.data_type is Class
) {
131 add_generic_type_arguments (in_arg_map
, base_type
.get_type_arguments (), expr
, true);
136 // chain up to other constructor in same class
137 int type_param_index
= 0;
138 var cl
= (Class
) m
.parent_symbol
;
139 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
140 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
141 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
142 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
147 } else if (m is CreationMethod
&& m
.parent_symbol is Struct
) {
148 ccall
.add_argument (new
CCodeIdentifier ("self"));
149 } else if (m
!= null && m
.get_type_parameters ().size
> 0 && !m
.has_generic_type_parameter
&& !m
.simple_generics
) {
151 add_generic_type_arguments (in_arg_map
, ma
.get_type_arguments (), expr
);
154 // the complete call expression, might include casts, comma expressions, and/or assignments
155 CCodeExpression ccall_expr
= ccall
;
157 if (m is ArrayResizeMethod
) {
158 var array_type
= (ArrayType
) ma
.inner
.value_type
;
159 in_arg_map
.set (get_param_pos (0), new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
160 } else if (m is ArrayMoveMethod
) {
161 requires_array_move
= true;
164 CCodeExpression instance
= null;
165 if (m
!= null && m
.is_async_callback
) {
166 if (current_method
.closure
) {
167 var block
= ((Method
) m
.parent_symbol
).body
;
168 instance
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), "_async_data_");
170 instance
= new
CCodeIdentifier ("data");
173 in_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance
);
174 out_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance
);
175 } else if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& !(m is CreationMethod
)) {
176 instance
= (CCodeExpression
) ma
.inner
.ccodenode
;
178 if ((ma
.member_name
== "begin" || ma
.member_name
== "end") && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
179 var inner_ma
= (MemberAccess
) ma
.inner
;
180 instance
= (CCodeExpression
) inner_ma
.inner
.ccodenode
;
183 var st
= m
.parent_symbol as Struct
;
184 if (st
!= null && !st
.is_simple_type ()) {
185 // we need to pass struct instance by reference
186 var unary
= instance as CCodeUnaryExpression
;
187 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
189 instance
= unary
.inner
;
190 } else if (instance is CCodeIdentifier
|| instance is CCodeMemberAccess
) {
191 instance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
);
193 // if instance is e.g. a function call, we can't take the address of the expression
194 // (tmp = expr, &tmp)
195 var ccomma
= new
CCodeCommaExpression ();
197 var temp_var
= get_temp_variable (ma
.inner
.target_type
, true, null, false);
198 temp_vars
.add (temp_var
);
199 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), instance
));
200 ccomma
.append_expression (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");
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"));
224 // Accessing the method of an instance
225 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
226 k
.add_argument ((CCodeExpression
) ma
.inner
.ccodenode
);
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) {
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 ()));
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 ()));
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 ();
262 foreach (Expression arg
in expr
.get_argument_list ()) {
263 var unary
= arg as UnaryExpression
;
264 if (unary
!= null && unary
.operator
== UnaryOperator
.OUT
) {
266 var param
= new
FormalParameter ("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
) {
271 var param
= new
FormalParameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
272 param
.direction
= ParameterDirection
.REF
;
273 m
.add_parameter (param
);
276 m
.add_parameter (new
FormalParameter ("param%d".printf (param_nr
), arg
.value_type
));
280 foreach (FormalParameter param
in m
.get_parameters ()) {
283 generate_dynamic_method_wrapper ((DynamicMethod
) m
);
284 } else if (m is CreationMethod
&& context
.profile
== Profile
.GOBJECT
&& m
.parent_symbol is Class
) {
285 ccall_expr
= new
CCodeAssignment (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 (ccall_expr
);
292 ccall_expr
= new
CCodeAssignment (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 var ccomma
= new
CCodeCommaExpression ();
297 ccomma
.append_expression (ccall_expr
);
299 /* type, dup func, and destroy func fields for generic types */
300 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
301 CCodeIdentifier param_name
;
303 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
305 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
306 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
308 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
309 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
311 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
312 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
319 bool ellipsis
= false;
323 Iterator
<FormalParameter
> params_it
= params
.iterator ();
324 foreach (Expression arg
in expr
.get_argument_list ()) {
325 CCodeExpression cexpr
= (CCodeExpression
) arg
.ccodenode
;
327 var carg_map
= in_arg_map
;
329 if (params_it
.next ()) {
330 var param
= params_it
.get ();
331 ellipsis
= param
.params_array
|| param
.ellipsis
;
333 // if the vala argument expands to multiple C arguments,
334 // we have to make sure that the C arguments don't depend
335 // on each other as there is no guaranteed argument
337 // http://bugzilla.gnome.org/show_bug.cgi?id=519597
338 bool multiple_cargs
= false;
340 if (param
.direction
== ParameterDirection
.OUT
) {
341 carg_map
= out_arg_map
;
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 if (param
.direction
== ParameterDirection
.OUT
) {
350 var temp_array_length
= get_temp_variable (new
CType (param
.array_length_type
));
351 temp_vars
.add (temp_array_length
);
352 array_length_expr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (temp_array_length
.name
));
354 var comma
= new
CCodeCommaExpression ();
355 LocalVariable? temp_result
= null;
356 if (!(m
.return_type is VoidType
)) {
357 temp_result
= get_temp_variable (m
.return_type
);
358 temp_vars
.add (temp_result
);
359 ccall_expr
= new
CCodeAssignment (get_variable_cexpression (temp_result
.name
), ccall_expr
);
362 comma
.append_expression (ccall_expr
);
363 comma
.append_expression (new
CCodeAssignment (get_variable_cexpression (get_array_length_cname (((UnaryExpression
) arg
).inner
.to_string (), dim
)), new
CCodeCastExpression (get_variable_cexpression (temp_array_length
.name
), int_type
.get_cname ())));
365 if (temp_result
!= null) {
366 comma
.append_expression (get_variable_cexpression (temp_result
.name
));
370 array_length_expr
= new
CCodeCastExpression (get_array_length_cexpression (arg
, dim
), param
.array_length_type
);
373 array_length_expr
= get_array_length_cexpression (arg
, dim
);
375 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), array_length_expr
);
377 multiple_cargs
= true;
378 } else if (param
.variable_type is DelegateType
) {
379 var deleg_type
= (DelegateType
) param
.variable_type
;
380 var d
= deleg_type
.delegate_symbol
;
382 CCodeExpression delegate_target_destroy_notify
;
383 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
384 if (param
.ctype
== "GClosure*") {
385 // one single GClosure parameter
386 var closure_new
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_cclosure_new"));
387 closure_new
.add_argument (new
CCodeCastExpression (cexpr
, "GCallback"));
388 closure_new
.add_argument (delegate_target
);
389 closure_new
.add_argument (delegate_target_destroy_notify
);
392 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), delegate_target
);
393 if (deleg_type
.value_owned
) {
394 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), delegate_target_destroy_notify
);
396 multiple_cargs
= true;
399 } else if (param
.variable_type is MethodType
) {
400 // callbacks in dynamic method calls
401 CCodeExpression delegate_target_destroy_notify
;
402 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
));
403 multiple_cargs
= true;
404 } else if (param
.variable_type is GenericType
) {
405 if (m
!= null && m
.simple_generics
) {
406 var generic_type
= (GenericType
) param
.variable_type
;
407 int type_param_index
= m
.get_type_parameter_index (generic_type
.type_parameter
.name
);
408 var type_arg
= ma
.get_type_arguments ().get (type_param_index
);
409 if (requires_copy (type_arg
)) {
410 carg_map
.set (get_param_pos (param
.cdestroy_notify_parameter_position
), get_destroy_func_expression (type_arg
));
412 carg_map
.set (get_param_pos (param
.cdestroy_notify_parameter_position
), new
CCodeConstant ("NULL"));
417 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
419 if (multiple_cargs
&& arg is MethodCall
) {
420 // if vala argument is invocation expression
421 // the auxiliary C argument(s) will depend on the main C argument
423 // (tmp = arg1, call (tmp, arg2, arg3,...))
425 var ccomma
= new
CCodeCommaExpression ();
427 var temp_decl
= get_temp_variable (arg
.value_type
, true, null, false);
428 temp_vars
.add (temp_decl
);
429 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_decl
.name
), cexpr
));
431 cexpr
= get_variable_cexpression (temp_decl
.name
);
433 ccomma
.append_expression (ccall_expr
);
438 // unref old value for non-null non-weak ref/out arguments
439 // disabled for arrays for now as that requires special handling
440 // (ret_tmp = call (&tmp), var1 = (assign_tmp = dup (tmp), free (var1), assign_tmp), ret_tmp)
441 if (param
.direction
!= ParameterDirection
.IN
&& requires_destroy (arg
.value_type
)
442 && (param
.direction
== ParameterDirection
.OUT
|| !param
.variable_type
.value_owned
)
443 && !(param
.variable_type is ArrayType
) && !(param
.variable_type is DelegateType
)) {
444 var unary
= (UnaryExpression
) arg
;
446 var ccomma
= new
CCodeCommaExpression ();
448 var temp_var
= get_temp_variable (param
.variable_type
, param
.variable_type
.value_owned
);
449 temp_vars
.add (temp_var
);
450 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
));
452 if (param
.direction
== ParameterDirection
.REF
) {
453 var crefcomma
= new
CCodeCommaExpression ();
454 crefcomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), (CCodeExpression
) unary
.inner
.ccodenode
));
455 crefcomma
.append_expression (cexpr
);
460 LocalVariable ret_temp_var
= null;
461 if (itype
.get_return_type () is VoidType
|| itype
.get_return_type ().is_real_struct_type () ||
462 (expr
.parent_node is ExpressionStatement
&& !requires_destroy (itype
.get_return_type ()))) {
463 ccomma
.append_expression (ccall_expr
);
465 ret_temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
466 temp_vars
.add (ret_temp_var
);
467 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (ret_temp_var
.name
), ccall_expr
));
470 var cassign_comma
= new
CCodeCommaExpression ();
472 var assign_temp_var
= get_temp_variable (unary
.inner
.value_type
, unary
.inner
.value_type
.value_owned
, null, false);
473 temp_vars
.add (assign_temp_var
);
475 cassign_comma
.append_expression (new
CCodeAssignment (get_variable_cexpression (assign_temp_var
.name
), transform_expression (get_variable_cexpression (temp_var
.name
), param
.variable_type
, unary
.inner
.value_type
, arg
)));
478 cassign_comma
.append_expression (get_unref_expression ((CCodeExpression
) unary
.inner
.ccodenode
, arg
.value_type
, arg
));
480 cassign_comma
.append_expression (get_variable_cexpression (assign_temp_var
.name
));
483 ccomma
.append_expression (new
CCodeAssignment ((CCodeExpression
) unary
.inner
.ccodenode
, cassign_comma
));
486 if (ret_temp_var
!= null) {
487 ccomma
.append_expression (get_variable_cexpression (ret_temp_var
.name
));
493 if (param
.ctype
!= null) {
494 cexpr
= new
CCodeCastExpression (cexpr
, param
.ctype
);
497 cexpr
= handle_struct_argument (null, arg
, cexpr
);
499 arg_pos
= get_param_pos (param
.cparameter_position
, ellipsis
);
501 // default argument position
502 cexpr
= handle_struct_argument (null, arg
, cexpr
);
503 arg_pos
= get_param_pos (i
, ellipsis
);
506 carg_map
.set (arg_pos
, cexpr
);
508 if (arg is NamedArgument
&& ellipsis
) {
509 var named_arg
= (NamedArgument
) arg
;
510 string name
= string.joinv ("-", named_arg
.name
.split ("_"));
511 carg_map
.set (get_param_pos (i
- 0.1, ellipsis
), new
CCodeConstant ("\"%s\"".printf (name
)));
516 if (params_it
.next ()) {
517 var param
= params_it
.get ();
519 /* if there are more parameters than arguments,
520 * the additional parameter is an ellipsis parameter
521 * otherwise there is a bug in the semantic analyzer
523 assert (param
.params_array
|| param
.ellipsis
);
527 /* add length argument for methods returning arrays */
528 if (m
!= null && m
.return_type is ArrayType
&& async_call
!= ccall
) {
529 var array_type
= (ArrayType
) m
.return_type
;
530 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
531 if (m
.array_null_terminated
) {
532 // handle calls to methods returning null-terminated arrays
533 var temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
534 var temp_ref
= get_variable_cexpression (temp_var
.name
);
536 temp_vars
.add (temp_var
);
538 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
540 requires_array_length
= true;
541 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
542 len_call
.add_argument (temp_ref
);
544 expr
.append_array_size (len_call
);
545 } else if (!m
.no_array_length
) {
546 LocalVariable temp_var
;
548 if (m
.array_length_type
== null) {
549 temp_var
= get_temp_variable (int_type
);
551 temp_var
= get_temp_variable (new
CType (m
.array_length_type
));
553 var temp_ref
= get_variable_cexpression (temp_var
.name
);
555 temp_vars
.add (temp_var
);
557 out_arg_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
559 expr
.append_array_size (temp_ref
);
561 expr
.append_array_size (new
CCodeConstant ("-1"));
564 } else if (m
!= null && m
.return_type is DelegateType
&& async_call
!= ccall
) {
565 var deleg_type
= (DelegateType
) m
.return_type
;
566 var d
= deleg_type
.delegate_symbol
;
568 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
569 var temp_ref
= get_variable_cexpression (temp_var
.name
);
571 temp_vars
.add (temp_var
);
573 out_arg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
575 expr
.delegate_target
= temp_ref
;
577 if (deleg_type
.value_owned
) {
578 temp_var
= get_temp_variable (new
DelegateType ((Delegate
) context
.root
.scope
.lookup ("GLib").scope
.lookup ("DestroyNotify")));
579 temp_ref
= get_variable_cexpression (temp_var
.name
);
581 temp_vars
.add (temp_var
);
583 out_arg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
+ 0.01), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
585 expr
.delegate_target_destroy_notify
= temp_ref
;
590 // add length argument for delegates returning arrays
591 // TODO: avoid code duplication with methods returning arrays, see above
592 if (deleg
!= null && deleg
.return_type is ArrayType
) {
593 var array_type
= (ArrayType
) deleg
.return_type
;
594 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
595 if (deleg
.array_null_terminated
) {
596 // handle calls to methods returning null-terminated arrays
597 var temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
598 var temp_ref
= get_variable_cexpression (temp_var
.name
);
600 temp_vars
.add (temp_var
);
602 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
604 requires_array_length
= true;
605 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
606 len_call
.add_argument (temp_ref
);
608 expr
.append_array_size (len_call
);
609 } else if (!deleg
.no_array_length
) {
610 var temp_var
= get_temp_variable (int_type
);
611 var temp_ref
= get_variable_cexpression (temp_var
.name
);
613 temp_vars
.add (temp_var
);
615 out_arg_map
.set (get_param_pos (deleg
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
617 expr
.append_array_size (temp_ref
);
619 expr
.append_array_size (new
CCodeConstant ("-1"));
622 } else if (deleg
!= null && deleg
.return_type is DelegateType
) {
623 var deleg_type
= (DelegateType
) deleg
.return_type
;
624 var d
= deleg_type
.delegate_symbol
;
626 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
627 var temp_ref
= get_variable_cexpression (temp_var
.name
);
629 temp_vars
.add (temp_var
);
631 out_arg_map
.set (get_param_pos (deleg
.cdelegate_target_parameter_position
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
633 expr
.delegate_target
= temp_ref
;
637 if (m
!= null && m
.coroutine
) {
638 if (expr
.is_yield_expression
) {
640 in_arg_map
.set (get_param_pos (-1), new
CCodeIdentifier (current_method
.get_cname () + "_ready"));
641 in_arg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("data"));
645 if (expr
.tree_can_fail
) {
647 current_method_inner_error
= true;
648 // add &inner_error before the ellipsis arguments
649 out_arg_map
.set (get_param_pos (-1), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
653 /* ensure variable argument list ends with NULL
654 * except when using printf-style arguments */
655 if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
656 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant (m
.sentinel
));
658 } else if (itype is DelegateType
) {
659 var deleg_type
= (DelegateType
) itype
;
660 var d
= deleg_type
.delegate_symbol
;
662 CCodeExpression delegate_target_destroy_notify
;
663 in_arg_map
.set (get_param_pos (d
.cinstance_parameter_position
), get_delegate_target_cexpression (expr
.call
, out delegate_target_destroy_notify
));
664 out_arg_map
.set (get_param_pos (d
.cinstance_parameter_position
), get_delegate_target_cexpression (expr
.call
, out delegate_target_destroy_notify
));
668 // structs are returned via out parameter
669 bool return_result_via_out_param
= itype
.get_return_type ().is_real_non_null_struct_type ();
671 // pass address for the return value of non-void signals without emitter functions
672 if (itype is SignalType
&& !(itype
.get_return_type () is VoidType
)) {
673 var sig
= ((SignalType
) itype
).signal_symbol
;
675 if (ma
!= null && ma
.inner is BaseAccess
&& sig
.is_virtual
) {
676 // normal return value for base access
677 } else if (!sig
.has_emitter
) {
678 return_result_via_out_param
= true;
682 if (return_result_via_out_param
) {
683 var temp_var
= get_temp_variable (itype
.get_return_type ());
684 var temp_ref
= get_variable_cexpression (temp_var
.name
);
686 temp_vars
.add (temp_var
);
688 out_arg_map
.set (get_param_pos (-3), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
690 var ccomma
= new
CCodeCommaExpression ();
691 ccomma
.append_expression ((CCodeExpression
) ccall_expr
);
692 ccomma
.append_expression ((CCodeExpression
) temp_ref
);
697 // append C arguments in the right order
702 if (async_call
!= ccall
) {
703 // don't append out arguments for .begin() calls
707 foreach (int pos
in out_arg_map
.get_keys ()) {
708 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
715 ccall
.add_argument (out_arg_map
.get (min_pos
));
720 if (async_call
!= null) {
724 foreach (int pos
in in_arg_map
.get_keys ()) {
725 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
732 async_call
.add_argument (in_arg_map
.get (min_pos
));
737 if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& m
.returns_modified_pointer
) {
738 expr
.ccodenode
= new
CCodeAssignment (instance
, ccall_expr
);
740 expr
.ccodenode
= ccall_expr
;
743 if (expr
.is_yield_expression
) {
744 if (pre_statement_fragment
== null) {
745 pre_statement_fragment
= new
CCodeFragment ();
748 // set state before calling async function to support immediate callbacks
749 int state
= next_coroutine_state
++;
751 state_switch_statement
.add_statement (new
CCodeCaseStatement (new
CCodeConstant (state
.to_string ())));
752 state_switch_statement
.add_statement (new
CCodeGotoStatement ("_state_%d".printf (state
)));
754 pre_statement_fragment
.append (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_state_"), new
CCodeConstant (state
.to_string ()))));
755 pre_statement_fragment
.append (new
CCodeExpressionStatement (async_call
));
756 pre_statement_fragment
.append (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
757 pre_statement_fragment
.append (new
CCodeLabel ("_state_%d".printf (state
)));
760 if (m is ArrayResizeMethod
) {
761 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
762 Iterator
<Expression
> arg_it
= expr
.get_argument_list ().iterator ();
764 var new_size
= (CCodeExpression
) arg_it
.get ().ccodenode
;
766 var temp_decl
= get_temp_variable (int_type
);
767 var temp_ref
= get_variable_cexpression (temp_decl
.name
);
769 temp_vars
.add (temp_decl
);
771 /* memset needs string.h */
772 cfile
.add_include ("string.h");
774 var clen
= get_array_length_cexpression (ma
.inner
, 1);
775 var celems
= (CCodeExpression
) ma
.inner
.ccodenode
;
776 var array_type
= (ArrayType
) ma
.inner
.value_type
;
777 var csizeof
= new
CCodeIdentifier ("sizeof (%s)".printf (array_type
.element_type
.get_cname ()));
778 var cdelta
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, temp_ref
, clen
);
779 var ccheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, temp_ref
, clen
);
781 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
782 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, celems
, clen
));
783 czero
.add_argument (new
CCodeConstant ("0"));
784 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeof
, cdelta
));
786 var ccomma
= new
CCodeCommaExpression ();
787 ccomma
.append_expression (new
CCodeAssignment (temp_ref
, new_size
));
788 ccomma
.append_expression ((CCodeExpression
) expr
.ccodenode
);
789 ccomma
.append_expression (new
CCodeConditionalExpression (ccheck
, czero
, new
CCodeConstant ("NULL")));
790 ccomma
.append_expression (new
CCodeAssignment (get_array_length_cexpression (ma
.inner
, 1), temp_ref
));
792 expr
.ccodenode
= ccomma
;