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