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 // (tmp = expr, &tmp)
200 var ccomma
= new
CCodeCommaExpression ();
202 var temp_var
= get_temp_variable (ma
.inner
.target_type
, true, null, false);
203 emit_temp_var (temp_var
);
204 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), instance
));
205 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
)));
211 in_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance
);
212 out_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance
);
213 } else if (m
!= null && m
.binding
== MemberBinding
.CLASS
) {
214 var cl
= (Class
) m
.parent_symbol
;
215 var cast
= new
CCodeFunctionCall (new
CCodeIdentifier (cl
.get_upper_case_cname (null) + "_CLASS"));
217 CCodeExpression klass
;
218 if (ma
.inner
== null) {
219 if (in_static_or_class_context
) {
220 // Accessing the method from a static or class constructor
221 klass
= new
CCodeIdentifier ("klass");
223 // Accessing the method from within an instance method
224 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
225 k
.add_argument (new
CCodeIdentifier ("self"));
229 // Accessing the method of an instance
230 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
231 k
.add_argument (get_cvalue (ma
.inner
));
235 cast
.add_argument (klass
);
236 in_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), cast
);
237 out_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), cast
);
240 if (m
!= null && m
.has_generic_type_parameter
) {
241 // insert type argument for macros
242 if (m
.get_type_parameters ().size
> 0) {
244 int type_param_index
= 0;
245 foreach (var type_arg
in ma
.get_type_arguments ()) {
246 in_arg_map
.set (get_param_pos (m
.generic_type_parameter_position
+ 0.01 * type_param_index
), new
CCodeIdentifier (type_arg
.get_cname ()));
250 // method in generic type
251 int type_param_index
= 0;
252 foreach (var type_arg
in ma
.inner
.value_type
.get_type_arguments ()) {
253 in_arg_map
.set (get_param_pos (m
.generic_type_parameter_position
+ 0.01 * type_param_index
), new
CCodeIdentifier (type_arg
.get_cname ()));
259 if (m is ArrayMoveMethod
) {
260 var array_type
= (ArrayType
) ma
.inner
.value_type
;
261 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
262 csizeof
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
263 in_arg_map
.set (get_param_pos (0.1), csizeof
);
264 } else if (m is DynamicMethod
) {
265 m
.clear_parameters ();
267 foreach (Expression arg
in expr
.get_argument_list ()) {
268 var unary
= arg as UnaryExpression
;
269 if (unary
!= null && unary
.operator
== UnaryOperator
.OUT
) {
271 var param
= new
Parameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
272 param
.direction
= ParameterDirection
.OUT
;
273 m
.add_parameter (param
);
274 } else if (unary
!= null && unary
.operator
== UnaryOperator
.REF
) {
276 var param
= new
Parameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
277 param
.direction
= ParameterDirection
.REF
;
278 m
.add_parameter (param
);
281 m
.add_parameter (new
Parameter ("param%d".printf (param_nr
), arg
.value_type
));
285 foreach (Parameter param
in m
.get_parameters ()) {
288 generate_dynamic_method_wrapper ((DynamicMethod
) m
);
289 } else if (m is CreationMethod
&& context
.profile
== Profile
.GOBJECT
&& m
.parent_symbol is Class
) {
290 ccall_expr
= new
CCodeAssignment (new
CCodeIdentifier ("self"), new
CCodeCastExpression (ccall
, current_class
.get_cname () + "*"));
292 if (current_method
.body
.captured
) {
293 // capture self after setting it
294 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), expr
.source_reference
));
295 ref_call
.add_argument (ccall_expr
);
297 ccall_expr
= new
CCodeAssignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method
.body
))), "self"), ref_call
);
300 if (!current_class
.is_compact
&& current_class
.get_type_parameters ().size
> 0) {
301 var ccomma
= new
CCodeCommaExpression ();
302 ccomma
.append_expression (ccall_expr
);
304 /* type, dup func, and destroy func fields for generic types */
305 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
306 CCodeIdentifier param_name
;
308 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
310 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
311 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
313 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
314 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
316 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
317 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
324 bool ellipsis
= false;
328 Iterator
<Parameter
> params_it
= params
.iterator ();
329 foreach (Expression arg
in expr
.get_argument_list ()) {
330 CCodeExpression cexpr
= get_cvalue (arg
);
332 var carg_map
= in_arg_map
;
334 if (params_it
.next ()) {
335 var param
= params_it
.get ();
336 ellipsis
= param
.params_array
|| param
.ellipsis
;
338 if (param
.direction
== ParameterDirection
.OUT
) {
339 carg_map
= out_arg_map
;
342 var unary
= arg as UnaryExpression
;
343 if (unary
== null || unary
.operator
!= UnaryOperator
.OUT
) {
344 if (!param
.no_array_length
&& param
.variable_type is ArrayType
) {
345 var array_type
= (ArrayType
) param
.variable_type
;
346 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
347 CCodeExpression? array_length_expr
= null;
348 if (param
.array_length_type
!= null) {
349 array_length_expr
= new
CCodeCastExpression (get_array_length_cexpression (arg
, dim
), param
.array_length_type
);
351 array_length_expr
= get_array_length_cexpression (arg
, dim
);
353 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), array_length_expr
);
355 } else if (param
.variable_type is DelegateType
) {
356 var deleg_type
= (DelegateType
) param
.variable_type
;
357 var d
= deleg_type
.delegate_symbol
;
359 CCodeExpression delegate_target_destroy_notify
;
360 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
361 assert (delegate_target
!= null);
362 if (param
.ctype
== "GClosure*") {
363 // one single GClosure parameter
364 var closure_new
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_cclosure_new"));
365 closure_new
.add_argument (new
CCodeCastExpression (cexpr
, "GCallback"));
366 closure_new
.add_argument (delegate_target
);
367 closure_new
.add_argument (delegate_target_destroy_notify
);
368 cexpr
= new
CCodeConditionalExpression (new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cexpr
, new
CCodeIdentifier ("NULL")), new
CCodeIdentifier ("NULL"), closure_new
);
370 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), delegate_target
);
371 if (deleg_type
.value_owned
) {
372 assert (delegate_target_destroy_notify
!= null);
373 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), delegate_target_destroy_notify
);
377 } else if (param
.variable_type is MethodType
) {
378 // callbacks in dynamic method calls
379 CCodeExpression delegate_target_destroy_notify
;
380 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
));
381 } else if (param
.variable_type is GenericType
) {
382 if (m
!= null && m
.simple_generics
) {
383 var generic_type
= (GenericType
) param
.variable_type
;
384 int type_param_index
= m
.get_type_parameter_index (generic_type
.type_parameter
.name
);
385 var type_arg
= ma
.get_type_arguments ().get (type_param_index
);
386 if (requires_copy (type_arg
)) {
387 carg_map
.set (get_param_pos (param
.cdestroy_notify_parameter_position
), get_destroy_func_expression (type_arg
));
389 carg_map
.set (get_param_pos (param
.cdestroy_notify_parameter_position
), new
CCodeConstant ("NULL"));
394 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
396 arg
.target_value
= null;
398 var temp_var
= get_temp_variable (param
.variable_type
, param
.variable_type
.value_owned
);
399 emit_temp_var (temp_var
);
400 set_cvalue (arg
, get_variable_cexpression (temp_var
.name
));
402 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (arg
));
404 if (!param
.no_array_length
&& param
.variable_type is ArrayType
) {
405 var array_type
= (ArrayType
) param
.variable_type
;
406 var array_length_type
= int_type
;
407 if (param
.array_length_type
!= null) {
408 array_length_type
= new
CType (param
.array_length_type
);
410 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
411 var temp_array_length
= get_temp_variable (array_length_type
);
412 emit_temp_var (temp_array_length
);
413 append_array_size (arg
, get_variable_cexpression (temp_array_length
.name
));
414 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_sizes (arg
).get (dim
- 1)));
416 } else if (param
.variable_type is DelegateType
) {
417 var deleg_type
= (DelegateType
) param
.variable_type
;
418 var d
= deleg_type
.delegate_symbol
;
420 temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
421 emit_temp_var (temp_var
);
422 set_delegate_target (arg
, get_variable_cexpression (temp_var
.name
));
423 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target (arg
)));
424 if (deleg_type
.value_owned
) {
425 temp_var
= get_temp_variable (new
DelegateType ((Delegate
) context
.root
.scope
.lookup ("GLib").scope
.lookup ("DestroyNotify")));
426 emit_temp_var (temp_var
);
427 set_delegate_target_destroy_notify (arg
, get_variable_cexpression (temp_var
.name
));
428 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target_destroy_notify (arg
)));
434 if (param
.ctype
!= null) {
435 cexpr
= new
CCodeCastExpression (cexpr
, param
.ctype
);
438 cexpr
= handle_struct_argument (null, arg
, cexpr
);
440 arg_pos
= get_param_pos (param
.cparameter_position
, ellipsis
);
442 // default argument position
443 cexpr
= handle_struct_argument (null, arg
, cexpr
);
444 arg_pos
= get_param_pos (i
, ellipsis
);
447 carg_map
.set (arg_pos
, cexpr
);
449 if (arg is NamedArgument
&& ellipsis
) {
450 var named_arg
= (NamedArgument
) arg
;
451 string name
= string.joinv ("-", named_arg
.name
.split ("_"));
452 carg_map
.set (get_param_pos (i
- 0.1, ellipsis
), new
CCodeConstant ("\"%s\"".printf (name
)));
457 if (params_it
.next ()) {
458 var param
= params_it
.get ();
460 /* if there are more parameters than arguments,
461 * the additional parameter is an ellipsis parameter
462 * otherwise there is a bug in the semantic analyzer
464 assert (param
.params_array
|| param
.ellipsis
);
468 /* add length argument for methods returning arrays */
469 if (m
!= null && m
.return_type is ArrayType
&& async_call
!= ccall
) {
470 var array_type
= (ArrayType
) m
.return_type
;
471 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
472 if (m
.array_null_terminated
) {
473 // handle calls to methods returning null-terminated arrays
474 var temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
475 var temp_ref
= get_variable_cexpression (temp_var
.name
);
477 emit_temp_var (temp_var
);
479 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
481 requires_array_length
= true;
482 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
483 len_call
.add_argument (temp_ref
);
485 append_array_size (expr
, len_call
);
486 } else if (!m
.no_array_length
) {
487 LocalVariable temp_var
;
489 if (m
.array_length_type
== null) {
490 temp_var
= get_temp_variable (int_type
);
492 temp_var
= get_temp_variable (new
CType (m
.array_length_type
));
494 var temp_ref
= get_variable_cexpression (temp_var
.name
);
496 emit_temp_var (temp_var
);
498 out_arg_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
500 append_array_size (expr
, temp_ref
);
502 append_array_size (expr
, new
CCodeConstant ("-1"));
505 } else if (m
!= null && m
.return_type is DelegateType
&& async_call
!= ccall
) {
506 var deleg_type
= (DelegateType
) m
.return_type
;
507 var d
= deleg_type
.delegate_symbol
;
509 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
510 var temp_ref
= get_variable_cexpression (temp_var
.name
);
512 emit_temp_var (temp_var
);
514 out_arg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
516 set_delegate_target (expr
, temp_ref
);
518 if (deleg_type
.value_owned
) {
519 temp_var
= get_temp_variable (new
DelegateType ((Delegate
) context
.root
.scope
.lookup ("GLib").scope
.lookup ("DestroyNotify")));
520 temp_ref
= get_variable_cexpression (temp_var
.name
);
522 emit_temp_var (temp_var
);
524 out_arg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
+ 0.01), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
526 set_delegate_target_destroy_notify (expr
, temp_ref
);
531 // add length argument for delegates returning arrays
532 // TODO: avoid code duplication with methods returning arrays, see above
533 if (deleg
!= null && deleg
.return_type is ArrayType
) {
534 var array_type
= (ArrayType
) deleg
.return_type
;
535 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
536 if (deleg
.array_null_terminated
) {
537 // handle calls to methods returning null-terminated arrays
538 var temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
539 var temp_ref
= get_variable_cexpression (temp_var
.name
);
541 emit_temp_var (temp_var
);
543 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
545 requires_array_length
= true;
546 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
547 len_call
.add_argument (temp_ref
);
549 append_array_size (expr
, len_call
);
550 } else if (!deleg
.no_array_length
) {
551 var temp_var
= get_temp_variable (int_type
);
552 var temp_ref
= get_variable_cexpression (temp_var
.name
);
554 emit_temp_var (temp_var
);
556 out_arg_map
.set (get_param_pos (deleg
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
558 append_array_size (expr
, temp_ref
);
560 append_array_size (expr
, new
CCodeConstant ("-1"));
563 } else if (deleg
!= null && deleg
.return_type is DelegateType
) {
564 var deleg_type
= (DelegateType
) deleg
.return_type
;
565 var d
= deleg_type
.delegate_symbol
;
567 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
568 var temp_ref
= get_variable_cexpression (temp_var
.name
);
570 emit_temp_var (temp_var
);
572 out_arg_map
.set (get_param_pos (deleg
.cdelegate_target_parameter_position
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
574 set_delegate_target (expr
, temp_ref
);
578 if (m
!= null && m
.coroutine
) {
579 if (expr
.is_yield_expression
) {
581 in_arg_map
.set (get_param_pos (-1), new
CCodeIdentifier (current_method
.get_cname () + "_ready"));
582 in_arg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("data"));
586 if (expr
.tree_can_fail
) {
588 current_method_inner_error
= true;
589 // add &inner_error before the ellipsis arguments
590 out_arg_map
.set (get_param_pos (-1), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
594 /* ensure variable argument list ends with NULL
595 * except when using printf-style arguments */
597 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant (Method
.DEFAULT_SENTINEL
));
598 } else if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
599 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant (m
.sentinel
));
603 if (itype is DelegateType
) {
604 var deleg_type
= (DelegateType
) itype
;
605 var d
= deleg_type
.delegate_symbol
;
607 CCodeExpression delegate_target_destroy_notify
;
608 in_arg_map
.set (get_param_pos (d
.cinstance_parameter_position
), get_delegate_target_cexpression (expr
.call
, out delegate_target_destroy_notify
));
609 out_arg_map
.set (get_param_pos (d
.cinstance_parameter_position
), get_delegate_target_cexpression (expr
.call
, out delegate_target_destroy_notify
));
613 // structs are returned via out parameter
614 bool return_result_via_out_param
= itype
.get_return_type ().is_real_non_null_struct_type ();
616 // pass address for the return value of non-void signals without emitter functions
617 if (itype is SignalType
&& !(itype
.get_return_type () is VoidType
)) {
618 var sig
= ((SignalType
) itype
).signal_symbol
;
620 if (ma
!= null && ma
.inner is BaseAccess
&& sig
.is_virtual
) {
621 // normal return value for base access
622 } else if (!sig
.has_emitter
) {
623 return_result_via_out_param
= true;
627 if (return_result_via_out_param
) {
628 var temp_var
= get_temp_variable (itype
.get_return_type ());
629 var temp_ref
= get_variable_cexpression (temp_var
.name
);
631 emit_temp_var (temp_var
);
633 out_arg_map
.set (get_param_pos (-3), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
635 var ccomma
= new
CCodeCommaExpression ();
636 ccomma
.append_expression ((CCodeExpression
) ccall_expr
);
637 ccomma
.append_expression ((CCodeExpression
) temp_ref
);
642 // append C arguments in the right order
647 if (async_call
!= ccall
) {
648 // don't append out arguments for .begin() calls
652 foreach (int pos
in out_arg_map
.get_keys ()) {
653 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
660 ccall
.add_argument (out_arg_map
.get (min_pos
));
665 if (async_call
!= null) {
669 foreach (int pos
in in_arg_map
.get_keys ()) {
670 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
677 async_call
.add_argument (in_arg_map
.get (min_pos
));
682 if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& m
.returns_modified_pointer
) {
683 ccall_expr
= new
CCodeAssignment (instance
, ccall_expr
);
686 if (expr
.is_yield_expression
) {
687 // set state before calling async function to support immediate callbacks
688 int state
= next_coroutine_state
++;
690 ccode
.add_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_state_"), new
CCodeConstant (state
.to_string ())));
691 ccode
.add_expression (async_call
);
692 ccode
.add_return (new
CCodeConstant ("FALSE"));
693 ccode
.add_label ("_state_%d".printf (state
));
696 if (m is ArrayResizeMethod
) {
697 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
698 Iterator
<Expression
> arg_it
= expr
.get_argument_list ().iterator ();
700 var new_size
= get_cvalue (arg_it
.get ());
702 var temp_decl
= get_temp_variable (int_type
);
703 var temp_ref
= get_variable_cexpression (temp_decl
.name
);
705 emit_temp_var (temp_decl
);
707 /* memset needs string.h */
708 cfile
.add_include ("string.h");
710 var clen
= get_array_length_cexpression (ma
.inner
, 1);
711 var celems
= get_cvalue (ma
.inner
);
712 var array_type
= (ArrayType
) ma
.inner
.value_type
;
713 var csizeof
= new
CCodeIdentifier ("sizeof (%s)".printf (array_type
.element_type
.get_cname ()));
714 var cdelta
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, temp_ref
, clen
);
715 var ccheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, temp_ref
, clen
);
717 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
718 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, celems
, clen
));
719 czero
.add_argument (new
CCodeConstant ("0"));
720 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeof
, cdelta
));
722 var ccomma
= new
CCodeCommaExpression ();
723 ccomma
.append_expression (new
CCodeAssignment (temp_ref
, new_size
));
724 ccomma
.append_expression (ccall_expr
);
725 ccomma
.append_expression (new
CCodeConditionalExpression (ccheck
, czero
, new
CCodeConstant ("NULL")));
726 ccomma
.append_expression (new
CCodeAssignment (get_array_length_cexpression (ma
.inner
, 1), temp_ref
));
728 var array_var
= ma
.inner
.symbol_reference
;
729 var array_local
= array_var as LocalVariable
;
730 if (array_var
!= null && array_var
.is_internal_symbol ()
731 && ((array_var is LocalVariable
&& !array_local
.captured
) || array_var is Field
)) {
732 ccomma
.append_expression (new
CCodeAssignment (get_array_size_cvalue (ma
.inner
.target_value
), temp_ref
));
735 set_cvalue (expr
, ccomma
);
740 if (expr
.parent_node is ExpressionStatement
&& !expr
.value_type
.is_disposable ()) {
741 ccode
.add_expression (ccall_expr
);
743 var result_type
= itype
.get_return_type ();
745 if (expr
.formal_value_type is GenericType
&& !(expr
.value_type is GenericType
)) {
746 var st
= expr
.formal_value_type
.type_parameter
.parent_symbol
.parent_symbol as Struct
;
747 if (expr
.formal_value_type
.type_parameter
.parent_symbol
== garray_type
||
748 (st
!= null && st
.get_cname () == "va_list")) {
749 // GArray and va_list don't use pointer-based generics
750 // above logic copied from visit_expression ()
751 // TODO avoid code duplication
752 result_type
= expr
.value_type
;
756 var temp_var
= get_temp_variable (result_type
, result_type
.value_owned
);
757 var temp_ref
= get_variable_cexpression (temp_var
.name
);
759 emit_temp_var (temp_var
);
761 ccode
.add_expression (new
CCodeAssignment (temp_ref
, ccall_expr
));
762 set_cvalue (expr
, temp_ref
);
765 params_it
= params
.iterator ();
766 foreach (Expression arg
in expr
.get_argument_list ()) {
767 if (params_it
.next ()) {
768 var param
= params_it
.get ();
769 if (param
.params_array
|| param
.ellipsis
) {
770 // ignore ellipsis arguments as we currently don't use temporary variables for them
775 var unary
= arg as UnaryExpression
;
776 if (unary
== null || unary
.operator
!= UnaryOperator
.OUT
) {
780 if (requires_destroy (arg
.value_type
)) {
782 ccode
.add_expression (get_unref_expression (get_cvalue (unary
.inner
), unary
.inner
.value_type
, unary
.inner
));
786 ccode
.add_expression (new
CCodeAssignment (get_cvalue (unary
.inner
), transform_expression (get_cvalue (unary
), unary
.target_type
, unary
.inner
.value_type
, arg
)));
788 var array_type
= arg
.value_type as ArrayType
;
789 if (array_type
!= null) {
790 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
791 ccode
.add_expression (new
CCodeAssignment (get_array_sizes (unary
.inner
).get (dim
- 1), get_array_sizes (unary
).get (dim
- 1)));
795 var delegate_type
= arg
.value_type as DelegateType
;
796 if (delegate_type
!= null) {
797 ccode
.add_expression (new
CCodeAssignment (get_delegate_target (unary
.inner
), get_delegate_target (unary
)));
802 private string generate_enum_tostring_function (Enum en
) {
803 var to_string_func
= "_%s_to_string".printf (en
.get_lower_case_cname ());
805 if (!add_wrapper (to_string_func
)) {
806 // wrapper already defined
807 return to_string_func
;
811 var function
= new
CCodeFunction (to_string_func
, "const char*");
812 function
.modifiers
= CCodeModifiers
.STATIC
;
814 function
.add_parameter (new
CCodeParameter ("value", en
.get_cname ()));
817 push_context (new
EmitContext ());
818 push_function (function
);
820 ccode
.open_switch (new
CCodeConstant ("value"));
821 foreach (var enum_value
in en
.get_values ()) {
822 ccode
.add_case (new
CCodeIdentifier (enum_value
.get_cname ()));
823 ccode
.add_return (new
CCodeConstant ("\""+enum_value
.get_cname ()+"\""));
826 ccode
.add_return (new
CCodeConstant ("NULL"));
829 cfile
.add_function_declaration (function
);
830 cfile
.add_function (function
);
834 return to_string_func
;