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 (get_cvalue (expr
.call
));
32 CCodeFunctionCall async_call
= 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
) {
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
;
56 ccall
= (CCodeFunctionCall
) get_cvalue (expr
.call
);
58 } else if (itype is ObjectType
) {
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
) {
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
) {
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
) {
103 params
= m
.get_async_begin_parameters ();
104 } else if (ma
.member_name
== "end" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
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
111 params
= m
.get_async_begin_parameters ();
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"));
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);
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 ())));
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
) {
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_");
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
) {
194 instance
= unary
.inner
;
195 } else if (instance is CCodeIdentifier
|| instance is CCodeMemberAccess
) {
196 instance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
);
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");
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 (get_cvalue (ma
.inner
));
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
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
) {
271 var param
= new
Parameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
272 param
.direction
= ParameterDirection
.REF
;
273 m
.add_parameter (param
);
276 m
.add_parameter (new
Parameter ("param%d".printf (param_nr
), arg
.value_type
));
280 foreach (Parameter 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 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
316 bool ellipsis
= false;
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
;
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
);
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
;
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
);
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
));
382 carg_map
.set (get_param_pos (param
.cdestroy_notify_parameter_position
), new
CCodeConstant ("NULL"));
388 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
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
;
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
);
432 cexpr
= handle_struct_argument (null, arg
, cexpr
);
434 arg_pos
= get_param_pos (param
.cparameter_position
, ellipsis
);
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
)));
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
);
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
);
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
);
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
;
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
);
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
;
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
) {
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
) {
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_")));
588 /* ensure variable argument list ends with NULL
589 * except when using printf-style arguments */
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
;
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
635 if (async_call
!= ccall
) {
636 // don't append out arguments for .begin() calls
640 foreach (int pos
in out_arg_map
.get_keys ()) {
641 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
648 ccall
.add_argument (out_arg_map
.get (min_pos
));
653 if (async_call
!= null) {
657 foreach (int pos
in in_arg_map
.get_keys ()) {
658 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
665 async_call
.add_argument (in_arg_map
.get (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 ();
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
);
730 if (expr
.parent_node is ExpressionStatement
&& !expr
.value_type
.is_disposable ()) {
731 if (ccall_expr
!= null) {
732 ccode
.add_expression (ccall_expr
);
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
767 var unary
= arg as UnaryExpression
;
768 if (unary
== null || unary
.operator
!= UnaryOperator
.OUT
) {
772 if (requires_destroy (arg
.value_type
)) {
774 ccode
.add_expression (get_unref_expression (get_cvalue (unary
.inner
), unary
.inner
.value_type
, unary
.inner
));
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
;
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 ()));
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 ()+"\""));
818 ccode
.add_return (new
CCodeConstant ("NULL"));
821 cfile
.add_function_declaration (function
);
822 cfile
.add_function (function
);
826 return to_string_func
;