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_");
34 data
.add_field ("GTask*", "_async_result");
35 if (!context
.require_glib_version (2, 44)) {
36 data
.add_field ("GAsyncReadyCallback", "_callback_");
37 data
.add_field ("gboolean", "_task_complete_");
40 if (m is CreationMethod
) {
41 data
.add_field ("GType", "object_type");
44 if (m
.binding
== MemberBinding
.INSTANCE
) {
45 var type_sym
= (TypeSymbol
) m
.parent_symbol
;
46 if (type_sym is ObjectTypeSymbol
) {
47 data
.add_field (get_ccode_name (type_sym
) + "*", "self");
49 data
.add_field (get_ccode_name (type_sym
), "self");
53 foreach (Parameter param
in m
.get_parameters ()) {
54 var param_type
= param
.variable_type
.copy ();
55 param_type
.value_owned
= true;
56 data
.add_field (get_ccode_name (param_type
), get_variable_cname (param
.name
));
58 if (param
.variable_type is ArrayType
) {
59 var array_type
= (ArrayType
) param
.variable_type
;
60 if (get_ccode_array_length (param
)) {
61 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
62 data
.add_field ("gint", get_parameter_array_length_cname (param
, dim
));
65 } else if (param
.variable_type is DelegateType
) {
66 var deleg_type
= (DelegateType
) param
.variable_type
;
67 if (deleg_type
.delegate_symbol
.has_target
) {
68 data
.add_field ("gpointer", get_ccode_delegate_target_name (param
));
69 if (deleg_type
.is_disposable ()) {
70 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
76 foreach (var type_param
in m
.get_type_parameters ()) {
77 data
.add_field ("GType", "%s_type".printf (type_param
.name
.down ()));
78 data
.add_field ("GBoxedCopyFunc", "%s_dup_func".printf (type_param
.name
.down ()));
79 data
.add_field ("GDestroyNotify", "%s_destroy_func".printf (type_param
.name
.down ()));
82 if (!(m
.return_type is VoidType
)) {
83 data
.add_field (get_ccode_name (m
.return_type
), "result");
84 if (m
.return_type is ArrayType
) {
85 var array_type
= (ArrayType
) m
.return_type
;
86 if (get_ccode_array_length (m
)) {
87 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
88 data
.add_field ("gint", get_array_length_cname ("result", dim
));
91 } else if (m
.return_type is DelegateType
) {
92 var deleg_type
= (DelegateType
) m
.return_type
;
93 if (deleg_type
.delegate_symbol
.has_target
) {
94 data
.add_field ("gpointer", get_delegate_target_cname ("result"));
95 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname ("result"));
103 CCodeFunction
generate_free_function (Method m
) {
104 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
106 var freefunc
= new
CCodeFunction (get_ccode_real_name (m
) + "_data_free", "void");
107 freefunc
.modifiers
= CCodeModifiers
.STATIC
;
108 freefunc
.add_parameter (new
CCodeParameter ("_data", "gpointer"));
110 push_context (new
EmitContext (m
));
111 push_function (freefunc
);
113 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_", new
CCodeIdentifier ("_data")));
115 foreach (Parameter param
in m
.get_parameters ()) {
116 if (!param
.captured
&& param
.direction
!= ParameterDirection
.OUT
) {
117 var param_type
= param
.variable_type
.copy ();
118 if (!param_type
.value_owned
) {
119 param_type
.value_owned
= !no_implicit_copy (param_type
);
122 if (requires_destroy (param_type
)) {
123 ccode
.add_expression (destroy_parameter (param
));
128 if (requires_destroy (m
.return_type
)) {
129 if (get_ccode_array_length (m
) || !(m
.return_type is ArrayType
)) {
130 /* this is very evil. */
131 var v
= new
LocalVariable (m
.return_type
, ".result");
132 ccode
.add_expression (destroy_local (v
));
134 var v
= new
GLibValue (m
.return_type
, new
CCodeIdentifier ("_data_->result"), true);
135 v
.array_null_terminated
= get_ccode_array_null_terminated (m
);
136 ccode
.add_expression (destroy_value (v
));
140 if (m
.binding
== MemberBinding
.INSTANCE
) {
141 var this_type
= m
.this_parameter
.variable_type
.copy ();
142 this_type
.value_owned
= true;
144 if (requires_destroy (this_type
)) {
145 ccode
.add_expression (destroy_parameter (m
.this_parameter
));
149 var freecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
150 freecall
.add_argument (new
CCodeIdentifier (dataname
));
151 freecall
.add_argument (new
CCodeIdentifier ("_data_"));
152 ccode
.add_expression (freecall
);
156 cfile
.add_function_declaration (freefunc
);
157 cfile
.add_function (freefunc
);
162 void generate_async_ready_callback_wrapper (Method m
, string function_name
) {
163 var function
= new
CCodeFunction (function_name
, "void");
164 function
.modifiers
= CCodeModifiers
.STATIC
;
166 function
.add_parameter (new
CCodeParameter ("*source_object", "GObject"));
167 function
.add_parameter (new
CCodeParameter ("*res", "GAsyncResult"));
168 function
.add_parameter (new
CCodeParameter ("*user_data", "void"));
170 push_function (function
);
172 // Set _task_complete_ to false after calling back to the real func
173 var async_result_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TASK"));
174 async_result_cast
.add_argument (new
CCodeIdentifier ("res"));
176 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
177 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_task_data_"));
179 var get_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_get_task_data"));
180 get_data_call
.add_argument (async_result_cast
);
182 var data_var
= new
CCodeIdentifier ("_task_data_");
183 ccode
.add_assignment (data_var
, get_data_call
);
185 var task_inner_callback
= new CCodeMemberAccess
.pointer (data_var
, "_callback_");
186 var callback_is_nonnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, task_inner_callback
, new
CCodeConstant ("NULL"));
188 ccode
.open_if (callback_is_nonnull
);
189 var nested_callback
= new
CCodeFunctionCall (task_inner_callback
);
190 nested_callback
.add_argument (new
CCodeIdentifier ("source_object"));
191 nested_callback
.add_argument (new
CCodeIdentifier ("res"));
192 nested_callback
.add_argument (new
CCodeIdentifier ("user_data"));
193 ccode
.add_expression (nested_callback
);
196 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_task_complete_"), new
CCodeConstant ("TRUE"));
200 cfile
.add_function_declaration (function
);
201 cfile
.add_function (function
);
204 void generate_async_function (Method m
) {
205 push_context (new
EmitContext ());
207 string? callback_wrapper
= null;
209 if (!context
.require_glib_version (2, 44)) {
210 callback_wrapper
= get_ccode_real_name (m
) + "_async_ready_wrapper";
211 generate_async_ready_callback_wrapper (m
, callback_wrapper
);
214 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
215 var asyncfunc
= new
CCodeFunction (get_ccode_real_name (m
), "void");
216 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
218 cparam_map
.set (get_param_pos (-1), new
CCodeParameter ("_callback_", "GAsyncReadyCallback"));
219 cparam_map
.set (get_param_pos (-0.9), new
CCodeParameter ("_user_data_", "gpointer"));
221 generate_cparameters (m
, cfile
, cparam_map
, asyncfunc
, null, null, null, 1);
223 if (m
.base_method
!= null || m
.base_interface_method
!= null) {
224 // declare *_real_* function
225 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
226 cfile
.add_function_declaration (asyncfunc
);
227 } else if (m
.is_private_symbol ()) {
228 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
229 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
230 asyncfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
233 push_function (asyncfunc
);
235 // logic copied from valaccodemethodmodule
236 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
240 base_method
= m
.base_method
;
242 base_method
= m
.base_interface_method
;
245 var base_expression_type
= new
ObjectType ((ObjectTypeSymbol
) base_method
.parent_symbol
);
246 var type_symbol
= m
.parent_symbol as ObjectTypeSymbol
;
248 var self_target_type
= new
ObjectType (type_symbol
);
249 var cself
= get_cvalue_ (transform_value (new
GLibValue (base_expression_type
, new
CCodeIdentifier ("base"), true), self_target_type
, m
));
250 ccode
.add_declaration ("%s *".printf (get_ccode_name (type_symbol
)), new
CCodeVariableDeclarator ("self"));
251 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
254 var dataalloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
255 dataalloc
.add_argument (new
CCodeIdentifier (dataname
));
257 var data_var
= new
CCodeIdentifier ("_data_");
259 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
260 ccode
.add_assignment (data_var
, dataalloc
);
262 if (!context
.require_glib_version (2, 44)) {
263 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_callback_"), new
CCodeConstant ("_callback_"));
266 var create_result
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_new"));
268 var t
= m
.parent_symbol as TypeSymbol
;
269 if (!(m is CreationMethod
) && m
.binding
== MemberBinding
.INSTANCE
&&
270 t
!= null && t
.is_subtype_of (gobject_type
)) {
271 var gobject_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT"));
272 gobject_cast
.add_argument (new
CCodeIdentifier ("self"));
274 create_result
.add_argument (gobject_cast
);
276 create_result
.add_argument (new
CCodeConstant ("NULL"));
279 Parameter cancellable_param
= null;
281 foreach (Parameter param
in m
.get_parameters ()) {
282 if (param
.variable_type is ObjectType
&& param
.variable_type
.data_type
.get_full_name () == "GLib.Cancellable") {
283 cancellable_param
= param
;
288 if (cancellable_param
== null) {
289 create_result
.add_argument (new
CCodeConstant ("NULL"));
291 create_result
.add_argument (new
CCodeIdentifier (get_variable_cname (cancellable_param
.name
)));
294 if (context
.require_glib_version (2, 44)) {
295 create_result
.add_argument (new
CCodeIdentifier ("_callback_"));
297 create_result
.add_argument (new
CCodeIdentifier (callback_wrapper
));
299 create_result
.add_argument (new
CCodeIdentifier ("_user_data_"));
301 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_async_result"), create_result
);
303 if (!context
.require_glib_version (2, 44)) {
304 var task_completed_var
= new CCodeMemberAccess
.pointer (data_var
, "_task_complete_");
305 var callback = new
CCodeIdentifier ("_callback_");
306 var callback_is_null
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, callback, new
CCodeConstant ("NULL"));
308 ccode
.open_if (callback_is_null
);
309 ccode
.add_assignment (task_completed_var
, new
CCodeConstant ("TRUE"));
313 var attach_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_set_task_data"));
315 attach_data_call
.add_argument (new CCodeMemberAccess
.pointer (data_var
, "_async_result"));
316 attach_data_call
.add_argument (data_var
);
317 attach_data_call
.add_argument (new
CCodeIdentifier (get_ccode_real_name (m
) + "_data_free"));
318 ccode
.add_expression (attach_data_call
);
320 if (m is CreationMethod
) {
321 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "object_type"), new
CCodeIdentifier ("object_type"));
322 } else if (m
.binding
== MemberBinding
.INSTANCE
) {
323 var this_type
= m
.this_parameter
.variable_type
.copy ();
324 this_type
.value_owned
= true;
326 // create copy if necessary as variables in async methods may need to be kept alive
327 CCodeExpression cself
= new
CCodeIdentifier ("self");
328 if (this_type
.is_real_non_null_struct_type ()) {
329 cself
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cself
);
331 if (requires_copy (this_type
)) {
332 cself
= get_cvalue_ (copy_value (new
GLibValue (m
.this_parameter
.variable_type
, cself
, true), m
.this_parameter
));
335 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "self"), cself
);
338 emit_context
.push_symbol (m
);
339 foreach (Parameter param
in m
.get_parameters ()) {
340 if (param
.direction
!= ParameterDirection
.OUT
) {
341 // create copy if necessary as variables in async methods may need to be kept alive
342 var old_captured
= param
.captured
;
343 param
.captured
= false;
344 current_method
.coroutine
= false;
347 if (param
.variable_type
.value_owned
) {
348 // do not use load_parameter for reference/ownership transfer
349 // otherwise delegate destroy notify will not be moved
350 value
= get_parameter_cvalue (param
);
352 value
= load_parameter (param
);
355 current_method
.coroutine
= true;
357 store_parameter (param
, value
);
359 param
.captured
= old_captured
;
362 emit_context
.pop_symbol ();
364 foreach (var type_param
in m
.get_type_parameters ()) {
365 var type
= "%s_type".printf (type_param
.name
.down ());
366 var dup_func
= "%s_dup_func".printf (type_param
.name
.down ());
367 var destroy_func
= "%s_destroy_func".printf (type_param
.name
.down ());
368 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, type
), new
CCodeIdentifier (type
));
369 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, dup_func
), new
CCodeIdentifier (dup_func
));
370 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, destroy_func
), new
CCodeIdentifier (destroy_func
));
373 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
) + "_co"));
374 ccall
.add_argument (data_var
);
375 ccode
.add_expression (ccall
);
377 cfile
.add_function (asyncfunc
);
382 public void append_struct (CCodeStruct structure
) {
383 var typename
= new
CCodeVariableDeclarator (structure
.name
.substring (1));
384 var typedef
= new
CCodeTypeDefinition ("struct " + structure
.name
, typename
);
385 cfile
.add_type_declaration (typedef
);
386 cfile
.add_type_definition (structure
);
389 public override void generate_method_declaration (Method m
, CCodeFile decl_space
) {
391 if (add_symbol_declaration (decl_space
, m
, get_ccode_name (m
))) {
395 var cl
= m
.parent_symbol as Class
;
397 var asyncfunc
= new
CCodeFunction (get_ccode_name (m
), "void");
398 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
399 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
401 if (m
.is_private_symbol ()) {
402 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
403 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
404 asyncfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
407 // do not generate _new functions for creation methods of abstract classes
408 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
409 generate_cparameters (m
, decl_space
, cparam_map
, asyncfunc
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")), 1);
411 decl_space
.add_function_declaration (asyncfunc
);
414 var finishfunc
= new
CCodeFunction (get_ccode_finish_name (m
));
415 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
416 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
418 if (m
.is_private_symbol ()) {
419 finishfunc
.modifiers
|= CCodeModifiers
.STATIC
;
420 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
421 finishfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
424 // do not generate _new functions for creation methods of abstract classes
425 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
426 generate_cparameters (m
, decl_space
, cparam_map
, finishfunc
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")), 2);
428 decl_space
.add_function_declaration (finishfunc
);
431 if (m is CreationMethod
&& cl
!= null) {
432 // _construct function
433 var function
= new
CCodeFunction (get_ccode_real_name (m
));
435 if (m
.is_private_symbol ()) {
436 function
.modifiers
|= CCodeModifiers
.STATIC
;
437 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
438 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
441 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
442 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, null, null, 1);
444 decl_space
.add_function_declaration (function
);
446 function
= new
CCodeFunction (get_ccode_finish_real_name (m
));
448 if (m
.is_private_symbol ()) {
449 function
.modifiers
|= CCodeModifiers
.STATIC
;
450 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
451 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
454 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
455 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, null, null, 2);
457 decl_space
.add_function_declaration (function
);
460 base.generate_method_declaration (m
, decl_space
);
464 public override void visit_method (Method m
) {
466 cfile
.add_include ("gio/gio.h");
467 if (!m
.is_internal_symbol ()) {
468 header_file
.add_include ("gio/gio.h");
471 if (!m
.is_abstract
&& m
.body
!= null) {
472 var data
= generate_data_struct (m
);
474 closure_struct
= data
;
476 generate_free_function (m
);
477 generate_async_function (m
);
478 generate_finish_function (m
);
480 // append the _co function
481 base.visit_method (m
);
482 closure_struct
= null;
484 // only append data struct here to make sure all struct member
485 // types are declared before the struct definition
486 append_struct (data
);
488 generate_method_declaration (m
, cfile
);
490 if (!m
.is_internal_symbol ()) {
491 generate_method_declaration (m
, header_file
);
493 if (!m
.is_private_symbol ()) {
494 generate_method_declaration (m
, internal_header_file
);
498 if (m
.is_abstract
|| m
.is_virtual
) {
499 // generate virtual function wrappers
500 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
501 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
502 generate_vfunc (m
, new
VoidType (), cparam_map
, carg_map
, "", 1);
504 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
505 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
506 generate_vfunc (m
, m
.return_type
, cparam_map
, carg_map
, "_finish", 2);
509 base.visit_method (m
);
513 public override void visit_creation_method (CreationMethod m
) {
515 base.visit_creation_method (m
);
517 push_line (m
.source_reference
);
519 bool visible
= !m
.is_private_symbol ();
523 if (m
.source_type
== SourceFileType
.FAST
) {
527 // do not generate _new functions for creation methods of abstract classes
528 if (current_type_symbol is Class
&& !current_class
.is_compact
&& !current_class
.is_abstract
) {
529 var vfunc
= new
CCodeFunction (get_ccode_name (m
));
531 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
532 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
534 push_function (vfunc
);
536 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
)));
537 vcall
.add_argument (new
CCodeIdentifier (get_ccode_type_id (current_class
)));
539 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, 1);
540 ccode
.add_expression (vcall
);
543 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
548 cfile
.add_function (vfunc
);
551 vfunc
= new
CCodeFunction (get_ccode_finish_name (m
));
553 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
554 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
556 push_function (vfunc
);
558 vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_finish_real_name (m
)));
560 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, 2);
561 ccode
.add_return (vcall
);
564 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
569 cfile
.add_function (vfunc
);
576 void generate_finish_function (Method m
) {
577 push_context (new
EmitContext ());
579 string dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
581 var finishfunc
= new
CCodeFunction (get_ccode_finish_real_name (m
));
583 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
585 cparam_map
.set (get_param_pos (0.1), new
CCodeParameter ("_res_", "GAsyncResult*"));
587 generate_cparameters (m
, cfile
, cparam_map
, finishfunc
, null, null, null, 2);
589 if (m
.is_private_symbol () || m
.base_method
!= null || m
.base_interface_method
!= null) {
590 finishfunc
.modifiers
|= CCodeModifiers
.STATIC
;
591 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
592 finishfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
595 push_function (finishfunc
);
597 var return_type
= m
.return_type
;
598 if (m is CreationMethod
) {
599 var type_sym
= (TypeSymbol
) m
.parent_symbol
;
600 if (type_sym is ObjectTypeSymbol
) {
601 ccode
.add_declaration (get_ccode_name (type_sym
) + "*", new
CCodeVariableDeclarator ("result"));
602 return_type
= ((ObjectTypeSymbol
) type_sym
).get_this_type ();
604 } else if (!(return_type is VoidType
) && !return_type
.is_real_non_null_struct_type ()) {
605 ccode
.add_declaration (get_ccode_name (m
.return_type
), new
CCodeVariableDeclarator ("result"));
608 var data_var
= new
CCodeIdentifier ("_data_");
610 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
612 var async_result_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TASK"));
613 async_result_cast
.add_argument (new
CCodeIdentifier ("_res_"));
615 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_propagate_pointer"));
616 ccall
.add_argument (async_result_cast
);
618 if (m
.get_error_types ().size
> 0) {
619 ccall
.add_argument (new
CCodeIdentifier ("error"));
621 ccall
.add_argument (new
CCodeConstant ("NULL"));
624 ccode
.add_assignment (data_var
, ccall
);
626 bool has_cancellable
= false;
628 foreach (Parameter param
in m
.get_parameters ()) {
629 if (param
.variable_type is ObjectType
&& param
.variable_type
.data_type
.get_full_name () == "GLib.Cancellable") {
630 has_cancellable
= true;
635 // If a task is cancelled, g_task_propagate_pointer returns NULL
636 if (m
.get_error_types ().size
> 0 || has_cancellable
) {
637 var is_null
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeConstant ("NULL"), data_var
);
639 ccode
.open_if (is_null
);
640 return_default_value (return_type
);
644 emit_context
.push_symbol (m
);
645 foreach (Parameter param
in m
.get_parameters ()) {
646 if (param
.direction
!= ParameterDirection
.IN
) {
647 return_out_parameter (param
);
648 if (!(param
.variable_type is ValueType
) || param
.variable_type
.nullable
) {
649 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, get_variable_cname (param
.name
)), new
CCodeConstant ("NULL"));
653 emit_context
.pop_symbol ();
655 if (m is CreationMethod
) {
656 ccode
.add_assignment (new
CCodeIdentifier ("result"), new CCodeMemberAccess
.pointer (data_var
, "self"));
657 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "self"), new
CCodeConstant ("NULL"));
658 ccode
.add_return (new
CCodeIdentifier ("result"));
659 } else if (return_type
.is_real_non_null_struct_type ()) {
660 // structs are returned via out parameter
661 CCodeExpression cexpr
= new CCodeMemberAccess
.pointer (data_var
, "result");
662 if (requires_copy (return_type
)) {
663 cexpr
= get_cvalue_ (copy_value (new
GLibValue (return_type
, cexpr
, true), return_type
));
665 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result")), cexpr
);
666 } else if (!(return_type is VoidType
)) {
667 ccode
.add_assignment (new
CCodeIdentifier ("result"), new CCodeMemberAccess
.pointer (data_var
, "result"));
668 if (return_type is ArrayType
) {
669 var array_type
= (ArrayType
) return_type
;
670 if (get_ccode_array_length (m
)) {
671 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
672 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
)));
675 } else if (return_type is DelegateType
&& ((DelegateType
) return_type
).delegate_symbol
.has_target
) {
676 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")));
678 if (!(return_type is ValueType
) || return_type
.nullable
) {
679 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "result"), new
CCodeConstant ("NULL"));
681 ccode
.add_return (new
CCodeIdentifier ("result"));
686 cfile
.add_function (finishfunc
);
691 public override string generate_ready_function (Method m
) {
692 // generate ready callback handler
694 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
696 var readyfunc
= new
CCodeFunction (get_ccode_name (m
) + "_ready", "void");
698 if (!add_wrapper (readyfunc
.name
)) {
699 // wrapper already defined
700 return readyfunc
.name
;
703 readyfunc
.add_parameter (new
CCodeParameter ("source_object", "GObject*"));
704 readyfunc
.add_parameter (new
CCodeParameter ("_res_", "GAsyncResult*"));
705 readyfunc
.add_parameter (new
CCodeParameter ("_user_data_", "gpointer"));
707 push_function (readyfunc
);
709 var data_var
= new
CCodeIdentifier ("_data_");
711 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
712 ccode
.add_assignment (data_var
, new
CCodeIdentifier ("_user_data_"));
713 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_source_object_"), new
CCodeIdentifier ("source_object"));
714 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_res_"), new
CCodeIdentifier ("_res_"));
716 if (!context
.require_glib_version (2, 44)) {
717 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_task_complete_"), new
CCodeConstant ("TRUE"));
720 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
) + "_co"));
721 ccall
.add_argument (data_var
);
722 ccode
.add_expression (ccall
);
724 readyfunc
.modifiers
|= CCodeModifiers
.STATIC
;
728 cfile
.add_function_declaration (readyfunc
);
729 cfile
.add_function (readyfunc
);
731 return readyfunc
.name
;
734 public override void generate_virtual_method_declaration (Method m
, CCodeFile decl_space
, CCodeStruct type_struct
) {
736 base.generate_virtual_method_declaration (m
, decl_space
, type_struct
);
740 if (!m
.is_abstract
&& !m
.is_virtual
) {
744 var creturn_type
= m
.return_type
;
745 if (m
.return_type
.is_real_non_null_struct_type ()) {
746 // structs are returned via out parameter
747 creturn_type
= new
VoidType ();
750 // add vfunc field to the type struct
751 var vdeclarator
= new
CCodeFunctionDeclarator (get_ccode_vfunc_name (m
));
752 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
754 generate_cparameters (m
, decl_space
, cparam_map
, new
CCodeFunction ("fake"), vdeclarator
, null, null, 1);
756 var vdecl
= new
CCodeDeclaration ("void");
757 vdecl
.add_declarator (vdeclarator
);
758 type_struct
.add_declaration (vdecl
);
760 // add vfunc field to the type struct
761 vdeclarator
= new
CCodeFunctionDeclarator (get_ccode_finish_vfunc_name (m
));
762 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
764 generate_cparameters (m
, decl_space
, cparam_map
, new
CCodeFunction ("fake"), vdeclarator
, null, null, 2);
766 vdecl
= new
CCodeDeclaration (get_ccode_name (creturn_type
));
767 vdecl
.add_declarator (vdeclarator
);
768 type_struct
.add_declaration (vdecl
);
771 public override void visit_yield_statement (YieldStatement stmt
) {
772 if (!is_in_coroutine ()) {
776 if (stmt
.yield_expression
== null) {
777 int state
= emit_context
.next_coroutine_state
++;
779 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_state_"), new
CCodeConstant (state
.to_string ()));
780 ccode
.add_return (new
CCodeConstant ("FALSE"));
781 ccode
.add_label ("_state_%d".printf (state
));
782 ccode
.add_statement (new
CCodeEmptyStatement ());
787 if (stmt
.yield_expression
.error
) {
792 ccode
.add_expression (get_cvalue (stmt
.yield_expression
));
794 if (stmt
.tree_can_fail
&& stmt
.yield_expression
.tree_can_fail
) {
795 // simple case, no node breakdown necessary
797 add_simple_check (stmt
.yield_expression
);
800 /* free temporary objects */
802 foreach (var value
in temp_ref_values
) {
803 ccode
.add_expression (destroy_value (value
));
806 temp_ref_values
.clear ();
809 public override void return_with_exception (CCodeExpression error_expr
)
811 if (!is_in_coroutine ()) {
812 base.return_with_exception (error_expr
);
816 var async_result_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_async_result");
817 CCodeFunctionCall set_error
= null;
819 set_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_return_error"));
820 set_error
.add_argument (async_result_expr
);
821 set_error
.add_argument (error_expr
);
822 ccode
.add_expression (set_error
);
824 append_local_free (current_symbol
, false);
826 // We already returned the error above, we must not return anything else here.
827 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
828 unref
.add_argument (async_result_expr
);
829 ccode
.add_expression (unref
);
831 ccode
.add_return (new
CCodeConstant ("FALSE"));
834 public override void visit_return_statement (ReturnStatement stmt
) {
835 base.visit_return_statement (stmt
);
837 if (!is_in_coroutine ()) {
844 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) {
846 decl_space
.add_include ("gio/gio.h");
848 if (direction
== 1) {
849 cparam_map
.set (get_param_pos (-1), new
CCodeParameter ("_callback_", "GAsyncReadyCallback"));
850 cparam_map
.set (get_param_pos (-0.9), new
CCodeParameter ("_user_data_", "gpointer"));
851 if (carg_map
!= null) {
852 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier ("_callback_"));
853 carg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("_user_data_"));
855 } else if (direction
== 2) {
856 cparam_map
.set (get_param_pos (0.1), new
CCodeParameter ("_res_", "GAsyncResult*"));
857 if (carg_map
!= null) {
858 carg_map
.set (get_param_pos (0.1), new
CCodeIdentifier ("_res_"));
862 base.generate_cparameters (m
, decl_space
, cparam_map
, func
, vdeclarator
, carg_map
, vcall
, direction
);
865 public string generate_async_callback_wrapper () {
866 string async_callback_wrapper_func
= "_vala_g_async_ready_callback";
868 if (!add_wrapper (async_callback_wrapper_func
)) {
869 return async_callback_wrapper_func
;
872 var function
= new
CCodeFunction (async_callback_wrapper_func
, "void");
873 function
.modifiers
= CCodeModifiers
.STATIC
;
875 function
.add_parameter (new
CCodeParameter ("*source_object", "GObject"));
876 function
.add_parameter (new
CCodeParameter ("*res", "GAsyncResult"));
877 function
.add_parameter (new
CCodeParameter ("*user_data", "void"));
879 push_function (function
);
881 var res_ref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref"));
882 res_ref
.add_argument (new
CCodeIdentifier ("res"));
884 CCodeFunctionCall ccall
= null;
886 // store reference to async result of inner async function in out async result
887 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_return_pointer"));
888 ccall
.add_argument (new
CCodeIdentifier ("user_data"));
889 ccall
.add_argument (res_ref
);
890 ccall
.add_argument (new
CCodeIdentifier ("g_object_unref"));
891 ccode
.add_expression (ccall
);
894 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
895 ccall
.add_argument (new
CCodeIdentifier ("user_data"));
896 ccode
.add_expression (ccall
);
900 cfile
.add_function_declaration (function
);
901 cfile
.add_function (function
);
903 return async_callback_wrapper_func
;