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 context.analyzer.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 unowned Enum en = (Enum) ma.inner.value_type.type_symbol;
55 ccall.call = new CCodeIdentifier (generate_enum_to_string_function (en));
56 } else if (context.profile == Profile.POSIX && ma.inner != null && ma.inner.value_type != null && ma.inner.value_type.type_symbol == string_type.type_symbol && 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 CCodeExpression? vcast = null;
99 if (m.base_method != null) {
100 unowned Class base_class = (Class) m.base_method.parent_symbol;
101 vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
102 ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
103 } else if (m.base_interface_method != null) {
104 unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
105 vcast = get_this_interface_cexpression (base_iface);
108 async_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m));
109 finish_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m));
111 } else if (m != null && get_ccode_no_wrapper (m) && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
112 var instance_value = ma.inner.target_value;
113 if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) {
114 var inner_ma = (MemberAccess) ma.inner;
115 instance_value = inner_ma.inner.target_value;
118 CCodeExpression? vcast = null;
119 if (m.parent_symbol is Class) {
120 unowned Class base_class = (Class) m.parent_symbol;
121 vcast = get_this_class_cexpression (base_class, instance_value);
122 } else if (m.parent_symbol is Interface) {
123 unowned Interface base_iface = (Interface) m.parent_symbol;
124 vcast = get_this_interface_cexpression (base_iface, instance_value);
127 async_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m));
128 finish_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m));
132 if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
135 params = m.get_async_begin_parameters ();
136 } else if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
139 params = m.get_async_end_parameters ();
140 } else if (!expr.is_yield_expression) {
141 // same as .begin, backwards compatible to bindings without async methods
143 params = m.get_async_begin_parameters ();
146 // output arguments used separately
147 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
148 // pass GAsyncResult stored in closure to finish function
149 out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), get_variable_cexpression ("_res_"));
153 if (m is CreationMethod && m.parent_symbol is Class) {
154 if (context.profile == Profile.GOBJECT) {
155 if (!((Class) m.parent_symbol).is_compact) {
156 ccall.add_argument (get_variable_cexpression ("object_type"));
159 ccall.add_argument (get_this_cexpression ());
162 if (!current_class.is_compact) {
163 int type_param_index = 0;
164 if (current_class != m.parent_symbol) {
165 // chain up to base class
166 foreach (DataType base_type in current_class.get_base_types ()) {
167 if (base_type.type_symbol is Class) {
168 List<TypeParameter> type_parameters = null;
169 if (get_ccode_real_name (m) == "g_object_new") {
170 // gobject-style chainup
171 type_parameters = ((Class) base_type.type_symbol).get_type_parameters ();
172 type_param_index += type_parameters.size;
174 add_generic_type_arguments (m, in_arg_map, base_type.get_type_arguments (), expr, true, type_parameters);
179 // chain up to other constructor in same class
180 var cl = (Class) m.parent_symbol;
181 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
182 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier (get_ccode_type_id (type_param)));
183 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (get_ccode_copy_function (type_param)));
184 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier (get_ccode_destroy_function (type_param)));
188 if (current_class.has_type_parameters () && get_ccode_real_name (m) == "g_object_new") {
189 // gobject-style construction
190 foreach (var type_param in current_class.get_type_parameters ()) {
191 var type_param_name = type_param.name.ascii_down ().replace ("_", "-");
192 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s-type\"".printf (type_param_name)));
193 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (get_ccode_type_id (type_param)));
194 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s-dup-func\"".printf (type_param_name)));
195 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeIdentifier (get_ccode_copy_function (type_param)));
196 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s-destroy-func\"".printf (type_param_name)));
197 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeIdentifier (get_ccode_destroy_function (type_param)));
201 } else if (current_class.is_subtype_of (gsource_type)) {
204 string class_prefix = get_ccode_lower_case_name (current_class);
205 string prepare_func = "NULL";
206 string check_func = "NULL";
207 foreach (Method impl in current_class.get_methods ()) {
208 if (!impl.overrides) {
213 prepare_func = "%s_real_prepare".printf (class_prefix);
216 check_func = "%s_real_check".printf (class_prefix);
223 var funcs = new CCodeDeclaration ("const GSourceFuncs");
224 funcs.modifiers = CCodeModifiers.STATIC;
225 funcs.add_declarator (new CCodeVariableDeclarator ("_source_funcs", new CCodeConstant ("{ %s, %s, %s_real_dispatch, %s_finalize}".printf (prepare_func, check_func, class_prefix, class_prefix))));
226 ccode.add_statement (funcs);
228 ccall.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_source_funcs")), "GSourceFuncs *"));
230 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
231 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (current_class)));
232 ccall.add_argument (csizeof);
233 } else if (current_class.base_class != null && get_ccode_simple_generics (m)) {
234 if (current_class != m.parent_symbol) {
235 foreach (DataType base_type in current_class.get_base_types ()) {
236 if (base_type.type_symbol is Class) {
237 add_generic_type_arguments (m, in_arg_map, base_type.get_type_arguments (), expr);
242 // TODO: simple generics are only supported in bindings.
245 } else if (m is CreationMethod && m.parent_symbol is Struct) {
246 ccall.add_argument (get_this_cexpression ());
247 } else if (m != null && m.has_type_parameters () && !get_ccode_has_generic_type_parameter (m) && !get_ccode_simple_generics (m) && (ccall != finish_call || expr.is_yield_expression)) {
249 // don't add generic arguments for .end() calls
250 add_generic_type_arguments (m, in_arg_map, ma.get_type_arguments (), expr);
253 // the complete call expression, might include casts, comma expressions, and/or assignments
254 CCodeExpression ccall_expr = ccall;
256 if (m is ArrayResizeMethod && context.profile != Profile.POSIX) {
257 var array_type = (ArrayType) ma.inner.value_type;
258 in_arg_map.set (get_param_pos (0), new CCodeIdentifier (get_ccode_name (array_type.element_type)));
259 } else if (m is ArrayMoveMethod) {
260 requires_array_move = true;
261 } else if (m is ArrayCopyMethod) {
262 expr.target_value = copy_value (ma.inner.target_value, expr);
266 CCodeExpression instance = null;
267 if (m != null && m.is_async_callback) {
268 if (current_method.closure) {
269 var block = ((Method) m.parent_symbol).body;
270 instance = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_");
272 instance = new CCodeIdentifier ("_data_");
275 in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
276 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
277 } else if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
278 var instance_value = ma.inner.target_value;
279 if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) {
280 var inner_ma = (MemberAccess) ma.inner;
281 instance_value = inner_ma.inner.target_value;
283 instance = get_cvalue_ (instance_value);
285 var st = m.parent_symbol as Struct;
286 if (st != null && !st.is_simple_type ()) {
287 // we need to pass struct instance by reference
288 if (!get_lvalue (instance_value)) {
289 instance_value = store_temp_value (instance_value, expr);
291 instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
295 in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
296 } else if (expr.is_yield_expression) {
297 in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
298 if (get_ccode_finish_instance (m)) {
299 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
301 } else if (ma.member_name != "end" || get_ccode_finish_instance (m)) {
302 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
303 in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
305 } else if (m != null && m.binding == MemberBinding.CLASS) {
306 unowned Class cl = (Class) m.parent_symbol;
307 var cast = get_this_class_cexpression (cl, ma.inner != null ? ma.inner.target_value : null);
308 in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), cast);
309 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), cast);
312 if (m != null && get_ccode_has_generic_type_parameter (m)) {
313 // insert type argument for macros
314 if (m.has_type_parameters ()) {
316 int type_param_index = 0;
317 foreach (var type_arg in ma.get_type_arguments ()) {
318 // real structs are passed by reference for simple generics
319 if (get_ccode_simple_generics (m) && type_arg.is_real_struct_type () && !type_arg.nullable && !(type_arg is PointerType)) {
320 type_arg = new PointerType (type_arg);
322 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)));
326 // method in generic type
327 int type_param_index = 0;
328 foreach (var type_arg in ma.inner.value_type.get_type_arguments ()) {
329 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)));
335 if (m is ArrayMoveMethod) {
336 var array_type = (ArrayType) ma.inner.value_type;
337 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
338 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
339 in_arg_map.set (get_param_pos (0.1), csizeof);
340 } else if (m is DynamicMethod) {
341 emit_context.push_symbol (m);
342 m.clear_parameters ();
344 foreach (Expression arg in expr.get_argument_list ()) {
345 var unary = arg as UnaryExpression;
346 if (unary != null && unary.operator == UnaryOperator.OUT) {
348 var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
349 param.direction = ParameterDirection.OUT;
350 m.add_parameter (param);
351 } else if (unary != null && unary.operator == UnaryOperator.REF) {
353 var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
354 param.direction = ParameterDirection.REF;
355 m.add_parameter (param);
358 m.add_parameter (new Parameter ("param%d".printf (param_nr), arg.value_type));
362 foreach (Parameter param in m.get_parameters ()) {
365 generate_dynamic_method_wrapper ((DynamicMethod) m);
366 emit_context.pop_symbol ();
367 } else if (m is CreationMethod && context.profile == Profile.GOBJECT && m.parent_symbol is Class) {
368 ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (current_class) + "*"));
370 if (current_method.body.captured) {
371 // capture self after setting it
372 var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), expr.source_reference));
373 ref_call.add_argument (get_this_cexpression ());
375 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method.body))), "self"), ref_call);
378 //FIXME Only needed for non-"g_object_new" calls, if there is no property clash
379 if (!current_class.is_compact && current_class.has_type_parameters ()) {
380 /* type, dup func, and destroy func fields for generic types */
381 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
382 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
383 var type = get_ccode_type_id (type_param);
384 var dup_func = get_ccode_copy_function (type_param);
385 var destroy_func = get_ccode_destroy_function (type_param);
386 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, type), new CCodeIdentifier (type));
387 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, dup_func), new CCodeIdentifier (dup_func));
388 ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, destroy_func), new CCodeIdentifier (destroy_func));
391 // object chainup can't be used as expression
395 bool ellipsis = false;
399 Iterator<Parameter> params_it = params.iterator ();
400 foreach (Expression arg in expr.get_argument_list ()) {
401 CCodeExpression cexpr = get_cvalue (arg);
403 var carg_map = in_arg_map;
405 Parameter? param = null;
406 if (params_it.next ()) {
407 param = params_it.get ();
408 ellipsis = param.params_array || param.ellipsis;
411 if (param != null && !ellipsis) {
412 if (param.direction == ParameterDirection.OUT) {
413 carg_map = out_arg_map;
416 var unary = arg as UnaryExpression;
417 if (unary == null || unary.operator != UnaryOperator.OUT) {
418 if (get_ccode_array_length (param) && param.variable_type is ArrayType && !((ArrayType) param.variable_type).fixed_length) {
419 var array_type = (ArrayType) param.variable_type;
420 var length_ctype = get_ccode_array_length_type (param);
421 if (unary != null && unary.operator == UnaryOperator.REF) {
422 length_ctype = "%s*".printf (length_ctype);
424 for (int dim = 1; dim <= array_type.rank; dim++) {
425 var array_length_expr = new CCodeCastExpression (get_array_length_cexpression (arg, dim), length_ctype);
426 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), array_length_expr);
428 } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
429 var deleg_type = (DelegateType) param.variable_type;
430 if (deleg_type.delegate_symbol.has_target) {
431 CCodeExpression delegate_target_destroy_notify;
432 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
433 assert (delegate_target != null);
434 if (get_ccode_type (param) == "GClosure*") {
435 // one single GClosure parameter
436 var closure_new = new CCodeFunctionCall (new CCodeIdentifier ("g_cclosure_new"));
437 closure_new.add_argument (new CCodeCastExpression (cexpr, "GCallback"));
438 closure_new.add_argument (delegate_target);
439 closure_new.add_argument (new CCodeCastExpression (delegate_target_destroy_notify, "GClosureNotify"));
440 //TODO Use get_non_null (arg.target_value)
441 if (arg.is_non_null ()) {
444 cexpr = new CCodeConditionalExpression (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cexpr, new CCodeConstant ("NULL")), new CCodeConstant ("NULL"), closure_new);
447 // Override previously given target/destroy only if it was NULL
448 // TODO https://gitlab.gnome.org/GNOME/vala/issues/59
449 var node = carg_map.get (get_param_pos (get_ccode_delegate_target_pos (param)));
450 if (node == null || (node is CCodeConstant && ((CCodeConstant) node).name == "NULL")) {
451 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
452 if (deleg_type.is_disposable ()) {
453 assert (delegate_target_destroy_notify != null);
454 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), delegate_target_destroy_notify);
459 } else if (param.variable_type is MethodType) {
460 // callbacks in dynamic method calls
461 CCodeExpression delegate_target_destroy_notify;
462 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), get_delegate_target_cexpression (arg, out delegate_target_destroy_notify));
463 } else if (param.variable_type is GenericType) {
464 if (m != null && get_ccode_simple_generics (m)) {
465 var generic_type = (GenericType) param.variable_type;
466 int type_param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
467 var type_arg = ma.get_type_arguments ().get (type_param_index);
468 if (param.variable_type.value_owned) {
469 if (requires_copy (type_arg)) {
470 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), get_destroy_func_expression (type_arg));
472 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), new CCodeConstant ("NULL"));
478 cexpr = handle_struct_argument (param, arg, cexpr);
480 arg.target_value = null;
482 var temp_var = get_temp_variable (param.variable_type, param.variable_type.value_owned, null, true);
483 emit_temp_var (temp_var);
484 set_cvalue (arg, get_variable_cexpression (temp_var.name));
485 arg.target_value.value_type = arg.target_type;
487 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
489 if (get_ccode_array_length (param) && param.variable_type is ArrayType && !((ArrayType) param.variable_type).fixed_length) {
490 var array_type = (ArrayType) param.variable_type;
491 var length_ctype = get_ccode_array_length_type (param);
492 for (int dim = 1; dim <= array_type.rank; dim++) {
493 var temp_array_length = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
494 emit_temp_var (temp_array_length);
495 append_array_length (arg, get_variable_cexpression (temp_array_length.name));
496 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)));
498 } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
499 var deleg_type = (DelegateType) param.variable_type;
500 if (deleg_type.delegate_symbol.has_target) {
501 temp_var = get_temp_variable (delegate_target_type, true, null, true);
502 emit_temp_var (temp_var);
503 set_delegate_target (arg, get_variable_cexpression (temp_var.name));
504 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target (arg)));
505 if (deleg_type.is_disposable ()) {
506 temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
507 emit_temp_var (temp_var);
508 set_delegate_target_destroy_notify (arg, get_variable_cexpression (temp_var.name));
509 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_destroy_notify (arg)));
515 if (get_ccode_type (param) != null) {
516 cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
519 // ellipsis arguments
520 var unary = arg as UnaryExpression;
521 if (ellipsis && unary != null && unary.operator == UnaryOperator.OUT) {
522 carg_map = out_arg_map;
524 arg.target_value = null;
526 // infer type and ownership from argument expression
527 var temp_var = get_temp_variable (arg.value_type, arg.value_type.value_owned, null, true);
528 emit_temp_var (temp_var);
529 set_cvalue (arg, get_variable_cexpression (temp_var.name));
530 arg.target_value.value_type = arg.value_type;
532 if (arg.value_type is DelegateType && ((DelegateType) arg.value_type).delegate_symbol.has_target) {
533 // Initialize target/destroy cvalues to allow assignment of delegates from varargs
534 unowned GLibValue arg_value = (GLibValue) arg.target_value;
535 if (arg_value.delegate_target_cvalue == null) {
536 arg_value.delegate_target_cvalue = new CCodeConstant ("NULL");
538 if (arg_value.delegate_target_destroy_notify_cvalue == null) {
539 arg_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
543 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
545 cexpr = handle_struct_argument (null, arg, cexpr);
549 if (itype is SignalType && ((SignalType) itype).signal_symbol is DynamicSignal) {
550 arg_pos = get_param_pos (i, false);
552 arg_pos = get_param_pos (param != null && !ellipsis ? get_ccode_pos (param) : i, ellipsis);
554 carg_map.set (arg_pos, cexpr);
556 if (m is ArrayResizeMethod && context.profile == Profile.POSIX) {
557 var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (((ArrayType) ma.inner.value_type).element_type)));
558 carg_map.set (arg_pos, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cexpr));
560 carg_map.set (arg_pos, cexpr);
563 if (arg is NamedArgument && ellipsis) {
564 var named_arg = (NamedArgument) arg;
565 string name = string.joinv ("-", named_arg.name.split ("_"));
566 carg_map.set (get_param_pos (i - 0.1, ellipsis), new CCodeConstant ("\"%s\"".printf (name)));
571 if (params_it.next ()) {
572 var param = params_it.get ();
574 /* if there are more parameters than arguments,
575 * the additional parameter is an ellipsis parameter
576 * otherwise there is a bug in the semantic analyzer
578 assert (param.params_array || param.ellipsis);
582 /* add length argument for methods returning arrays */
583 if (m != null && m.return_type is ArrayType && async_call != ccall) {
584 var array_type = (ArrayType) m.return_type;
585 for (int dim = 1; dim <= array_type.rank; dim++) {
586 if (get_ccode_array_null_terminated (m)) {
587 // handle calls to methods returning null-terminated arrays
588 var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
589 var temp_ref = get_variable_cexpression (temp_var.name);
591 emit_temp_var (temp_var);
593 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
595 requires_array_length = true;
596 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
597 len_call.add_argument (temp_ref);
599 append_array_length (expr, len_call);
600 } else if (get_ccode_array_length (m)) {
601 var length_ctype = get_ccode_array_length_type (m);
602 var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
603 var temp_ref = get_variable_cexpression (temp_var.name);
605 emit_temp_var (temp_var);
607 out_arg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
609 append_array_length (expr, temp_ref);
610 } else if (get_ccode_array_length_expr (m) != null) {
611 append_array_length (expr, new CCodeConstant (get_ccode_array_length_expr (m)));
613 append_array_length (expr, new CCodeConstant ("-1"));
616 } else if (m != null && m.return_type is DelegateType && async_call != ccall) {
617 var deleg_type = (DelegateType) m.return_type;
618 if (get_ccode_delegate_target (m) && deleg_type.delegate_symbol.has_target) {
619 var temp_var = get_temp_variable (delegate_target_type, true, null, true);
620 var temp_ref = get_variable_cexpression (temp_var.name);
622 emit_temp_var (temp_var);
624 out_arg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
626 set_delegate_target (expr, temp_ref);
628 if (deleg_type.is_disposable ()) {
629 temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
630 temp_ref = get_variable_cexpression (temp_var.name);
632 emit_temp_var (temp_var);
634 out_arg_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
636 set_delegate_target_destroy_notify (expr, temp_ref);
638 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
641 set_delegate_target (expr, new CCodeConstant ("NULL"));
642 if (deleg_type.delegate_symbol.has_target) {
643 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
648 // add length argument for delegates returning arrays
649 // TODO: avoid code duplication with methods returning arrays, see above
650 if (deleg != null && deleg.return_type is ArrayType) {
651 var array_type = (ArrayType) deleg.return_type;
652 for (int dim = 1; dim <= array_type.rank; dim++) {
653 if (get_ccode_array_null_terminated (deleg)) {
654 // handle calls to methods returning null-terminated arrays
655 var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
656 var temp_ref = get_variable_cexpression (temp_var.name);
658 emit_temp_var (temp_var);
660 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
662 requires_array_length = true;
663 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
664 len_call.add_argument (temp_ref);
666 append_array_length (expr, len_call);
667 } else if (get_ccode_array_length (deleg)) {
668 var length_ctype = get_ccode_array_length_type (deleg);
669 var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
670 var temp_ref = get_variable_cexpression (temp_var.name);
672 emit_temp_var (temp_var);
674 out_arg_map.set (get_param_pos (get_ccode_array_length_pos (deleg) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
676 append_array_length (expr, temp_ref);
678 append_array_length (expr, new CCodeConstant ("-1"));
681 } else if (deleg != null && deleg.return_type is DelegateType && get_ccode_delegate_target (deleg)) {
682 var deleg_type = (DelegateType) deleg.return_type;
683 if (deleg_type.delegate_symbol.has_target) {
684 var temp_var = get_temp_variable (delegate_target_type, true, null, true);
685 var temp_ref = get_variable_cexpression (temp_var.name);
687 emit_temp_var (temp_var);
689 out_arg_map.set (get_param_pos (get_ccode_delegate_target_pos (deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
691 set_delegate_target (expr, temp_ref);
693 if (deleg_type.is_disposable ()) {
694 temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
695 temp_ref = get_variable_cexpression (temp_var.name);
697 emit_temp_var (temp_var);
699 out_arg_map.set (get_param_pos (get_ccode_destroy_notify_pos (deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
701 set_delegate_target_destroy_notify (expr, temp_ref);
706 if (m != null && m.coroutine) {
707 if (expr.is_yield_expression) {
709 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
710 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
714 if (expr.tree_can_fail) {
716 current_method_inner_error = true;
717 // add &inner_error before the ellipsis arguments
718 out_arg_map.set (get_param_pos (get_ccode_error_pos ((Callable) m ?? deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
719 } else if (m != null && m.has_error_type_parameter () && async_call != ccall) {
720 // inferred error argument from base method
721 out_arg_map.set (get_param_pos (get_ccode_error_pos (m)), new CCodeConstant ("NULL"));
725 /* ensure variable argument list ends with NULL
726 * except when using printf-style arguments */
727 if (itype is SignalType) {
728 // g_signal_emit*() does not require more
729 } else if (m == null) {
730 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
731 } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "" && !expr.is_constructv_chainup) {
732 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
736 if (deleg != null && deleg.has_target) {
737 CCodeExpression delegate_target_destroy_notify;
738 in_arg_map.set (get_param_pos (get_ccode_instance_pos (deleg)), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
739 out_arg_map.set (get_param_pos (get_ccode_instance_pos (deleg)), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
742 // structs are returned via out parameter
743 bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type ();
745 // pass address for the return value of non-void signals without emitter functions
746 if (itype is SignalType && !(itype.get_return_type () is VoidType)) {
747 var sig = ((SignalType) itype).signal_symbol;
749 if (ma != null && ma.inner is BaseAccess && sig.is_virtual) {
750 // normal return value for base access
751 } else if (!get_ccode_has_emitter (sig) || ma.source_reference.file == sig.source_reference.file) {
752 return_result_via_out_param = true;
756 if (async_call == ccall) {
757 // skip out parameter for .begin() calls
758 return_result_via_out_param = false;
761 CCodeExpression out_param_ref = null;
763 if (return_result_via_out_param) {
764 var out_param_var = get_temp_variable (itype.get_return_type (), true, null, true);
765 out_param_ref = get_variable_cexpression (out_param_var.name);
766 emit_temp_var (out_param_var);
767 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, out_param_ref));
770 // append C arguments in the right order
775 if (async_call != ccall) {
776 // don't append out arguments for .begin() calls
780 foreach (int pos in out_arg_map.get_keys ()) {
781 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
788 ccall.add_argument (out_arg_map.get (min_pos));
793 if (async_call != null) {
797 foreach (int pos in in_arg_map.get_keys ()) {
798 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
805 async_call.add_argument (in_arg_map.get (min_pos));
810 if (expr.is_yield_expression) {
811 // set state before calling async function to support immediate callbacks
812 int state = emit_context.next_coroutine_state++;
814 ccode.add_assignment (get_variable_cexpression ("_state_"), new CCodeConstant (state.to_string ()));
815 ccode.add_expression (async_call);
816 ccode.add_return (new CCodeConstant ("FALSE"));
817 ccode.add_label ("_state_%d".printf (state));
820 if (expr.is_assert) {
821 string message = ((string) expr.source_reference.begin.pos).substring (0, (int) (expr.source_reference.end.pos - expr.source_reference.begin.pos));
822 ccall.call = new CCodeIdentifier ("_vala_assert");
823 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
824 requires_assert = true;
828 // Transform and add free function argument to GLib.[List,Queue,SList].remove[_all] calls
829 unowned DataType? collection_type = null;
830 if (ma != null && ma.inner != null) {
831 collection_type = ma.inner.value_type;
833 if (collection_type != null
834 && (collection_type.type_symbol == glist_type || collection_type.type_symbol == gslist_type || collection_type.type_symbol == gqueue_type)
835 && (ma.member_name == "remove" || ma.member_name == "remove_all")
836 //FIXME Perform stricter type argument check earlier
837 && collection_type.check_type_arguments (context)) {
838 var remove_method = (Method) collection_type.type_symbol.scope.lookup (ma.member_name + "_full");
839 var type_arg = collection_type.get_type_arguments ()[0];
840 if (remove_method != null && requires_destroy (type_arg)) {
841 // only add them once per source file
842 if (add_generated_external_symbol (remove_method)) {
843 visit_method (remove_method);
845 ccall.call = new CCodeIdentifier (get_ccode_name (remove_method));
846 ccall.add_argument (get_destroy0_func_expression (type_arg));
850 if (return_result_via_out_param) {
851 ccode.add_expression (ccall_expr);
852 ccall_expr = out_param_ref;
855 if (m != null && m.binding == MemberBinding.INSTANCE && m.returns_modified_pointer) {
856 if (ma != null && ma.inner.symbol_reference is Property && ma.inner is MemberAccess) {
857 var prop = (Property) ma.inner.symbol_reference;
858 store_property (prop, ((MemberAccess) ma.inner).inner, new GLibValue (expr.value_type, ccall_expr));
861 ccall_expr = new CCodeAssignment (instance, ccall_expr);
865 // real structs are passed by reference for simple generics
866 if (m != null && get_ccode_simple_generics (m) && m.return_type is GenericType
867 && expr.value_type.is_real_struct_type () && !expr.value_type.nullable && !(expr.value_type is PointerType)) {
868 ccall_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeParenthesizedExpression (ccall_expr));
871 if (m != null && get_ccode_type (m) != null && get_ccode_type (m) != get_ccode_name (m.return_type)) {
872 // Bug 699956: Implement cast for method return type if [CCode type=] annotation is specified
873 ccall_expr = new CCodeCastExpression (ccall_expr, get_ccode_name (m.return_type));
876 if (m is ArrayResizeMethod) {
877 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
878 Iterator<Expression> arg_it = expr.get_argument_list ().iterator ();
880 var new_size = get_cvalue (arg_it.get ());
882 var array_type = (ArrayType) ma.inner.value_type;
883 var temp_decl = get_temp_variable (array_type.length_type);
884 var temp_ref = get_variable_cexpression (temp_decl.name);
886 emit_temp_var (temp_decl);
888 /* memset needs string.h */
889 cfile.add_include ("string.h");
891 var clen = get_array_length_cexpression (ma.inner, 1);
892 var celems = get_cvalue (ma.inner);
893 var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (array_type.element_type)));
894 var cdelta = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen);
895 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
897 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
898 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
899 czero.add_argument (new CCodeConstant ("0"));
900 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
902 ccode.add_assignment (temp_ref, new_size);
903 ccode.add_expression (ccall_expr);
904 ccode.add_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
905 ccode.add_assignment (get_array_length_cexpression (ma.inner, 1), temp_ref);
907 var array_var = ma.inner.symbol_reference;
908 if (array_var != null && array_var.is_internal_symbol ()
909 && (array_var is LocalVariable || array_var is Field)) {
910 ccode.add_assignment (get_array_size_cvalue (ma.inner.target_value), temp_ref);
916 if (expr.parent_node is ExpressionStatement && !expr.value_type.is_disposable ()) {
917 if (ccall_expr != null && !return_result_via_out_param) {
918 ccode.add_expression (ccall_expr);
921 var result_type = itype.get_return_type ();
923 if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
924 var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
925 var st = type_parameter.parent_symbol.parent_symbol as Struct;
926 if (type_parameter.parent_symbol == garray_type ||
927 (st != null && get_ccode_name (st) == "va_list")) {
928 // GArray and va_list don't use pointer-based generics
929 // above logic copied from visit_expression ()
930 // TODO avoid code duplication
931 result_type = expr.value_type;
933 if (st != null && get_ccode_name (st) == "va_list" && ma.member_name == "arg") {
934 if (result_type is DelegateType && ((DelegateType) result_type).delegate_symbol.has_target) {
935 set_cvalue (expr, null);
936 // Initialize target/destroy cvalues to allow assignment of delegates from varargs
937 unowned GLibValue arg_value = (GLibValue) expr.target_value;
938 if (arg_value.delegate_target_cvalue == null) {
939 arg_value.delegate_target_cvalue = new CCodeConstant ("NULL");
941 if (arg_value.delegate_target_destroy_notify_cvalue == null) {
942 arg_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
948 if (m != null && m.get_format_arg_index () >= 0) {
949 set_cvalue (expr, ccall_expr);
950 } else if (m != null && m.get_attribute_bool ("CCode", "use_inplace", false)) {
951 set_cvalue (expr, ccall_expr);
952 } else if (!return_result_via_out_param
953 && !has_ref_out_argument (expr)
954 && (result_type is ValueType && !result_type.is_disposable ())) {
955 set_cvalue (expr, ccall_expr);
956 } else if (!return_result_via_out_param) {
957 var temp_var = get_temp_variable (result_type, result_type.value_owned, null, false);
958 var temp_ref = get_variable_cexpression (temp_var.name);
960 emit_temp_var (temp_var);
962 ccode.add_assignment (temp_ref, ccall_expr);
963 set_cvalue (expr, temp_ref);
964 ((GLibValue) expr.target_value).lvalue = true;
966 set_cvalue (expr, ccall_expr);
967 ((GLibValue) expr.target_value).lvalue = true;
971 params_it = params.iterator ();
972 foreach (Expression arg in expr.get_argument_list ()) {
973 Parameter param = null;
975 if (params_it.next ()) {
976 param = params_it.get ();
979 var unary = arg as UnaryExpression;
981 // update possible stale _*_size_ variable
982 if (unary != null && unary.operator == UnaryOperator.REF) {
983 if (param != null && get_ccode_array_length (param) && param.variable_type is ArrayType
984 && !((ArrayType) param.variable_type).fixed_length && ((ArrayType) param.variable_type).rank == 1) {
985 unowned Variable? array_var = unary.inner.symbol_reference as Variable;
986 if ((array_var is LocalVariable || array_var is Field) && array_var.is_internal_symbol ()
987 && array_var.variable_type is ArrayType && !((ArrayType) array_var.variable_type).fixed_length) {
988 ccode.add_assignment (get_array_size_cvalue (unary.inner.target_value), get_array_length_cvalue (unary.inner.target_value, 1));
993 if (unary == null || unary.operator != UnaryOperator.OUT) {
997 if (requires_destroy (unary.inner.value_type)) {
999 ccode.add_expression (destroy_value (unary.inner.target_value));
1002 // infer type of out-parameter from argument
1003 if (ma.symbol_reference is DynamicMethod && unary.target_value.value_type == null) {
1004 unary.target_value.value_type = unary.inner.value_type.copy ();
1008 store_value (unary.inner.target_value, transform_value (unary.target_value, unary.inner.value_type, arg), expr.source_reference);
1010 // handle out null terminated arrays
1011 if (param != null && get_ccode_array_null_terminated (param)) {
1012 requires_array_length = true;
1013 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1014 len_call.add_argument (get_cvalue_ (unary.inner.target_value));
1016 ccode.add_assignment (get_array_length_cvalue (unary.inner.target_value, 1), len_call);
1020 if (m is CreationMethod && m.parent_symbol is Class && ((current_class.is_compact && current_class.base_class != null) || current_class.is_subtype_of (gsource_type))) {
1021 var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (current_class, null))));
1022 cinitcall.add_argument (get_this_cexpression ());
1023 if (!current_class.is_compact) {
1024 cinitcall.add_argument (new CCodeConstant ("NULL"));
1026 ccode.add_expression (cinitcall);
1030 private string generate_enum_to_string_function (Enum en) {
1031 var to_string_func = "_%s_to_string".printf (get_ccode_lower_case_name (en));
1033 if (!add_wrapper (to_string_func)) {
1034 // wrapper already defined
1035 return to_string_func;
1039 var function = new CCodeFunction (to_string_func, "const char*");
1040 function.modifiers = CCodeModifiers.STATIC;
1042 function.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
1045 push_context (new EmitContext ());
1046 push_function (function);
1048 ccode.open_switch (new CCodeConstant ("value"));
1049 foreach (var enum_value in en.get_values ()) {
1050 ccode.add_case (new CCodeIdentifier (get_ccode_name (enum_value)));
1051 ccode.add_return (new CCodeConstant ("\""+get_ccode_name (enum_value)+"\""));
1054 ccode.add_return (new CCodeConstant ("NULL"));
1057 cfile.add_function_declaration (function);
1058 cfile.add_function (function);
1062 return to_string_func;
1065 bool has_ref_out_argument (MethodCall c) {
1066 foreach (var arg in c.get_argument_list ()) {
1067 unowned UnaryExpression? unary = arg as UnaryExpression;
1068 if (unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) {
1075 string generate_string_printf_function () {
1076 if (!add_wrapper ("string_printf")) {
1077 // wrapper already defined
1078 return "string_printf";
1082 var function = new CCodeFunction ("string_printf", "char*");
1083 function.add_parameter (new CCodeParameter ("format", "const char*"));
1084 function.add_parameter (new CCodeParameter.with_ellipsis ());
1085 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.PRINTF;
1088 push_context (new EmitContext ());
1089 push_function (function);
1091 ccode.add_declaration ("int", new CCodeVariableDeclarator ("length"));
1092 ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("ap"));
1093 ccode.add_declaration ("char*", new CCodeVariableDeclarator ("result"));
1095 var vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1096 vastart.add_argument (new CCodeIdentifier ("ap"));
1097 vastart.add_argument (new CCodeIdentifier ("format"));
1099 ccode.add_expression (vastart);
1101 if (context.profile == Profile.POSIX) {
1102 cfile.add_include ("stdio.h");
1105 var vsnprintf = new CCodeFunctionCall (new CCodeIdentifier ("vsnprintf"));
1106 vsnprintf.add_argument (new CCodeConstant ("NULL"));
1107 vsnprintf.add_argument (new CCodeConstant ("0"));
1108 vsnprintf.add_argument (new CCodeIdentifier ("format"));
1109 vsnprintf.add_argument (new CCodeIdentifier ("ap"));
1111 ccode.add_assignment (new CCodeIdentifier ("length"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, vsnprintf, new CCodeConstant ("1")));
1113 var va_end = new CCodeFunctionCall (new CCodeIdentifier ("va_end"));
1114 va_end.add_argument (new CCodeIdentifier ("ap"));
1116 ccode.add_expression (va_end);
1118 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
1119 malloc.add_argument (new CCodeIdentifier ("length"));
1121 ccode.add_assignment (new CCodeIdentifier ("result"), malloc);
1123 vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1124 vastart.add_argument (new CCodeIdentifier ("ap"));
1125 vastart.add_argument (new CCodeIdentifier ("format"));
1127 ccode.add_expression (vastart);
1129 vsnprintf = new CCodeFunctionCall (new CCodeIdentifier ("vsnprintf"));
1130 vsnprintf.add_argument (new CCodeIdentifier ("result"));
1131 vsnprintf.add_argument (new CCodeIdentifier ("length"));
1132 vsnprintf.add_argument (new CCodeIdentifier ("format"));
1133 vsnprintf.add_argument (new CCodeIdentifier ("ap"));
1135 ccode.add_expression (vsnprintf);
1137 va_end = new CCodeFunctionCall (new CCodeIdentifier ("va_end"));
1138 va_end.add_argument (new CCodeIdentifier ("ap"));
1140 ccode.add_expression (va_end);
1142 ccode.add_return (new CCodeIdentifier ("result"));
1145 cfile.add_include ("stdarg.h");
1146 cfile.add_function_declaration (function);
1147 cfile.add_function (function);
1151 return "string_printf";