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 ("GAsyncResult*", "_res_");
32 data
.add_field ("GSimpleAsyncResult*", "_async_result");
34 if (m
.binding
== MemberBinding
.INSTANCE
) {
35 var type_sym
= (TypeSymbol
) m
.parent_symbol
;
36 data
.add_field (type_sym
.get_cname () + "*", "self");
39 foreach (FormalParameter param
in m
.get_parameters ()) {
40 var param_type
= param
.variable_type
.copy ();
41 param_type
.value_owned
= true;
42 data
.add_field (param_type
.get_cname (), get_variable_cname (param
.name
));
44 if (param
.variable_type is ArrayType
) {
45 var array_type
= (ArrayType
) param
.variable_type
;
46 if (!param
.no_array_length
) {
47 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
48 data
.add_field ("gint", get_array_length_cname (get_variable_cname (param
.name
), dim
));
51 } else if (param
.variable_type is DelegateType
) {
52 var deleg_type
= (DelegateType
) param
.variable_type
;
53 if (deleg_type
.delegate_symbol
.has_target
) {
54 data
.add_field ("gpointer", get_delegate_target_cname (get_variable_cname (param
.name
)));
55 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname (get_variable_cname (param
.name
)));
60 if (!(m
.return_type is VoidType
)) {
61 data
.add_field (m
.return_type
.get_cname (), "result");
62 if (m
.return_type is ArrayType
) {
63 var array_type
= (ArrayType
) m
.return_type
;
64 if (!m
.no_array_length
) {
65 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
66 data
.add_field ("gint", get_array_length_cname ("result", dim
));
69 } else if (m
.return_type is DelegateType
) {
70 var deleg_type
= (DelegateType
) m
.return_type
;
71 if (deleg_type
.delegate_symbol
.has_target
) {
72 data
.add_field ("gpointer", get_delegate_target_cname ("result"));
73 data
.add_field ("GDestroyNotify", get_delegate_target_destroy_notify_cname ("result"));
81 CCodeFunction
generate_free_function (Method m
) {
82 var dataname
= Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data";
84 var freefunc
= new
CCodeFunction (m
.get_real_cname () + "_data_free", "void");
85 freefunc
.modifiers
= CCodeModifiers
.STATIC
;
86 freefunc
.add_parameter (new
CCodeFormalParameter ("_data", "gpointer"));
88 var freeblock
= new
CCodeBlock ();
89 freefunc
.block
= freeblock
;
91 var datadecl
= new
CCodeDeclaration (dataname
+ "*");
92 datadecl
.add_declarator (new
CCodeVariableDeclarator ("data", new
CCodeIdentifier ("_data")));
93 freeblock
.add_statement (datadecl
);
95 push_context (new
EmitContext (m
));
97 foreach (FormalParameter param
in m
.get_parameters ()) {
98 if (param
.direction
!= ParameterDirection
.OUT
) {
99 var param_type
= param
.variable_type
.copy ();
100 param_type
.value_owned
= true;
102 if (requires_destroy (param_type
)) {
103 var ma
= new MemberAccess
.simple (param
.name
);
104 ma
.symbol_reference
= param
;
105 ma
.value_type
= param
.variable_type
.copy ();
106 freeblock
.add_statement (new
CCodeExpressionStatement (get_unref_expression (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), get_variable_cname (param
.name
)), param
.variable_type
, ma
)));
111 if (requires_destroy (m
.return_type
)) {
112 /* this is very evil. */
113 var v
= new
LocalVariable (m
.return_type
, ".result");
114 var ma
= new MemberAccess
.simple (".result");
115 ma
.symbol_reference
= v
;
116 var unref_expr
= get_unref_expression (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "result"), m
.return_type
, ma
);
117 freeblock
.add_statement (new
CCodeExpressionStatement (unref_expr
));
120 var cl
= m
.parent_symbol as Class
;
121 if (m
.binding
== MemberBinding
.INSTANCE
&& cl
!= null) {
122 var unref_func
= cl
.get_unref_function ();
124 if (unref_func
!= null) {
125 var unref_call
= new
CCodeFunctionCall (new
CCodeIdentifier (unref_func
));
126 unref_call
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "self"));
127 freeblock
.add_statement (new
CCodeExpressionStatement (unref_call
));
133 var freecall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_free"));
134 freecall
.add_argument (new
CCodeIdentifier (dataname
));
135 freecall
.add_argument (new
CCodeIdentifier ("data"));
136 freeblock
.add_statement (new
CCodeExpressionStatement (freecall
));
141 CCodeFunction
generate_async_function (Method m
) {
142 var asyncblock
= new
CCodeBlock ();
144 // logic copied from valaccodemethodmodule
145 if (m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
149 base_method
= m
.base_method
;
151 base_method
= m
.base_interface_method
;
154 var base_expression_type
= new
ObjectType ((ObjectTypeSymbol
) base_method
.parent_symbol
);
155 var type_symbol
= m
.parent_symbol as ObjectTypeSymbol
;
157 var self_target_type
= new
ObjectType (type_symbol
);
158 var cself
= transform_expression (new
CCodeIdentifier ("base"), base_expression_type
, self_target_type
);
159 var cdecl
= new
CCodeDeclaration ("%s *".printf (type_symbol
.get_cname ()));
160 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", cself
));
161 asyncblock
.add_statement (cdecl
);
164 var dataname
= Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data";
165 var asyncfunc
= new
CCodeFunction (m
.get_real_cname (), "void");
166 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
168 var dataalloc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_slice_new0"));
169 dataalloc
.add_argument (new
CCodeIdentifier (dataname
));
171 var data_var
= new
CCodeIdentifier ("_data_");
173 var datadecl
= new
CCodeDeclaration (dataname
+ "*");
174 datadecl
.add_declarator (new
CCodeVariableDeclarator ("_data_"));
175 asyncblock
.add_statement (datadecl
);
176 asyncblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (data_var
, dataalloc
)));
178 var create_result
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_new"));
180 var cl
= m
.parent_symbol as Class
;
181 if (m
.binding
== MemberBinding
.INSTANCE
&&
182 cl
!= null && cl
.is_subtype_of (gobject_type
)) {
183 var gobject_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT"));
184 gobject_cast
.add_argument (new
CCodeIdentifier ("self"));
186 create_result
.add_argument (gobject_cast
);
188 if (context
.require_glib_version (2, 20)) {
189 create_result
.add_argument (new
CCodeConstant ("NULL"));
191 var object_creation
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_newv"));
192 object_creation
.add_argument (new
CCodeConstant ("G_TYPE_OBJECT"));
193 object_creation
.add_argument (new
CCodeConstant ("0"));
194 object_creation
.add_argument (new
CCodeConstant ("NULL"));
196 create_result
.add_argument (object_creation
);
200 create_result
.add_argument (new
CCodeIdentifier ("_callback_"));
201 create_result
.add_argument (new
CCodeIdentifier ("_user_data_"));
202 create_result
.add_argument (new
CCodeIdentifier (m
.get_real_cname ()));
204 asyncblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (data_var
, "_async_result"), create_result
)));
206 var set_op_res_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_set_op_res_gpointer"));
207 set_op_res_call
.add_argument (new CCodeMemberAccess
.pointer (data_var
, "_async_result"));
208 set_op_res_call
.add_argument (data_var
);
209 set_op_res_call
.add_argument (new
CCodeIdentifier (m
.get_real_cname () + "_data_free"));
210 asyncblock
.add_statement (new
CCodeExpressionStatement (set_op_res_call
));
212 if (m
.binding
== MemberBinding
.INSTANCE
) {
213 CCodeExpression self_expr
= new
CCodeIdentifier ("self");
214 string? ref_function
= null;
216 if (cl
!= null && (ref_function
= cl
.get_ref_function ()) != null) {
217 var refcall
= new
CCodeFunctionCall (new
CCodeIdentifier (ref_function
));
218 refcall
.add_argument (self_expr
);
222 asyncblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (data_var
, "self"), self_expr
)));
225 foreach (FormalParameter param
in m
.get_parameters ()) {
226 if (param
.direction
!= ParameterDirection
.OUT
) {
227 var param_type
= param
.variable_type
.copy ();
228 param_type
.value_owned
= true;
230 // create copy if necessary as variables in async methods may need to be kept alive
231 CCodeExpression cparam
= get_variable_cexpression (param
.name
);
232 if (param
.variable_type
.is_real_non_null_struct_type ()) {
233 cparam
= new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, cparam
);
235 if (requires_copy (param_type
) && !param
.variable_type
.value_owned
) {
236 var ma
= new MemberAccess
.simple (param
.name
);
237 ma
.symbol_reference
= param
;
238 cparam
= get_ref_cexpression (param
.variable_type
, cparam
, ma
, param
);
241 asyncblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (data_var
, get_variable_cname (param
.name
)), cparam
)));
242 if (param
.variable_type is ArrayType
) {
243 var array_type
= (ArrayType
) param
.variable_type
;
244 if (!param
.no_array_length
) {
245 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
246 asyncblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (data_var
, get_array_length_cname (get_variable_cname (param
.name
), dim
)), new
CCodeIdentifier (get_array_length_cname (get_variable_cname (param
.name
), dim
)))));
249 } else if (param
.variable_type is DelegateType
) {
250 var deleg_type
= (DelegateType
) param
.variable_type
;
251 if (deleg_type
.delegate_symbol
.has_target
) {
252 asyncblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (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
))))));
253 if (deleg_type
.value_owned
) {
254 asyncblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (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
))))));
261 var cfrag
= new
CCodeFragment ();
262 append_temp_decl (cfrag
, temp_vars
);
264 asyncblock
.add_statement (cfrag
);
266 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname () + "_co"));
267 ccall
.add_argument (data_var
);
268 asyncblock
.add_statement (new
CCodeExpressionStatement (ccall
));
270 cparam_map
.set (get_param_pos (-1), new
CCodeFormalParameter ("_callback_", "GAsyncReadyCallback"));
271 cparam_map
.set (get_param_pos (-0.9), new
CCodeFormalParameter ("_user_data_", "gpointer"));
273 generate_cparameters (m
, cfile
, cparam_map
, asyncfunc
, null, null, null, 1);
275 if (m
.base_method
!= null || m
.base_interface_method
!= null) {
276 // declare *_real_* function
277 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
278 cfile
.add_type_member_declaration (asyncfunc
.copy ());
279 } else if (m
.is_private_symbol ()) {
280 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
283 asyncfunc
.block
= asyncblock
;
288 void append_struct (CCodeStruct structure
) {
289 var typename
= new
CCodeVariableDeclarator (structure
.name
.substring (1));
290 var typedef
= new
CCodeTypeDefinition ("struct " + structure
.name
, typename
);
291 cfile
.add_type_declaration (typedef
);
292 cfile
.add_type_definition (structure
);
295 void append_function (CCodeFunction function
) {
296 var block
= function
.block
;
297 function
.block
= null;
299 cfile
.add_type_member_declaration (function
.copy ());
301 function
.block
= block
;
302 cfile
.add_function (function
);
305 public override void generate_method_declaration (Method m
, CCodeFile decl_space
) {
307 if (add_symbol_declaration (decl_space
, m
, m
.get_cname ())) {
311 var asyncfunc
= new
CCodeFunction (m
.get_cname (), "void");
312 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
313 cparam_map
.set (get_param_pos (-1), new
CCodeFormalParameter ("_callback_", "GAsyncReadyCallback"));
314 cparam_map
.set (get_param_pos (-0.9), new
CCodeFormalParameter ("_user_data_", "gpointer"));
316 generate_cparameters (m
, decl_space
, cparam_map
, asyncfunc
, null, null, null, 1);
318 if (m
.is_private_symbol ()) {
319 asyncfunc
.modifiers
|= CCodeModifiers
.STATIC
;
322 decl_space
.add_type_member_declaration (asyncfunc
);
324 var finishfunc
= new
CCodeFunction (m
.get_finish_cname ());
325 cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
326 cparam_map
.set (get_param_pos (0.1), new
CCodeFormalParameter ("_res_", "GAsyncResult*"));
328 generate_cparameters (m
, decl_space
, cparam_map
, finishfunc
, null, null, null, 2);
330 if (m
.is_private_symbol ()) {
331 finishfunc
.modifiers
|= CCodeModifiers
.STATIC
;
334 decl_space
.add_type_member_declaration (finishfunc
);
336 base.generate_method_declaration (m
, decl_space
);
340 public override void visit_method (Method m
) {
342 cfile
.add_include ("gio/gio.h");
343 if (!m
.is_internal_symbol ()) {
344 header_file
.add_include ("gio/gio.h");
347 if (!m
.is_abstract
&& m
.body
!= null) {
348 var data
= generate_data_struct (m
);
350 append_function (generate_free_function (m
));
351 cfile
.add_function (generate_async_function (m
));
352 cfile
.add_function (generate_finish_function (m
));
353 append_function (generate_ready_function (m
));
355 // append the _co function
356 closure_struct
= data
;
357 base.visit_method (m
);
358 closure_struct
= null;
360 // only append data struct here to make sure all struct member
361 // types are declared before the struct definition
362 append_struct (data
);
364 generate_method_declaration (m
, cfile
);
366 if (!m
.is_internal_symbol ()) {
367 generate_method_declaration (m
, header_file
);
369 if (!m
.is_private_symbol ()) {
370 generate_method_declaration (m
, internal_header_file
);
374 if (m
.is_abstract
|| m
.is_virtual
) {
375 // generate virtual function wrappers
376 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
377 var carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
378 generate_vfunc (m
, new
VoidType (), cparam_map
, carg_map
, "", 1);
380 cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
381 carg_map
= new HashMap
<int,CCodeExpression
> (direct_hash
, direct_equal
);
382 generate_vfunc (m
, m
.return_type
, cparam_map
, carg_map
, "_finish", 2);
385 base.visit_method (m
);
390 CCodeFunction
generate_finish_function (Method m
) {
391 string dataname
= Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data";
393 var finishfunc
= new
CCodeFunction (m
.get_finish_real_cname ());
395 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
397 var finishblock
= new
CCodeBlock ();
399 var return_type
= m
.return_type
;
400 if (!(return_type is VoidType
) && !return_type
.is_real_non_null_struct_type ()) {
401 var cdecl
= new
CCodeDeclaration (m
.return_type
.get_cname ());
402 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result"));
403 finishblock
.add_statement (cdecl
);
406 var data_var
= new
CCodeIdentifier ("_data_");
408 var datadecl
= new
CCodeDeclaration (dataname
+ "*");
409 datadecl
.add_declarator (new
CCodeVariableDeclarator ("_data_"));
410 finishblock
.add_statement (datadecl
);
412 var simple_async_result_cast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_SIMPLE_ASYNC_RESULT"));
413 simple_async_result_cast
.add_argument (new
CCodeIdentifier ("_res_"));
415 if (m
.get_error_types ().size
> 0) {
416 // propagate error from async method
417 var propagate_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_propagate_error"));
418 propagate_error
.add_argument (simple_async_result_cast
);
419 propagate_error
.add_argument (new
CCodeIdentifier ("error"));
420 var errorblock
= new
CCodeBlock ();
421 if (return_type is VoidType
|| return_type
.is_real_non_null_struct_type ()) {
422 errorblock
.add_statement (new
CCodeReturnStatement ());
424 errorblock
.add_statement (new
CCodeReturnStatement (default_value_for_type (return_type
, false)));
426 finishblock
.add_statement (new
CCodeIfStatement (propagate_error
, errorblock
));
429 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_get_op_res_gpointer"));
430 ccall
.add_argument (simple_async_result_cast
);
431 finishblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (data_var
, ccall
)));
433 foreach (FormalParameter param
in m
.get_parameters ()) {
434 if (param
.direction
!= ParameterDirection
.IN
) {
435 finishblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (param
.name
)), new CCodeMemberAccess
.pointer (data_var
, get_variable_cname (param
.name
)))));
436 if (!(param
.variable_type is ValueType
) || param
.variable_type
.nullable
) {
437 finishblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (data_var
, get_variable_cname (param
.name
)), new
CCodeConstant ("NULL"))));
442 if (return_type
.is_real_non_null_struct_type ()) {
443 // structs are returned via out parameter
444 CCodeExpression cexpr
= new CCodeMemberAccess
.pointer (data_var
, "result");
445 if (requires_copy (return_type
)) {
446 cexpr
= get_ref_cexpression (return_type
, cexpr
, null, return_type
);
448 finishblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier ("result")), cexpr
)));
449 } else if (!(return_type is VoidType
)) {
450 finishblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("result"), new CCodeMemberAccess
.pointer (data_var
, "result"))));
451 if (return_type is ArrayType
) {
452 var array_type
= (ArrayType
) return_type
;
453 if (!m
.no_array_length
) {
454 for (int dim
= 1; dim
<= array_type
.rank
; dim
++) {
455 finishblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (get_array_length_cname ("result", dim
))), new CCodeMemberAccess
.pointer (data_var
, get_array_length_cname ("result", dim
)))));
458 } else if (return_type is DelegateType
&& ((DelegateType
) return_type
).delegate_symbol
.has_target
) {
459 finishblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeUnaryExpression (CCodeUnaryOperator
.POINTER_INDIRECTION
, new
CCodeIdentifier (get_delegate_target_cname ("result"))), new CCodeMemberAccess
.pointer (data_var
, get_delegate_target_cname ("result")))));
461 if (!(return_type is ValueType
) || return_type
.nullable
) {
462 finishblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (data_var
, "result"), new
CCodeConstant ("NULL"))));
464 finishblock
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("result")));
467 var cfrag
= new
CCodeFragment ();
468 append_temp_decl (cfrag
, temp_vars
);
470 finishblock
.add_statement (cfrag
);
472 cparam_map
.set (get_param_pos (0.1), new
CCodeFormalParameter ("_res_", "GAsyncResult*"));
474 generate_cparameters (m
, cfile
, cparam_map
, finishfunc
, null, null, null, 2);
476 if (m
.is_private_symbol () || m
.base_method
!= null || m
.base_interface_method
!= null) {
477 finishfunc
.modifiers
|= CCodeModifiers
.STATIC
;
480 finishfunc
.block
= finishblock
;
485 CCodeFunction
generate_ready_function (Method m
) {
486 // generate ready callback handler
487 var dataname
= Symbol
.lower_case_to_camel_case (m
.get_cname ()) + "Data";
489 var readyfunc
= new
CCodeFunction (m
.get_cname () + "_ready", "void");
491 readyfunc
.add_parameter (new
CCodeFormalParameter ("source_object", "GObject*"));
492 readyfunc
.add_parameter (new
CCodeFormalParameter ("_res_", "GAsyncResult*"));
493 readyfunc
.add_parameter (new
CCodeFormalParameter ("_user_data_", "gpointer"));
495 var readyblock
= new
CCodeBlock ();
497 var datadecl
= new
CCodeDeclaration (dataname
+ "*");
498 datadecl
.add_declarator (new
CCodeVariableDeclarator ("data"));
499 readyblock
.add_statement (datadecl
);
500 readyblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data"), new
CCodeIdentifier ("_user_data_"))));
501 readyblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_res_"), new
CCodeIdentifier ("_res_"))));
503 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (m
.get_real_cname () + "_co"));
504 ccall
.add_argument (new
CCodeIdentifier ("data"));
505 readyblock
.add_statement (new
CCodeExpressionStatement (ccall
));
507 readyfunc
.modifiers
|= CCodeModifiers
.STATIC
;
509 readyfunc
.block
= readyblock
;
514 public override void generate_virtual_method_declaration (Method m
, CCodeFile decl_space
, CCodeStruct type_struct
) {
516 base.generate_virtual_method_declaration (m
, decl_space
, type_struct
);
520 if (!m
.is_abstract
&& !m
.is_virtual
) {
524 var creturn_type
= m
.return_type
;
525 if (m
.return_type
.is_real_non_null_struct_type ()) {
526 // structs are returned via out parameter
527 creturn_type
= new
VoidType ();
530 // add vfunc field to the type struct
531 var vdeclarator
= new
CCodeFunctionDeclarator (m
.vfunc_name
);
532 var cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
534 generate_cparameters (m
, decl_space
, cparam_map
, new
CCodeFunction ("fake"), vdeclarator
, null, null, 1);
536 var vdecl
= new
CCodeDeclaration ("void");
537 vdecl
.add_declarator (vdeclarator
);
538 type_struct
.add_declaration (vdecl
);
540 // add vfunc field to the type struct
541 vdeclarator
= new
CCodeFunctionDeclarator (m
.get_finish_vfunc_name ());
542 cparam_map
= new HashMap
<int,CCodeFormalParameter
> (direct_hash
, direct_equal
);
544 generate_cparameters (m
, decl_space
, cparam_map
, new
CCodeFunction ("fake"), vdeclarator
, null, null, 2);
546 vdecl
= new
CCodeDeclaration (creturn_type
.get_cname ());
547 vdecl
.add_declarator (vdeclarator
);
548 type_struct
.add_declaration (vdecl
);
551 public override void visit_yield_statement (YieldStatement stmt
) {
552 if (current_method
== null || !current_method
.coroutine
) {
553 stmt
.ccodenode
= new
CCodeEmptyStatement ();
557 if (stmt
.yield_expression
== null) {
558 var cfrag
= new
CCodeFragment ();
559 stmt
.ccodenode
= cfrag
;
561 int state
= next_coroutine_state
++;
563 state_switch_statement
.add_statement (new
CCodeCaseStatement (new
CCodeConstant (state
.to_string ())));
564 state_switch_statement
.add_statement (new
CCodeGotoStatement ("_state_%d".printf (state
)));
566 cfrag
.append (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_state_"), new
CCodeConstant (state
.to_string ()))));
567 cfrag
.append (new
CCodeReturnStatement (new
CCodeConstant ("FALSE")));
568 cfrag
.append (new
CCodeLabel ("_state_%d".printf (state
)));
569 cfrag
.append (new
CCodeEmptyStatement ());
574 if (stmt
.yield_expression
.error
) {
579 stmt
.ccodenode
= new
CCodeExpressionStatement ((CCodeExpression
) stmt
.yield_expression
.ccodenode
);
581 if (stmt
.tree_can_fail
&& stmt
.yield_expression
.tree_can_fail
) {
582 // simple case, no node breakdown necessary
584 var cfrag
= new
CCodeFragment ();
586 cfrag
.append (stmt
.ccodenode
);
588 add_simple_check (stmt
.yield_expression
, cfrag
);
590 stmt
.ccodenode
= cfrag
;
593 /* free temporary objects */
595 if (((List
<LocalVariable
>) temp_vars
).size
== 0) {
596 /* nothing to do without temporary variables */
600 var cfrag
= new
CCodeFragment ();
601 append_temp_decl (cfrag
, temp_vars
);
603 cfrag
.append (stmt
.ccodenode
);
605 foreach (LocalVariable local
in temp_ref_vars
) {
606 var ma
= new MemberAccess
.simple (local
.name
);
607 ma
.symbol_reference
= local
;
608 cfrag
.append (new
CCodeExpressionStatement (get_unref_expression (new
CCodeIdentifier (local
.name
), local
.variable_type
, ma
)));
611 stmt
.ccodenode
= cfrag
;
614 temp_ref_vars
.clear ();
617 public override CCodeStatement
return_with_exception (CCodeExpression error_expr
)
619 if (!current_method
.coroutine
) {
620 return base.return_with_exception (error_expr
);
623 var block
= new
CCodeBlock ();
625 var set_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_simple_async_result_set_from_error"));
626 set_error
.add_argument (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("data"), "_async_result"));
627 set_error
.add_argument (error_expr
);
628 block
.add_statement (new
CCodeExpressionStatement (set_error
));
630 var free_error
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_error_free"));
631 free_error
.add_argument (error_expr
);
632 block
.add_statement (new
CCodeExpressionStatement (free_error
));
634 var free_locals
= new
CCodeFragment ();
635 append_local_free (current_symbol
, free_locals
, false);
636 block
.add_statement (free_locals
);
638 block
.add_statement (complete_async ());
643 public override void visit_return_statement (ReturnStatement stmt
) {
644 base.visit_return_statement (stmt
);
646 if (current_method
== null || !current_method
.coroutine
) {
650 var cfrag
= (CCodeFragment
) stmt
.ccodenode
;
652 cfrag
.append (complete_async ());
655 public override void generate_cparameters (Method m
, CCodeFile decl_space
, Map
<int,CCodeFormalParameter
> cparam_map
, CCodeFunction func
, CCodeFunctionDeclarator? vdeclarator
= null, Map
<int,CCodeExpression
>? carg_map
= null, CCodeFunctionCall? vcall
= null, int direction
= 3) {
657 decl_space
.add_include ("gio/gio.h");
659 if (direction
== 1) {
660 cparam_map
.set (get_param_pos (-1), new
CCodeFormalParameter ("_callback_", "GAsyncReadyCallback"));
661 cparam_map
.set (get_param_pos (-0.9), new
CCodeFormalParameter ("_user_data_", "gpointer"));
662 if (carg_map
!= null) {
663 carg_map
.set (get_param_pos (-1), new
CCodeIdentifier ("_callback_"));
664 carg_map
.set (get_param_pos (-0.9), new
CCodeIdentifier ("_user_data_"));
666 } else if (direction
== 2) {
667 cparam_map
.set (get_param_pos (0.1), new
CCodeFormalParameter ("_res_", "GAsyncResult*"));
668 if (carg_map
!= null) {
669 carg_map
.set (get_param_pos (0.1), new
CCodeIdentifier ("_res_"));
673 base.generate_cparameters (m
, decl_space
, cparam_map
, func
, vdeclarator
, carg_map
, vcall
, direction
);