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 (context
.profile
== Profile
.POSIX
&& ma
.inner
!= null && ma
.inner
.value_type
!= null && ma
.inner
.value_type
.data_type
== string_type
.data_type
&& ma
.member_name
== "printf") {
57 ccall
.call
= new
CCodeIdentifier (generate_string_printf_function ());
58 } else if (expr
.is_constructv_chainup
) {
59 ccall
.call
= new
CCodeIdentifier (get_ccode_constructv_name ((CreationMethod
) m
));
61 } else if (itype is SignalType
) {
62 var sig_type
= (SignalType
) itype
;
63 if (ma
!= null && ma
.inner is BaseAccess
&& sig_type
.signal_symbol
.is_virtual
) {
64 m
= sig_type
.signal_symbol
.default_handler
;
66 ccall
= (CCodeFunctionCall
) get_cvalue (expr
.call
);
68 } else if (itype is ObjectType
) {
70 var cl
= (Class
) ((ObjectType
) itype
).type_symbol
;
71 m
= cl
.default_construction_method
;
72 generate_method_declaration (m
, cfile
);
73 var real_name
= get_ccode_real_name (m
);
74 if (expr
.is_constructv_chainup
) {
75 real_name
= get_ccode_constructv_name ((CreationMethod
) m
);
77 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (real_name
));
78 } else if (itype is StructValueType
) {
80 var st
= (Struct
) ((StructValueType
) itype
).type_symbol
;
81 m
= st
.default_construction_method
;
82 generate_method_declaration (m
, cfile
);
83 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
)));
84 } else if (itype is DelegateType
) {
85 deleg
= ((DelegateType
) itype
).delegate_symbol
;
88 var in_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
89 var out_arg_map
= in_arg_map
;
91 if (m
!= null && m
.coroutine
) {
94 async_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_name (m
)));
95 finish_call
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_finish_name (m
)));
97 if (ma
.inner is BaseAccess
) {
98 if (m
.base_method
!= null) {
99 var base_class
= (Class
) m
.base_method
.parent_symbol
;
100 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class
, null))));
101 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class
, null))));
103 async_call
.call
= new CCodeMemberAccess
.pointer (vcast
, get_ccode_vfunc_name (m
));
104 finish_call
.call
= new CCodeMemberAccess
.pointer (vcast
, get_ccode_finish_vfunc_name (m
));
105 } else if (m
.base_interface_method
!= null) {
106 var base_iface
= (Interface
) m
.base_interface_method
.parent_symbol
;
107 string parent_iface_var
= "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class
), get_ccode_lower_case_name (base_iface
));
109 async_call
.call
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), get_ccode_vfunc_name (m
));
110 finish_call
.call
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier (parent_iface_var
), get_ccode_finish_vfunc_name (m
));
114 if (ma
.member_name
== "begin" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
117 params
= m
.get_async_begin_parameters ();
118 } else if (ma
.member_name
== "end" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
121 params
= m
.get_async_end_parameters ();
122 } else if (!expr
.is_yield_expression
) {
123 // same as .begin, backwards compatible to bindings without async methods
125 params
= m
.get_async_begin_parameters ();
129 // output arguments used separately
130 out_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
131 // pass GAsyncResult stored in closure to finish function
132 out_arg_map
.set (get_param_pos (0.1), new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_res_"));
136 if (m is CreationMethod
&& m
.parent_symbol is Class
) {
137 if (context
.profile
== Profile
.GOBJECT
) {
138 if (!((Class
) m
.parent_symbol
).is_compact
) {
139 ccall
.add_argument (get_variable_cexpression ("object_type"));
142 ccall
.add_argument (get_this_cexpression ());
145 if (!current_class
.is_compact
) {
146 if (current_class
!= m
.parent_symbol
) {
147 // chain up to base class
148 foreach (DataType base_type
in current_class
.get_base_types ()) {
149 if (base_type
.data_type is Class
) {
150 List
<TypeParameter
> type_parameters
= null;
151 if (get_ccode_real_name (m
) == "g_object_new") {
152 // gobject-style chainup
153 type_parameters
= ((Class
) base_type
.data_type
).get_type_parameters ();
155 add_generic_type_arguments (in_arg_map
, base_type
.get_type_arguments (), expr
, true, type_parameters
);
160 // chain up to other constructor in same class
161 int type_param_index
= 0;
162 var cl
= (Class
) m
.parent_symbol
;
163 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
164 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.01), new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ())));
165 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.02), new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ())));
166 in_arg_map
.set (get_param_pos (0.1 * type_param_index
+ 0.03), new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ())));
170 } else if (current_class
.base_class
== gsource_type
) {
173 string class_prefix
= get_ccode_lower_case_name (current_class
);
175 var funcs
= new
CCodeDeclaration ("const GSourceFuncs");
176 funcs
.modifiers
= CCodeModifiers
.STATIC
;
177 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
))));
178 ccode
.add_statement (funcs
);
180 ccall
.add_argument (new
CCodeCastExpression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("_source_funcs")), "GSourceFuncs *"));
182 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
183 csizeof
.add_argument (new
CCodeIdentifier (get_ccode_name (current_class
)));
184 ccall
.add_argument (csizeof
);
186 } else if (m is CreationMethod
&& m
.parent_symbol is Struct
) {
187 ccall
.add_argument (get_this_cexpression ());
188 } 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
)) {
190 // don't add generic arguments for .end() calls
191 add_generic_type_arguments (in_arg_map
, ma
.get_type_arguments (), expr
);
194 // the complete call expression, might include casts, comma expressions, and/or assignments
195 CCodeExpression ccall_expr
= ccall
;
197 if (m is ArrayResizeMethod
) {
198 var array_type
= (ArrayType
) ma
.inner
.value_type
;
199 in_arg_map
.set (get_param_pos (0), new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
200 } else if (m is ArrayMoveMethod
) {
201 requires_array_move
= true;
202 } else if (m is ArrayCopyMethod
) {
203 expr
.target_value
= copy_value (ma
.inner
.target_value
, expr
);
207 CCodeExpression instance
= null;
208 if (m
!= null && m
.is_async_callback
) {
209 if (current_method
.closure
) {
210 var block
= ((Method
) m
.parent_symbol
).body
;
211 instance
= new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block
))), "_async_data_");
213 instance
= new
CCodeIdentifier ("_data_");
216 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
217 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
218 } else if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& !(m is CreationMethod
)) {
219 var instance_value
= ma
.inner
.target_value
;
220 if ((ma
.member_name
== "begin" || ma
.member_name
== "end") && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
221 var inner_ma
= (MemberAccess
) ma
.inner
;
222 instance_value
= inner_ma
.inner
.target_value
;
224 instance
= get_cvalue_ (instance_value
);
226 var st
= m
.parent_symbol as Struct
;
227 if (st
!= null && !st
.is_simple_type ()) {
228 // we need to pass struct instance by reference
229 if (!get_lvalue (instance_value
)) {
230 instance_value
= store_temp_value (instance_value
, expr
);
232 instance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue_ (instance_value
));
235 if (expr
.is_yield_expression
) {
236 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
237 if (get_ccode_finish_instance (m
)) {
238 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
240 } else if (ma
.member_name
!= "end" || get_ccode_finish_instance (m
)) {
241 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
242 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), instance
);
244 } else if (m
!= null && m
.binding
== MemberBinding
.CLASS
) {
245 var cl
= (Class
) m
.parent_symbol
;
246 var cast
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_upper_case_name (cl
, null) + "_CLASS"));
248 CCodeExpression klass
;
249 if (ma
.inner
== null) {
250 if (get_this_type () == null) {
251 // Accessing the method from a static or class constructor
252 klass
= new
CCodeIdentifier ("klass");
254 // Accessing the method from within an instance method
255 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
256 k
.add_argument (get_this_cexpression ());
260 // Accessing the method of an instance
261 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
262 k
.add_argument (get_cvalue (ma
.inner
));
266 cast
.add_argument (klass
);
267 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), cast
);
268 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (m
)), cast
);
271 if (m
!= null && get_ccode_has_generic_type_parameter (m
)) {
272 // insert type argument for macros
273 if (m
.get_type_parameters ().size
> 0) {
275 int type_param_index
= 0;
276 foreach (var type_arg
in ma
.get_type_arguments ()) {
277 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
)));
281 // method in generic type
282 int type_param_index
= 0;
283 foreach (var type_arg
in ma
.inner
.value_type
.get_type_arguments ()) {
284 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
)));
290 if (m is ArrayMoveMethod
) {
291 var array_type
= (ArrayType
) ma
.inner
.value_type
;
292 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
293 csizeof
.add_argument (new
CCodeIdentifier (get_ccode_name (array_type
.element_type
)));
294 in_arg_map
.set (get_param_pos (0.1), csizeof
);
295 } else if (m is DynamicMethod
) {
296 m
.clear_parameters ();
298 foreach (Expression arg
in expr
.get_argument_list ()) {
299 var unary
= arg as UnaryExpression
;
300 if (unary
!= null && unary
.operator
== UnaryOperator
.OUT
) {
302 var param
= new
Parameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
303 param
.direction
= ParameterDirection
.OUT
;
304 m
.add_parameter (param
);
305 } else if (unary
!= null && unary
.operator
== UnaryOperator
.REF
) {
307 var param
= new
Parameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
308 param
.direction
= ParameterDirection
.REF
;
309 m
.add_parameter (param
);
312 m
.add_parameter (new
Parameter ("param%d".printf (param_nr
), arg
.value_type
));
316 foreach (Parameter param
in m
.get_parameters ()) {
319 generate_dynamic_method_wrapper ((DynamicMethod
) m
);
320 } else if (m is CreationMethod
&& context
.profile
== Profile
.GOBJECT
&& m
.parent_symbol is Class
) {
321 ccode
.add_assignment (get_this_cexpression (), new
CCodeCastExpression (ccall
, get_ccode_name (current_class
) + "*"));
323 if (current_method
.body
.captured
) {
324 // capture self after setting it
325 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (new
ObjectType (current_class
), expr
.source_reference
));
326 ref_call
.add_argument (get_this_cexpression ());
328 ccode
.add_assignment (new CCodeMemberAccess
.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method
.body
))), "self"), ref_call
);
331 if (!current_class
.is_compact
&& current_class
.get_type_parameters ().size
> 0) {
332 /* type, dup func, and destroy func fields for generic types */
333 var suffices
= new
string[] {"type", "dup_func", "destroy_func"};
334 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
335 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
337 foreach (string suffix
in suffices
) {
338 var param_name
= new
CCodeIdentifier ("%s_%s".printf (type_param
.name
.down (), suffix
));
339 ccode
.add_assignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
);
343 // object chainup can't be used as expression
347 bool ellipsis
= false;
351 Iterator
<Parameter
> params_it
= params
.iterator ();
352 foreach (Expression arg
in expr
.get_argument_list ()) {
353 CCodeExpression cexpr
= get_cvalue (arg
);
355 var carg_map
= in_arg_map
;
357 if (params_it
.next ()) {
358 var param
= params_it
.get ();
359 ellipsis
= param
.params_array
|| param
.ellipsis
;
361 if (param
.direction
== ParameterDirection
.OUT
) {
362 carg_map
= out_arg_map
;
365 var unary
= arg as UnaryExpression
;
366 if (unary
== null || unary
.operator
!= UnaryOperator
.OUT
) {
367 if (get_ccode_array_length (param
) && param
.variable_type is ArrayType
) {
368 var array_type
= (ArrayType
) param
.variable_type
;
369 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
370 CCodeExpression? array_length_expr
= null;
371 if (get_ccode_array_length_type (param
) != null) {
372 string length_ctype
= get_ccode_array_length_type (param
);
373 if (unary
!= null && unary
.operator
== UnaryOperator
.REF
) {
374 length_ctype
= "%s*".printf (length_ctype
);
376 array_length_expr
= new
CCodeCastExpression (get_array_length_cexpression (arg
, dim
), length_ctype
);
378 array_length_expr
= get_array_length_cexpression (arg
, dim
);
380 carg_map
.set (get_param_pos (get_ccode_array_length_pos (param
) + 0.01 * dim
), array_length_expr
);
382 } else if (param
.variable_type is DelegateType
) {
383 var deleg_type
= (DelegateType
) param
.variable_type
;
384 if (deleg_type
.delegate_symbol
.has_target
) {
385 CCodeExpression delegate_target_destroy_notify
;
386 var delegate_target
= get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
);
387 assert (delegate_target
!= null);
388 if (get_ccode_type (param
) == "GClosure*") {
389 // one single GClosure parameter
390 var closure_new
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_cclosure_new"));
391 closure_new
.add_argument (new
CCodeCastExpression (cexpr
, "GCallback"));
392 closure_new
.add_argument (delegate_target
);
393 closure_new
.add_argument (new
CCodeCastExpression (delegate_target_destroy_notify
, "GClosureNotify"));
394 cexpr
= new
CCodeConditionalExpression (new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, cexpr
, new
CCodeIdentifier ("NULL")), new
CCodeIdentifier ("NULL"), closure_new
);
396 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
)), delegate_target
);
397 if (deleg_type
.is_disposable ()) {
398 assert (delegate_target_destroy_notify
!= null);
399 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
) + 0.01), delegate_target_destroy_notify
);
403 } else if (param
.variable_type is MethodType
) {
404 // callbacks in dynamic method calls
405 CCodeExpression delegate_target_destroy_notify
;
406 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
)), get_delegate_target_cexpression (arg
, out delegate_target_destroy_notify
));
407 } else if (param
.variable_type is GenericType
) {
408 if (m
!= null && get_ccode_simple_generics (m
)) {
409 var generic_type
= (GenericType
) param
.variable_type
;
410 int type_param_index
= m
.get_type_parameter_index (generic_type
.type_parameter
.name
);
411 var type_arg
= ma
.get_type_arguments ().get (type_param_index
);
412 if (param
.variable_type
.value_owned
) {
413 if (requires_copy (type_arg
)) {
414 carg_map
.set (get_param_pos (get_ccode_destroy_notify_pos (param
)), get_destroy_func_expression (type_arg
));
416 carg_map
.set (get_param_pos (get_ccode_destroy_notify_pos (param
)), new
CCodeConstant ("NULL"));
422 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
424 arg
.target_value
= null;
426 var temp_var
= get_temp_variable (param
.variable_type
, param
.variable_type
.value_owned
, null, true);
427 emit_temp_var (temp_var
);
428 set_cvalue (arg
, get_variable_cexpression (temp_var
.name
));
429 arg
.target_value
.value_type
= arg
.target_type
;
431 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_cvalue (arg
));
433 if (get_ccode_array_length (param
) && param
.variable_type is ArrayType
) {
434 var array_type
= (ArrayType
) param
.variable_type
;
435 var array_length_type
= int_type
;
436 if (get_ccode_array_length_type (param
) != null) {
437 array_length_type
= new
CType (get_ccode_array_length_type (param
));
439 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
440 var temp_array_length
= get_temp_variable (array_length_type
);
441 emit_temp_var (temp_array_length
);
442 append_array_length (arg
, get_variable_cexpression (temp_array_length
.name
));
443 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)));
445 } else if (param
.variable_type is DelegateType
) {
446 var deleg_type
= (DelegateType
) param
.variable_type
;
447 if (deleg_type
.delegate_symbol
.has_target
) {
448 temp_var
= get_temp_variable (new
PointerType (new
VoidType ()), true, null, true);
449 emit_temp_var (temp_var
);
450 set_delegate_target (arg
, get_variable_cexpression (temp_var
.name
));
451 carg_map
.set (get_param_pos (get_ccode_delegate_target_pos (param
)), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_delegate_target (arg
)));
452 if (deleg_type
.is_disposable ()) {
453 temp_var
= get_temp_variable (gdestroynotify_type
, true, null, true);
454 emit_temp_var (temp_var
);
455 set_delegate_target_destroy_notify (arg
, get_variable_cexpression (temp_var
.name
));
456 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
)));
462 if (get_ccode_type (param
) != null) {
463 cexpr
= new
CCodeCastExpression (cexpr
, get_ccode_type (param
));
466 cexpr
= handle_struct_argument (null, arg
, cexpr
);
468 arg_pos
= get_param_pos (get_ccode_pos (param
), ellipsis
);
470 // default argument position
471 cexpr
= handle_struct_argument (null, arg
, cexpr
);
472 arg_pos
= get_param_pos (i
, ellipsis
);
475 carg_map
.set (arg_pos
, cexpr
);
477 if (arg is NamedArgument
&& ellipsis
) {
478 var named_arg
= (NamedArgument
) arg
;
479 string name
= string.joinv ("-", named_arg
.name
.split ("_"));
480 carg_map
.set (get_param_pos (i
- 0.1, ellipsis
), new
CCodeConstant ("\"%s\"".printf (name
)));
485 if (params_it
.next ()) {
486 var param
= params_it
.get ();
488 /* if there are more parameters than arguments,
489 * the additional parameter is an ellipsis parameter
490 * otherwise there is a bug in the semantic analyzer
492 assert (param
.params_array
|| param
.ellipsis
);
496 /* add length argument for methods returning arrays */
497 if (m
!= null && m
.return_type is ArrayType
&& async_call
!= ccall
) {
498 var array_type
= (ArrayType
) m
.return_type
;
499 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
500 if (get_ccode_array_null_terminated (m
)) {
501 // handle calls to methods returning null-terminated arrays
502 var temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
503 var temp_ref
= get_variable_cexpression (temp_var
.name
);
505 emit_temp_var (temp_var
);
507 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
509 requires_array_length
= true;
510 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
511 len_call
.add_argument (temp_ref
);
513 append_array_length (expr
, len_call
);
514 } else if (get_ccode_array_length (m
)) {
515 LocalVariable temp_var
;
517 if (get_ccode_array_length_type (m
) == null) {
518 temp_var
= get_temp_variable (int_type
);
520 temp_var
= get_temp_variable (new
CType (get_ccode_array_length_type (m
)));
522 var temp_ref
= get_variable_cexpression (temp_var
.name
);
524 emit_temp_var (temp_var
);
526 out_arg_map
.set (get_param_pos (get_ccode_array_length_pos (m
) + 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
528 append_array_length (expr
, temp_ref
);
529 } else if (get_ccode_array_length_expr (m
) != null) {
530 append_array_length (expr
, new
CCodeConstant (get_ccode_array_length_expr (m
)));
532 append_array_length (expr
, new
CCodeConstant ("-1"));
535 } else if (m
!= null && m
.return_type is DelegateType
&& async_call
!= ccall
) {
536 var deleg_type
= (DelegateType
) m
.return_type
;
537 if (deleg_type
.delegate_symbol
.has_target
) {
538 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
539 var temp_ref
= get_variable_cexpression (temp_var
.name
);
541 emit_temp_var (temp_var
);
543 out_arg_map
.set (get_param_pos (get_ccode_delegate_target_pos (m
)), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
545 set_delegate_target (expr
, temp_ref
);
547 if (deleg_type
.is_disposable ()) {
548 temp_var
= get_temp_variable (gdestroynotify_type
);
549 temp_ref
= get_variable_cexpression (temp_var
.name
);
551 emit_temp_var (temp_var
);
553 out_arg_map
.set (get_param_pos (get_ccode_delegate_target_pos (m
) + 0.01), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
555 set_delegate_target_destroy_notify (expr
, temp_ref
);
557 set_delegate_target_destroy_notify (expr
, new
CCodeConstant ("NULL"));
560 set_delegate_target (expr
, new
CCodeConstant ("NULL"));
564 // add length argument for delegates returning arrays
565 // TODO: avoid code duplication with methods returning arrays, see above
566 if (deleg
!= null && deleg
.return_type is ArrayType
) {
567 var array_type
= (ArrayType
) deleg
.return_type
;
568 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
569 if (get_ccode_array_null_terminated (deleg
)) {
570 // handle calls to methods returning null-terminated arrays
571 var temp_var
= get_temp_variable (itype
.get_return_type (), true, null, false);
572 var temp_ref
= get_variable_cexpression (temp_var
.name
);
574 emit_temp_var (temp_var
);
576 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
578 requires_array_length
= true;
579 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
580 len_call
.add_argument (temp_ref
);
582 append_array_length (expr
, len_call
);
583 } else if (get_ccode_array_length (deleg
)) {
584 var temp_var
= get_temp_variable (int_type
);
585 var temp_ref
= get_variable_cexpression (temp_var
.name
);
587 emit_temp_var (temp_var
);
589 out_arg_map
.set (get_param_pos (get_ccode_array_length_pos (deleg
) + 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
591 append_array_length (expr
, temp_ref
);
593 append_array_length (expr
, new
CCodeConstant ("-1"));
596 } else if (deleg
!= null && deleg
.return_type is DelegateType
) {
597 var deleg_type
= (DelegateType
) deleg
.return_type
;
598 if (deleg_type
.delegate_symbol
.has_target
) {
599 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
600 var temp_ref
= get_variable_cexpression (temp_var
.name
);
602 emit_temp_var (temp_var
);
604 out_arg_map
.set (get_param_pos (get_ccode_delegate_target_pos (deleg
)), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
606 set_delegate_target (expr
, temp_ref
);
608 if (deleg_type
.is_disposable ()) {
609 temp_var
= get_temp_variable (gdestroynotify_type
);
610 temp_ref
= get_variable_cexpression (temp_var
.name
);
612 emit_temp_var (temp_var
);
614 out_arg_map
.set (get_param_pos (get_ccode_delegate_target_pos (deleg
) + 0.01), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
616 set_delegate_target_destroy_notify (expr
, temp_ref
);
621 if (m
!= null && m
.coroutine
) {
622 if (expr
.is_yield_expression
) {
624 in_arg_map
.set (get_param_pos (-1), new
CCodeIdentifier (generate_ready_function (current_method
)));
625 in_arg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("_data_"));
629 if (expr
.tree_can_fail
) {
631 current_method_inner_error
= true;
632 // add &inner_error before the ellipsis arguments
633 out_arg_map
.set (get_param_pos (-1), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
634 } else if (m
!= null && m
.has_error_type_parameter () && async_call
!= ccall
) {
635 // inferred error argument from base method
636 out_arg_map
.set (get_param_pos (-1), new
CCodeConstant ("NULL"));
640 /* ensure variable argument list ends with NULL
641 * except when using printf-style arguments */
643 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant ("NULL"));
644 } else if (!m
.printf_format
&& !m
.scanf_format
&& get_ccode_sentinel (m
) != "" && !expr
.is_constructv_chainup
) {
645 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant (get_ccode_sentinel (m
)));
649 if (itype is DelegateType
) {
650 var deleg_type
= (DelegateType
) itype
;
651 var d
= deleg_type
.delegate_symbol
;
653 CCodeExpression delegate_target_destroy_notify
;
654 in_arg_map
.set (get_param_pos (get_ccode_instance_pos (d
)), get_delegate_target_cexpression (expr
.call
, out delegate_target_destroy_notify
));
655 out_arg_map
.set (get_param_pos (get_ccode_instance_pos (d
)), get_delegate_target_cexpression (expr
.call
, out delegate_target_destroy_notify
));
659 // structs are returned via out parameter
660 bool return_result_via_out_param
= itype
.get_return_type ().is_real_non_null_struct_type ();
662 // pass address for the return value of non-void signals without emitter functions
663 if (itype is SignalType
&& !(itype
.get_return_type () is VoidType
)) {
664 var sig
= ((SignalType
) itype
).signal_symbol
;
666 if (ma
!= null && ma
.inner is BaseAccess
&& sig
.is_virtual
) {
667 // normal return value for base access
668 } else if (!get_signal_has_emitter (sig
) || ma
.source_reference
.file
== sig
.source_reference
.file
) {
669 return_result_via_out_param
= true;
673 if (async_call
== ccall
) {
674 // skip out parameter for .begin() calls
675 return_result_via_out_param
= false;
678 CCodeExpression out_param_ref
= null;
680 if (return_result_via_out_param
) {
681 var out_param_var
= get_temp_variable (itype
.get_return_type (), true, null, true);
682 out_param_ref
= get_variable_cexpression (out_param_var
.name
);
683 emit_temp_var (out_param_var
);
684 out_arg_map
.set (get_param_pos (-3), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, out_param_ref
));
687 // append C arguments in the right order
692 if (async_call
!= ccall
) {
693 // don't append out arguments for .begin() calls
697 foreach (int pos
in out_arg_map
.get_keys ()) {
698 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
705 ccall
.add_argument (out_arg_map
.get (min_pos
));
710 if (async_call
!= null) {
714 foreach (int pos
in in_arg_map
.get_keys ()) {
715 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
722 async_call
.add_argument (in_arg_map
.get (min_pos
));
727 if (expr
.is_yield_expression
) {
728 // set state before calling async function to support immediate callbacks
729 int state
= emit_context
.next_coroutine_state
++;
731 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_state_"), new
CCodeConstant (state
.to_string ()));
732 ccode
.add_expression (async_call
);
733 ccode
.add_return (new
CCodeConstant ("FALSE"));
734 ccode
.add_label ("_state_%d".printf (state
));
737 if (expr
.is_assert
) {
738 string message
= ((string) expr
.source_reference
.begin
.pos
).substring (0, (int) (expr
.source_reference
.end
.pos
- expr
.source_reference
.begin
.pos
));
739 ccall
.call
= new
CCodeIdentifier ("_vala_assert");
740 ccall
.add_argument (new
CCodeConstant ("\"%s\"".printf (message
.replace ("\n", " ").escape (""))));
741 requires_assert
= true;
745 if (return_result_via_out_param
) {
746 ccode
.add_expression (ccall_expr
);
747 ccall_expr
= out_param_ref
;
750 if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& m
.returns_modified_pointer
) {
751 if (ma
!= null && ma
.inner
.symbol_reference is Property
&& ma
.inner is MemberAccess
) {
752 var prop
= (Property
) ma
.inner
.symbol_reference
;
753 store_property (prop
, ((MemberAccess
) ma
.inner
).inner
, new
GLibValue (expr
.value_type
, ccall_expr
));
756 ccall_expr
= new
CCodeAssignment (instance
, ccall_expr
);
760 if (m
!= null && get_ccode_type (m
) != null && get_ccode_type (m
) != get_ccode_name (m
.return_type
)) {
761 // Bug 699956: Implement cast for method return type if [CCode type=] annotation is specified
762 ccall_expr
= new
CCodeCastExpression (ccall_expr
, get_ccode_name (m
.return_type
));
765 if (m is ArrayResizeMethod
) {
766 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
767 Iterator
<Expression
> arg_it
= expr
.get_argument_list ().iterator ();
769 var new_size
= get_cvalue (arg_it
.get ());
771 var temp_decl
= get_temp_variable (int_type
);
772 var temp_ref
= get_variable_cexpression (temp_decl
.name
);
774 emit_temp_var (temp_decl
);
776 /* memset needs string.h */
777 cfile
.add_include ("string.h");
779 var clen
= get_array_length_cexpression (ma
.inner
, 1);
780 var celems
= get_cvalue (ma
.inner
);
781 var array_type
= (ArrayType
) ma
.inner
.value_type
;
782 var csizeof
= new
CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (array_type
.element_type
)));
783 var cdelta
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, temp_ref
, clen
);
784 var ccheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, temp_ref
, clen
);
786 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
787 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, celems
, clen
));
788 czero
.add_argument (new
CCodeConstant ("0"));
789 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeof
, cdelta
));
791 ccode
.add_assignment (temp_ref
, new_size
);
792 ccode
.add_expression (ccall_expr
);
793 ccode
.add_expression (new
CCodeConditionalExpression (ccheck
, czero
, new
CCodeConstant ("NULL")));
794 ccode
.add_assignment (get_array_length_cexpression (ma
.inner
, 1), temp_ref
);
796 var array_var
= ma
.inner
.symbol_reference
;
797 var array_local
= array_var as LocalVariable
;
798 if (array_var
!= null && array_var
.is_internal_symbol ()
799 && ((array_var is LocalVariable
&& !array_local
.captured
) || array_var is Field
)) {
800 ccode
.add_assignment (get_array_size_cvalue (ma
.inner
.target_value
), temp_ref
);
806 if (expr
.parent_node is ExpressionStatement
&& !expr
.value_type
.is_disposable ()) {
807 if (ccall_expr
!= null && !return_result_via_out_param
) {
808 ccode
.add_expression (ccall_expr
);
811 var result_type
= itype
.get_return_type ();
813 if (expr
.formal_value_type is GenericType
&& !(expr
.value_type is GenericType
)) {
814 var type_parameter
= ((GenericType
) expr
.formal_value_type
).type_parameter
;
815 var st
= type_parameter
.parent_symbol
.parent_symbol as Struct
;
816 if (type_parameter
.parent_symbol
== garray_type
||
817 (st
!= null && get_ccode_name (st
) == "va_list")) {
818 // GArray and va_list don't use pointer-based generics
819 // above logic copied from visit_expression ()
820 // TODO avoid code duplication
821 result_type
= expr
.value_type
;
825 if (m
!= null && m
.get_format_arg_index () >= 0) {
826 set_cvalue (expr
, ccall_expr
);
827 } else if (m
!= null && m
.get_attribute_bool ("CCode", "use_inplace", false)) {
828 set_cvalue (expr
, ccall_expr
);
829 } else if (!return_result_via_out_param
830 && ((m
!= null && !has_ref_out_param (m
)) || (deleg
!= null && !has_ref_out_param (deleg
)))
831 && (result_type is ValueType
&& !result_type
.is_disposable ())) {
832 set_cvalue (expr
, ccall_expr
);
833 } else if (!return_result_via_out_param
) {
834 var temp_var
= get_temp_variable (result_type
, result_type
.value_owned
, null, false);
835 var temp_ref
= get_variable_cexpression (temp_var
.name
);
837 emit_temp_var (temp_var
);
839 ccode
.add_assignment (temp_ref
, ccall_expr
);
840 set_cvalue (expr
, temp_ref
);
841 ((GLibValue
) expr
.target_value
).lvalue
= true;
843 set_cvalue (expr
, ccall_expr
);
844 ((GLibValue
) expr
.target_value
).lvalue
= true;
848 params_it
= params
.iterator ();
849 foreach (Expression arg
in expr
.get_argument_list ()) {
850 Parameter param
= null;
852 if (params_it
.next ()) {
853 param
= params_it
.get ();
854 if (param
.params_array
|| param
.ellipsis
) {
855 // ignore ellipsis arguments as we currently don't use temporary variables for them
860 var unary
= arg as UnaryExpression
;
861 if (unary
== null || unary
.operator
!= UnaryOperator
.OUT
) {
865 if (requires_destroy (unary
.inner
.value_type
)) {
867 ccode
.add_expression (destroy_value (unary
.inner
.target_value
));
871 store_value (unary
.inner
.target_value
, transform_value (unary
.target_value
, unary
.inner
.value_type
, arg
), expr
.source_reference
);
873 // handle out null terminated arrays
874 if (param
!= null && get_ccode_array_null_terminated (param
)) {
875 requires_array_length
= true;
876 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
877 len_call
.add_argument (get_cvalue_ (unary
.inner
.target_value
));
879 ccode
.add_assignment (get_array_length_cvalue (unary
.inner
.target_value
, 1), len_call
);
883 if (m is CreationMethod
&& m
.parent_symbol is Class
&& ((current_class
.is_compact
&& current_class
.base_class
!= null) || current_class
.base_class
== gsource_type
)) {
884 var cinitcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (current_class
, null))));
885 cinitcall
.add_argument (get_this_cexpression ());
886 ccode
.add_expression (cinitcall
);
890 private string generate_enum_tostring_function (Enum en
) {
891 var to_string_func
= "_%s_to_string".printf (get_ccode_lower_case_name (en
));
893 if (!add_wrapper (to_string_func
)) {
894 // wrapper already defined
895 return to_string_func
;
899 var function
= new
CCodeFunction (to_string_func
, "const char*");
900 function
.modifiers
= CCodeModifiers
.STATIC
;
902 function
.add_parameter (new
CCodeParameter ("value", get_ccode_name (en
)));
905 push_context (new
EmitContext ());
906 push_function (function
);
908 ccode
.open_switch (new
CCodeConstant ("value"));
909 foreach (var enum_value
in en
.get_values ()) {
910 ccode
.add_case (new
CCodeIdentifier (get_ccode_name (enum_value
)));
911 ccode
.add_return (new
CCodeConstant ("\""+get_ccode_name (enum_value
)+"\""));
914 ccode
.add_return (new
CCodeConstant ("NULL"));
917 cfile
.add_function_declaration (function
);
918 cfile
.add_function (function
);
922 return to_string_func
;
925 bool has_ref_out_param (Callable c
) {
926 foreach (var param
in c
.get_parameters ()) {
927 if (param
.direction
!= ParameterDirection
.IN
) {
934 string generate_string_printf_function () {
935 if (!add_wrapper ("string_printf")) {
936 // wrapper already defined
937 return "string_printf";
941 var function
= new
CCodeFunction ("string_printf", "char*");
942 function
.add_parameter (new
CCodeParameter ("format", "const char*"));
943 function
.add_parameter (new CCodeParameter
.with_ellipsis ());
944 function
.modifiers
= CCodeModifiers
.STATIC
;
947 push_context (new
EmitContext ());
948 push_function (function
);
950 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("length"));
951 ccode
.add_declaration ("va_list", new
CCodeVariableDeclarator ("ap"));
952 ccode
.add_declaration ("char*", new
CCodeVariableDeclarator ("result"));
954 var va_start
= new
CCodeFunctionCall (new
CCodeIdentifier ("va_start"));
955 va_start
.add_argument (new
CCodeIdentifier ("ap"));
956 va_start
.add_argument (new
CCodeIdentifier ("format"));
958 ccode
.add_expression (va_start
);
960 var vsnprintf
= new
CCodeFunctionCall (new
CCodeIdentifier ("vsnprintf"));
961 vsnprintf
.add_argument (new
CCodeConstant ("NULL"));
962 vsnprintf
.add_argument (new
CCodeConstant ("0"));
963 vsnprintf
.add_argument (new
CCodeIdentifier ("format"));
964 vsnprintf
.add_argument (new
CCodeIdentifier ("ap"));
966 ccode
.add_assignment (new
CCodeIdentifier ("length"), new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, vsnprintf
, new
CCodeConstant ("1")));
968 var va_end
= new
CCodeFunctionCall (new
CCodeIdentifier ("va_end"));
969 va_end
.add_argument (new
CCodeIdentifier ("ap"));
971 ccode
.add_expression (va_end
);
973 var malloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("malloc"));
974 malloc
.add_argument (new
CCodeIdentifier ("length"));
976 ccode
.add_assignment (new
CCodeIdentifier ("result"), malloc
);
978 va_start
= new
CCodeFunctionCall (new
CCodeIdentifier ("va_start"));
979 va_start
.add_argument (new
CCodeIdentifier ("ap"));
980 va_start
.add_argument (new
CCodeIdentifier ("format"));
982 ccode
.add_expression (va_start
);
984 vsnprintf
= new
CCodeFunctionCall (new
CCodeIdentifier ("vsnprintf"));
985 vsnprintf
.add_argument (new
CCodeIdentifier ("result"));
986 vsnprintf
.add_argument (new
CCodeIdentifier ("length"));
987 vsnprintf
.add_argument (new
CCodeIdentifier ("format"));
988 vsnprintf
.add_argument (new
CCodeIdentifier ("ap"));
990 ccode
.add_expression (vsnprintf
);
992 va_end
= new
CCodeFunctionCall (new
CCodeIdentifier ("va_end"));
993 va_end
.add_argument (new
CCodeIdentifier ("ap"));
995 ccode
.add_expression (va_end
);
997 ccode
.add_return (new
CCodeIdentifier ("result"));
1000 cfile
.add_include ("stdarg.h");
1001 cfile
.add_function_declaration (function
);
1002 cfile
.add_function (function
);
1006 return "string_printf";