1 /* valaccodemethodcallmodule.vala
3 * Copyright (C) 2006-2009 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>
28 internal class Vala
.CCodeMethodCallModule
: CCodeAssignmentModule
{
29 public CCodeMethodCallModule (CCodeGenerator codegen
, CCodeModule? next
) {
33 public override void visit_method_call (MethodCall expr
) {
34 expr
.accept_children (codegen
);
36 // the bare function call
37 var ccall
= new
CCodeFunctionCall ((CCodeExpression
) expr
.call
.ccodenode
);
39 CCodeFunctionCall async_call
= null;
42 Delegate deleg
= null;
43 Gee
.List
<FormalParameter
> params
;
45 var ma
= expr
.call as MemberAccess
;
47 var itype
= expr
.call
.value_type
;
48 params
= itype
.get_parameters ();
50 if (itype is MethodType
) {
52 m
= ((MethodType
) itype
).method_symbol
;
53 } else if (itype is SignalType
) {
54 var sig_type
= (SignalType
) itype
;
55 if (ma
!= null && ma
.inner is BaseAccess
&& sig_type
.signal_symbol
.is_virtual
) {
56 m
= sig_type
.signal_symbol
.default_handler
;
58 ccall
= (CCodeFunctionCall
) expr
.call
.ccodenode
;
60 } else if (itype is ObjectType
) {
62 var cl
= (Class
) ((ObjectType
) itype
).type_symbol
;
63 m
= cl
.default_construction_method
;
64 generate_method_declaration (m
, source_declarations
);
65 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname ()));
66 } else if (itype is DelegateType
) {
67 deleg
= ((DelegateType
) itype
).delegate_symbol
;
70 var in_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
71 var out_arg_map
= in_arg_map
;
73 if (m
!= null && m
.coroutine
) {
76 async_call
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_cname ()));
78 if (ma
.member_name
== "begin" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
81 params
= m
.get_async_begin_parameters ();
82 } else if (ma
.member_name
== "end" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
84 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_finish_cname ()));
85 params
= m
.get_async_end_parameters ();
86 } else if (!expr
.is_yield_expression
) {
87 // same as .begin, backwards compatible to bindings without async methods
89 params
= m
.get_async_begin_parameters ();
91 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_finish_cname ()));
93 // output arguments used separately
94 out_arg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
95 // pass GAsyncResult stored in closure to finish function
96 out_arg_map
.set (get_param_pos (0.1), new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "res"));
100 if (m is CreationMethod
) {
101 if (context
.profile
== Profile
.GOBJECT
) {
102 if (!((Class
) m
.parent_symbol
).is_compact
) {
103 ccall
.add_argument (new
CCodeIdentifier ("object_type"));
106 ccall
.add_argument (new
CCodeIdentifier ("self"));
109 foreach (DataType base_type
in current_class
.get_base_types ()) {
110 if (base_type
.data_type is Class
) {
111 add_generic_type_arguments (ccall
, base_type
.get_type_arguments (), expr
, true);
115 } else if (m
!= null && m
.get_type_parameters ().size
> 0) {
117 add_generic_type_arguments (ccall
, ma
.get_type_arguments (), expr
);
120 // the complete call expression, might include casts, comma expressions, and/or assignments
121 CCodeExpression ccall_expr
= ccall
;
123 if (m is ArrayResizeMethod
) {
124 var array_type
= (ArrayType
) ma
.inner
.value_type
;
125 in_arg_map
.set (get_param_pos (0), new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
126 } else if (m is ArrayMoveMethod
) {
127 requires_array_move
= true;
130 CCodeExpression instance
= null;
131 if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& !(m is CreationMethod
)) {
132 instance
= (CCodeExpression
) ma
.inner
.ccodenode
;
134 if (ma
.member_name
== "begin" && ma
.inner
.symbol_reference
== ma
.symbol_reference
) {
135 var inner_ma
= (MemberAccess
) ma
.inner
;
136 instance
= (CCodeExpression
) inner_ma
.inner
.ccodenode
;
139 var st
= m
.parent_symbol as Struct
;
140 if (st
!= null && !st
.is_simple_type ()) {
141 // we need to pass struct instance by reference
142 var unary
= instance as CCodeUnaryExpression
;
143 if (unary
!= null && unary
.operator
== CCodeUnaryOperator
.POINTER_INDIRECTION
) {
145 instance
= unary
.inner
;
146 } else if (instance is CCodeIdentifier
|| instance is CCodeMemberAccess
) {
147 instance
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, instance
);
149 // if instance is e.g. a function call, we can't take the address of the expression
150 // (tmp = expr, &tmp)
151 var ccomma
= new
CCodeCommaExpression ();
153 var temp_var
= get_temp_variable (ma
.inner
.target_type
);
154 temp_vars
.insert (0, temp_var
);
155 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), instance
));
156 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
)));
162 in_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance
);
163 out_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), instance
);
164 } else if (m
!= null && m
.binding
== MemberBinding
.CLASS
) {
165 var cl
= (Class
) m
.parent_symbol
;
166 var cast
= new
CCodeFunctionCall (new
CCodeIdentifier (cl
.get_upper_case_cname (null) + "_CLASS"));
168 CCodeExpression klass
;
169 if (ma
.inner
== null) {
170 if (in_static_or_class_context
) {
171 // Accessing the method from a static or class constructor
172 klass
= new
CCodeIdentifier ("klass");
174 // Accessing the method from within an instance method
175 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
176 k
.add_argument (new
CCodeIdentifier ("self"));
180 // Accessing the method of an instance
181 var k
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_GET_CLASS"));
182 k
.add_argument ((CCodeExpression
) ma
.inner
.ccodenode
);
186 cast
.add_argument (klass
);
187 in_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), cast
);
188 out_arg_map
.set (get_param_pos (m
.cinstance_parameter_position
), cast
);
191 if (m
!= null && m
.has_generic_type_parameter
) {
192 // insert type argument for macros
193 int type_param_index
= 0;
194 foreach (var type_arg
in ma
.inner
.value_type
.get_type_arguments ()) {
195 in_arg_map
.set (get_param_pos (m
.generic_type_parameter_position
+ 0.01 * type_param_index
), new
CCodeIdentifier (type_arg
.get_cname ()));
200 if (m is ArrayMoveMethod
) {
201 var array_type
= (ArrayType
) ma
.inner
.value_type
;
202 var csizeof
= new
CCodeFunctionCall (new
CCodeIdentifier ("sizeof"));
203 csizeof
.add_argument (new
CCodeIdentifier (array_type
.element_type
.get_cname ()));
204 in_arg_map
.set (get_param_pos (0.1), csizeof
);
205 } else if (m is DynamicMethod
) {
206 m
.clear_parameters ();
208 foreach (Expression arg
in expr
.get_argument_list ()) {
209 var unary
= arg as UnaryExpression
;
210 if (unary
!= null && unary
.operator
== UnaryOperator
.OUT
) {
212 var param
= new
FormalParameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
213 param
.direction
= ParameterDirection
.OUT
;
214 m
.add_parameter (param
);
215 } else if (unary
!= null && unary
.operator
== UnaryOperator
.REF
) {
217 var param
= new
FormalParameter ("param%d".printf (param_nr
), unary
.inner
.value_type
);
218 param
.direction
= ParameterDirection
.REF
;
219 m
.add_parameter (param
);
222 m
.add_parameter (new
FormalParameter ("param%d".printf (param_nr
), arg
.value_type
));
226 foreach (FormalParameter param
in m
.get_parameters ()) {
227 param
.accept (codegen
);
229 head
.generate_dynamic_method_wrapper ((DynamicMethod
) m
);
230 } else if (m is CreationMethod
&& context
.profile
== Profile
.GOBJECT
) {
231 ccall_expr
= new
CCodeAssignment (new
CCodeIdentifier ("self"), new
CCodeCastExpression (ccall
, current_class
.get_cname () + "*"));
233 if (!current_class
.is_compact
&& current_class
.get_type_parameters ().size
> 0) {
234 var ccomma
= new
CCodeCommaExpression ();
235 ccomma
.append_expression (ccall_expr
);
237 /* type, dup func, and destroy func fields for generic types */
238 foreach (TypeParameter type_param
in current_class
.get_type_parameters ()) {
239 CCodeIdentifier param_name
;
241 var priv_access
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv");
243 param_name
= new
CCodeIdentifier ("%s_type".printf (type_param
.name
.down ()));
244 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
246 param_name
= new
CCodeIdentifier ("%s_dup_func".printf (type_param
.name
.down ()));
247 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
249 param_name
= new
CCodeIdentifier ("%s_destroy_func".printf (type_param
.name
.down ()));
250 ccomma
.append_expression (new
CCodeAssignment (new CCodeMemberAccess
.pointer (priv_access
, param_name
.name
), param_name
));
257 bool ellipsis
= false;
261 Iterator
<FormalParameter
> params_it
= params
.iterator ();
262 foreach (Expression arg
in expr
.get_argument_list ()) {
263 CCodeExpression cexpr
= (CCodeExpression
) arg
.ccodenode
;
265 var carg_map
= in_arg_map
;
267 if (params_it
.next ()) {
268 var param
= params_it
.get ();
269 ellipsis
= param
.params_array
|| param
.ellipsis
;
271 // if the vala argument expands to multiple C arguments,
272 // we have to make sure that the C arguments don't depend
273 // on each other as there is no guaranteed argument
275 // http://bugzilla.gnome.org/show_bug.cgi?id=519597
276 bool multiple_cargs
= false;
278 if (param
.direction
== ParameterDirection
.OUT
) {
279 carg_map
= out_arg_map
;
282 if (!param
.no_array_length
&& param
.parameter_type is ArrayType
) {
283 var array_type
= (ArrayType
) param
.parameter_type
;
284 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
285 carg_map
.set (get_param_pos (param
.carray_length_parameter_position
+ 0.01 * dim
), head
.get_array_length_cexpression (arg
, dim
));
287 multiple_cargs
= true;
288 } else if (param
.parameter_type is DelegateType
) {
289 var deleg_type
= (DelegateType
) param
.parameter_type
;
290 var d
= deleg_type
.delegate_symbol
;
292 var delegate_target
= get_delegate_target_cexpression (arg
);
293 if (deleg_type
.value_owned
) {
294 CCodeExpression delegate_target_destroy_notify
;
295 var delegate_method
= arg
.symbol_reference as Method
;
296 var lambda
= arg as LambdaExpression
;
297 var arg_ma
= arg as MemberAccess
;
298 if (lambda
!= null) {
299 if (delegate_method
.closure
) {
300 var closure_block
= current_symbol as Block
;
301 while (closure_block
!= null && !closure_block
.captured
) {
302 closure_block
= closure_block
.parent_symbol as Block
;
304 int block_id
= get_block_id (closure_block
);
305 var ref_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("block%d_data_ref".printf (block_id
)));
306 ref_call
.add_argument (delegate_target
);
307 delegate_target
= ref_call
;
308 delegate_target_destroy_notify
= new
CCodeIdentifier ("block%d_data_unref".printf (block_id
));
309 } else if (get_this_type () != null) {
310 // type of delegate target is same as `this'
311 // for lambda expressions in instance methods
312 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (get_this_type (), arg
.source_reference
));
313 ref_call
.add_argument (delegate_target
);
314 delegate_target
= ref_call
;
315 delegate_target_destroy_notify
= get_destroy_func_expression (get_this_type ());
317 delegate_target_destroy_notify
= new
CCodeConstant ("NULL");
319 } else if (delegate_method
!= null && delegate_method
.binding
== MemberBinding
.INSTANCE
320 && arg_ma
!= null && arg_ma
.inner
!= null && arg_ma
.inner
.value_type
.data_type
!= null
321 && arg_ma
.inner
.value_type
.data_type
.is_reference_counting ()) {
322 var ref_call
= new
CCodeFunctionCall (get_dup_func_expression (arg_ma
.inner
.value_type
, arg
.source_reference
));
323 ref_call
.add_argument (delegate_target
);
324 delegate_target
= ref_call
;
325 delegate_target_destroy_notify
= get_destroy_func_expression (arg_ma
.inner
.value_type
);
327 delegate_target_destroy_notify
= new
CCodeConstant ("NULL");
329 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
+ 0.01), delegate_target_destroy_notify
);
331 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), delegate_target
);
332 multiple_cargs
= true;
334 } else if (param
.parameter_type is MethodType
) {
335 carg_map
.set (get_param_pos (param
.cdelegate_target_parameter_position
), get_delegate_target_cexpression (arg
));
336 multiple_cargs
= true;
339 cexpr
= handle_struct_argument (param
, arg
, cexpr
);
341 if (multiple_cargs
&& arg is MethodCall
) {
342 // if vala argument is invocation expression
343 // the auxiliary C argument(s) will depend on the main C argument
345 // (tmp = arg1, call (tmp, arg2, arg3,...))
347 var ccomma
= new
CCodeCommaExpression ();
349 var temp_decl
= get_temp_variable (arg
.value_type
);
350 temp_vars
.insert (0, temp_decl
);
351 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_decl
.name
), cexpr
));
353 cexpr
= get_variable_cexpression (temp_decl
.name
);
355 ccomma
.append_expression (ccall_expr
);
360 // unref old value for non-null non-weak ref/out arguments
361 // disabled for arrays for now as that requires special handling
362 // (ret_tmp = call (&tmp), var1 = (assign_tmp = dup (tmp), free (var1), assign_tmp), ret_tmp)
363 if (param
.direction
!= ParameterDirection
.IN
&& requires_destroy (arg
.value_type
)
364 && (param
.direction
== ParameterDirection
.OUT
|| !param
.parameter_type
.value_owned
)
365 && !(param
.parameter_type is ArrayType
)) {
366 var unary
= (UnaryExpression
) arg
;
368 var ccomma
= new
CCodeCommaExpression ();
370 var temp_var
= get_temp_variable (param
.parameter_type
, param
.parameter_type
.value_owned
);
371 temp_vars
.insert (0, temp_var
);
372 cexpr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_var
.name
));
374 if (param
.direction
== ParameterDirection
.REF
) {
375 var crefcomma
= new
CCodeCommaExpression ();
376 crefcomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), (CCodeExpression
) unary
.inner
.ccodenode
));
377 crefcomma
.append_expression (cexpr
);
382 LocalVariable ret_temp_var
= null;
383 if (itype
.get_return_type () is VoidType
) {
384 ccomma
.append_expression (ccall_expr
);
386 ret_temp_var
= get_temp_variable (itype
.get_return_type ());
387 temp_vars
.insert (0, ret_temp_var
);
388 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (ret_temp_var
.name
), ccall_expr
));
391 var cassign_comma
= new
CCodeCommaExpression ();
393 var assign_temp_var
= get_temp_variable (unary
.inner
.value_type
, unary
.inner
.value_type
.value_owned
);
394 temp_vars
.insert (0, assign_temp_var
);
396 cassign_comma
.append_expression (new
CCodeAssignment (get_variable_cexpression (assign_temp_var
.name
), transform_expression (get_variable_cexpression (temp_var
.name
), param
.parameter_type
, unary
.inner
.value_type
, arg
)));
399 cassign_comma
.append_expression (get_unref_expression ((CCodeExpression
) unary
.inner
.ccodenode
, arg
.value_type
, arg
));
401 cassign_comma
.append_expression (get_variable_cexpression (assign_temp_var
.name
));
404 ccomma
.append_expression (new
CCodeAssignment ((CCodeExpression
) unary
.inner
.ccodenode
, cassign_comma
));
407 if (!(itype
.get_return_type () is VoidType
)) {
408 ccomma
.append_expression (get_variable_cexpression (ret_temp_var
.name
));
414 if (param
.ctype
!= null) {
415 cexpr
= new
CCodeCastExpression (cexpr
, param
.ctype
);
418 arg_pos
= get_param_pos (param
.cparameter_position
, ellipsis
);
420 // default argument position
421 arg_pos
= get_param_pos (i
, ellipsis
);
424 carg_map
.set (arg_pos
, cexpr
);
428 if (params_it
.next ()) {
429 var param
= params_it
.get ();
431 /* if there are more parameters than arguments,
432 * the additional parameter is an ellipsis parameter
433 * otherwise there is a bug in the semantic analyzer
435 assert (param
.params_array
|| param
.ellipsis
);
439 /* add length argument for methods returning arrays */
440 if (m
!= null && m
.return_type is ArrayType
) {
441 var array_type
= (ArrayType
) m
.return_type
;
442 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
443 if (m
.array_null_terminated
) {
444 // handle calls to methods returning null-terminated arrays
445 var temp_var
= get_temp_variable (itype
.get_return_type ());
446 var temp_ref
= get_variable_cexpression (temp_var
.name
);
448 temp_vars
.insert (0, temp_var
);
450 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
452 requires_array_length
= true;
453 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
454 len_call
.add_argument (temp_ref
);
456 expr
.append_array_size (len_call
);
457 } else if (!m
.no_array_length
) {
458 LocalVariable temp_var
;
460 if (m
.array_length_type
== null) {
461 temp_var
= get_temp_variable (int_type
);
463 temp_var
= get_temp_variable (new
CType (m
.array_length_type
));
465 var temp_ref
= get_variable_cexpression (temp_var
.name
);
467 temp_vars
.insert (0, temp_var
);
469 out_arg_map
.set (get_param_pos (m
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
471 expr
.append_array_size (temp_ref
);
473 expr
.append_array_size (new
CCodeConstant ("-1"));
476 } else if (m
!= null && m
.return_type is DelegateType
) {
477 var deleg_type
= (DelegateType
) m
.return_type
;
478 var d
= deleg_type
.delegate_symbol
;
480 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
481 var temp_ref
= get_variable_cexpression (temp_var
.name
);
483 temp_vars
.insert (0, temp_var
);
485 out_arg_map
.set (get_param_pos (m
.cdelegate_target_parameter_position
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
487 expr
.delegate_target
= temp_ref
;
491 // add length argument for delegates returning arrays
492 // TODO: avoid code duplication with methods returning arrays, see above
493 if (deleg
!= null && deleg
.return_type is ArrayType
) {
494 var array_type
= (ArrayType
) deleg
.return_type
;
495 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
496 if (deleg
.array_null_terminated
) {
497 // handle calls to methods returning null-terminated arrays
498 var temp_var
= get_temp_variable (itype
.get_return_type ());
499 var temp_ref
= get_variable_cexpression (temp_var
.name
);
501 temp_vars
.insert (0, temp_var
);
503 ccall_expr
= new
CCodeAssignment (temp_ref
, ccall_expr
);
505 requires_array_length
= true;
506 var len_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("_vala_array_length"));
507 len_call
.add_argument (temp_ref
);
509 expr
.append_array_size (len_call
);
510 } else if (!deleg
.no_array_length
) {
511 var temp_var
= get_temp_variable (int_type
);
512 var temp_ref
= get_variable_cexpression (temp_var
.name
);
514 temp_vars
.insert (0, temp_var
);
516 out_arg_map
.set (get_param_pos (deleg
.carray_length_parameter_position
+ 0.01 * dim
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
518 expr
.append_array_size (temp_ref
);
520 expr
.append_array_size (new
CCodeConstant ("-1"));
523 } else if (deleg
!= null && deleg
.return_type is DelegateType
) {
524 var deleg_type
= (DelegateType
) deleg
.return_type
;
525 var d
= deleg_type
.delegate_symbol
;
527 var temp_var
= get_temp_variable (new
PointerType (new
VoidType ()));
528 var temp_ref
= get_variable_cexpression (temp_var
.name
);
530 temp_vars
.insert (0, temp_var
);
532 out_arg_map
.set (get_param_pos (deleg
.cdelegate_target_parameter_position
), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
534 expr
.delegate_target
= temp_ref
;
538 if (m
!= null && m
.coroutine
) {
539 if (expr
.is_yield_expression
) {
541 in_arg_map
.set (get_param_pos (-1), new
CCodeIdentifier (current_method
.get_cname () + "_ready"));
542 in_arg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("data"));
546 if (m is CreationMethod
&& m
.get_error_types ().size
> 0) {
547 out_arg_map
.set (get_param_pos (-1), new
CCodeIdentifier ("error"));
548 } else if (expr
.tree_can_fail
) {
550 current_method_inner_error
= true;
551 // add &inner_error before the ellipsis arguments
552 out_arg_map
.set (get_param_pos (-1), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression ("_inner_error_")));
556 /* ensure variable argument list ends with NULL
557 * except when using printf-style arguments */
558 if (!m
.printf_format
&& !m
.scanf_format
&& m
.sentinel
!= "") {
559 in_arg_map
.set (get_param_pos (-1, true), new
CCodeConstant (m
.sentinel
));
561 } else if (itype is DelegateType
) {
562 var deleg_type
= (DelegateType
) itype
;
563 var d
= deleg_type
.delegate_symbol
;
565 in_arg_map
.set (get_param_pos (d
.cinstance_parameter_position
), get_delegate_target_cexpression (expr
.call
));
566 out_arg_map
.set (get_param_pos (d
.cinstance_parameter_position
), get_delegate_target_cexpression (expr
.call
));
570 // structs are returned via out parameter
571 bool return_result_via_out_param
= itype
.get_return_type ().is_real_struct_type ();
573 // pass address for the return value of non-void signals without emitter functions
574 if (itype is SignalType
&& !(itype
.get_return_type () is VoidType
)) {
575 var sig
= ((SignalType
) itype
).signal_symbol
;
577 if (ma
!= null && ma
.inner is BaseAccess
&& sig
.is_virtual
) {
578 // normal return value for base access
579 } else if (!sig
.has_emitter
) {
580 return_result_via_out_param
= true;
584 if (return_result_via_out_param
) {
585 var temp_var
= get_temp_variable (itype
.get_return_type ());
586 var temp_ref
= get_variable_cexpression (temp_var
.name
);
588 temp_vars
.insert (0, temp_var
);
590 out_arg_map
.set (get_param_pos (-3, true), new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, temp_ref
));
592 var ccomma
= new
CCodeCommaExpression ();
593 ccomma
.append_expression ((CCodeExpression
) ccall_expr
);
594 ccomma
.append_expression ((CCodeExpression
) temp_ref
);
599 // append C arguments in the right order
604 if (async_call
!= ccall
) {
605 // don't append out arguments for .begin() calls
609 foreach (int pos
in out_arg_map
.get_keys ()) {
610 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
617 ccall
.add_argument (out_arg_map
.get (min_pos
));
622 if (async_call
!= null) {
626 foreach (int pos
in in_arg_map
.get_keys ()) {
627 if (pos
> last_pos
&& (min_pos
== -1 || pos
< min_pos
)) {
634 async_call
.add_argument (in_arg_map
.get (min_pos
));
639 if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
&& m
.returns_modified_pointer
) {
640 expr
.ccodenode
= new
CCodeAssignment (instance
, ccall_expr
);
642 expr
.ccodenode
= ccall_expr
;
645 if (m
!= null && m
.coroutine
&& current_method
!= null && current_method
.coroutine
) {
646 if (ma
.member_name
!= "begin" || ma
.inner
.symbol_reference
!= ma
.symbol_reference
) {
647 if (pre_statement_fragment
== null) {
648 pre_statement_fragment
= new
CCodeFragment ();
650 pre_statement_fragment
.append (new
CCodeExpressionStatement (async_call
));
652 int state
= next_coroutine_state
++;
653 pre_statement_fragment
.append (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "state"), new
CCodeConstant (state
.to_string ()))));
654 pre_statement_fragment
.append (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
655 pre_statement_fragment
.append (new
CCodeCaseStatement (new
CCodeConstant (state
.to_string ())));
659 if (m is ArrayResizeMethod
) {
660 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
661 Iterator
<Expression
> arg_it
= expr
.get_argument_list ().iterator ();
663 var new_size
= (CCodeExpression
) arg_it
.get ().ccodenode
;
665 var temp_decl
= get_temp_variable (int_type
);
666 var temp_ref
= get_variable_cexpression (temp_decl
.name
);
668 temp_vars
.insert (0, temp_decl
);
670 /* memset needs string.h */
671 source_declarations
.add_include ("string.h");
673 var clen
= head
.get_array_length_cexpression (ma
.inner
, 1);
674 var celems
= (CCodeExpression
) ma
.inner
.ccodenode
;
675 var array_type
= (ArrayType
) ma
.inner
.value_type
;
676 var csizeof
= new
CCodeIdentifier ("sizeof (%s)".printf (array_type
.element_type
.get_cname ()));
677 var cdelta
= new
CCodeBinaryExpression (CCodeBinaryOperator
.MINUS
, temp_ref
, clen
);
678 var ccheck
= new
CCodeBinaryExpression (CCodeBinaryOperator
.GREATER_THAN
, temp_ref
, clen
);
680 var czero
= new
CCodeFunctionCall (new
CCodeIdentifier ("memset"));
681 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, celems
, clen
));
682 czero
.add_argument (new
CCodeConstant ("0"));
683 czero
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.MUL
, csizeof
, cdelta
));
685 var ccomma
= new
CCodeCommaExpression ();
686 ccomma
.append_expression (new
CCodeAssignment (temp_ref
, new_size
));
687 ccomma
.append_expression ((CCodeExpression
) expr
.ccodenode
);
688 ccomma
.append_expression (new
CCodeConditionalExpression (ccheck
, czero
, new
CCodeConstant ("NULL")));
689 ccomma
.append_expression (new
CCodeAssignment (head
.get_array_length_cexpression (ma
.inner
, 1), temp_ref
));
691 expr
.ccodenode
= ccomma
;