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 if (context
.require_glib_version (2, 36)) {
35 data
.add_field ("GTask*", "_async_result");
36 if (!context
.require_glib_version (2, 44)) {
37 data
.add_field ("GAsyncReadyCallback", "_callback_");
38 data
.add_field ("gboolean", "_task_complete_");
41 data
.add_field ("GSimpleAsyncResult*", "_async_result");
44 if (m is CreationMethod
) {
45 data
.add_field ("GType", "object_type");
48 if (m
.binding
== MemberBinding
.INSTANCE
) {
49 var type_sym
= (TypeSymbol
) m
.parent_symbol
;
50 if (type_sym is ObjectTypeSymbol
) {
51 data
.add_field (get_ccode_name (type_sym
) + "*", "self");
53 data
.add_field (get_ccode_name (type_sym
), "self");
57 foreach (Parameter param
in m
.get_parameters ()) {
58 bool is_unowned_delegate
= param
.variable_type is DelegateType
&& !param
.variable_type
.value_owned
;
60 var param_type
= param
.variable_type
.copy ();
61 param_type
.value_owned
= true;
62 data
.add_field (get_ccode_name (param_type
), get_variable_cname (param
.name
));
64 if (param
.variable_type is ArrayType
) {
65 var array_type
= (ArrayType
) param
.variable_type
;
66 if (get_ccode_array_length (param
)) {
67 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
68 data
.add_field ("gint", get_parameter_array_length_cname (param
, dim
));
71 } else if (param
.variable_type is DelegateType
) {
72 var deleg_type
= (DelegateType
) param
.variable_type
;
73 if (deleg_type
.delegate_symbol
.has_target
) {
74 data
.add_field ("gpointer", get_ccode_delegate_target_name (param
));
75 if (!is_unowned_delegate
) {
76 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
82 foreach (var type_param
in m
.get_type_parameters ()) {
83 data
.add_field ("GType", "%s_type".printf (type_param
.name
.down ()));
84 data
.add_field ("GBoxedCopyFunc", "%s_dup_func".printf (type_param
.name
.down ()));
85 data
.add_field ("GDestroyNotify", "%s_destroy_func".printf (type_param
.name
.down ()));
88 if (!(m
.return_type is VoidType
)) {
89 data
.add_field (get_ccode_name (m
.return_type
), "result");
90 if (m
.return_type is ArrayType
) {
91 var array_type
= (ArrayType
) m
.return_type
;
92 if (get_ccode_array_length (m
)) {
93 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
94 data
.add_field ("gint", get_array_length_cname ("result", dim
));
97 } else if (m
.return_type is DelegateType
) {
98 var deleg_type
= (DelegateType
) m
.return_type
;
99 if (deleg_type
.delegate_symbol
.has_target
) {
100 data
.add_field ("gpointer", get_delegate_target_cname ("result"));
101 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname ("result"));
109 CCodeFunction
generate_free_function (Method m
) {
110 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
112 var freefunc
= new
CCodeFunction (get_ccode_real_name (m
) + "_data_free", "void");
113 freefunc
.modifiers
= CCodeModifiers
.STATIC
;
114 freefunc
.add_parameter (new
CCodeParameter ("_data", "gpointer"));
116 push_context (new
EmitContext (m
));
117 push_function (freefunc
);
119 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_", new
CCodeIdentifier ("_data")));
121 foreach (Parameter param
in m
.get_parameters ()) {
122 if (!param
.captured
&& param
.direction
!= ParameterDirection
.OUT
) {
123 var param_type
= param
.variable_type
.copy ();
124 if (!param_type
.value_owned
) {
125 param_type
.value_owned
= !no_implicit_copy (param_type
);
128 if (requires_destroy (param_type
)) {
129 ccode
.add_expression (destroy_parameter (param
));
134 if (requires_destroy (m
.return_type
)) {
135 if (get_ccode_array_length (m
) || !(m
.return_type is ArrayType
)) {
136 /* this is very evil. */
137 var v
= new
LocalVariable (m
.return_type
, ".result");
138 ccode
.add_expression (destroy_local (v
));
140 var v
= new
GLibValue (m
.return_type
, new
CCodeIdentifier ("_data_->result"), true);
141 v
.array_null_terminated
= get_ccode_array_null_terminated (m
);
142 ccode
.add_expression (destroy_value (v
));
146 if (m
.binding
== MemberBinding
.INSTANCE
) {
147 var this_type
= m
.this_parameter
.variable_type
.copy ();
148 this_type
.value_owned
= true;
150 if (requires_destroy (this_type
)) {
151 ccode
.add_expression (destroy_parameter (m
.this_parameter
));
155 var freecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
156 freecall
.add_argument (new
CCodeIdentifier (dataname
));
157 freecall
.add_argument (new
CCodeIdentifier ("_data_"));
158 ccode
.add_expression (freecall
);
162 cfile
.add_function_declaration (freefunc
);
163 cfile
.add_function (freefunc
);
168 void generate_async_ready_callback_wrapper (Method m
, string function_name
) {
169 var function
= new
CCodeFunction (function_name
, "void");
170 function
.modifiers
= CCodeModifiers
.STATIC
;
172 function
.add_parameter (new
CCodeParameter ("*source_object", "GObject"));
173 function
.add_parameter (new
CCodeParameter ("*res", "GAsyncResult"));
174 function
.add_parameter (new
CCodeParameter ("*user_data", "void"));
176 push_function (function
);
178 // Set _task_complete_ to false after calling back to the real func
179 var async_result_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TASK"));
180 async_result_cast
.add_argument (new
CCodeIdentifier ("res"));
182 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
183 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_task_data_"));
185 var get_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_get_task_data"));
186 get_data_call
.add_argument (async_result_cast
);
188 var data_var
= new
CCodeIdentifier ("_task_data_");
189 ccode
.add_assignment (data_var
, get_data_call
);
191 var task_inner_callback
= new CCodeMemberAccess
.pointer (data_var
, "_callback_");
192 var callback_is_nonnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, task_inner_callback
, new
CCodeConstant ("NULL"));
194 ccode
.open_if (callback_is_nonnull
);
195 var nested_callback
= new
CCodeFunctionCall (task_inner_callback
);
196 nested_callback
.add_argument (new
CCodeIdentifier ("source_object"));
197 nested_callback
.add_argument (new
CCodeIdentifier ("res"));
198 nested_callback
.add_argument (new
CCodeIdentifier ("user_data"));
199 ccode
.add_expression (nested_callback
);
202 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_task_complete_"), new
CCodeConstant ("TRUE"));
206 cfile
.add_function_declaration (function
);
207 cfile
.add_function (function
);
210 void generate_async_function (Method m
) {
211 push_context (new
EmitContext ());
213 string? callback_wrapper
= null;
215 if (context
.require_glib_version (2, 36) && !context
.require_glib_version (2, 44)) {
216 callback_wrapper
= get_ccode_real_name (m
) + "_async_ready_wrapper";
217 generate_async_ready_callback_wrapper (m
, callback_wrapper
);
220 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
221 var asyncfunc
= new
CCodeFunction (get_ccode_real_name (m
), "void");
222 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
224 cparam_map
.set (get_param_pos (-1), new
CCodeParameter ("_callback_", "GAsyncReadyCallback"));
225 cparam_map
.set (get_param_pos (-0.9), new
CCodeParameter ("_user_data_", "gpointer"));
227 generate_cparameters (m
, cfile
, cparam_map
, asyncfunc
, null, null, null, 1);
229 if (m
.base_method
!= null || m
.base_interface_method
!= null) {
230 // declare *_real_* function
231 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
232 cfile
.add_function_declaration (asyncfunc
);
233 } else if (m
.is_private_symbol ()) {
234 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
235 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
236 asyncfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
239 push_function (asyncfunc
);
241 // logic copied from valaccodemethodmodule
242 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
246 base_method
= m
.base_method
;
248 base_method
= m
.base_interface_method
;
251 var base_expression_type
= new
ObjectType ((ObjectTypeSymbol
) base_method
.parent_symbol
);
252 var type_symbol
= m
.parent_symbol as ObjectTypeSymbol
;
254 var self_target_type
= new
ObjectType (type_symbol
);
255 var cself
= get_cvalue_ (transform_value (new
GLibValue (base_expression_type
, new
CCodeIdentifier ("base"), true), self_target_type
, m
));
256 ccode
.add_declaration ("%s *".printf (get_ccode_name (type_symbol
)), new
CCodeVariableDeclarator ("self"));
257 ccode
.add_assignment (new
CCodeIdentifier ("self"), cself
);
260 var dataalloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
261 dataalloc
.add_argument (new
CCodeIdentifier (dataname
));
263 var data_var
= new
CCodeIdentifier ("_data_");
265 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
266 ccode
.add_assignment (data_var
, dataalloc
);
268 CCodeFunctionCall? create_result
= null;
270 if (context
.require_glib_version (2, 36)) {
271 if (!context
.require_glib_version (2, 44)) {
272 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_callback_"), new
CCodeConstant ("_callback_"));
274 create_result
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_new"));
276 create_result
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_new"));
279 var t
= m
.parent_symbol as TypeSymbol
;
280 if (!(m is CreationMethod
) && m
.binding
== MemberBinding
.INSTANCE
&&
281 t
!= null && t
.is_subtype_of (gobject_type
)) {
282 var gobject_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT"));
283 gobject_cast
.add_argument (new
CCodeIdentifier ("self"));
285 create_result
.add_argument (gobject_cast
);
287 create_result
.add_argument (new
CCodeConstant ("NULL"));
290 if (context
.require_glib_version (2, 36)) {
291 Parameter cancellable_param
= null;
293 foreach (Parameter param
in m
.get_parameters ()) {
294 if (param
.variable_type is ObjectType
&& param
.variable_type
.data_type
.get_full_name () == "GLib.Cancellable") {
295 cancellable_param
= param
;
300 if (cancellable_param
== null) {
301 create_result
.add_argument (new
CCodeConstant ("NULL"));
303 create_result
.add_argument (new
CCodeIdentifier (get_variable_cname (cancellable_param
.name
)));
307 if (!context
.require_glib_version (2, 36) || context
.require_glib_version (2, 44)) {
308 create_result
.add_argument (new
CCodeIdentifier ("_callback_"));
310 create_result
.add_argument (new
CCodeIdentifier (callback_wrapper
));
312 create_result
.add_argument (new
CCodeIdentifier ("_user_data_"));
314 if (!context
.require_glib_version (2, 36)) {
315 create_result
.add_argument (new
CCodeIdentifier (get_ccode_real_name (m
)));
318 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_async_result"), create_result
);
320 CCodeFunctionCall attach_data_call
;
322 if (!context
.require_glib_version (2, 36)) {
323 attach_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_set_op_res_gpointer"));
325 if (!context
.require_glib_version (2, 44)) {
326 var task_completed_var
= new CCodeMemberAccess
.pointer (data_var
, "_task_complete_");
327 var callback = new
CCodeIdentifier ("_callback_");
328 var callback_is_null
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, callback, new
CCodeConstant ("NULL"));
330 ccode
.open_if (callback_is_null
);
331 ccode
.add_assignment (task_completed_var
, new
CCodeConstant ("TRUE"));
335 attach_data_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_set_task_data"));
338 attach_data_call
.add_argument (new CCodeMemberAccess
.pointer (data_var
, "_async_result"));
339 attach_data_call
.add_argument (data_var
);
340 attach_data_call
.add_argument (new
CCodeIdentifier (get_ccode_real_name (m
) + "_data_free"));
341 ccode
.add_expression (attach_data_call
);
343 if (m is CreationMethod
) {
344 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "object_type"), new
CCodeIdentifier ("object_type"));
345 } else if (m
.binding
== MemberBinding
.INSTANCE
) {
346 var this_type
= m
.this_parameter
.variable_type
.copy ();
347 this_type
.value_owned
= true;
349 // create copy if necessary as variables in async methods may need to be kept alive
350 CCodeExpression cself
= new
CCodeIdentifier ("self");
351 if (this_type
.is_real_non_null_struct_type ()) {
352 cself
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cself
);
354 if (requires_copy (this_type
)) {
355 cself
= get_cvalue_ (copy_value (new
GLibValue (m
.this_parameter
.variable_type
, cself
, true), m
.this_parameter
));
358 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "self"), cself
);
361 emit_context
.push_symbol (m
);
362 foreach (Parameter param
in m
.get_parameters ()) {
363 if (param
.direction
!= ParameterDirection
.OUT
) {
364 // create copy if necessary as variables in async methods may need to be kept alive
365 var old_captured
= param
.captured
;
366 param
.captured
= false;
367 current_method
.coroutine
= false;
370 if (param
.variable_type
.value_owned
) {
371 // do not use load_parameter for reference/ownership transfer
372 // otherwise delegate destroy notify will not be moved
373 value
= get_parameter_cvalue (param
);
375 value
= load_parameter (param
);
378 current_method
.coroutine
= true;
380 store_parameter (param
, value
);
382 param
.captured
= old_captured
;
385 emit_context
.pop_symbol ();
387 foreach (var type_param
in m
.get_type_parameters ()) {
388 var type
= "%s_type".printf (type_param
.name
.down ());
389 var dup_func
= "%s_dup_func".printf (type_param
.name
.down ());
390 var destroy_func
= "%s_destroy_func".printf (type_param
.name
.down ());
391 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, type
), new
CCodeIdentifier (type
));
392 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, dup_func
), new
CCodeIdentifier (dup_func
));
393 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, destroy_func
), new
CCodeIdentifier (destroy_func
));
396 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
) + "_co"));
397 ccall
.add_argument (data_var
);
398 ccode
.add_expression (ccall
);
400 cfile
.add_function (asyncfunc
);
405 void append_struct (CCodeStruct structure
) {
406 var typename
= new
CCodeVariableDeclarator (structure
.name
.substring (1));
407 var typedef
= new
CCodeTypeDefinition ("struct " + structure
.name
, typename
);
408 cfile
.add_type_declaration (typedef
);
409 cfile
.add_type_definition (structure
);
412 public override void generate_method_declaration (Method m
, CCodeFile decl_space
) {
414 if (add_symbol_declaration (decl_space
, m
, get_ccode_name (m
))) {
418 var cl
= m
.parent_symbol as Class
;
420 var asyncfunc
= new
CCodeFunction (get_ccode_name (m
), "void");
421 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
422 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
424 if (m
.is_private_symbol ()) {
425 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
426 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
427 asyncfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
430 // do not generate _new functions for creation methods of abstract classes
431 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
432 generate_cparameters (m
, decl_space
, cparam_map
, asyncfunc
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")), 1);
434 decl_space
.add_function_declaration (asyncfunc
);
437 var finishfunc
= new
CCodeFunction (get_ccode_finish_name (m
));
438 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
439 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
441 if (m
.is_private_symbol ()) {
442 finishfunc
.modifiers
|= CCodeModifiers
.STATIC
;
443 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
444 finishfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
447 // do not generate _new functions for creation methods of abstract classes
448 if (!(m is CreationMethod
&& cl
!= null && cl
.is_abstract
)) {
449 generate_cparameters (m
, decl_space
, cparam_map
, finishfunc
, null, carg_map
, new
CCodeFunctionCall (new
CCodeIdentifier ("fake")), 2);
451 decl_space
.add_function_declaration (finishfunc
);
454 if (m is CreationMethod
&& cl
!= null) {
455 // _construct function
456 var function
= new
CCodeFunction (get_ccode_real_name (m
));
458 if (m
.is_private_symbol ()) {
459 function
.modifiers
|= CCodeModifiers
.STATIC
;
460 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
461 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
464 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
465 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, null, null, 1);
467 decl_space
.add_function_declaration (function
);
469 function
= new
CCodeFunction (get_ccode_finish_real_name (m
));
471 if (m
.is_private_symbol ()) {
472 function
.modifiers
|= CCodeModifiers
.STATIC
;
473 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
474 function
.modifiers
|= CCodeModifiers
.INTERNAL
;
477 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
478 generate_cparameters (m
, decl_space
, cparam_map
, function
, null, null, null, 2);
480 decl_space
.add_function_declaration (function
);
483 base.generate_method_declaration (m
, decl_space
);
487 public override void visit_method (Method m
) {
489 cfile
.add_include ("gio/gio.h");
490 if (!m
.is_internal_symbol ()) {
491 header_file
.add_include ("gio/gio.h");
494 if (!m
.is_abstract
&& m
.body
!= null) {
495 var data
= generate_data_struct (m
);
497 closure_struct
= data
;
499 generate_free_function (m
);
500 generate_async_function (m
);
501 generate_finish_function (m
);
503 // append the _co function
504 base.visit_method (m
);
505 closure_struct
= null;
507 // only append data struct here to make sure all struct member
508 // types are declared before the struct definition
509 append_struct (data
);
511 generate_method_declaration (m
, cfile
);
513 if (!m
.is_internal_symbol ()) {
514 generate_method_declaration (m
, header_file
);
516 if (!m
.is_private_symbol ()) {
517 generate_method_declaration (m
, internal_header_file
);
521 if (m
.is_abstract
|| m
.is_virtual
) {
522 // generate virtual function wrappers
523 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
524 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
525 generate_vfunc (m
, new
VoidType (), cparam_map
, carg_map
, "", 1);
527 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
528 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
529 generate_vfunc (m
, m
.return_type
, cparam_map
, carg_map
, "_finish", 2);
532 base.visit_method (m
);
536 public override void visit_creation_method (CreationMethod m
) {
538 base.visit_creation_method (m
);
540 push_line (m
.source_reference
);
542 bool visible
= !m
.is_private_symbol ();
546 if (m
.source_type
== SourceFileType
.FAST
) {
550 // do not generate _new functions for creation methods of abstract classes
551 if (current_type_symbol is Class
&& !current_class
.is_compact
&& !current_class
.is_abstract
) {
552 var vfunc
= new
CCodeFunction (get_ccode_name (m
));
554 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
555 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
557 push_function (vfunc
);
559 var vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
)));
560 vcall
.add_argument (new
CCodeIdentifier (get_ccode_type_id (current_class
)));
562 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, 1);
563 ccode
.add_expression (vcall
);
566 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
571 cfile
.add_function (vfunc
);
574 vfunc
= new
CCodeFunction (get_ccode_finish_name (m
));
576 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
577 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
579 push_function (vfunc
);
581 vcall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_finish_real_name (m
)));
583 generate_cparameters (m
, cfile
, cparam_map
, vfunc
, null, carg_map
, vcall
, 2);
584 ccode
.add_return (vcall
);
587 vfunc
.modifiers
|= CCodeModifiers
.STATIC
;
592 cfile
.add_function (vfunc
);
599 void generate_finish_function (Method m
) {
600 push_context (new
EmitContext ());
602 string dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
604 var finishfunc
= new
CCodeFunction (get_ccode_finish_real_name (m
));
606 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
608 cparam_map
.set (get_param_pos (0.1), new
CCodeParameter ("_res_", "GAsyncResult*"));
610 generate_cparameters (m
, cfile
, cparam_map
, finishfunc
, null, null, null, 2);
612 if (m
.is_private_symbol () || m
.base_method
!= null || m
.base_interface_method
!= null) {
613 finishfunc
.modifiers
|= CCodeModifiers
.STATIC
;
614 } else if (context
.hide_internal
&& m
.is_internal_symbol ()) {
615 finishfunc
.modifiers
|= CCodeModifiers
.INTERNAL
;
618 push_function (finishfunc
);
620 var return_type
= m
.return_type
;
621 if (m is CreationMethod
) {
622 var type_sym
= (TypeSymbol
) m
.parent_symbol
;
623 if (type_sym is ObjectTypeSymbol
) {
624 ccode
.add_declaration (get_ccode_name (type_sym
) + "*", new
CCodeVariableDeclarator ("result"));
626 } else if (!(return_type is VoidType
) && !return_type
.is_real_non_null_struct_type ()) {
627 ccode
.add_declaration (get_ccode_name (m
.return_type
), new
CCodeVariableDeclarator ("result"));
630 var data_var
= new
CCodeIdentifier ("_data_");
632 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
634 if (context
.require_glib_version (2, 36)) {
635 var async_result_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_TASK"));
636 async_result_cast
.add_argument (new
CCodeIdentifier ("_res_"));
638 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_propagate_pointer"));
639 ccall
.add_argument (async_result_cast
);
641 if (m
.get_error_types ().size
> 0) {
642 ccall
.add_argument (new
CCodeIdentifier ("error"));
644 ccall
.add_argument (new
CCodeConstant ("NULL"));
647 ccode
.add_assignment (data_var
, ccall
);
649 bool has_cancellable
= false;
651 foreach (Parameter param
in m
.get_parameters ()) {
652 if (param
.variable_type is ObjectType
&& param
.variable_type
.data_type
.get_full_name () == "GLib.Cancellable") {
653 has_cancellable
= true;
658 // If a task is cancelled, g_task_propagate_pointer returns NULL
659 if (m
.get_error_types ().size
> 0 || has_cancellable
) {
660 var is_null
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeConstant ("NULL"), data_var
);
662 ccode
.open_if (is_null
);
663 return_default_value (return_type
);
667 var simple_async_result_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_SIMPLE_ASYNC_RESULT"));
668 simple_async_result_cast
.add_argument (new
CCodeIdentifier ("_res_"));
670 if (m
.get_error_types ().size
> 0) {
671 // propagate error from async method
672 var propagate_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_propagate_error"));
673 propagate_error
.add_argument (simple_async_result_cast
);
674 propagate_error
.add_argument (new
CCodeIdentifier ("error"));
676 ccode
.open_if (propagate_error
);
677 return_default_value (return_type
);
681 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_get_op_res_gpointer"));
682 ccall
.add_argument (simple_async_result_cast
);
683 ccode
.add_assignment (data_var
, ccall
);
686 emit_context
.push_symbol (m
);
687 foreach (Parameter param
in m
.get_parameters ()) {
688 if (param
.direction
!= ParameterDirection
.IN
) {
689 return_out_parameter (param
);
690 if (!(param
.variable_type is ValueType
) || param
.variable_type
.nullable
) {
691 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, get_variable_cname (param
.name
)), new
CCodeConstant ("NULL"));
695 emit_context
.pop_symbol ();
697 if (m is CreationMethod
) {
698 ccode
.add_assignment (new
CCodeIdentifier ("result"), new CCodeMemberAccess
.pointer (data_var
, "self"));
699 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "self"), new
CCodeConstant ("NULL"));
700 ccode
.add_return (new
CCodeIdentifier ("result"));
701 } else if (return_type
.is_real_non_null_struct_type ()) {
702 // structs are returned via out parameter
703 CCodeExpression cexpr
= new CCodeMemberAccess
.pointer (data_var
, "result");
704 if (requires_copy (return_type
)) {
705 cexpr
= get_cvalue_ (copy_value (new
GLibValue (return_type
, cexpr
, true), return_type
));
707 ccode
.add_assignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result")), cexpr
);
708 } else if (!(return_type is VoidType
)) {
709 ccode
.add_assignment (new
CCodeIdentifier ("result"), new CCodeMemberAccess
.pointer (data_var
, "result"));
710 if (return_type is ArrayType
) {
711 var array_type
= (ArrayType
) return_type
;
712 if (get_ccode_array_length (m
)) {
713 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
714 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
)));
717 } else if (return_type is DelegateType
&& ((DelegateType
) return_type
).delegate_symbol
.has_target
) {
718 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")));
720 if (!(return_type is ValueType
) || return_type
.nullable
) {
721 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "result"), new
CCodeConstant ("NULL"));
723 ccode
.add_return (new
CCodeIdentifier ("result"));
728 cfile
.add_function (finishfunc
);
733 public override string generate_ready_function (Method m
) {
734 // generate ready callback handler
736 var dataname
= Symbol
.lower_case_to_camel_case (get_ccode_name (m
)) + "Data";
738 var readyfunc
= new
CCodeFunction (get_ccode_name (m
) + "_ready", "void");
740 if (!add_wrapper (readyfunc
.name
)) {
741 // wrapper already defined
742 return readyfunc
.name
;
745 readyfunc
.add_parameter (new
CCodeParameter ("source_object", "GObject*"));
746 readyfunc
.add_parameter (new
CCodeParameter ("_res_", "GAsyncResult*"));
747 readyfunc
.add_parameter (new
CCodeParameter ("_user_data_", "gpointer"));
749 push_function (readyfunc
);
751 var data_var
= new
CCodeIdentifier ("_data_");
753 ccode
.add_declaration (dataname
+ "*", new
CCodeVariableDeclarator ("_data_"));
754 ccode
.add_assignment (data_var
, new
CCodeIdentifier ("_user_data_"));
755 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_source_object_"), new
CCodeIdentifier ("source_object"));
756 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_res_"), new
CCodeIdentifier ("_res_"));
758 if (context
.require_glib_version (2, 36) && !context
.require_glib_version (2, 44)) {
759 ccode
.add_assignment (new CCodeMemberAccess
.pointer (data_var
, "_task_complete_"), new
CCodeConstant ("TRUE"));
762 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_real_name (m
) + "_co"));
763 ccall
.add_argument (data_var
);
764 ccode
.add_expression (ccall
);
766 readyfunc
.modifiers
|= CCodeModifiers
.STATIC
;
770 cfile
.add_function_declaration (readyfunc
);
771 cfile
.add_function (readyfunc
);
773 return readyfunc
.name
;
776 public override void generate_virtual_method_declaration (Method m
, CCodeFile decl_space
, CCodeStruct type_struct
) {
778 base.generate_virtual_method_declaration (m
, decl_space
, type_struct
);
782 if (!m
.is_abstract
&& !m
.is_virtual
) {
786 var creturn_type
= m
.return_type
;
787 if (m
.return_type
.is_real_non_null_struct_type ()) {
788 // structs are returned via out parameter
789 creturn_type
= new
VoidType ();
792 // add vfunc field to the type struct
793 var vdeclarator
= new
CCodeFunctionDeclarator (get_ccode_vfunc_name (m
));
794 var cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
796 generate_cparameters (m
, decl_space
, cparam_map
, new
CCodeFunction ("fake"), vdeclarator
, null, null, 1);
798 var vdecl
= new
CCodeDeclaration ("void");
799 vdecl
.add_declarator (vdeclarator
);
800 type_struct
.add_declaration (vdecl
);
802 // add vfunc field to the type struct
803 vdeclarator
= new
CCodeFunctionDeclarator (get_ccode_finish_vfunc_name (m
));
804 cparam_map
= new HashMap
<int,CCodeParameter
> (direct_hash
, direct_equal
);
806 generate_cparameters (m
, decl_space
, cparam_map
, new
CCodeFunction ("fake"), vdeclarator
, null, null, 2);
808 vdecl
= new
CCodeDeclaration (get_ccode_name (creturn_type
));
809 vdecl
.add_declarator (vdeclarator
);
810 type_struct
.add_declaration (vdecl
);
813 public override void visit_yield_statement (YieldStatement stmt
) {
814 if (!is_in_coroutine ()) {
818 if (stmt
.yield_expression
== null) {
819 int state
= emit_context
.next_coroutine_state
++;
821 ccode
.add_assignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_state_"), new
CCodeConstant (state
.to_string ()));
822 ccode
.add_return (new
CCodeConstant ("FALSE"));
823 ccode
.add_label ("_state_%d".printf (state
));
824 ccode
.add_statement (new
CCodeEmptyStatement ());
829 if (stmt
.yield_expression
.error
) {
834 ccode
.add_expression (get_cvalue (stmt
.yield_expression
));
836 if (stmt
.tree_can_fail
&& stmt
.yield_expression
.tree_can_fail
) {
837 // simple case, no node breakdown necessary
839 add_simple_check (stmt
.yield_expression
);
842 /* free temporary objects */
844 foreach (var value
in temp_ref_values
) {
845 ccode
.add_expression (destroy_value (value
));
848 temp_ref_values
.clear ();
851 public override void return_with_exception (CCodeExpression error_expr
)
853 if (!is_in_coroutine ()) {
854 base.return_with_exception (error_expr
);
858 var async_result_expr
= new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("_data_"), "_async_result");
859 CCodeFunctionCall set_error
= null;
861 if (context
.require_glib_version (2, 36)) {
862 set_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_return_error"));
864 set_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_take_error"));
866 set_error
.add_argument (async_result_expr
);
867 set_error
.add_argument (error_expr
);
868 ccode
.add_expression (set_error
);
870 append_local_free (current_symbol
, false);
872 if (context
.require_glib_version (2, 36)) {
873 // We already returned the error above, we must not return anything else here.
874 var unref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
875 unref
.add_argument (async_result_expr
);
876 ccode
.add_expression (unref
);
878 ccode
.add_return (new
CCodeConstant ("FALSE"));
884 public override void visit_return_statement (ReturnStatement stmt
) {
885 base.visit_return_statement (stmt
);
887 if (!is_in_coroutine ()) {
894 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) {
896 decl_space
.add_include ("gio/gio.h");
898 if (direction
== 1) {
899 cparam_map
.set (get_param_pos (-1), new
CCodeParameter ("_callback_", "GAsyncReadyCallback"));
900 cparam_map
.set (get_param_pos (-0.9), new
CCodeParameter ("_user_data_", "gpointer"));
901 if (carg_map
!= null) {
902 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier ("_callback_"));
903 carg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("_user_data_"));
905 } else if (direction
== 2) {
906 cparam_map
.set (get_param_pos (0.1), new
CCodeParameter ("_res_", "GAsyncResult*"));
907 if (carg_map
!= null) {
908 carg_map
.set (get_param_pos (0.1), new
CCodeIdentifier ("_res_"));
912 base.generate_cparameters (m
, decl_space
, cparam_map
, func
, vdeclarator
, carg_map
, vcall
, direction
);
915 public string generate_async_callback_wrapper () {
916 string async_callback_wrapper_func
= "_vala_g_async_ready_callback";
918 if (!add_wrapper (async_callback_wrapper_func
)) {
919 return async_callback_wrapper_func
;
922 var function
= new
CCodeFunction (async_callback_wrapper_func
, "void");
923 function
.modifiers
= CCodeModifiers
.STATIC
;
925 function
.add_parameter (new
CCodeParameter ("*source_object", "GObject"));
926 function
.add_parameter (new
CCodeParameter ("*res", "GAsyncResult"));
927 function
.add_parameter (new
CCodeParameter ("*user_data", "void"));
929 push_function (function
);
931 var res_ref
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref"));
932 res_ref
.add_argument (new
CCodeIdentifier ("res"));
934 CCodeFunctionCall ccall
= null;
936 // store reference to async result of inner async function in out async result
937 if (context
.require_glib_version (2, 36)) {
938 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_task_return_pointer"));
940 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_set_op_res_gpointer"));
943 ccall
.add_argument (new
CCodeIdentifier ("user_data"));
944 ccall
.add_argument (res_ref
);
945 ccall
.add_argument (new
CCodeIdentifier ("g_object_unref"));
946 ccode
.add_expression (ccall
);
948 if (!context
.require_glib_version (2, 36)) {
949 // call user-provided callback
950 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_complete"));
951 ccall
.add_argument (new
CCodeIdentifier ("user_data"));
952 ccode
.add_expression (ccall
);
956 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_unref"));
957 ccall
.add_argument (new
CCodeIdentifier ("user_data"));
958 ccode
.add_expression (ccall
);
962 cfile
.add_function_declaration (function
);
963 cfile
.add_function (function
);
965 return async_callback_wrapper_func
;