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 bool is_unowned_delegate
= param
.variable_type is DelegateType
&& !param
.variable_type
.value_owned
;
56 var param_type
= param
.variable_type
.copy ();
57 param_type
.value_owned
= true;
58 data
.add_field (get_ccode_name (param_type
), get_variable_cname (param
.name
));
60 if (param
.variable_type is ArrayType
) {
61 var array_type
= (ArrayType
) param
.variable_type
;
62 if (get_ccode_array_length (param
)) {
63 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
64 data
.add_field ("gint", get_parameter_array_length_cname (param
, dim
));
67 } else if (param
.variable_type is DelegateType
) {
68 var deleg_type
= (DelegateType
) param
.variable_type
;
69 if (deleg_type
.delegate_symbol
.has_target
) {
70 data
.add_field ("gpointer", get_ccode_delegate_target_name (param
));
71 if (!is_unowned_delegate
) {
72 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
78 foreach (var type_param
in m
.get_type_parameters ()) {
79 data
.add_field ("GType", "%s_type".printf (type_param
.name
.down ()));
80 data
.add_field ("GBoxedCopyFunc", "%s_dup_func".printf (type_param
.name
.down ()));
81 data
.add_field ("GDestroyNotify", "%s_destroy_func".printf (type_param
.name
.down ()));
84 if (!(m
.return_type is VoidType
)) {
85 data
.add_field (get_ccode_name (m
.return_type
), "result");
86 if (m
.return_type is ArrayType
) {
87 var array_type
= (ArrayType
) m
.return_type
;
88 if (get_ccode_array_length (m
)) {
89 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
90 data
.add_field ("gint", get_array_length_cname ("result", dim
));
93 } else if (m
.return_type is DelegateType
) {
94 var deleg_type
= (DelegateType
) m
.return_type
;
95 if (deleg_type
.delegate_symbol
.has_target
) {
96 data
.add_field ("gpointer", get_delegate_target_cname ("result"));
97 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname ("result"));
105 CCodeFunction
generate_free_function (Method m
) {
106 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
108 var freefunc
= new
CCodeFunction (get_ccode_real_name (m
) + "_data_free", "void");
109 freefunc
.modifiers
= CCodeModifiers
.STATIC
;
110 freefunc
.add_parameter (new
CCodeParameter ("_data", "gpointer"));
112 push_context (new
EmitContext (m
));
113 push_function (freefunc
);
115 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_", new
CCodeIdentifier ("_data")));
117 foreach (Parameter param
in m
.get_parameters ()) {
118 if (!param
.captured
&& param
.direction
!= ParameterDirection
.OUT
) {
119 var param_type
= param
.variable_type
.copy ();
120 if (!param_type
.value_owned
) {
121 param_type
.value_owned
= !no_implicit_copy (param_type
);
124 if (requires_destroy (param_type
)) {
125 ccode
.add_expression (destroy_parameter (param
));
130 if (requires_destroy (m
.return_type
)) {
131 if (get_ccode_array_length (m
) || !(m
.return_type is ArrayType
)) {
132 /* this is very evil. */
133 var v
= new
LocalVariable (m
.return_type
, ".result");
134 ccode
.add_expression (destroy_local (v
));
136 var v
= new
GLibValue (m
.return_type
, new
CCodeIdentifier ("_data_->result"), true);
137 v
.array_null_terminated
= get_ccode_array_null_terminated (m
);
138 ccode
.add_expression (destroy_value (v
));
142 if (m
.binding
== MemberBinding
.INSTANCE
) {
143 var this_type
= m
.this_parameter
.variable_type
.copy ();
144 this_type
.value_owned
= true;
146 if (requires_destroy (this_type
)) {
147 ccode
.add_expression (destroy_parameter (m
.this_parameter
));
151 var freecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
152 freecall
.add_argument (new
CCodeIdentifier (dataname
));
153 freecall
.add_argument (new
CCodeIdentifier ("_data_"));
154 ccode
.add_expression (freecall
);
158 cfile
.add_function_declaration (freefunc
);
159 cfile
.add_function (freefunc
);
164 void generate_async_ready_callback_wrapper (Method m
, string function_name
) {
165 var function
= new
CCodeFunction (function_name
, "void");
166 function
.modifiers
= CCodeModifiers
.STATIC
;
168 function
.add_parameter (new
CCodeParameter ("*source_object", "GObject"));
169 function
.add_parameter (new
CCodeParameter ("*res", "GAsyncResult"));
170 function
.add_parameter (new
CCodeParameter ("*user_data", "void"));
172 push_function (function
);
174 // Set _task_complete_ to false after calling back to the real func
175 var async_result_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TASK"));
176 async_result_cast
.add_argument (new
CCodeIdentifier ("res"));
178 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
179 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_task_data_"));
181 var get_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_get_task_data"));
182 get_data_call
.add_argument (async_result_cast
);
184 var data_var
= new
CCodeIdentifier ("_task_data_");
185 ccode
.add_assignment (data_var
, get_data_call
);
187 var task_inner_callback
= new CCodeMemberAccess
.pointer (data_var
, "_callback_");
188 var callback_is_nonnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, task_inner_callback
, new
CCodeConstant ("NULL"));
190 ccode
.open_if (callback_is_nonnull
);
191 var nested_callback
= new
CCodeFunctionCall (task_inner_callback
);
192 nested_callback
.add_argument (new
CCodeIdentifier ("source_object"));
193 nested_callback
.add_argument (new
CCodeIdentifier ("res"));
194 nested_callback
.add_argument (new
CCodeIdentifier ("user_data"));
195 ccode
.add_expression (nested_callback
);
198 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_task_complete_"), new
CCodeConstant ("TRUE"));
202 cfile
.add_function_declaration (function
);
203 cfile
.add_function (function
);
206 void generate_async_function (Method m
) {
207 push_context (new
EmitContext ());
209 string? callback_wrapper
= null;
211 if (!context
.require_glib_version (2, 44)) {
212 callback_wrapper
= get_ccode_real_name (m
) + "_async_ready_wrapper";
213 generate_async_ready_callback_wrapper (m
, callback_wrapper
);
216 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
217 var asyncfunc
= new
CCodeFunction (get_ccode_real_name (m
), "void");
218 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
220 cparam_map
.set (get_param_pos (-1), new
CCodeParameter ("_callback_", "GAsyncReadyCallback"));
221 cparam_map
.set (get_param_pos (-0.9), new
CCodeParameter ("_user_data_", "gpointer"));
223 generate_cparameters (m
, cfile
, cparam_map
, asyncfunc
, null, null, null, 1);
225 if (m
.base_method
!= null || m
.base_interface_method
!= null) {
226 // declare *_real_* function
227 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
228 cfile
.add_function_declaration (asyncfunc
);
229 } else if (m
.is_private_symbol ()) {
230 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
231 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
232 asyncfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
235 push_function (asyncfunc
);
237 // logic copied from valaccodemethodmodule
238 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
242 base_method
= m
.base_method
;
244 base_method
= m
.base_interface_method
;
247 var base_expression_type
= new
ObjectType ((ObjectTypeSymbol
) base_method
.parent_symbol
);
248 var type_symbol
= m
.parent_symbol as ObjectTypeSymbol
;
250 var self_target_type
= new
ObjectType (type_symbol
);
251 var cself
= get_cvalue_ (transform_value (new
GLibValue (base_expression_type
, new
CCodeIdentifier ("base"), true), self_target_type
, m
));
252 ccode
.add_declaration ("%s *".printf (get_ccode_name (type_symbol
)), new
CCodeVariableDeclarator ("self"));
253 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
256 var dataalloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
257 dataalloc
.add_argument (new
CCodeIdentifier (dataname
));
259 var data_var
= new
CCodeIdentifier ("_data_");
261 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
262 ccode
.add_assignment (data_var
, dataalloc
);
264 if (!context
.require_glib_version (2, 44)) {
265 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_callback_"), new
CCodeConstant ("_callback_"));
268 var create_result
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_new"));
270 var t
= m
.parent_symbol as TypeSymbol
;
271 if (!(m is CreationMethod
) && m
.binding
== MemberBinding
.INSTANCE
&&
272 t
!= null && t
.is_subtype_of (gobject_type
)) {
273 var gobject_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT"));
274 gobject_cast
.add_argument (new
CCodeIdentifier ("self"));
276 create_result
.add_argument (gobject_cast
);
278 create_result
.add_argument (new
CCodeConstant ("NULL"));
281 Parameter cancellable_param
= null;
283 foreach (Parameter param
in m
.get_parameters ()) {
284 if (param
.variable_type is ObjectType
&& param
.variable_type
.data_type
.get_full_name () == "GLib.Cancellable") {
285 cancellable_param
= param
;
290 if (cancellable_param
== null) {
291 create_result
.add_argument (new
CCodeConstant ("NULL"));
293 create_result
.add_argument (new
CCodeIdentifier (get_variable_cname (cancellable_param
.name
)));
296 if (context
.require_glib_version (2, 44)) {
297 create_result
.add_argument (new
CCodeIdentifier ("_callback_"));
299 create_result
.add_argument (new
CCodeIdentifier (callback_wrapper
));
301 create_result
.add_argument (new
CCodeIdentifier ("_user_data_"));
303 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_async_result"), create_result
);
305 if (!context
.require_glib_version (2, 44)) {
306 var task_completed_var
= new CCodeMemberAccess
.pointer (data_var
, "_task_complete_");
307 var callback = new
CCodeIdentifier ("_callback_");
308 var callback_is_null
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, callback, new
CCodeConstant ("NULL"));
310 ccode
.open_if (callback_is_null
);
311 ccode
.add_assignment (task_completed_var
, new
CCodeConstant ("TRUE"));
315 var attach_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_set_task_data"));
317 attach_data_call
.add_argument (new CCodeMemberAccess
.pointer (data_var
, "_async_result"));
318 attach_data_call
.add_argument (data_var
);
319 attach_data_call
.add_argument (new
CCodeIdentifier (get_ccode_real_name (m
) + "_data_free"));
320 ccode
.add_expression (attach_data_call
);
322 if (m is CreationMethod
) {
323 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "object_type"), new
CCodeIdentifier ("object_type"));
324 } else if (m
.binding
== MemberBinding
.INSTANCE
) {
325 var this_type
= m
.this_parameter
.variable_type
.copy ();
326 this_type
.value_owned
= true;
328 // create copy if necessary as variables in async methods may need to be kept alive
329 CCodeExpression cself
= new
CCodeIdentifier ("self");
330 if (this_type
.is_real_non_null_struct_type ()) {
331 cself
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cself
);
333 if (requires_copy (this_type
)) {
334 cself
= get_cvalue_ (copy_value (new
GLibValue (m
.this_parameter
.variable_type
, cself
, true), m
.this_parameter
));
337 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "self"), cself
);
340 emit_context
.push_symbol (m
);
341 foreach (Parameter param
in m
.get_parameters ()) {
342 if (param
.direction
!= ParameterDirection
.OUT
) {
343 // create copy if necessary as variables in async methods may need to be kept alive
344 var old_captured
= param
.captured
;
345 param
.captured
= false;
346 current_method
.coroutine
= false;
349 if (param
.variable_type
.value_owned
) {
350 // do not use load_parameter for reference/ownership transfer
351 // otherwise delegate destroy notify will not be moved
352 value
= get_parameter_cvalue (param
);
354 value
= load_parameter (param
);
357 current_method
.coroutine
= true;
359 store_parameter (param
, value
);
361 param
.captured
= old_captured
;
364 emit_context
.pop_symbol ();
366 foreach (var type_param
in m
.get_type_parameters ()) {
367 var type
= "%s_type".printf (type_param
.name
.down ());
368 var dup_func
= "%s_dup_func".printf (type_param
.name
.down ());
369 var destroy_func
= "%s_destroy_func".printf (type_param
.name
.down ());
370 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, type
), new
CCodeIdentifier (type
));
371 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, dup_func
), new
CCodeIdentifier (dup_func
));
372 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, destroy_func
), new
CCodeIdentifier (destroy_func
));
375 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
) + "_co"));
376 ccall
.add_argument (data_var
);
377 ccode
.add_expression (ccall
);
379 cfile
.add_function (asyncfunc
);
384 void append_struct (CCodeStruct structure
) {
385 var typename
= new
CCodeVariableDeclarator (structure
.name
.substring (1));
386 var typedef
= new
CCodeTypeDefinition ("struct " + structure
.name
, typename
);
387 cfile
.add_type_declaration (typedef
);
388 cfile
.add_type_definition (structure
);
391 public override void generate_method_declaration (Method m
, CCodeFile decl_space
) {
393 if (add_symbol_declaration (decl_space
, m
, get_ccode_name (m
))) {
397 var cl
= m
.parent_symbol as Class
;
399 var asyncfunc
= new
CCodeFunction (get_ccode_name (m
), "void");
400 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
401 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
403 if (m
.is_private_symbol ()) {
404 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
405 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
406 asyncfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
409 // do not generate _new functions for creation methods of abstract classes
410 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
411 generate_cparameters (m
, decl_space
, cparam_map
, asyncfunc
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")), 1);
413 decl_space
.add_function_declaration (asyncfunc
);
416 var finishfunc
= new
CCodeFunction (get_ccode_finish_name (m
));
417 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
418 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
420 if (m
.is_private_symbol ()) {
421 finishfunc
.modifiers
|= CCodeModifiers
.STATIC
;
422 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
423 finishfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
426 // do not generate _new functions for creation methods of abstract classes
427 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
428 generate_cparameters (m
, decl_space
, cparam_map
, finishfunc
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")), 2);
430 decl_space
.add_function_declaration (finishfunc
);
433 if (m is CreationMethod
&& cl
!= null) {
434 // _construct function
435 var function
= new
CCodeFunction (get_ccode_real_name (m
));
437 if (m
.is_private_symbol ()) {
438 function
.modifiers
|= CCodeModifiers
.STATIC
;
439 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
440 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
443 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
444 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, null, null, 1);
446 decl_space
.add_function_declaration (function
);
448 function
= new
CCodeFunction (get_ccode_finish_real_name (m
));
450 if (m
.is_private_symbol ()) {
451 function
.modifiers
|= CCodeModifiers
.STATIC
;
452 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
453 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
456 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
457 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, null, null, 2);
459 decl_space
.add_function_declaration (function
);
462 base.generate_method_declaration (m
, decl_space
);
466 public override void visit_method (Method m
) {
468 cfile
.add_include ("gio/gio.h");
469 if (!m
.is_internal_symbol ()) {
470 header_file
.add_include ("gio/gio.h");
473 if (!m
.is_abstract
&& m
.body
!= null) {
474 var data
= generate_data_struct (m
);
476 closure_struct
= data
;
478 generate_free_function (m
);
479 generate_async_function (m
);
480 generate_finish_function (m
);
482 // append the _co function
483 base.visit_method (m
);
484 closure_struct
= null;
486 // only append data struct here to make sure all struct member
487 // types are declared before the struct definition
488 append_struct (data
);
490 generate_method_declaration (m
, cfile
);
492 if (!m
.is_internal_symbol ()) {
493 generate_method_declaration (m
, header_file
);
495 if (!m
.is_private_symbol ()) {
496 generate_method_declaration (m
, internal_header_file
);
500 if (m
.is_abstract
|| m
.is_virtual
) {
501 // generate virtual function wrappers
502 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
503 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
504 generate_vfunc (m
, new
VoidType (), cparam_map
, carg_map
, "", 1);
506 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
507 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
508 generate_vfunc (m
, m
.return_type
, cparam_map
, carg_map
, "_finish", 2);
511 base.visit_method (m
);
515 public override void visit_creation_method (CreationMethod m
) {
517 base.visit_creation_method (m
);
519 push_line (m
.source_reference
);
521 bool visible
= !m
.is_private_symbol ();
525 if (m
.source_type
== SourceFileType
.FAST
) {
529 // do not generate _new functions for creation methods of abstract classes
530 if (current_type_symbol is Class
&& !current_class
.is_compact
&& !current_class
.is_abstract
) {
531 var vfunc
= new
CCodeFunction (get_ccode_name (m
));
533 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
534 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
536 push_function (vfunc
);
538 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
)));
539 vcall
.add_argument (new
CCodeIdentifier (get_ccode_type_id (current_class
)));
541 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, 1);
542 ccode
.add_expression (vcall
);
545 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
550 cfile
.add_function (vfunc
);
553 vfunc
= new
CCodeFunction (get_ccode_finish_name (m
));
555 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
556 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
558 push_function (vfunc
);
560 vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_finish_real_name (m
)));
562 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, 2);
563 ccode
.add_return (vcall
);
566 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
571 cfile
.add_function (vfunc
);
578 void generate_finish_function (Method m
) {
579 push_context (new
EmitContext ());
581 string dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
583 var finishfunc
= new
CCodeFunction (get_ccode_finish_real_name (m
));
585 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
587 cparam_map
.set (get_param_pos (0.1), new
CCodeParameter ("_res_", "GAsyncResult*"));
589 generate_cparameters (m
, cfile
, cparam_map
, finishfunc
, null, null, null, 2);
591 if (m
.is_private_symbol () || m
.base_method
!= null || m
.base_interface_method
!= null) {
592 finishfunc
.modifiers
|= CCodeModifiers
.STATIC
;
593 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
594 finishfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
597 push_function (finishfunc
);
599 var return_type
= m
.return_type
;
600 if (m is CreationMethod
) {
601 var type_sym
= (TypeSymbol
) m
.parent_symbol
;
602 if (type_sym is ObjectTypeSymbol
) {
603 ccode
.add_declaration (get_ccode_name (type_sym
) + "*", new
CCodeVariableDeclarator ("result"));
605 } else if (!(return_type is VoidType
) && !return_type
.is_real_non_null_struct_type ()) {
606 ccode
.add_declaration (get_ccode_name (m
.return_type
), new
CCodeVariableDeclarator ("result"));
609 var data_var
= new
CCodeIdentifier ("_data_");
611 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
613 var async_result_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TASK"));
614 async_result_cast
.add_argument (new
CCodeIdentifier ("_res_"));
616 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_propagate_pointer"));
617 ccall
.add_argument (async_result_cast
);
619 if (m
.get_error_types ().size
> 0) {
620 ccall
.add_argument (new
CCodeIdentifier ("error"));
622 ccall
.add_argument (new
CCodeConstant ("NULL"));
625 ccode
.add_assignment (data_var
, ccall
);
627 bool has_cancellable
= false;
629 foreach (Parameter param
in m
.get_parameters ()) {
630 if (param
.variable_type is ObjectType
&& param
.variable_type
.data_type
.get_full_name () == "GLib.Cancellable") {
631 has_cancellable
= true;
636 // If a task is cancelled, g_task_propagate_pointer returns NULL
637 if (m
.get_error_types ().size
> 0 || has_cancellable
) {
638 var is_null
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeConstant ("NULL"), data_var
);
640 ccode
.open_if (is_null
);
641 return_default_value (return_type
);
645 emit_context
.push_symbol (m
);
646 foreach (Parameter param
in m
.get_parameters ()) {
647 if (param
.direction
!= ParameterDirection
.IN
) {
648 return_out_parameter (param
);
649 if (!(param
.variable_type is ValueType
) || param
.variable_type
.nullable
) {
650 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, get_variable_cname (param
.name
)), new
CCodeConstant ("NULL"));
654 emit_context
.pop_symbol ();
656 if (m is CreationMethod
) {
657 ccode
.add_assignment (new
CCodeIdentifier ("result"), new CCodeMemberAccess
.pointer (data_var
, "self"));
658 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "self"), new
CCodeConstant ("NULL"));
659 ccode
.add_return (new
CCodeIdentifier ("result"));
660 } else if (return_type
.is_real_non_null_struct_type ()) {
661 // structs are returned via out parameter
662 CCodeExpression cexpr
= new CCodeMemberAccess
.pointer (data_var
, "result");
663 if (requires_copy (return_type
)) {
664 cexpr
= get_cvalue_ (copy_value (new
GLibValue (return_type
, cexpr
, true), return_type
));
666 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result")), cexpr
);
667 } else if (!(return_type is VoidType
)) {
668 ccode
.add_assignment (new
CCodeIdentifier ("result"), new CCodeMemberAccess
.pointer (data_var
, "result"));
669 if (return_type is ArrayType
) {
670 var array_type
= (ArrayType
) return_type
;
671 if (get_ccode_array_length (m
)) {
672 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
673 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
)));
676 } else if (return_type is DelegateType
&& ((DelegateType
) return_type
).delegate_symbol
.has_target
) {
677 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")));
679 if (!(return_type is ValueType
) || return_type
.nullable
) {
680 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "result"), new
CCodeConstant ("NULL"));
682 ccode
.add_return (new
CCodeIdentifier ("result"));
687 cfile
.add_function (finishfunc
);
692 public override string generate_ready_function (Method m
) {
693 // generate ready callback handler
695 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
697 var readyfunc
= new
CCodeFunction (get_ccode_name (m
) + "_ready", "void");
699 if (!add_wrapper (readyfunc
.name
)) {
700 // wrapper already defined
701 return readyfunc
.name
;
704 readyfunc
.add_parameter (new
CCodeParameter ("source_object", "GObject*"));
705 readyfunc
.add_parameter (new
CCodeParameter ("_res_", "GAsyncResult*"));
706 readyfunc
.add_parameter (new
CCodeParameter ("_user_data_", "gpointer"));
708 push_function (readyfunc
);
710 var data_var
= new
CCodeIdentifier ("_data_");
712 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
713 ccode
.add_assignment (data_var
, new
CCodeIdentifier ("_user_data_"));
714 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_source_object_"), new
CCodeIdentifier ("source_object"));
715 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_res_"), new
CCodeIdentifier ("_res_"));
717 if (!context
.require_glib_version (2, 44)) {
718 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_task_complete_"), new
CCodeConstant ("TRUE"));
721 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
) + "_co"));
722 ccall
.add_argument (data_var
);
723 ccode
.add_expression (ccall
);
725 readyfunc
.modifiers
|= CCodeModifiers
.STATIC
;
729 cfile
.add_function_declaration (readyfunc
);
730 cfile
.add_function (readyfunc
);
732 return readyfunc
.name
;
735 public override void generate_virtual_method_declaration (Method m
, CCodeFile decl_space
, CCodeStruct type_struct
) {
737 base.generate_virtual_method_declaration (m
, decl_space
, type_struct
);
741 if (!m
.is_abstract
&& !m
.is_virtual
) {
745 var creturn_type
= m
.return_type
;
746 if (m
.return_type
.is_real_non_null_struct_type ()) {
747 // structs are returned via out parameter
748 creturn_type
= new
VoidType ();
751 // add vfunc field to the type struct
752 var vdeclarator
= new
CCodeFunctionDeclarator (get_ccode_vfunc_name (m
));
753 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
755 generate_cparameters (m
, decl_space
, cparam_map
, new
CCodeFunction ("fake"), vdeclarator
, null, null, 1);
757 var vdecl
= new
CCodeDeclaration ("void");
758 vdecl
.add_declarator (vdeclarator
);
759 type_struct
.add_declaration (vdecl
);
761 // add vfunc field to the type struct
762 vdeclarator
= new
CCodeFunctionDeclarator (get_ccode_finish_vfunc_name (m
));
763 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
765 generate_cparameters (m
, decl_space
, cparam_map
, new
CCodeFunction ("fake"), vdeclarator
, null, null, 2);
767 vdecl
= new
CCodeDeclaration (get_ccode_name (creturn_type
));
768 vdecl
.add_declarator (vdeclarator
);
769 type_struct
.add_declaration (vdecl
);
772 public override void visit_yield_statement (YieldStatement stmt
) {
773 if (!is_in_coroutine ()) {
777 if (stmt
.yield_expression
== null) {
778 int state
= emit_context
.next_coroutine_state
++;
780 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_state_"), new
CCodeConstant (state
.to_string ()));
781 ccode
.add_return (new
CCodeConstant ("FALSE"));
782 ccode
.add_label ("_state_%d".printf (state
));
783 ccode
.add_statement (new
CCodeEmptyStatement ());
788 if (stmt
.yield_expression
.error
) {
793 ccode
.add_expression (get_cvalue (stmt
.yield_expression
));
795 if (stmt
.tree_can_fail
&& stmt
.yield_expression
.tree_can_fail
) {
796 // simple case, no node breakdown necessary
798 add_simple_check (stmt
.yield_expression
);
801 /* free temporary objects */
803 foreach (var value
in temp_ref_values
) {
804 ccode
.add_expression (destroy_value (value
));
807 temp_ref_values
.clear ();
810 public override void return_with_exception (CCodeExpression error_expr
)
812 if (!is_in_coroutine ()) {
813 base.return_with_exception (error_expr
);
817 var async_result_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_async_result");
818 CCodeFunctionCall set_error
= null;
820 set_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_return_error"));
821 set_error
.add_argument (async_result_expr
);
822 set_error
.add_argument (error_expr
);
823 ccode
.add_expression (set_error
);
825 append_local_free (current_symbol
, false);
827 // We already returned the error above, we must not return anything else here.
828 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
829 unref
.add_argument (async_result_expr
);
830 ccode
.add_expression (unref
);
832 ccode
.add_return (new
CCodeConstant ("FALSE"));
835 public override void visit_return_statement (ReturnStatement stmt
) {
836 base.visit_return_statement (stmt
);
838 if (!is_in_coroutine ()) {
845 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) {
847 decl_space
.add_include ("gio/gio.h");
849 if (direction
== 1) {
850 cparam_map
.set (get_param_pos (-1), new
CCodeParameter ("_callback_", "GAsyncReadyCallback"));
851 cparam_map
.set (get_param_pos (-0.9), new
CCodeParameter ("_user_data_", "gpointer"));
852 if (carg_map
!= null) {
853 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier ("_callback_"));
854 carg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("_user_data_"));
856 } else if (direction
== 2) {
857 cparam_map
.set (get_param_pos (0.1), new
CCodeParameter ("_res_", "GAsyncResult*"));
858 if (carg_map
!= null) {
859 carg_map
.set (get_param_pos (0.1), new
CCodeIdentifier ("_res_"));
863 base.generate_cparameters (m
, decl_space
, cparam_map
, func
, vdeclarator
, carg_map
, vcall
, direction
);
866 public string generate_async_callback_wrapper () {
867 string async_callback_wrapper_func
= "_vala_g_async_ready_callback";
869 if (!add_wrapper (async_callback_wrapper_func
)) {
870 return async_callback_wrapper_func
;
873 var function
= new
CCodeFunction (async_callback_wrapper_func
, "void");
874 function
.modifiers
= CCodeModifiers
.STATIC
;
876 function
.add_parameter (new
CCodeParameter ("*source_object", "GObject"));
877 function
.add_parameter (new
CCodeParameter ("*res", "GAsyncResult"));
878 function
.add_parameter (new
CCodeParameter ("*user_data", "void"));
880 push_function (function
);
882 var res_ref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref"));
883 res_ref
.add_argument (new
CCodeIdentifier ("res"));
885 CCodeFunctionCall ccall
= null;
887 // store reference to async result of inner async function in out async result
888 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_return_pointer"));
889 ccall
.add_argument (new
CCodeIdentifier ("user_data"));
890 ccall
.add_argument (res_ref
);
891 ccall
.add_argument (new
CCodeIdentifier ("g_object_unref"));
892 ccode
.add_expression (ccall
);
895 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
896 ccall
.add_argument (new
CCodeIdentifier ("user_data"));
897 ccode
.add_expression (ccall
);
901 cfile
.add_function_declaration (function
);
902 cfile
.add_function (function
);
904 return async_callback_wrapper_func
;