1 /* valagasyncmodule.vala
3 * Copyright (C) 2008-2012 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
25 public class Vala.GAsyncModule : GtkModule {
26 CCodeStruct generate_data_struct (Method m) {
27 string dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
28 var data = new CCodeStruct ("_" + dataname);
30 data.add_field ("int", "_state_");
31 data.add_field ("GObject*", "_source_object_");
32 data.add_field ("GAsyncResult*", "_res_");
33 data.add_field ("GTask*", "_async_result");
35 if (m is CreationMethod) {
36 data.add_field ("GType", "object_type");
39 if (m.binding == MemberBinding.INSTANCE) {
40 var type_sym = (TypeSymbol) m.parent_symbol;
41 if (type_sym is ObjectTypeSymbol) {
42 data.add_field (get_ccode_name (type_sym) + "*", "self");
44 data.add_field (get_ccode_name (type_sym), "self");
48 foreach (Parameter param in m.get_parameters ()) {
49 var param_type = param.variable_type.copy ();
50 param_type.value_owned = true;
51 data.add_field (get_ccode_name (param_type), get_ccode_name (param), 0, get_ccode_declarator_suffix (param_type));
53 if (param.variable_type is ArrayType) {
54 var array_type = (ArrayType) param.variable_type;
55 if (get_ccode_array_length (param) && !((ArrayType) array_type).fixed_length) {
56 var length_ctype = get_ccode_array_length_type (param);
57 for (int dim = 1; dim <= array_type.rank; dim++) {
58 data.add_field (length_ctype, get_variable_array_length_cname (param, dim));
61 } else if (param.variable_type is DelegateType) {
62 var deleg_type = (DelegateType) param.variable_type;
63 if (deleg_type.delegate_symbol.has_target) {
64 data.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (param));
65 if (deleg_type.is_disposable ()) {
66 data.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (param));
72 foreach (var type_param in m.get_type_parameters ()) {
73 data.add_field ("GType", get_ccode_type_id (type_param));
74 data.add_field ("GBoxedCopyFunc", get_ccode_copy_function (type_param));
75 data.add_field ("GDestroyNotify", get_ccode_destroy_function (type_param));
78 if (!(m.return_type is VoidType)) {
79 data.add_field (get_ccode_name (m.return_type), "result");
80 if (m.return_type is ArrayType) {
81 var array_type = (ArrayType) m.return_type;
82 if (get_ccode_array_length (m)) {
83 var length_ctype = get_ccode_array_length_type (m);
84 for (int dim = 1; dim <= array_type.rank; dim++) {
85 data.add_field (length_ctype, get_array_length_cname ("result", dim));
88 } else if (m.return_type is DelegateType) {
89 var deleg_type = (DelegateType) m.return_type;
90 if (deleg_type.delegate_symbol.has_target) {
91 data.add_field (get_ccode_name (delegate_target_type), get_delegate_target_cname ("result"));
92 data.add_field (get_ccode_name (delegate_target_destroy_type), get_delegate_target_destroy_notify_cname ("result"));
100 CCodeFunction generate_free_function (Method m) {
101 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
103 var freefunc = new CCodeFunction (get_ccode_real_name (m) + "_data_free", "void");
104 freefunc.modifiers = CCodeModifiers.STATIC;
105 freefunc.add_parameter (new CCodeParameter ("_data", "gpointer"));
107 push_context (new EmitContext (m));
108 push_function (freefunc);
110 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_", new CCodeIdentifier ("_data")));
112 foreach (Parameter param in m.get_parameters ()) {
113 if (!param.captured && param.direction != ParameterDirection.OUT) {
114 var param_type = param.variable_type.copy ();
115 if (!param_type.value_owned) {
116 param_type.value_owned = !no_implicit_copy (param_type);
119 if (requires_destroy (param_type)) {
120 ccode.add_expression (destroy_parameter (param));
125 if (requires_destroy (m.return_type)) {
126 if (get_ccode_array_length (m) || !(m.return_type is ArrayType)) {
127 /* this is very evil. */
128 var v = new LocalVariable (m.return_type, ".result");
129 ccode.add_expression (destroy_local (v));
131 var v = new GLibValue (m.return_type, new CCodeIdentifier ("_data_->result"), true);
132 v.array_null_terminated = get_ccode_array_null_terminated (m);
133 ccode.add_expression (destroy_value (v));
137 if (m.binding == MemberBinding.INSTANCE) {
138 var this_type = m.this_parameter.variable_type.copy ();
139 this_type.value_owned = true;
141 if (requires_destroy (this_type)) {
142 ccode.add_expression (destroy_parameter (m.this_parameter));
146 var freecall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
147 freecall.add_argument (new CCodeIdentifier (dataname));
148 freecall.add_argument (new CCodeIdentifier ("_data_"));
149 ccode.add_expression (freecall);
153 cfile.add_function_declaration (freefunc);
154 cfile.add_function (freefunc);
159 void generate_async_function (Method m) {
160 push_context (new EmitContext ());
162 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
163 var asyncfunc = new CCodeFunction (get_ccode_real_name (m), "void");
164 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
166 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
167 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
169 generate_cparameters (m, cfile, cparam_map, asyncfunc, null, null, null, 1);
171 if (m.base_method != null || m.base_interface_method != null) {
172 // declare *_real_* function
173 asyncfunc.modifiers |= CCodeModifiers.STATIC;
174 cfile.add_function_declaration (asyncfunc);
175 } else if (m.is_private_symbol ()) {
176 asyncfunc.modifiers |= CCodeModifiers.STATIC;
177 } else if (context.hide_internal && m.is_internal_symbol ()) {
178 asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
181 push_function (asyncfunc);
183 // FIXME partial code duplication with CCodeMethodModule.visit_method
184 unowned Class? cl = m.parent_symbol as Class;
186 if (m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)
187 && m.base_method == null && m.base_interface_method == null) {
188 create_type_check_statement (m, new VoidType (), cl, true, "self");
191 foreach (Parameter param in m.get_parameters ()) {
192 if (param.ellipsis || param.params_array) {
196 if (param.direction == ParameterDirection.IN) {
197 unowned TypeSymbol? t = param.variable_type.type_symbol;
198 if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) {
199 create_type_check_statement (m, new VoidType (), t, !param.variable_type.nullable, get_ccode_name (param));
204 // logic copied from valaccodemethodmodule
205 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
208 if (m.overrides && m.base_method != null) {
209 base_method = m.base_method;
211 base_method = m.base_interface_method;
214 var base_expression_type = new ObjectType ((ObjectTypeSymbol) base_method.parent_symbol);
215 var type_symbol = m.parent_symbol as ObjectTypeSymbol;
217 var self_target_type = new ObjectType (type_symbol);
218 var cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
219 ccode.add_declaration ("%s *".printf (get_ccode_name (type_symbol)), new CCodeVariableDeclarator ("self"));
220 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
223 var dataalloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
224 dataalloc.add_argument (new CCodeIdentifier (dataname));
226 var data_var = new CCodeIdentifier ("_data_");
228 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
229 ccode.add_assignment (data_var, dataalloc);
231 var create_result = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new"));
233 var t = m.parent_symbol as TypeSymbol;
234 if (!(m is CreationMethod) && m.binding == MemberBinding.INSTANCE &&
235 t != null && t.is_subtype_of (gobject_type)) {
236 var gobject_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
237 gobject_cast.add_argument (new CCodeIdentifier ("self"));
239 create_result.add_argument (gobject_cast);
241 create_result.add_argument (new CCodeConstant ("NULL"));
244 Parameter cancellable_param = null;
246 foreach (Parameter param in m.get_parameters ()) {
247 if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
248 cancellable_param = param;
253 if (cancellable_param == null) {
254 create_result.add_argument (new CCodeConstant ("NULL"));
256 create_result.add_argument (new CCodeIdentifier (get_ccode_name (cancellable_param)));
259 create_result.add_argument (new CCodeIdentifier ("_callback_"));
260 create_result.add_argument (new CCodeIdentifier ("_user_data_"));
262 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_async_result"), create_result);
264 var attach_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_set_task_data"));
266 attach_data_call.add_argument (new CCodeMemberAccess.pointer (data_var, "_async_result"));
267 attach_data_call.add_argument (data_var);
268 attach_data_call.add_argument (new CCodeIdentifier (get_ccode_real_name (m) + "_data_free"));
269 ccode.add_expression (attach_data_call);
271 if (m is CreationMethod) {
272 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "object_type"), new CCodeIdentifier ("object_type"));
273 } else if (m.binding == MemberBinding.INSTANCE) {
274 var this_type = m.this_parameter.variable_type.copy ();
275 this_type.value_owned = true;
277 // create copy if necessary as variables in async methods may need to be kept alive
278 CCodeExpression cself = new CCodeIdentifier ("self");
279 if (this_type.is_real_non_null_struct_type ()) {
280 cself = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cself);
282 if (requires_copy (this_type)) {
283 cself = get_cvalue_ (copy_value (new GLibValue (m.this_parameter.variable_type, cself, true), m.this_parameter));
286 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), cself);
289 emit_context.push_symbol (m);
290 foreach (Parameter param in m.get_parameters ()) {
291 if (param.direction != ParameterDirection.OUT) {
292 // create copy if necessary as variables in async methods may need to be kept alive
293 var old_captured = param.captured;
294 param.captured = false;
295 current_method.coroutine = false;
298 if (param.variable_type.value_owned) {
299 // do not use load_parameter for reference/ownership transfer
300 // otherwise delegate destroy notify will not be moved
301 value = get_parameter_cvalue (param);
303 value = load_parameter (param);
306 current_method.coroutine = true;
308 store_parameter (param, value);
310 param.captured = old_captured;
313 emit_context.pop_symbol ();
315 foreach (var type_param in m.get_type_parameters ()) {
316 var type = get_ccode_type_id (type_param);
317 var dup_func = get_ccode_copy_function (type_param);
318 var destroy_func = get_ccode_destroy_function (type_param);
319 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, type), new CCodeIdentifier (type));
320 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, dup_func), new CCodeIdentifier (dup_func));
321 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, destroy_func), new CCodeIdentifier (destroy_func));
324 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
325 ccall.add_argument (data_var);
326 ccode.add_expression (ccall);
328 cfile.add_function (asyncfunc);
333 public void append_struct (CCodeStruct structure) {
334 var typename = new CCodeVariableDeclarator (structure.name.substring (1));
335 var typedef = new CCodeTypeDefinition ("struct " + structure.name, typename);
336 cfile.add_type_declaration (typedef);
337 cfile.add_type_definition (structure);
340 public override bool generate_method_declaration (Method m, CCodeFile decl_space) {
342 if ((m.is_abstract || m.is_virtual) && get_ccode_no_wrapper (m)) {
345 if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
349 generate_type_declaration (new MethodType (m), decl_space);
351 var cl = m.parent_symbol as Class;
353 var asyncfunc = new CCodeFunction (get_ccode_name (m), "void");
354 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
355 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
357 if (m.is_private_symbol () || m.entry_point) {
358 asyncfunc.modifiers |= CCodeModifiers.STATIC;
359 } else if (context.hide_internal && m.is_internal_symbol ()) {
360 asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
362 asyncfunc.modifiers |= CCodeModifiers.EXTERN;
363 requires_vala_extern = true;
366 // do not generate _new functions for creation methods of abstract classes
367 if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
368 generate_cparameters (m, decl_space, cparam_map, asyncfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 1);
370 decl_space.add_function_declaration (asyncfunc);
373 var finishfunc = new CCodeFunction (get_ccode_finish_name (m));
374 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
375 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
377 if (m.is_private_symbol () || m.entry_point) {
378 finishfunc.modifiers |= CCodeModifiers.STATIC;
379 } else if (context.hide_internal && m.is_internal_symbol ()) {
380 finishfunc.modifiers |= CCodeModifiers.INTERNAL;
382 finishfunc.modifiers |= CCodeModifiers.EXTERN;
383 requires_vala_extern = true;
386 // do not generate _new functions for creation methods of abstract classes
387 if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
388 generate_cparameters (m, decl_space, cparam_map, finishfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 2);
390 decl_space.add_function_declaration (finishfunc);
393 if (m is CreationMethod && cl != null) {
394 // _construct function
395 var function = new CCodeFunction (get_ccode_real_name (m));
397 if (m.is_private_symbol ()) {
398 function.modifiers |= CCodeModifiers.STATIC;
399 } else if (context.hide_internal && m.is_internal_symbol ()) {
400 function.modifiers |= CCodeModifiers.INTERNAL;
402 function.modifiers |= CCodeModifiers.EXTERN;
403 requires_vala_extern = true;
406 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
407 generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 1);
409 decl_space.add_function_declaration (function);
411 function = new CCodeFunction (get_ccode_finish_real_name (m));
413 if (m.is_private_symbol ()) {
414 function.modifiers |= CCodeModifiers.STATIC;
415 } else if (context.hide_internal && m.is_internal_symbol ()) {
416 function.modifiers |= CCodeModifiers.INTERNAL;
418 function.modifiers |= CCodeModifiers.EXTERN;
419 requires_vala_extern = true;
422 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
423 generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 2);
425 decl_space.add_function_declaration (function);
430 return base.generate_method_declaration (m, decl_space);
434 public override void visit_method (Method m) {
436 cfile.add_include ("gio/gio.h");
437 if (!m.is_internal_symbol ()) {
438 header_file.add_include ("gio/gio.h");
441 if (!m.is_abstract && m.body != null) {
442 var data = generate_data_struct (m);
444 closure_struct = data;
446 generate_free_function (m);
447 generate_async_function (m);
448 generate_finish_function (m);
450 // append the _co function
451 base.visit_method (m);
452 closure_struct = null;
454 // only append data struct here to make sure all struct member
455 // types are declared before the struct definition
456 append_struct (data);
458 generate_method_declaration (m, cfile);
460 if (!m.is_internal_symbol ()) {
461 generate_method_declaration (m, header_file);
463 if (!m.is_private_symbol ()) {
464 generate_method_declaration (m, internal_header_file);
468 if ((m.is_abstract || m.is_virtual) && !get_ccode_no_wrapper (m)) {
469 // generate virtual function wrappers
470 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
471 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
472 generate_vfunc (m, new VoidType (), cparam_map, carg_map, "", 1);
474 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
475 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
476 generate_vfunc (m, m.return_type, cparam_map, carg_map, "_finish", 2);
479 base.visit_method (m);
483 public override void visit_creation_method (CreationMethod m) {
485 base.visit_creation_method (m);
487 push_line (m.source_reference);
489 bool visible = !m.is_private_symbol ();
493 if (m.source_type == SourceFileType.FAST) {
497 // do not generate _new functions for creation methods of abstract classes
498 if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
499 var vfunc = new CCodeFunction (get_ccode_name (m));
501 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
502 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
504 push_function (vfunc);
506 var vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
507 vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
509 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 1);
510 ccode.add_expression (vcall);
513 vfunc.modifiers |= CCodeModifiers.STATIC;
518 cfile.add_function (vfunc);
521 vfunc = new CCodeFunction (get_ccode_finish_name (m));
523 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
524 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
526 push_function (vfunc);
528 vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_real_name (m)));
530 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 2);
531 ccode.add_return (vcall);
534 vfunc.modifiers |= CCodeModifiers.STATIC;
539 cfile.add_function (vfunc);
546 void generate_finish_function (Method m) {
547 push_context (new EmitContext ());
549 string dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
551 var finishfunc = new CCodeFunction (get_ccode_finish_real_name (m));
553 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
555 cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
557 generate_cparameters (m, cfile, cparam_map, finishfunc, null, null, null, 2);
559 if (m.is_private_symbol () || m.base_method != null || m.base_interface_method != null) {
560 finishfunc.modifiers |= CCodeModifiers.STATIC;
561 } else if (context.hide_internal && m.is_internal_symbol ()) {
562 finishfunc.modifiers |= CCodeModifiers.INTERNAL;
565 push_function (finishfunc);
567 var return_type = m.return_type;
568 if (m is CreationMethod) {
569 var type_sym = (TypeSymbol) m.parent_symbol;
570 if (type_sym is ObjectTypeSymbol) {
571 ccode.add_declaration (get_ccode_name (type_sym) + "*", new CCodeVariableDeclarator ("result"));
572 return_type = SemanticAnalyzer.get_this_type (m, type_sym);
574 } else if (!(return_type is VoidType) && !return_type.is_real_non_null_struct_type ()) {
575 ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator ("result"));
578 var data_var = new CCodeIdentifier ("_data_");
580 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
582 var async_result_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_TASK"));
583 async_result_cast.add_argument (new CCodeIdentifier ("_res_"));
585 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer"));
586 ccall.add_argument (async_result_cast);
588 if (m.tree_can_fail) {
589 ccall.add_argument (new CCodeIdentifier ("error"));
591 ccall.add_argument (new CCodeConstant ("NULL"));
594 ccode.add_assignment (data_var, ccall);
596 bool has_cancellable = false;
598 foreach (Parameter param in m.get_parameters ()) {
599 if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
600 has_cancellable = true;
605 // If a task is cancelled, g_task_propagate_pointer returns NULL
606 if (m.tree_can_fail || has_cancellable) {
607 var is_null = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), data_var);
609 ccode.open_if (is_null);
610 return_default_value (return_type);
614 emit_context.push_symbol (m);
615 foreach (Parameter param in m.get_parameters ()) {
616 if (param.direction != ParameterDirection.IN) {
617 return_out_parameter (param);
618 if (!(param.variable_type is ValueType) || param.variable_type.nullable) {
619 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_ccode_name (param)), new CCodeConstant ("NULL"));
623 emit_context.pop_symbol ();
625 if (m is CreationMethod) {
626 ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "self"));
627 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), new CCodeConstant ("NULL"));
628 ccode.add_return (new CCodeIdentifier ("result"));
629 } else if (return_type.is_real_non_null_struct_type ()) {
630 // structs are returned via out parameter
631 CCodeExpression cexpr = new CCodeMemberAccess.pointer (data_var, "result");
632 if (requires_copy (return_type)) {
633 cexpr = get_cvalue_ (copy_value (new GLibValue (return_type, cexpr, true), return_type));
635 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result")), cexpr);
636 } else if (!(return_type is VoidType)) {
637 ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "result"));
638 if (return_type is ArrayType) {
639 var array_type = (ArrayType) return_type;
640 if (get_ccode_array_length (m)) {
641 for (int dim = 1; dim <= array_type.rank; dim++) {
642 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_array_length_cname ("result", dim))), new CCodeMemberAccess.pointer (data_var, get_array_length_cname ("result", dim)));
645 } else if (return_type is DelegateType && ((DelegateType) return_type).delegate_symbol.has_target) {
646 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_delegate_target_cname ("result"))), new CCodeMemberAccess.pointer (data_var, get_delegate_target_cname ("result")));
648 if (!(return_type is ValueType) || return_type.nullable) {
649 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "result"), new CCodeConstant ("NULL"));
651 ccode.add_return (new CCodeIdentifier ("result"));
656 cfile.add_function (finishfunc);
661 public override string generate_ready_function (Method m) {
662 // generate ready callback handler
664 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
666 var readyfunc = new CCodeFunction (get_ccode_name (m) + "_ready", "void");
668 if (!add_wrapper (readyfunc.name)) {
669 // wrapper already defined
670 return readyfunc.name;
673 readyfunc.add_parameter (new CCodeParameter ("source_object", "GObject*"));
674 readyfunc.add_parameter (new CCodeParameter ("_res_", "GAsyncResult*"));
675 readyfunc.add_parameter (new CCodeParameter ("_user_data_", "gpointer"));
677 push_function (readyfunc);
679 var data_var = new CCodeIdentifier ("_data_");
681 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
682 ccode.add_assignment (data_var, new CCodeIdentifier ("_user_data_"));
683 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_source_object_"), new CCodeIdentifier ("source_object"));
684 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_res_"), new CCodeIdentifier ("_res_"));
686 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
687 ccall.add_argument (data_var);
688 ccode.add_expression (ccall);
690 readyfunc.modifiers |= CCodeModifiers.STATIC;
694 cfile.add_function_declaration (readyfunc);
695 cfile.add_function (readyfunc);
697 return readyfunc.name;
700 public override void generate_virtual_method_declaration (Method m, CCodeFile decl_space, CCodeStruct type_struct) {
702 base.generate_virtual_method_declaration (m, decl_space, type_struct);
706 if (!m.is_abstract && !m.is_virtual) {
710 var creturn_type = get_callable_creturn_type (m);
712 // add vfunc field to the type struct
713 var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
714 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
716 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 1);
718 var vdecl = new CCodeDeclaration ("void");
719 vdecl.add_declarator (vdeclarator);
720 type_struct.add_declaration (vdecl);
722 // add vfunc field to the type struct
723 vdeclarator = new CCodeFunctionDeclarator (get_ccode_finish_vfunc_name (m));
724 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
726 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 2);
728 vdecl = new CCodeDeclaration (get_ccode_name (creturn_type));
729 vdecl.add_declarator (vdeclarator);
730 type_struct.add_declaration (vdecl);
733 public override void visit_yield_statement (YieldStatement stmt) {
734 if (!is_in_coroutine ()) {
738 int state = emit_context.next_coroutine_state++;
740 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
741 ccode.add_return (new CCodeConstant ("FALSE"));
742 ccode.add_label ("_state_%d".printf (state));
743 ccode.add_statement (new CCodeEmptyStatement ());
746 public override void return_with_exception (CCodeExpression error_expr)
748 if (!is_in_coroutine ()) {
749 base.return_with_exception (error_expr);
753 var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_async_result");
754 CCodeFunctionCall set_error = null;
756 set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_error"));
757 set_error.add_argument (async_result_expr);
758 set_error.add_argument (error_expr);
759 ccode.add_expression (set_error);
761 // free local variables
762 append_local_free (current_symbol);
764 // free possibly already assigned out-parameter
765 append_out_param_free (current_method);
767 // We already returned the error above, we must not return anything else here.
768 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
769 unref.add_argument (async_result_expr);
770 ccode.add_expression (unref);
772 ccode.add_return (new CCodeConstant ("FALSE"));
775 public override void visit_return_statement (ReturnStatement stmt) {
776 base.visit_return_statement (stmt);
778 if (!is_in_coroutine ()) {
785 public override void generate_cparameters (Method m, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
787 decl_space.add_include ("gio/gio.h");
789 if (direction == 1) {
790 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
791 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
792 if (carg_map != null) {
793 carg_map.set (get_param_pos (-1), new CCodeIdentifier ("_callback_"));
794 carg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_user_data_"));
796 } else if (direction == 2) {
797 cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
798 if (carg_map != null) {
799 carg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeIdentifier ("_res_"));
803 base.generate_cparameters (m, decl_space, cparam_map, func, vdeclarator, carg_map, vcall, direction);
806 public string generate_async_callback_wrapper () {
807 string async_callback_wrapper_func = "_vala_g_async_ready_callback";
809 if (!add_wrapper (async_callback_wrapper_func)) {
810 return async_callback_wrapper_func;
813 var function = new CCodeFunction (async_callback_wrapper_func, "void");
814 function.modifiers = CCodeModifiers.STATIC;
816 function.add_parameter (new CCodeParameter ("*source_object", "GObject"));
817 function.add_parameter (new CCodeParameter ("*res", "GAsyncResult"));
818 function.add_parameter (new CCodeParameter ("*user_data", "void"));
820 push_function (function);
822 var res_ref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
823 res_ref.add_argument (new CCodeIdentifier ("res"));
825 CCodeFunctionCall ccall = null;
827 // store reference to async result of inner async function in out async result
828 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_pointer"));
829 ccall.add_argument (new CCodeIdentifier ("user_data"));
830 ccall.add_argument (res_ref);
831 ccall.add_argument (new CCodeIdentifier ("g_object_unref"));
832 ccode.add_expression (ccall);
835 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
836 ccall.add_argument (new CCodeIdentifier ("user_data"));
837 ccode.add_expression (ccall);
841 cfile.add_function_declaration (function);
842 cfile.add_function (function);
844 return async_callback_wrapper_func;