girparser: Report unused metadata only if repository has been parsed.
[vala-lang.git] / codegen / valagasyncmodule.vala
blobfa0e4a7917fa7db58aae3b970d357aa23d822392
1 /* valagasyncmodule.vala
3 * Copyright (C) 2008-2010 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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 public class Vala.GAsyncModule : GSignalModule {
26 CCodeStruct generate_data_struct (Method m) {
27 string dataname = Symbol.lower_case_to_camel_case (m.get_cname ()) + "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 ("GSimpleAsyncResult*", "_async_result");
35 if (m.binding == MemberBinding.INSTANCE) {
36 var type_sym = (TypeSymbol) m.parent_symbol;
37 if (type_sym is ObjectTypeSymbol) {
38 data.add_field (type_sym.get_cname () + "*", "self");
39 } else {
40 data.add_field (type_sym.get_cname (), "self");
44 foreach (Parameter param in m.get_parameters ()) {
45 var param_type = param.variable_type.copy ();
46 param_type.value_owned = true;
47 data.add_field (param_type.get_cname (), get_variable_cname (param.name));
49 if (param.variable_type is ArrayType) {
50 var array_type = (ArrayType) param.variable_type;
51 if (!param.no_array_length) {
52 for (int dim = 1; dim <= array_type.rank; dim++) {
53 data.add_field ("gint", get_parameter_array_length_cname (param, dim));
56 } else if (param.variable_type is DelegateType) {
57 var deleg_type = (DelegateType) param.variable_type;
58 if (deleg_type.delegate_symbol.has_target) {
59 data.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param.name)));
60 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
65 if (!(m.return_type is VoidType)) {
66 data.add_field (m.return_type.get_cname (), "result");
67 if (m.return_type is ArrayType) {
68 var array_type = (ArrayType) m.return_type;
69 if (!m.no_array_length) {
70 for (int dim = 1; dim <= array_type.rank; dim++) {
71 data.add_field ("gint", get_array_length_cname ("result", dim));
74 } else if (m.return_type is DelegateType) {
75 var deleg_type = (DelegateType) m.return_type;
76 if (deleg_type.delegate_symbol.has_target) {
77 data.add_field ("gpointer", get_delegate_target_cname ("result"));
78 data.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname ("result"));
83 return data;
86 CCodeFunction generate_free_function (Method m) {
87 var dataname = Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data";
89 var freefunc = new CCodeFunction (m.get_real_cname () + "_data_free", "void");
90 freefunc.modifiers = CCodeModifiers.STATIC;
91 freefunc.add_parameter (new CCodeParameter ("_data", "gpointer"));
93 var freeblock = new CCodeBlock ();
94 freefunc.block = freeblock;
96 var datadecl = new CCodeDeclaration (dataname + "*");
97 datadecl.add_declarator (new CCodeVariableDeclarator ("data", new CCodeIdentifier ("_data")));
98 freeblock.add_statement (datadecl);
100 push_context (new EmitContext (m));
102 foreach (Parameter param in m.get_parameters ()) {
103 if (param.direction != ParameterDirection.OUT) {
104 bool is_unowned_delegate = param.variable_type is DelegateType && !param.variable_type.value_owned;
106 var param_type = param.variable_type.copy ();
107 param_type.value_owned = true;
109 if (requires_destroy (param_type) && !is_unowned_delegate) {
110 // do not try to access closure blocks
111 bool old_captured = param.captured;
112 param.captured = false;
114 freeblock.add_statement (new CCodeExpressionStatement (destroy_parameter (param)));
116 param.captured = old_captured;
121 if (requires_destroy (m.return_type)) {
122 /* this is very evil. */
123 var v = new LocalVariable (m.return_type, ".result");
124 var ma = new MemberAccess.simple (".result");
125 ma.symbol_reference = v;
126 ma.value_type = v.variable_type.copy ();
127 visit_member_access (ma);
128 var unref_expr = get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "result"), m.return_type, ma);
129 freeblock.add_statement (new CCodeExpressionStatement (unref_expr));
132 if (m.binding == MemberBinding.INSTANCE) {
133 var this_type = m.this_parameter.variable_type.copy ();
134 this_type.value_owned = true;
136 if (requires_destroy (this_type)) {
137 var ma = new MemberAccess.simple ("this");
138 ma.symbol_reference = m.this_parameter;
139 ma.value_type = m.this_parameter.variable_type.copy ();
140 visit_member_access (ma);
141 freeblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "self"), m.this_parameter.variable_type, ma)));
145 pop_context ();
147 var freecall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
148 freecall.add_argument (new CCodeIdentifier (dataname));
149 freecall.add_argument (new CCodeIdentifier ("data"));
150 freeblock.add_statement (new CCodeExpressionStatement (freecall));
152 return freefunc;
155 void generate_async_function (Method m) {
156 push_context (new EmitContext ());
158 var dataname = Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data";
159 var asyncfunc = new CCodeFunction (m.get_real_cname (), "void");
160 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
162 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
163 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
165 generate_cparameters (m, cfile, cparam_map, asyncfunc, null, null, null, 1);
167 if (m.base_method != null || m.base_interface_method != null) {
168 // declare *_real_* function
169 asyncfunc.modifiers |= CCodeModifiers.STATIC;
170 cfile.add_function_declaration (asyncfunc);
171 } else if (m.is_private_symbol ()) {
172 asyncfunc.modifiers |= CCodeModifiers.STATIC;
175 push_function (asyncfunc);
177 // logic copied from valaccodemethodmodule
178 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
179 Method base_method;
181 if (m.overrides) {
182 base_method = m.base_method;
183 } else {
184 base_method = m.base_interface_method;
187 var base_expression_type = new ObjectType ((ObjectTypeSymbol) base_method.parent_symbol);
188 var type_symbol = m.parent_symbol as ObjectTypeSymbol;
190 var self_target_type = new ObjectType (type_symbol);
191 var cself = transform_expression (new CCodeIdentifier ("base"), base_expression_type, self_target_type);
192 ccode.add_declaration ("%s *".printf (type_symbol.get_cname ()), new CCodeVariableDeclarator ("self"));
193 ccode.add_assignment (new CCodeIdentifier ("self"), cself);
196 var dataalloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
197 dataalloc.add_argument (new CCodeIdentifier (dataname));
199 var data_var = new CCodeIdentifier ("_data_");
201 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
202 ccode.add_assignment (data_var, dataalloc);
204 var create_result = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_new"));
206 var cl = m.parent_symbol as Class;
207 if (m.binding == MemberBinding.INSTANCE &&
208 cl != null && cl.is_subtype_of (gobject_type)) {
209 var gobject_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
210 gobject_cast.add_argument (new CCodeIdentifier ("self"));
212 create_result.add_argument (gobject_cast);
213 } else {
214 if (context.require_glib_version (2, 20)) {
215 create_result.add_argument (new CCodeConstant ("NULL"));
216 } else {
217 var object_creation = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
218 object_creation.add_argument (new CCodeConstant ("G_TYPE_OBJECT"));
219 object_creation.add_argument (new CCodeConstant ("0"));
220 object_creation.add_argument (new CCodeConstant ("NULL"));
222 create_result.add_argument (object_creation);
226 create_result.add_argument (new CCodeIdentifier ("_callback_"));
227 create_result.add_argument (new CCodeIdentifier ("_user_data_"));
228 create_result.add_argument (new CCodeIdentifier (m.get_real_cname ()));
230 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_async_result"), create_result);
232 var set_op_res_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_set_op_res_gpointer"));
233 set_op_res_call.add_argument (new CCodeMemberAccess.pointer (data_var, "_async_result"));
234 set_op_res_call.add_argument (data_var);
235 set_op_res_call.add_argument (new CCodeIdentifier (m.get_real_cname () + "_data_free"));
236 ccode.add_expression (set_op_res_call);
238 if (m.binding == MemberBinding.INSTANCE) {
239 var this_type = m.this_parameter.variable_type.copy ();
240 this_type.value_owned = true;
242 // create copy if necessary as variables in async methods may need to be kept alive
243 CCodeExpression cself = new CCodeIdentifier ("self");
244 if (this_type.is_real_non_null_struct_type ()) {
245 cself = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cself);
247 if (requires_copy (this_type)) {
248 var ma = new MemberAccess.simple ("this");
249 ma.symbol_reference = m.this_parameter;
250 ma.value_type = m.this_parameter.variable_type.copy ();
251 visit_member_access (ma);
252 cself = get_ref_cexpression (m.this_parameter.variable_type, cself, ma, m.this_parameter);
255 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), cself);
258 foreach (Parameter param in m.get_parameters ()) {
259 if (param.direction != ParameterDirection.OUT) {
260 var param_type = param.variable_type.copy ();
261 param_type.value_owned = true;
263 // create copy if necessary as variables in async methods may need to be kept alive
264 CCodeExpression cparam = new CCodeIdentifier (get_variable_cname (param.name));
265 if (param.variable_type.is_real_non_null_struct_type ()) {
266 cparam = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cparam);
268 if (requires_copy (param_type) && !param.variable_type.value_owned) {
269 var ma = new MemberAccess.simple (param.name);
270 ma.symbol_reference = param;
271 ma.value_type = param.variable_type.copy ();
272 visit_member_access (ma);
273 cparam = get_ref_cexpression (param.variable_type, cparam, ma, param);
276 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_variable_cname (param.name)), cparam);
277 if (param.variable_type is ArrayType) {
278 var array_type = (ArrayType) param.variable_type;
279 if (!param.no_array_length) {
280 for (int dim = 1; dim <= array_type.rank; dim++) {
281 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_parameter_array_length_cname (param, dim)), new CCodeIdentifier (get_parameter_array_length_cname (param, dim)));
284 } else if (param.variable_type is DelegateType) {
285 var deleg_type = (DelegateType) param.variable_type;
286 if (deleg_type.delegate_symbol.has_target) {
287 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_delegate_target_cname (get_variable_cname (param.name))), new CCodeIdentifier (get_delegate_target_cname (get_variable_cname (param.name))));
288 if (deleg_type.value_owned) {
289 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_delegate_target_destroy_notify_cname (get_variable_cname (param.name))), new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (param.name))));
296 var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname () + "_co"));
297 ccall.add_argument (data_var);
298 ccode.add_expression (ccall);
300 cfile.add_function (asyncfunc);
302 pop_context ();
305 void append_struct (CCodeStruct structure) {
306 var typename = new CCodeVariableDeclarator (structure.name.substring (1));
307 var typedef = new CCodeTypeDefinition ("struct " + structure.name, typename);
308 cfile.add_type_declaration (typedef);
309 cfile.add_type_definition (structure);
312 void append_function (CCodeFunction function) {
313 cfile.add_function_declaration (function);
314 cfile.add_function (function);
317 public override void generate_method_declaration (Method m, CCodeFile decl_space) {
318 if (m.coroutine) {
319 if (add_symbol_declaration (decl_space, m, m.get_cname ())) {
320 return;
323 var asyncfunc = new CCodeFunction (m.get_cname (), "void");
324 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
325 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
326 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
328 generate_cparameters (m, decl_space, cparam_map, asyncfunc, null, null, null, 1);
330 if (m.is_private_symbol ()) {
331 asyncfunc.modifiers |= CCodeModifiers.STATIC;
334 decl_space.add_function_declaration (asyncfunc);
336 var finishfunc = new CCodeFunction (m.get_finish_cname ());
337 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
338 cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
340 generate_cparameters (m, decl_space, cparam_map, finishfunc, null, null, null, 2);
342 if (m.is_private_symbol ()) {
343 finishfunc.modifiers |= CCodeModifiers.STATIC;
346 decl_space.add_function_declaration (finishfunc);
347 } else {
348 base.generate_method_declaration (m, decl_space);
352 public override void visit_method (Method m) {
353 if (m.coroutine) {
354 cfile.add_include ("gio/gio.h");
355 if (!m.is_internal_symbol ()) {
356 header_file.add_include ("gio/gio.h");
359 if (!m.is_abstract && m.body != null) {
360 var data = generate_data_struct (m);
362 closure_struct = data;
364 append_function (generate_free_function (m));
365 generate_async_function (m);
366 generate_finish_function (m);
368 // append the _co function
369 base.visit_method (m);
370 closure_struct = null;
372 // only append data struct here to make sure all struct member
373 // types are declared before the struct definition
374 append_struct (data);
375 } else {
376 generate_method_declaration (m, cfile);
378 if (!m.is_internal_symbol ()) {
379 generate_method_declaration (m, header_file);
381 if (!m.is_private_symbol ()) {
382 generate_method_declaration (m, internal_header_file);
386 if (m.is_abstract || m.is_virtual) {
387 // generate virtual function wrappers
388 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
389 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
390 generate_vfunc (m, new VoidType (), cparam_map, carg_map, "", 1);
392 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
393 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
394 generate_vfunc (m, m.return_type, cparam_map, carg_map, "_finish", 2);
396 } else {
397 base.visit_method (m);
402 void generate_finish_function (Method m) {
403 push_context (new EmitContext ());
405 string dataname = Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data";
407 var finishfunc = new CCodeFunction (m.get_finish_real_cname ());
409 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
411 cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
413 generate_cparameters (m, cfile, cparam_map, finishfunc, null, null, null, 2);
415 if (m.is_private_symbol () || m.base_method != null || m.base_interface_method != null) {
416 finishfunc.modifiers |= CCodeModifiers.STATIC;
419 push_function (finishfunc);
421 var return_type = m.return_type;
422 if (!(return_type is VoidType) && !return_type.is_real_non_null_struct_type ()) {
423 ccode.add_declaration (m.return_type.get_cname (), new CCodeVariableDeclarator ("result"));
426 var data_var = new CCodeIdentifier ("_data_");
428 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
430 var simple_async_result_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_SIMPLE_ASYNC_RESULT"));
431 simple_async_result_cast.add_argument (new CCodeIdentifier ("_res_"));
433 if (m.get_error_types ().size > 0) {
434 // propagate error from async method
435 var propagate_error = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_propagate_error"));
436 propagate_error.add_argument (simple_async_result_cast);
437 propagate_error.add_argument (new CCodeIdentifier ("error"));
439 ccode.open_if (propagate_error);
440 return_default_value (return_type);
441 ccode.close ();
444 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_get_op_res_gpointer"));
445 ccall.add_argument (simple_async_result_cast);
446 ccode.add_assignment (data_var, ccall);
448 foreach (Parameter param in m.get_parameters ()) {
449 if (param.direction != ParameterDirection.IN) {
450 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), new CCodeMemberAccess.pointer (data_var, get_variable_cname (param.name)));
451 if (!(param.variable_type is ValueType) || param.variable_type.nullable) {
452 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_variable_cname (param.name)), new CCodeConstant ("NULL"));
457 if (return_type.is_real_non_null_struct_type ()) {
458 // structs are returned via out parameter
459 CCodeExpression cexpr = new CCodeMemberAccess.pointer (data_var, "result");
460 if (requires_copy (return_type)) {
461 cexpr = get_ref_cexpression (return_type, cexpr, null, return_type);
463 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result")), cexpr);
464 } else if (!(return_type is VoidType)) {
465 ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "result"));
466 if (return_type is ArrayType) {
467 var array_type = (ArrayType) return_type;
468 if (!m.no_array_length) {
469 for (int dim = 1; dim <= array_type.rank; dim++) {
470 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)));
473 } else if (return_type is DelegateType && ((DelegateType) return_type).delegate_symbol.has_target) {
474 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")));
476 if (!(return_type is ValueType) || return_type.nullable) {
477 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "result"), new CCodeConstant ("NULL"));
479 ccode.add_return (new CCodeIdentifier ("result"));
482 pop_function ();
484 cfile.add_function (finishfunc);
486 pop_context ();
489 public override string generate_ready_function (Method m) {
490 // generate ready callback handler
492 var dataname = Symbol.lower_case_to_camel_case (m.get_cname ()) + "Data";
494 var readyfunc = new CCodeFunction (m.get_cname () + "_ready", "void");
496 if (!add_wrapper (readyfunc.name)) {
497 // wrapper already defined
498 return readyfunc.name;
501 readyfunc.add_parameter (new CCodeParameter ("source_object", "GObject*"));
502 readyfunc.add_parameter (new CCodeParameter ("_res_", "GAsyncResult*"));
503 readyfunc.add_parameter (new CCodeParameter ("_user_data_", "gpointer"));
505 var readyblock = new CCodeBlock ();
507 var datadecl = new CCodeDeclaration (dataname + "*");
508 datadecl.add_declarator (new CCodeVariableDeclarator ("data"));
509 readyblock.add_statement (datadecl);
510 readyblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data"), new CCodeIdentifier ("_user_data_"))));
511 readyblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_source_object_"), new CCodeIdentifier ("source_object"))));
512 readyblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_res_"), new CCodeIdentifier ("_res_"))));
514 var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname () + "_co"));
515 ccall.add_argument (new CCodeIdentifier ("data"));
516 readyblock.add_statement (new CCodeExpressionStatement (ccall));
518 readyfunc.modifiers |= CCodeModifiers.STATIC;
520 readyfunc.block = readyblock;
522 append_function (readyfunc);
524 return readyfunc.name;
527 public override void generate_virtual_method_declaration (Method m, CCodeFile decl_space, CCodeStruct type_struct) {
528 if (!m.coroutine) {
529 base.generate_virtual_method_declaration (m, decl_space, type_struct);
530 return;
533 if (!m.is_abstract && !m.is_virtual) {
534 return;
537 var creturn_type = m.return_type;
538 if (m.return_type.is_real_non_null_struct_type ()) {
539 // structs are returned via out parameter
540 creturn_type = new VoidType ();
543 // add vfunc field to the type struct
544 var vdeclarator = new CCodeFunctionDeclarator (m.vfunc_name);
545 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
547 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 1);
549 var vdecl = new CCodeDeclaration ("void");
550 vdecl.add_declarator (vdeclarator);
551 type_struct.add_declaration (vdecl);
553 // add vfunc field to the type struct
554 vdeclarator = new CCodeFunctionDeclarator (m.get_finish_vfunc_name ());
555 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
557 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 2);
559 vdecl = new CCodeDeclaration (creturn_type.get_cname ());
560 vdecl.add_declarator (vdeclarator);
561 type_struct.add_declaration (vdecl);
564 public override void visit_yield_statement (YieldStatement stmt) {
565 if (!is_in_coroutine ()) {
566 return;
569 if (stmt.yield_expression == null) {
570 int state = next_coroutine_state++;
572 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_state_"), new CCodeConstant (state.to_string ()));
573 ccode.add_return (new CCodeConstant ("FALSE"));
574 ccode.add_label ("_state_%d".printf (state));
575 ccode.add_statement (new CCodeEmptyStatement ());
577 return;
580 if (stmt.yield_expression.error) {
581 stmt.error = true;
582 return;
585 ccode.add_expression (get_cvalue (stmt.yield_expression));
587 if (stmt.tree_can_fail && stmt.yield_expression.tree_can_fail) {
588 // simple case, no node breakdown necessary
590 add_simple_check (stmt.yield_expression);
593 /* free temporary objects */
595 foreach (LocalVariable local in temp_ref_vars) {
596 ccode.add_expression (destroy_local (local));
599 temp_ref_vars.clear ();
602 public override void return_with_exception (CCodeExpression error_expr)
604 if (!is_in_coroutine ()) {
605 base.return_with_exception (error_expr);
606 return;
609 var set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_set_from_error"));
610 set_error.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_async_result"));
611 set_error.add_argument (error_expr);
612 ccode.add_expression (set_error);
614 var free_error = new CCodeFunctionCall (new CCodeIdentifier ("g_error_free"));
615 free_error.add_argument (error_expr);
616 ccode.add_expression (free_error);
618 append_local_free (current_symbol, false);
620 complete_async ();
623 public override void visit_return_statement (ReturnStatement stmt) {
624 base.visit_return_statement (stmt);
626 if (!is_in_coroutine ()) {
627 return;
630 complete_async ();
633 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) {
634 if (m.coroutine) {
635 decl_space.add_include ("gio/gio.h");
637 if (direction == 1) {
638 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
639 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
640 if (carg_map != null) {
641 carg_map.set (get_param_pos (-1), new CCodeIdentifier ("_callback_"));
642 carg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_user_data_"));
644 } else if (direction == 2) {
645 cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
646 if (carg_map != null) {
647 carg_map.set (get_param_pos (0.1), new CCodeIdentifier ("_res_"));
651 base.generate_cparameters (m, decl_space, cparam_map, func, vdeclarator, carg_map, vcall, direction);
654 public string generate_async_callback_wrapper () {
655 string async_callback_wrapper_func = "_vala_g_async_ready_callback";
657 if (!add_wrapper (async_callback_wrapper_func)) {
658 return async_callback_wrapper_func;
661 var function = new CCodeFunction (async_callback_wrapper_func, "void");
662 function.modifiers = CCodeModifiers.STATIC;
664 function.add_parameter (new CCodeParameter ("*source_object", "GObject"));
665 function.add_parameter (new CCodeParameter ("*res", "GAsyncResult"));
666 function.add_parameter (new CCodeParameter ("*user_data", "void"));
668 push_function (function);
670 var res_ref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
671 res_ref.add_argument (new CCodeIdentifier ("res"));
673 // store reference to async result of inner async function in out async result
674 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_set_op_res_gpointer"));
675 ccall.add_argument (new CCodeIdentifier ("user_data"));
676 ccall.add_argument (res_ref);
677 ccall.add_argument (new CCodeIdentifier ("g_object_unref"));
678 ccode.add_expression (ccall);
680 // call user-provided callback
681 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
682 ccall.add_argument (new CCodeIdentifier ("user_data"));
683 ccode.add_expression (ccall);
685 // free async result
686 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
687 ccall.add_argument (new CCodeIdentifier ("user_data"));
688 ccode.add_expression (ccall);
690 pop_function ();
692 cfile.add_function_declaration (function);
693 cfile.add_function (function);
695 return async_callback_wrapper_func;