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;
33 CCodeFunctionCall finish_call
= null;
36 Delegate deleg
= null;
37 List
<Parameter
> params
;
39 var ma
= expr
.call as MemberAccess
;
41 var itype
= expr
.call
.value_type
;
42 params
= itype
.get_parameters ();
44 if (itype is MethodType
) {
46 m
= ((MethodType
) itype
).method_symbol
;
48 if (!get_ccode_simple_generics (m
)) {
49 check_type_arguments (ma
);
52 if (ma
.inner
!= null && ma
.inner
.value_type is EnumValueType
&& ((EnumValueType
) ma
.inner
.value_type
).get_to_string_method() == m
) {
53 // Enum.VALUE.to_string()
54 var en
= (Enum
) ma
.inner
.value_type
.data_type
;
55 ccall
.call
= new
CCodeIdentifier (generate_enum_tostring_function (en
));
56 } else if (expr
.is_constructv_chainup
) {
57 ccall
.call
= new
CCodeIdentifier (get_ccode_constructv_name ((CreationMethod
) m
));
59 } else if (itype is SignalType
) {
60 var sig_type
= (SignalType
) itype
;
61 if (ma
!= null && ma
.inner is BaseAccess
&& sig_type
.signal_symbol
.is_virtual
) {
62 m
= sig_type
.signal_symbol
.default_handler
;
64 ccall
= (CCodeFunctionCall
) get_cvalue (expr
.call
);
66 } else if (itype is ObjectType
) {
68 var cl
= (Class
) ((ObjectType
) itype
).type_symbol
;
69 m
= cl
.default_construction_method
;
70 generate_method_declaration (m
, cfile
);
71 var real_name
= get_ccode_real_name (m
);
72 if (expr
.is_constructv_chainup
) {
73 real_name
= get_ccode_constructv_name ((CreationMethod
) m
);
75 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (real_name
));
76 } else if (itype is StructValueType
) {
78 var st
= (Struct
) ((StructValueType
) itype
).type_symbol
;
79 m
= st
.default_construction_method
;
80 generate_method_declaration (m
, cfile
);
81 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
)));
82 } else if (itype is DelegateType
) {
83 deleg
= ((DelegateType
) itype
).delegate_symbol
;
86 var in_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
87 var out_arg_map
= in_arg_map
;
89 if (m
!= null && m
.coroutine
) {
92 async_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_name (m
)));
93 finish_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_finish_name (m
)));
95 if (ma
.inner is BaseAccess
) {
96 if (m
.base_method
!= null) {
97 var base_class
= (Class
) m
.base_method
.parent_symbol
;
98 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class
, null))));
99 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class
, null))));
101 async_call
.call
= new CCodeMemberAccess
.pointer (vcast
, get_ccode_vfunc_name (m
));
102 finish_call
.call
= new CCodeMemberAccess
.pointer (vcast
, get_ccode_finish_vfunc_name (m
));
103 } else if (m
.base_interface_method
!= null) {
104 var base_iface
= (Interface
) m
.base_interface_method
.parent_symbol
;
105 string parent_iface_var
= "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class
), get_ccode_lower_case_name (base_iface
));
107 async_call
.call
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), get_ccode_vfunc_name (m
));
108 finish_call
.call
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), get_ccode_finish_vfunc_name (m
));
112 if (ma
.member_name
== "begin" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
115 params
= m
.get_async_begin_parameters ();
116 } else if (ma
.member_name
== "end" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
119 params
= m
.get_async_end_parameters ();
120 } else if (!expr
.is_yield_expression
) {
121 // same as .begin, backwards compatible to bindings without async methods
123 params
= m
.get_async_begin_parameters ();
127 // output arguments used separately
128 out_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
129 // pass GAsyncResult stored in closure to finish function
130 out_arg_map
.set (get_param_pos (0.1), new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_res_"));
134 if (m is CreationMethod
&& m
.parent_symbol is Class
) {
135 if (!((Class
) m
.parent_symbol
).is_compact
) {
136 ccall
.add_argument (get_variable_cexpression ("object_type"));
139 if (!current_class
.is_compact
) {
140 if (current_class
!= m
.parent_symbol
) {
141 // chain up to base class
142 foreach (DataType base_type
in current_class
.get_base_types ()) {
143 if (base_type
.data_type is Class
) {
144 List
<TypeParameter
> type_parameters
= null;
145 if (get_ccode_real_name (m
) == "g_object_new") {
146 // gobject-style chainup
147 type_parameters
= ((Class
) base_type
.data_type
).get_type_parameters ();
149 add_generic_type_arguments (in_arg_map
, base_type
.get_type_arguments (), expr
, true, type_parameters
);
154 // chain up to other constructor in same class
155 int type_param_index
= 0;
156 var cl
= (Class
) m
.parent_symbol
;
157 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
158 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
159 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
160 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
164 } else if (current_class
.base_class
== gsource_type
) {
167 string class_prefix
= get_ccode_lower_case_name (current_class
);
169 var funcs
= new
CCodeDeclaration ("const GSourceFuncs");
170 funcs
.modifiers
= CCodeModifiers
.STATIC
;
171 funcs
.add_declarator (new
CCodeVariableDeclarator ("_source_funcs", new
CCodeConstant ("{ %s_real_prepare, %s_real_check, %s_real_dispatch, %s_finalize}".printf (class_prefix
, class_prefix
, class_prefix
, class_prefix
))));
172 ccode
.add_statement (funcs
);
174 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("_source_funcs")));
176 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
177 csizeof
.add_argument (new
CCodeIdentifier (get_ccode_name (current_class
)));
178 ccall
.add_argument (csizeof
);
180 } else if (m is CreationMethod
&& m
.parent_symbol is Struct
) {
181 ccall
.add_argument (get_this_cexpression ());
182 } else if (m
!= null && m
.get_type_parameters ().size
> 0 && !get_ccode_has_generic_type_parameter (m
) && !get_ccode_simple_generics (m
) && (ccall
!= finish_call
|| expr
.is_yield_expression
)) {
184 // don't add generic arguments for .end() calls
185 add_generic_type_arguments (in_arg_map
, ma
.get_type_arguments (), expr
);
188 // the complete call expression, might include casts, comma expressions, and/or assignments
189 CCodeExpression ccall_expr
= ccall
;
191 if (m is ArrayResizeMethod
) {
192 var array_type
= (ArrayType
) ma
.inner
.value_type
;
193 in_arg_map
.set (get_param_pos (0), new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
194 } else if (m is ArrayMoveMethod
) {
195 requires_array_move
= true;
196 } else if (m is ArrayCopyMethod
) {
197 expr
.target_value
= copy_value (ma
.inner
.target_value
, expr
);
201 CCodeExpression instance
= null;
202 if (m
!= null && m
.is_async_callback
) {
203 if (current_method
.closure
) {
204 var block
= ((Method
) m
.parent_symbol
).body
;
205 instance
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), "_async_data_");
207 instance
= new
CCodeIdentifier ("_data_");
210 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
211 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
212 } else if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& !(m is CreationMethod
)) {
213 var instance_value
= ma
.inner
.target_value
;
214 if ((ma
.member_name
== "begin" || ma
.member_name
== "end") && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
215 var inner_ma
= (MemberAccess
) ma
.inner
;
216 instance_value
= inner_ma
.inner
.target_value
;
218 instance
= get_cvalue_ (instance_value
);
220 var st
= m
.parent_symbol as Struct
;
221 if (st
!= null && !st
.is_simple_type ()) {
222 // we need to pass struct instance by reference
223 if (!get_lvalue (instance_value
)) {
224 instance_value
= store_temp_value (instance_value
, expr
);
226 instance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (instance_value
));
229 if (expr
.is_yield_expression
) {
230 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
231 if (get_ccode_finish_instance (m
)) {
232 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
234 } else if (ma
.member_name
!= "end" || get_ccode_finish_instance (m
)) {
235 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
236 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
238 } else if (m
!= null && m
.binding
== MemberBinding
.CLASS
) {
239 var cl
= (Class
) m
.parent_symbol
;
240 var cast
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_upper_case_name (cl
, null) + "_CLASS"));
242 CCodeExpression klass
;
243 if (ma
.inner
== null) {
244 if (get_this_type () == null) {
245 // Accessing the method from a static or class constructor
246 klass
= new
CCodeIdentifier ("klass");
248 // Accessing the method from within an instance method
249 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
250 k
.add_argument (get_this_cexpression ());
254 // Accessing the method of an instance
255 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
256 k
.add_argument (get_cvalue (ma
.inner
));
260 cast
.add_argument (klass
);
261 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), cast
);
262 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), cast
);
265 if (m
!= null && get_ccode_has_generic_type_parameter (m
)) {
266 // insert type argument for macros
267 if (m
.get_type_parameters ().size
> 0) {
269 int type_param_index
= 0;
270 foreach (var type_arg
in ma
.get_type_arguments ()) {
271 in_arg_map
.set (get_param_pos (get_ccode_generic_type_pos (m
) + 0.01 * type_param_index
), new
CCodeIdentifier (get_ccode_name (type_arg
)));
275 // method in generic type
276 int type_param_index
= 0;
277 foreach (var type_arg
in ma
.inner
.value_type
.get_type_arguments ()) {
278 in_arg_map
.set (get_param_pos (get_ccode_generic_type_pos (m
) + 0.01 * type_param_index
), new
CCodeIdentifier (get_ccode_name (type_arg
)));
284 if (m is ArrayMoveMethod
) {
285 var array_type
= (ArrayType
) ma
.inner
.value_type
;
286 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
287 csizeof
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
288 in_arg_map
.set (get_param_pos (0.1), csizeof
);
289 } else if (m is DynamicMethod
) {
290 m
.clear_parameters ();
292 foreach (Expression arg
in expr
.get_argument_list ()) {
293 var unary
= arg as UnaryExpression
;
294 if (unary
!= null && unary
.operator
== UnaryOperator
.OUT
) {
296 var param
= new
Parameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
297 param
.direction
= ParameterDirection
.OUT
;
298 m
.add_parameter (param
);
299 } else if (unary
!= null && unary
.operator
== UnaryOperator
.REF
) {
301 var param
= new
Parameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
302 param
.direction
= ParameterDirection
.REF
;
303 m
.add_parameter (param
);
306 m
.add_parameter (new
Parameter ("param%d".printf (param_nr
), arg
.value_type
));
310 foreach (Parameter param
in m
.get_parameters ()) {
313 generate_dynamic_method_wrapper ((DynamicMethod
) m
);
314 } else if (m is CreationMethod
&& m
.parent_symbol is Class
) {
315 ccode
.add_assignment (get_this_cexpression (), new
CCodeCastExpression (ccall
, get_ccode_name (current_class
) + "*"));
317 if (current_method
.body
.captured
) {
318 // capture self after setting it
319 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), expr
.source_reference
));
320 ref_call
.add_argument (get_this_cexpression ());
322 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method
.body
))), "self"), ref_call
);
325 if (!current_class
.is_compact
&& current_class
.get_type_parameters ().size
> 0) {
326 /* type, dup func, and destroy func fields for generic types */
327 var suffices
= new
string[] {"type", "dup_func", "destroy_func"};
328 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
329 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
331 foreach (string suffix
in suffices
) {
332 var param_name
= new
CCodeIdentifier ("%s_%s".printf (type_param
.name
.down (), suffix
));
333 ccode
.add_assignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
337 // object chainup can't be used as expression
341 bool ellipsis
= false;
345 Iterator
<Parameter
> params_it
= params
.iterator ();
346 foreach (Expression arg
in expr
.get_argument_list ()) {
347 CCodeExpression cexpr
= get_cvalue (arg
);
349 var carg_map
= in_arg_map
;
351 if (params_it
.next ()) {
352 var param
= params_it
.get ();
353 ellipsis
= param
.params_array
|| param
.ellipsis
;
355 if (param
.direction
== ParameterDirection
.OUT
) {
356 carg_map
= out_arg_map
;
359 var unary
= arg as UnaryExpression
;
360 if (unary
== null || unary
.operator
!= UnaryOperator
.OUT
) {
361 if (get_ccode_array_length (param
) && param
.variable_type is ArrayType
) {
362 var array_type
= (ArrayType
) param
.variable_type
;
363 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
364 CCodeExpression? array_length_expr
= null;
365 if (get_ccode_array_length_type (param
) != null) {
366 array_length_expr
= new
CCodeCastExpression (get_array_length_cexpression (arg
, dim
), get_ccode_array_length_type (param
));
368 array_length_expr
= get_array_length_cexpression (arg
, dim
);
370 carg_map
.set (get_param_pos (get_ccode_array_length_pos (param
) + 0.01 * dim
), array_length_expr
);
372 } else if (param
.variable_type is DelegateType
) {
373 var deleg_type
= (DelegateType
) param
.variable_type
;
374 var d
= deleg_type
.delegate_symbol
;
376 CCodeExpression delegate_target_destroy_notify
;
377 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
378 assert (delegate_target
!= null);
379 if (get_ccode_type (param
) == "GClosure*") {
380 // one single GClosure parameter
381 var closure_new
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_cclosure_new"));
382 closure_new
.add_argument (new
CCodeCastExpression (cexpr
, "GCallback"));
383 closure_new
.add_argument (delegate_target
);
384 closure_new
.add_argument (new
CCodeCastExpression (delegate_target_destroy_notify
, "GClosureNotify"));
385 cexpr
= new
CCodeConditionalExpression (new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cexpr
, new
CCodeIdentifier ("NULL")), new
CCodeIdentifier ("NULL"), closure_new
);
387 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
)), delegate_target
);
388 if (deleg_type
.is_disposable ()) {
389 assert (delegate_target_destroy_notify
!= null);
390 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
) + 0.01), delegate_target_destroy_notify
);
394 } else if (param
.variable_type is MethodType
) {
395 // callbacks in dynamic method calls
396 CCodeExpression delegate_target_destroy_notify
;
397 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
)), get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
));
398 } else if (param
.variable_type is GenericType
) {
399 if (m
!= null && get_ccode_simple_generics (m
)) {
400 var generic_type
= (GenericType
) param
.variable_type
;
401 int type_param_index
= m
.get_type_parameter_index (generic_type
.type_parameter
.name
);
402 var type_arg
= ma
.get_type_arguments ().get (type_param_index
);
403 if (param
.variable_type
.value_owned
) {
404 if (requires_copy (type_arg
)) {
405 carg_map
.set (get_param_pos (get_ccode_destroy_notify_pos (param
)), get_destroy_func_expression (type_arg
));
407 carg_map
.set (get_param_pos (get_ccode_destroy_notify_pos (param
)), new
CCodeConstant ("NULL"));
413 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
415 arg
.target_value
= null;
417 var temp_var
= get_temp_variable (param
.variable_type
, param
.variable_type
.value_owned
, null, true);
418 emit_temp_var (temp_var
);
419 set_cvalue (arg
, get_variable_cexpression (temp_var
.name
));
420 arg
.target_value
.value_type
= arg
.target_type
;
422 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (arg
));
424 if (get_ccode_array_length (param
) && param
.variable_type is ArrayType
) {
425 var array_type
= (ArrayType
) param
.variable_type
;
426 var array_length_type
= int_type
;
427 if (get_ccode_array_length_type (param
) != null) {
428 array_length_type
= new
CType (get_ccode_array_length_type (param
));
430 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
431 var temp_array_length
= get_temp_variable (array_length_type
);
432 emit_temp_var (temp_array_length
);
433 append_array_length (arg
, get_variable_cexpression (temp_array_length
.name
));
434 carg_map
.set (get_param_pos (get_ccode_array_length_pos (param
) + 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_array_lengths (arg
).get (dim
- 1)));
436 } else if (param
.variable_type is DelegateType
) {
437 var deleg_type
= (DelegateType
) param
.variable_type
;
438 var d
= deleg_type
.delegate_symbol
;
440 temp_var
= get_temp_variable (new
PointerType (new
VoidType ()), true, null, true);
441 emit_temp_var (temp_var
);
442 set_delegate_target (arg
, get_variable_cexpression (temp_var
.name
));
443 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
)), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target (arg
)));
444 if (deleg_type
.is_disposable ()) {
445 temp_var
= get_temp_variable (gdestroynotify_type
, true, null, true);
446 emit_temp_var (temp_var
);
447 set_delegate_target_destroy_notify (arg
, get_variable_cexpression (temp_var
.name
));
448 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
) + 0.01), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target_destroy_notify (arg
)));
454 if (get_ccode_type (param
) != null) {
455 cexpr
= new
CCodeCastExpression (cexpr
, get_ccode_type (param
));
458 cexpr
= handle_struct_argument (null, arg
, cexpr
);
460 arg_pos
= get_param_pos (get_ccode_pos (param
), ellipsis
);
462 // default argument position
463 cexpr
= handle_struct_argument (null, arg
, cexpr
);
464 arg_pos
= get_param_pos (i
, ellipsis
);
467 carg_map
.set (arg_pos
, cexpr
);
469 if (arg is NamedArgument
&& ellipsis
) {
470 var named_arg
= (NamedArgument
) arg
;
471 string name
= string.joinv ("-", named_arg
.name
.split ("_"));
472 carg_map
.set (get_param_pos (i
- 0.1, ellipsis
), new
CCodeConstant ("\"%s\"".printf (name
)));
477 if (params_it
.next ()) {
478 var param
= params_it
.get ();
480 /* if there are more parameters than arguments,
481 * the additional parameter is an ellipsis parameter
482 * otherwise there is a bug in the semantic analyzer
484 assert (param
.params_array
|| param
.ellipsis
);
488 /* add length argument for methods returning arrays */
489 if (m
!= null && m
.return_type is ArrayType
&& async_call
!= ccall
) {
490 var array_type
= (ArrayType
) m
.return_type
;
491 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
492 if (get_ccode_array_null_terminated (m
)) {
493 // handle calls to methods returning null-terminated arrays
494 var temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
495 var temp_ref
= get_variable_cexpression (temp_var
.name
);
497 emit_temp_var (temp_var
);
499 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
501 requires_array_length
= true;
502 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
503 len_call
.add_argument (temp_ref
);
505 append_array_length (expr
, len_call
);
506 } else if (get_ccode_array_length (m
)) {
507 LocalVariable temp_var
;
509 if (get_ccode_array_length_type (m
) == null) {
510 temp_var
= get_temp_variable (int_type
);
512 temp_var
= get_temp_variable (new
CType (get_ccode_array_length_type (m
)));
514 var temp_ref
= get_variable_cexpression (temp_var
.name
);
516 emit_temp_var (temp_var
);
518 out_arg_map
.set (get_param_pos (get_ccode_array_length_pos (m
) + 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
520 append_array_length (expr
, temp_ref
);
521 } else if (get_ccode_array_length_expr (m
) != null) {
522 append_array_length (expr
, new
CCodeConstant (get_ccode_array_length_expr (m
)));
524 append_array_length (expr
, new
CCodeConstant ("-1"));
527 } else if (m
!= null && m
.return_type is DelegateType
&& async_call
!= ccall
) {
528 var deleg_type
= (DelegateType
) m
.return_type
;
529 var d
= deleg_type
.delegate_symbol
;
531 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
532 var temp_ref
= get_variable_cexpression (temp_var
.name
);
534 emit_temp_var (temp_var
);
536 out_arg_map
.set (get_param_pos (get_ccode_delegate_target_pos (m
)), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
538 set_delegate_target (expr
, temp_ref
);
540 if (deleg_type
.is_disposable ()) {
541 temp_var
= get_temp_variable (gdestroynotify_type
);
542 temp_ref
= get_variable_cexpression (temp_var
.name
);
544 emit_temp_var (temp_var
);
546 out_arg_map
.set (get_param_pos (get_ccode_delegate_target_pos (m
) + 0.01), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
548 set_delegate_target_destroy_notify (expr
, temp_ref
);
550 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
553 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
557 // add length argument for delegates returning arrays
558 // TODO: avoid code duplication with methods returning arrays, see above
559 if (deleg
!= null && deleg
.return_type is ArrayType
) {
560 var array_type
= (ArrayType
) deleg
.return_type
;
561 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
562 if (get_ccode_array_null_terminated (deleg
)) {
563 // handle calls to methods returning null-terminated arrays
564 var temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
565 var temp_ref
= get_variable_cexpression (temp_var
.name
);
567 emit_temp_var (temp_var
);
569 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
571 requires_array_length
= true;
572 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
573 len_call
.add_argument (temp_ref
);
575 append_array_length (expr
, len_call
);
576 } else if (get_ccode_array_length (deleg
)) {
577 var temp_var
= get_temp_variable (int_type
);
578 var temp_ref
= get_variable_cexpression (temp_var
.name
);
580 emit_temp_var (temp_var
);
582 out_arg_map
.set (get_param_pos (get_ccode_array_length_pos (deleg
) + 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
584 append_array_length (expr
, temp_ref
);
586 append_array_length (expr
, new
CCodeConstant ("-1"));
589 } else if (deleg
!= null && deleg
.return_type is DelegateType
) {
590 var deleg_type
= (DelegateType
) deleg
.return_type
;
591 var d
= deleg_type
.delegate_symbol
;
593 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
594 var temp_ref
= get_variable_cexpression (temp_var
.name
);
596 emit_temp_var (temp_var
);
598 out_arg_map
.set (get_param_pos (get_ccode_delegate_target_pos (deleg
)), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
600 set_delegate_target (expr
, temp_ref
);
602 if (deleg_type
.is_disposable ()) {
603 temp_var
= get_temp_variable (gdestroynotify_type
);
604 temp_ref
= get_variable_cexpression (temp_var
.name
);
606 emit_temp_var (temp_var
);
608 out_arg_map
.set (get_param_pos (get_ccode_delegate_target_pos (deleg
) + 0.01), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
610 set_delegate_target_destroy_notify (expr
, temp_ref
);
615 if (m
!= null && m
.coroutine
) {
616 if (expr
.is_yield_expression
) {
618 in_arg_map
.set (get_param_pos (-1), new
CCodeIdentifier (generate_ready_function (current_method
)));
619 in_arg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("_data_"));
623 if (expr
.tree_can_fail
) {
625 current_method_inner_error
= true;
626 // add &inner_error before the ellipsis arguments
627 out_arg_map
.set (get_param_pos (-1), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
628 } else if (m
!= null && m
.has_error_type_parameter () && async_call
!= ccall
) {
629 // inferred error argument from base method
630 out_arg_map
.set (get_param_pos (-1), new
CCodeConstant ("NULL"));
634 /* ensure variable argument list ends with NULL
635 * except when using printf-style arguments */
637 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant ("NULL"));
638 } else if (!m
.printf_format
&& !m
.scanf_format
&& get_ccode_sentinel (m
) != "" && !expr
.is_constructv_chainup
) {
639 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant (get_ccode_sentinel (m
)));
643 if (itype is DelegateType
) {
644 var deleg_type
= (DelegateType
) itype
;
645 var d
= deleg_type
.delegate_symbol
;
647 CCodeExpression delegate_target_destroy_notify
;
648 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (d
)), get_delegate_target_cexpression (expr
.call
, out delegate_target_destroy_notify
));
649 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (d
)), get_delegate_target_cexpression (expr
.call
, out delegate_target_destroy_notify
));
653 // structs are returned via out parameter
654 bool return_result_via_out_param
= itype
.get_return_type ().is_real_non_null_struct_type ();
656 // pass address for the return value of non-void signals without emitter functions
657 if (itype is SignalType
&& !(itype
.get_return_type () is VoidType
)) {
658 var sig
= ((SignalType
) itype
).signal_symbol
;
660 if (ma
!= null && ma
.inner is BaseAccess
&& sig
.is_virtual
) {
661 // normal return value for base access
662 } else if (!get_signal_has_emitter (sig
) || ma
.source_reference
.file
== sig
.source_reference
.file
) {
663 return_result_via_out_param
= true;
667 if (async_call
== ccall
) {
668 // skip out parameter for .begin() calls
669 return_result_via_out_param
= false;
672 CCodeExpression out_param_ref
= null;
674 if (return_result_via_out_param
) {
675 var out_param_var
= get_temp_variable (itype
.get_return_type (), true, null, true);
676 out_param_ref
= get_variable_cexpression (out_param_var
.name
);
677 emit_temp_var (out_param_var
);
678 out_arg_map
.set (get_param_pos (-3), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, out_param_ref
));
681 // append C arguments in the right order
686 if (async_call
!= ccall
) {
687 // don't append out arguments for .begin() calls
691 foreach (int pos
in out_arg_map
.get_keys ()) {
692 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
699 ccall
.add_argument (out_arg_map
.get (min_pos
));
704 if (async_call
!= null) {
708 foreach (int pos
in in_arg_map
.get_keys ()) {
709 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
716 async_call
.add_argument (in_arg_map
.get (min_pos
));
721 if (expr
.is_yield_expression
) {
722 // set state before calling async function to support immediate callbacks
723 int state
= emit_context
.next_coroutine_state
++;
725 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_state_"), new
CCodeConstant (state
.to_string ()));
726 ccode
.add_expression (async_call
);
727 ccode
.add_return (new
CCodeConstant ("FALSE"));
728 ccode
.add_label ("_state_%d".printf (state
));
731 if (expr
.is_assert
) {
732 string message
= ((string) expr
.source_reference
.begin
.pos
).substring (0, (int) (expr
.source_reference
.end
.pos
- expr
.source_reference
.begin
.pos
));
733 ccall
.call
= new
CCodeIdentifier ("_vala_assert");
734 ccall
.add_argument (new
CCodeConstant ("\"%s\"".printf (message
.replace ("\n", " ").escape (""))));
735 requires_assert
= true;
739 if (return_result_via_out_param
) {
740 ccode
.add_expression (ccall_expr
);
741 ccall_expr
= out_param_ref
;
744 if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& m
.returns_modified_pointer
) {
745 if (ma
!= null && ma
.inner
.symbol_reference is Property
&& ma
.inner is MemberAccess
) {
746 var prop
= (Property
) ma
.inner
.symbol_reference
;
747 store_property (prop
, ((MemberAccess
) ma
.inner
).inner
, new
GLibValue (expr
.value_type
, ccall_expr
));
750 ccall_expr
= new
CCodeAssignment (instance
, ccall_expr
);
754 if (m
!= null && get_ccode_type (m
) != null && get_ccode_type (m
) != get_ccode_name (m
.return_type
)) {
755 // Bug 699956: Implement cast for method return type if [CCode type=] annotation is specified
756 ccall_expr
= new
CCodeCastExpression (ccall_expr
, get_ccode_name (m
.return_type
));
759 if (m is ArrayResizeMethod
) {
760 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
761 Iterator
<Expression
> arg_it
= expr
.get_argument_list ().iterator ();
763 var new_size
= get_cvalue (arg_it
.get ());
765 var temp_decl
= get_temp_variable (int_type
);
766 var temp_ref
= get_variable_cexpression (temp_decl
.name
);
768 emit_temp_var (temp_decl
);
770 /* memset needs string.h */
771 cfile
.add_include ("string.h");
773 var clen
= get_array_length_cexpression (ma
.inner
, 1);
774 var celems
= get_cvalue (ma
.inner
);
775 var array_type
= (ArrayType
) ma
.inner
.value_type
;
776 var csizeof
= new
CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (array_type
.element_type
)));
777 var cdelta
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, temp_ref
, clen
);
778 var ccheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, temp_ref
, clen
);
780 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
781 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, celems
, clen
));
782 czero
.add_argument (new
CCodeConstant ("0"));
783 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeof
, cdelta
));
785 ccode
.add_assignment (temp_ref
, new_size
);
786 ccode
.add_expression (ccall_expr
);
787 ccode
.add_expression (new
CCodeConditionalExpression (ccheck
, czero
, new
CCodeConstant ("NULL")));
788 ccode
.add_assignment (get_array_length_cexpression (ma
.inner
, 1), temp_ref
);
790 var array_var
= ma
.inner
.symbol_reference
;
791 var array_local
= array_var as LocalVariable
;
792 if (array_var
!= null && array_var
.is_internal_symbol ()
793 && ((array_var is LocalVariable
&& !array_local
.captured
) || array_var is Field
)) {
794 ccode
.add_assignment (get_array_size_cvalue (ma
.inner
.target_value
), temp_ref
);
800 if (expr
.parent_node is ExpressionStatement
&& !expr
.value_type
.is_disposable ()) {
801 if (ccall_expr
!= null && !return_result_via_out_param
) {
802 ccode
.add_expression (ccall_expr
);
805 var result_type
= itype
.get_return_type ();
807 if (expr
.formal_value_type is GenericType
&& !(expr
.value_type is GenericType
)) {
808 var type_parameter
= ((GenericType
) expr
.formal_value_type
).type_parameter
;
809 var st
= type_parameter
.parent_symbol
.parent_symbol as Struct
;
810 if (type_parameter
.parent_symbol
== garray_type
||
811 (st
!= null && get_ccode_name (st
) == "va_list")) {
812 // GArray and va_list don't use pointer-based generics
813 // above logic copied from visit_expression ()
814 // TODO avoid code duplication
815 result_type
= expr
.value_type
;
819 if (m
!= null && m
.get_format_arg_index () >= 0) {
820 set_cvalue (expr
, ccall_expr
);
821 } else if (m
!= null && m
.get_attribute_bool ("CCode", "use_inplace", false)) {
822 set_cvalue (expr
, ccall_expr
);
823 } else if (!return_result_via_out_param
824 && ((m
!= null && !has_ref_out_param (m
)) || (deleg
!= null && !has_ref_out_param (deleg
)))
825 && (result_type is ValueType
&& !result_type
.is_disposable ())) {
826 set_cvalue (expr
, ccall_expr
);
827 } else if (!return_result_via_out_param
) {
828 var temp_var
= get_temp_variable (result_type
, result_type
.value_owned
, null, false);
829 var temp_ref
= get_variable_cexpression (temp_var
.name
);
831 emit_temp_var (temp_var
);
833 ccode
.add_assignment (temp_ref
, ccall_expr
);
834 set_cvalue (expr
, temp_ref
);
835 ((GLibValue
) expr
.target_value
).lvalue
= true;
837 set_cvalue (expr
, ccall_expr
);
838 ((GLibValue
) expr
.target_value
).lvalue
= true;
842 params_it
= params
.iterator ();
843 foreach (Expression arg
in expr
.get_argument_list ()) {
844 Parameter param
= null;
846 if (params_it
.next ()) {
847 param
= params_it
.get ();
848 if (param
.params_array
|| param
.ellipsis
) {
849 // ignore ellipsis arguments as we currently don't use temporary variables for them
854 var unary
= arg as UnaryExpression
;
855 if (unary
== null || unary
.operator
!= UnaryOperator
.OUT
) {
859 if (requires_destroy (unary
.inner
.value_type
)) {
861 ccode
.add_expression (destroy_value (unary
.inner
.target_value
));
865 store_value (unary
.inner
.target_value
, transform_value (unary
.target_value
, unary
.inner
.value_type
, arg
), expr
.source_reference
);
867 // handle out null terminated arrays
868 if (param
!= null && get_ccode_array_null_terminated (param
)) {
869 requires_array_length
= true;
870 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
871 len_call
.add_argument (get_cvalue_ (unary
.inner
.target_value
));
873 ccode
.add_assignment (get_array_length_cvalue (unary
.inner
.target_value
, 1), len_call
);
877 if (m is CreationMethod
&& m
.parent_symbol is Class
&& ((current_class
.is_compact
&& current_class
.base_class
!= null) || current_class
.base_class
== gsource_type
)) {
878 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (current_class
, null))));
879 cinitcall
.add_argument (get_this_cexpression ());
880 ccode
.add_expression (cinitcall
);
884 private string generate_enum_tostring_function (Enum en
) {
885 var to_string_func
= "_%s_to_string".printf (get_ccode_lower_case_name (en
));
887 if (!add_wrapper (to_string_func
)) {
888 // wrapper already defined
889 return to_string_func
;
893 var function
= new
CCodeFunction (to_string_func
, "const char*");
894 function
.modifiers
= CCodeModifiers
.STATIC
;
896 function
.add_parameter (new
CCodeParameter ("value", get_ccode_name (en
)));
899 push_context (new
EmitContext ());
900 push_function (function
);
902 ccode
.open_switch (new
CCodeConstant ("value"));
903 foreach (var enum_value
in en
.get_values ()) {
904 ccode
.add_case (new
CCodeIdentifier (get_ccode_name (enum_value
)));
905 ccode
.add_return (new
CCodeConstant ("\""+get_ccode_name (enum_value
)+"\""));
908 ccode
.add_return (new
CCodeConstant ("NULL"));
911 cfile
.add_function_declaration (function
);
912 cfile
.add_function (function
);
916 return to_string_func
;
919 bool has_ref_out_param (Callable c
) {
920 foreach (var param
in c
.get_parameters ()) {
921 if (param
.direction
!= ParameterDirection
.IN
) {