Line data Source code
1 : /* valagasyncmodule.vala
2 : *
3 : * Copyright (C) 2008-2012 Jürg Billeter
4 : *
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.
9 :
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.
14 :
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
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 2914 : public class Vala.GAsyncModule : GtkModule {
26 127 : CCodeStruct generate_data_struct (Method m) {
27 127 : string dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
28 127 : var data = new CCodeStruct ("_" + dataname);
29 :
30 127 : data.add_field ("int", "_state_");
31 127 : data.add_field ("GObject*", "_source_object_");
32 127 : data.add_field ("GAsyncResult*", "_res_");
33 127 : data.add_field ("GTask*", "_async_result");
34 :
35 127 : if (m is CreationMethod) {
36 9 : data.add_field ("GType", "object_type");
37 : }
38 :
39 196 : if (m.binding == MemberBinding.INSTANCE) {
40 436 : var type_sym = (TypeSymbol) m.parent_symbol;
41 69 : if (type_sym is ObjectTypeSymbol) {
42 69 : data.add_field (get_ccode_name (type_sym) + "*", "self");
43 : } else {
44 0 : data.add_field (get_ccode_name (type_sym), "self");
45 : }
46 : }
47 :
48 219 : foreach (Parameter param in m.get_parameters ()) {
49 46 : var param_type = param.variable_type.copy ();
50 46 : param_type.value_owned = true;
51 46 : data.add_field (get_ccode_name (param_type), get_ccode_name (param), 0, get_ccode_declarator_suffix (param_type));
52 :
53 53 : if (param.variable_type is ArrayType) {
54 7 : var array_type = (ArrayType) param.variable_type;
55 12 : if (get_ccode_array_length (param) && !((ArrayType) array_type).fixed_length) {
56 5 : var length_ctype = get_ccode_array_length_type (param);
57 10 : for (int dim = 1; dim <= array_type.rank; dim++) {
58 5 : data.add_field (length_ctype, get_variable_array_length_cname (param, dim));
59 : }
60 : }
61 41 : } else if (param.variable_type is DelegateType) {
62 2 : var deleg_type = (DelegateType) param.variable_type;
63 2 : if (deleg_type.delegate_symbol.has_target) {
64 2 : data.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (param));
65 2 : if (deleg_type.is_disposable ()) {
66 2 : data.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (param));
67 : }
68 : }
69 : }
70 : }
71 :
72 137 : foreach (var type_param in m.get_type_parameters ()) {
73 5 : data.add_field ("GType", get_ccode_type_id (type_param));
74 5 : data.add_field ("GBoxedCopyFunc", get_ccode_copy_function (type_param));
75 5 : data.add_field ("GDestroyNotify", get_ccode_destroy_function (type_param));
76 : }
77 :
78 127 : if (!(m.return_type is VoidType)) {
79 31 : data.add_field (get_ccode_name (m.return_type), "result");
80 34 : if (m.return_type is ArrayType) {
81 3 : var array_type = (ArrayType) m.return_type;
82 5 : if (get_ccode_array_length (m)) {
83 2 : var length_ctype = get_ccode_array_length_type (m);
84 4 : for (int dim = 1; dim <= array_type.rank; dim++) {
85 2 : data.add_field (length_ctype, get_array_length_cname ("result", dim));
86 : }
87 : }
88 29 : } else if (m.return_type is DelegateType) {
89 1 : var deleg_type = (DelegateType) m.return_type;
90 1 : if (deleg_type.delegate_symbol.has_target) {
91 1 : data.add_field (get_ccode_name (delegate_target_type), get_delegate_target_cname ("result"));
92 1 : data.add_field (get_ccode_name (delegate_target_destroy_type), get_delegate_target_destroy_notify_cname ("result"));
93 : }
94 : }
95 : }
96 :
97 127 : return data;
98 : }
99 :
100 127 : CCodeFunction generate_free_function (Method m) {
101 127 : var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
102 :
103 127 : var freefunc = new CCodeFunction (get_ccode_real_name (m) + "_data_free", "void");
104 127 : freefunc.modifiers = CCodeModifiers.STATIC;
105 127 : freefunc.add_parameter (new CCodeParameter ("_data", "gpointer"));
106 :
107 127 : push_context (new EmitContext (m));
108 127 : push_function (freefunc);
109 :
110 127 : ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_", new CCodeIdentifier ("_data")));
111 :
112 219 : foreach (Parameter param in m.get_parameters ()) {
113 77 : if (!param.captured && param.direction != ParameterDirection.OUT) {
114 31 : var param_type = param.variable_type.copy ();
115 31 : if (!param_type.value_owned) {
116 29 : param_type.value_owned = !no_implicit_copy (param_type);
117 : }
118 :
119 31 : if (requires_destroy (param_type)) {
120 15 : ccode.add_expression (destroy_parameter (param));
121 : }
122 : }
123 : }
124 :
125 127 : if (requires_destroy (m.return_type)) {
126 36 : if (get_ccode_array_length (m) || !(m.return_type is ArrayType)) {
127 : /* this is very evil. */
128 17 : var v = new LocalVariable (m.return_type, ".result");
129 17 : ccode.add_expression (destroy_local (v));
130 : } else {
131 1 : var v = new GLibValue (m.return_type, new CCodeIdentifier ("_data_->result"), true);
132 1 : v.array_null_terminated = get_ccode_array_null_terminated (m);
133 1 : ccode.add_expression (destroy_value (v));
134 : }
135 : }
136 :
137 196 : if (m.binding == MemberBinding.INSTANCE) {
138 69 : var this_type = m.this_parameter.variable_type.copy ();
139 69 : this_type.value_owned = true;
140 :
141 69 : if (requires_destroy (this_type)) {
142 69 : ccode.add_expression (destroy_parameter (m.this_parameter));
143 : }
144 : }
145 :
146 127 : var freecall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
147 127 : freecall.add_argument (new CCodeIdentifier (dataname));
148 127 : freecall.add_argument (new CCodeIdentifier ("_data_"));
149 127 : ccode.add_expression (freecall);
150 :
151 127 : pop_context ();
152 :
153 127 : cfile.add_function_declaration (freefunc);
154 127 : cfile.add_function (freefunc);
155 :
156 127 : return freefunc;
157 : }
158 :
159 254 : void generate_async_function (Method m) {
160 127 : push_context (new EmitContext ());
161 :
162 127 : var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
163 127 : var asyncfunc = new CCodeFunction (get_ccode_real_name (m), "void");
164 127 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
165 :
166 127 : cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
167 127 : cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
168 :
169 127 : generate_cparameters (m, cfile, cparam_map, asyncfunc, null, null, null, 1);
170 :
171 127 : if (m.base_method != null || m.base_interface_method != null) {
172 : // declare *_real_* function
173 30 : asyncfunc.modifiers |= CCodeModifiers.STATIC;
174 30 : cfile.add_function_declaration (asyncfunc);
175 97 : } else if (m.is_private_symbol ()) {
176 5 : asyncfunc.modifiers |= CCodeModifiers.STATIC;
177 92 : } else if (context.hide_internal && m.is_internal_symbol ()) {
178 0 : asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
179 : }
180 :
181 127 : push_function (asyncfunc);
182 :
183 : // FIXME partial code duplication with CCodeMethodModule.visit_method
184 127 : unowned Class? cl = m.parent_symbol as Class;
185 190 : if (cl != null) {
186 63 : if (m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)
187 53 : && m.base_method == null && m.base_interface_method == null) {
188 29 : create_type_check_statement (m, new VoidType (), cl, true, "self");
189 : }
190 : }
191 219 : foreach (Parameter param in m.get_parameters ()) {
192 46 : if (param.ellipsis || param.params_array) {
193 0 : break;
194 : }
195 :
196 46 : if (param.direction == ParameterDirection.IN) {
197 36 : unowned TypeSymbol? t = param.variable_type.type_symbol;
198 36 : if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) {
199 12 : create_type_check_statement (m, new VoidType (), t, !param.variable_type.nullable, get_ccode_name (param));
200 : }
201 : }
202 : }
203 :
204 : // logic copied from valaccodemethodmodule
205 142 : if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
206 : Method base_method;
207 :
208 15 : if (m.overrides && m.base_method != null) {
209 10 : base_method = m.base_method;
210 : } else {
211 5 : base_method = m.base_interface_method;
212 : }
213 :
214 15 : var base_expression_type = new ObjectType ((ObjectTypeSymbol) base_method.parent_symbol);
215 15 : var type_symbol = m.parent_symbol as ObjectTypeSymbol;
216 :
217 15 : var self_target_type = new ObjectType (type_symbol);
218 202 : var cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
219 15 : ccode.add_declaration ("%s *".printf (get_ccode_name (type_symbol)), new CCodeVariableDeclarator ("self"));
220 15 : ccode.add_assignment (new CCodeIdentifier ("self"), cself);
221 : }
222 :
223 127 : var dataalloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
224 127 : dataalloc.add_argument (new CCodeIdentifier (dataname));
225 :
226 127 : var data_var = new CCodeIdentifier ("_data_");
227 :
228 127 : ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
229 127 : ccode.add_assignment (data_var, dataalloc);
230 :
231 127 : var create_result = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new"));
232 :
233 127 : var t = m.parent_symbol as TypeSymbol;
234 229 : if (!(m is CreationMethod) && m.binding == MemberBinding.INSTANCE &&
235 60 : t != null && t.is_subtype_of (gobject_type)) {
236 42 : var gobject_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
237 42 : gobject_cast.add_argument (new CCodeIdentifier ("self"));
238 :
239 42 : create_result.add_argument (gobject_cast);
240 : } else {
241 85 : create_result.add_argument (new CCodeConstant ("NULL"));
242 : }
243 :
244 127 : Parameter cancellable_param = null;
245 :
246 217 : foreach (Parameter param in m.get_parameters ()) {
247 46 : if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
248 1 : cancellable_param = param;
249 1 : break;
250 : }
251 : }
252 :
253 127 : if (cancellable_param == null) {
254 126 : create_result.add_argument (new CCodeConstant ("NULL"));
255 : } else {
256 1 : create_result.add_argument (new CCodeIdentifier (get_ccode_name (cancellable_param)));
257 : }
258 :
259 127 : create_result.add_argument (new CCodeIdentifier ("_callback_"));
260 127 : create_result.add_argument (new CCodeIdentifier ("_user_data_"));
261 :
262 127 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_async_result"), create_result);
263 :
264 127 : var attach_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_set_task_data"));
265 :
266 127 : attach_data_call.add_argument (new CCodeMemberAccess.pointer (data_var, "_async_result"));
267 127 : attach_data_call.add_argument (data_var);
268 127 : attach_data_call.add_argument (new CCodeIdentifier (get_ccode_real_name (m) + "_data_free"));
269 127 : ccode.add_expression (attach_data_call);
270 :
271 127 : if (m is CreationMethod) {
272 9 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "object_type"), new CCodeIdentifier ("object_type"));
273 178 : } else if (m.binding == MemberBinding.INSTANCE) {
274 60 : var this_type = m.this_parameter.variable_type.copy ();
275 60 : this_type.value_owned = true;
276 :
277 : // create copy if necessary as variables in async methods may need to be kept alive
278 60 : CCodeExpression cself = new CCodeIdentifier ("self");
279 60 : if (this_type.is_real_non_null_struct_type ()) {
280 0 : cself = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cself);
281 : }
282 60 : if (requires_copy (this_type)) {
283 120 : cself = get_cvalue_ (copy_value (new GLibValue (m.this_parameter.variable_type, cself, true), m.this_parameter));
284 : }
285 :
286 60 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), cself);
287 : }
288 :
289 127 : emit_context.push_symbol (m);
290 219 : foreach (Parameter param in m.get_parameters ()) {
291 82 : if (param.direction != ParameterDirection.OUT) {
292 : // create copy if necessary as variables in async methods may need to be kept alive
293 36 : var old_captured = param.captured;
294 36 : param.captured = false;
295 36 : current_method.coroutine = false;
296 :
297 : TargetValue value;
298 36 : if (param.variable_type.value_owned) {
299 : // do not use load_parameter for reference/ownership transfer
300 : // otherwise delegate destroy notify will not be moved
301 3 : value = get_parameter_cvalue (param);
302 : } else {
303 33 : value = load_parameter (param);
304 : }
305 :
306 36 : current_method.coroutine = true;
307 :
308 36 : store_parameter (param, value);
309 :
310 36 : param.captured = old_captured;
311 : }
312 : }
313 127 : emit_context.pop_symbol ();
314 :
315 137 : foreach (var type_param in m.get_type_parameters ()) {
316 5 : var type = get_ccode_type_id (type_param);
317 5 : var dup_func = get_ccode_copy_function (type_param);
318 5 : var destroy_func = get_ccode_destroy_function (type_param);
319 5 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, type), new CCodeIdentifier (type));
320 5 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, dup_func), new CCodeIdentifier (dup_func));
321 5 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, destroy_func), new CCodeIdentifier (destroy_func));
322 : }
323 :
324 127 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
325 127 : ccall.add_argument (data_var);
326 127 : ccode.add_expression (ccall);
327 :
328 127 : cfile.add_function (asyncfunc);
329 :
330 127 : pop_context ();
331 : }
332 :
333 302 : public void append_struct (CCodeStruct structure) {
334 151 : var typename = new CCodeVariableDeclarator (structure.name.substring (1));
335 151 : var typedef = new CCodeTypeDefinition ("struct " + structure.name, typename);
336 151 : cfile.add_type_declaration (typedef);
337 151 : cfile.add_type_definition (structure);
338 : }
339 :
340 28825 : public override bool generate_method_declaration (Method m, CCodeFile decl_space) {
341 28825 : if (m.coroutine) {
342 549 : if ((m.is_abstract || m.is_virtual) && get_ccode_no_wrapper (m)) {
343 262 : return false;
344 : }
345 525 : if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
346 262 : return false;
347 : }
348 :
349 287 : generate_type_declaration (new MethodType (m), decl_space);
350 :
351 287 : var cl = m.parent_symbol as Class;
352 :
353 287 : var asyncfunc = new CCodeFunction (get_ccode_name (m), "void");
354 287 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
355 287 : var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
356 :
357 287 : if (m.is_private_symbol () || m.entry_point) {
358 18 : asyncfunc.modifiers |= CCodeModifiers.STATIC;
359 269 : } else if (context.hide_internal && m.is_internal_symbol ()) {
360 0 : asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
361 : } else {
362 269 : asyncfunc.modifiers |= CCodeModifiers.EXTERN;
363 269 : requires_vala_extern = true;
364 : }
365 :
366 : // do not generate _new functions for creation methods of abstract classes
367 287 : if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
368 284 : generate_cparameters (m, decl_space, cparam_map, asyncfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 1);
369 :
370 284 : decl_space.add_function_declaration (asyncfunc);
371 : }
372 :
373 287 : var finishfunc = new CCodeFunction (get_ccode_finish_name (m));
374 287 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
375 287 : carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
376 :
377 287 : if (m.is_private_symbol () || m.entry_point) {
378 18 : finishfunc.modifiers |= CCodeModifiers.STATIC;
379 269 : } else if (context.hide_internal && m.is_internal_symbol ()) {
380 0 : finishfunc.modifiers |= CCodeModifiers.INTERNAL;
381 : } else {
382 269 : finishfunc.modifiers |= CCodeModifiers.EXTERN;
383 269 : requires_vala_extern = true;
384 : }
385 :
386 : // do not generate _new functions for creation methods of abstract classes
387 287 : if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
388 284 : generate_cparameters (m, decl_space, cparam_map, finishfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 2);
389 :
390 284 : decl_space.add_function_declaration (finishfunc);
391 : }
392 :
393 307 : if (m is CreationMethod && cl != null) {
394 : // _construct function
395 20 : var function = new CCodeFunction (get_ccode_real_name (m));
396 :
397 20 : if (m.is_private_symbol ()) {
398 0 : function.modifiers |= CCodeModifiers.STATIC;
399 20 : } else if (context.hide_internal && m.is_internal_symbol ()) {
400 0 : function.modifiers |= CCodeModifiers.INTERNAL;
401 : } else {
402 20 : function.modifiers |= CCodeModifiers.EXTERN;
403 20 : requires_vala_extern = true;
404 : }
405 :
406 20 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
407 20 : generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 1);
408 :
409 20 : decl_space.add_function_declaration (function);
410 :
411 20 : function = new CCodeFunction (get_ccode_finish_real_name (m));
412 :
413 20 : if (m.is_private_symbol ()) {
414 0 : function.modifiers |= CCodeModifiers.STATIC;
415 20 : } else if (context.hide_internal && m.is_internal_symbol ()) {
416 0 : function.modifiers |= CCodeModifiers.INTERNAL;
417 : } else {
418 20 : function.modifiers |= CCodeModifiers.EXTERN;
419 20 : requires_vala_extern = true;
420 : }
421 :
422 20 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
423 20 : generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 2);
424 :
425 20 : decl_space.add_function_declaration (function);
426 : }
427 :
428 287 : return true;
429 : } else {
430 28276 : return base.generate_method_declaration (m, decl_space);
431 : }
432 : }
433 :
434 5094 : public override void visit_method (Method m) {
435 5094 : if (m.coroutine) {
436 153 : cfile.add_include ("gio/gio.h");
437 153 : if (!m.is_internal_symbol ()) {
438 32 : header_file.add_include ("gio/gio.h");
439 : }
440 :
441 280 : if (!m.is_abstract && m.body != null) {
442 127 : var data = generate_data_struct (m);
443 :
444 254 : closure_struct = data;
445 :
446 127 : generate_free_function (m);
447 127 : generate_async_function (m);
448 127 : generate_finish_function (m);
449 :
450 : // append the _co function
451 127 : base.visit_method (m);
452 127 : closure_struct = null;
453 :
454 : // only append data struct here to make sure all struct member
455 : // types are declared before the struct definition
456 127 : append_struct (data);
457 : } else {
458 26 : generate_method_declaration (m, cfile);
459 :
460 26 : if (!m.is_internal_symbol ()) {
461 7 : generate_method_declaration (m, header_file);
462 : }
463 26 : if (!m.is_private_symbol ()) {
464 26 : generate_method_declaration (m, internal_header_file);
465 : }
466 : }
467 :
468 189 : if ((m.is_abstract || m.is_virtual) && !get_ccode_no_wrapper (m)) {
469 : // generate virtual function wrappers
470 36 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
471 36 : var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
472 36 : generate_vfunc (m, new VoidType (), cparam_map, carg_map, "", 1);
473 :
474 36 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
475 36 : carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
476 36 : generate_vfunc (m, m.return_type, cparam_map, carg_map, "_finish", 2);
477 : }
478 : } else {
479 4941 : base.visit_method (m);
480 : }
481 : }
482 :
483 845 : public override void visit_creation_method (CreationMethod m) {
484 845 : if (!m.coroutine) {
485 836 : base.visit_creation_method (m);
486 : } else {
487 9 : push_line (m.source_reference);
488 :
489 9 : bool visible = !m.is_private_symbol ();
490 :
491 9 : visit_method (m);
492 :
493 9 : if (m.source_type == SourceFileType.FAST) {
494 : return;
495 : }
496 :
497 : // do not generate _new functions for creation methods of abstract classes
498 17 : if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
499 8 : var vfunc = new CCodeFunction (get_ccode_name (m));
500 :
501 8 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
502 8 : var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
503 :
504 8 : push_function (vfunc);
505 :
506 8 : var vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
507 8 : vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
508 :
509 8 : generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 1);
510 8 : ccode.add_expression (vcall);
511 :
512 8 : if (!visible) {
513 0 : vfunc.modifiers |= CCodeModifiers.STATIC;
514 : }
515 :
516 8 : pop_function ();
517 :
518 8 : cfile.add_function (vfunc);
519 :
520 :
521 8 : vfunc = new CCodeFunction (get_ccode_finish_name (m));
522 :
523 8 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
524 8 : carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
525 :
526 8 : push_function (vfunc);
527 :
528 8 : vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_real_name (m)));
529 :
530 8 : generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 2);
531 8 : ccode.add_return (vcall);
532 :
533 8 : if (!visible) {
534 0 : vfunc.modifiers |= CCodeModifiers.STATIC;
535 : }
536 :
537 8 : pop_function ();
538 :
539 8 : cfile.add_function (vfunc);
540 : }
541 :
542 9 : pop_line ();
543 : }
544 : }
545 :
546 254 : void generate_finish_function (Method m) {
547 127 : push_context (new EmitContext ());
548 :
549 127 : string dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
550 :
551 127 : var finishfunc = new CCodeFunction (get_ccode_finish_real_name (m));
552 :
553 127 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
554 :
555 127 : cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
556 :
557 127 : generate_cparameters (m, cfile, cparam_map, finishfunc, null, null, null, 2);
558 :
559 127 : if (m.is_private_symbol () || m.base_method != null || m.base_interface_method != null) {
560 35 : finishfunc.modifiers |= CCodeModifiers.STATIC;
561 92 : } else if (context.hide_internal && m.is_internal_symbol ()) {
562 0 : finishfunc.modifiers |= CCodeModifiers.INTERNAL;
563 : }
564 :
565 127 : push_function (finishfunc);
566 :
567 127 : var return_type = m.return_type;
568 136 : if (m is CreationMethod) {
569 9 : var type_sym = (TypeSymbol) m.parent_symbol;
570 9 : if (type_sym is ObjectTypeSymbol) {
571 9 : ccode.add_declaration (get_ccode_name (type_sym) + "*", new CCodeVariableDeclarator ("result"));
572 9 : return_type = SemanticAnalyzer.get_this_type (m, type_sym);
573 : }
574 118 : } else if (!(return_type is VoidType) && !return_type.is_real_non_null_struct_type ()) {
575 30 : ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator ("result"));
576 : }
577 :
578 127 : var data_var = new CCodeIdentifier ("_data_");
579 :
580 127 : ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
581 :
582 127 : var async_result_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_TASK"));
583 127 : async_result_cast.add_argument (new CCodeIdentifier ("_res_"));
584 :
585 127 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer"));
586 127 : ccall.add_argument (async_result_cast);
587 :
588 127 : if (m.tree_can_fail) {
589 22 : ccall.add_argument (new CCodeIdentifier ("error"));
590 : } else {
591 105 : ccall.add_argument (new CCodeConstant ("NULL"));
592 : }
593 :
594 127 : ccode.add_assignment (data_var, ccall);
595 :
596 127 : bool has_cancellable = false;
597 :
598 217 : foreach (Parameter param in m.get_parameters ()) {
599 46 : if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
600 1 : has_cancellable = true;
601 1 : break;
602 : }
603 : }
604 :
605 : // If a task is cancelled, g_task_propagate_pointer returns NULL
606 149 : if (m.tree_can_fail || has_cancellable) {
607 22 : var is_null = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), data_var);
608 :
609 22 : ccode.open_if (is_null);
610 22 : return_default_value (return_type);
611 22 : ccode.close ();
612 : }
613 :
614 127 : emit_context.push_symbol (m);
615 219 : foreach (Parameter param in m.get_parameters ()) {
616 46 : if (param.direction != ParameterDirection.IN) {
617 10 : return_out_parameter (param);
618 10 : if (!(param.variable_type is ValueType) || param.variable_type.nullable) {
619 4 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_ccode_name (param)), new CCodeConstant ("NULL"));
620 : }
621 : }
622 : }
623 127 : emit_context.pop_symbol ();
624 :
625 127 : if (m is CreationMethod) {
626 9 : ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "self"));
627 9 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), new CCodeConstant ("NULL"));
628 9 : ccode.add_return (new CCodeIdentifier ("result"));
629 119 : } else if (return_type.is_real_non_null_struct_type ()) {
630 : // structs are returned via out parameter
631 1 : CCodeExpression cexpr = new CCodeMemberAccess.pointer (data_var, "result");
632 1 : if (requires_copy (return_type)) {
633 0 : cexpr = get_cvalue_ (copy_value (new GLibValue (return_type, cexpr, true), return_type));
634 : }
635 1 : ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result")), cexpr);
636 117 : } else if (!(return_type is VoidType)) {
637 30 : ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "result"));
638 33 : if (return_type is ArrayType) {
639 3 : var array_type = (ArrayType) return_type;
640 3 : if (get_ccode_array_length (m)) {
641 4 : for (int dim = 1; dim <= array_type.rank; dim++) {
642 2 : 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)));
643 : }
644 : }
645 27 : } else if (return_type is DelegateType && ((DelegateType) return_type).delegate_symbol.has_target) {
646 1 : 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")));
647 : }
648 30 : if (!(return_type is ValueType) || return_type.nullable) {
649 18 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "result"), new CCodeConstant ("NULL"));
650 : }
651 30 : ccode.add_return (new CCodeIdentifier ("result"));
652 : }
653 :
654 127 : pop_function ();
655 :
656 127 : cfile.add_function (finishfunc);
657 :
658 127 : pop_context ();
659 : }
660 :
661 52 : public override string generate_ready_function (Method m) {
662 : // generate ready callback handler
663 :
664 52 : var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
665 :
666 52 : var readyfunc = new CCodeFunction (get_ccode_name (m) + "_ready", "void");
667 :
668 52 : if (!add_wrapper (readyfunc.name)) {
669 : // wrapper already defined
670 48 : return readyfunc.name;
671 : }
672 :
673 28 : readyfunc.add_parameter (new CCodeParameter ("source_object", "GObject*"));
674 28 : readyfunc.add_parameter (new CCodeParameter ("_res_", "GAsyncResult*"));
675 28 : readyfunc.add_parameter (new CCodeParameter ("_user_data_", "gpointer"));
676 :
677 28 : push_function (readyfunc);
678 :
679 28 : var data_var = new CCodeIdentifier ("_data_");
680 :
681 28 : ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
682 28 : ccode.add_assignment (data_var, new CCodeIdentifier ("_user_data_"));
683 28 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_source_object_"), new CCodeIdentifier ("source_object"));
684 28 : ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_res_"), new CCodeIdentifier ("_res_"));
685 :
686 28 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
687 28 : ccall.add_argument (data_var);
688 28 : ccode.add_expression (ccall);
689 :
690 28 : readyfunc.modifiers |= CCodeModifiers.STATIC;
691 :
692 28 : pop_function ();
693 :
694 28 : cfile.add_function_declaration (readyfunc);
695 28 : cfile.add_function (readyfunc);
696 :
697 56 : return readyfunc.name;
698 : }
699 :
700 5598 : public override void generate_virtual_method_declaration (Method m, CCodeFile decl_space, CCodeStruct type_struct) {
701 5500 : if (!m.coroutine) {
702 5286 : base.generate_virtual_method_declaration (m, decl_space, type_struct);
703 5286 : return;
704 : }
705 :
706 214 : if (!m.is_abstract && !m.is_virtual) {
707 : return;
708 : }
709 :
710 98 : var creturn_type = get_callable_creturn_type (m);
711 :
712 : // add vfunc field to the type struct
713 98 : var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
714 98 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
715 :
716 98 : generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 1);
717 :
718 98 : var vdecl = new CCodeDeclaration ("void");
719 98 : vdecl.add_declarator (vdeclarator);
720 98 : type_struct.add_declaration (vdecl);
721 :
722 : // add vfunc field to the type struct
723 98 : vdeclarator = new CCodeFunctionDeclarator (get_ccode_finish_vfunc_name (m));
724 98 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
725 :
726 98 : generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 2);
727 :
728 98 : vdecl = new CCodeDeclaration (get_ccode_name (creturn_type));
729 98 : vdecl.add_declarator (vdeclarator);
730 98 : type_struct.add_declaration (vdecl);
731 : }
732 :
733 17 : public override void visit_yield_statement (YieldStatement stmt) {
734 17 : if (!is_in_coroutine ()) {
735 : return;
736 : }
737 :
738 17 : int state = emit_context.next_coroutine_state++;
739 :
740 17 : ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
741 17 : ccode.add_return (new CCodeConstant ("FALSE"));
742 17 : ccode.add_label ("_state_%d".printf (state));
743 17 : ccode.add_statement (new CCodeEmptyStatement ());
744 : }
745 :
746 244 : public override void return_with_exception (CCodeExpression error_expr)
747 : {
748 227 : if (!is_in_coroutine ()) {
749 210 : base.return_with_exception (error_expr);
750 210 : return;
751 : }
752 :
753 17 : var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_async_result");
754 17 : CCodeFunctionCall set_error = null;
755 :
756 17 : set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_error"));
757 17 : set_error.add_argument (async_result_expr);
758 17 : set_error.add_argument (error_expr);
759 17 : ccode.add_expression (set_error);
760 :
761 : // free local variables
762 17 : append_local_free (current_symbol);
763 :
764 : // free possibly already assigned out-parameter
765 17 : append_out_param_free (current_method);
766 :
767 : // We already returned the error above, we must not return anything else here.
768 17 : var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
769 17 : unref.add_argument (async_result_expr);
770 17 : ccode.add_expression (unref);
771 :
772 17 : ccode.add_return (new CCodeConstant ("FALSE"));
773 : }
774 :
775 2842 : public override void visit_return_statement (ReturnStatement stmt) {
776 2842 : base.visit_return_statement (stmt);
777 :
778 2842 : if (!is_in_coroutine ()) {
779 : return;
780 : }
781 :
782 30 : complete_async ();
783 : }
784 :
785 17597 : 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) {
786 17597 : if (m.coroutine) {
787 1351 : decl_space.add_include ("gio/gio.h");
788 :
789 1351 : if (direction == 1) {
790 612 : cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
791 612 : cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
792 612 : if (carg_map != null) {
793 328 : carg_map.set (get_param_pos (-1), new CCodeIdentifier ("_callback_"));
794 328 : carg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_user_data_"));
795 : }
796 739 : } else if (direction == 2) {
797 612 : cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
798 612 : if (carg_map != null) {
799 328 : carg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeIdentifier ("_res_"));
800 : }
801 : }
802 : }
803 17597 : base.generate_cparameters (m, decl_space, cparam_map, func, vdeclarator, carg_map, vcall, direction);
804 : }
805 :
806 13 : public string generate_async_callback_wrapper () {
807 13 : string async_callback_wrapper_func = "_vala_g_async_ready_callback";
808 :
809 13 : if (!add_wrapper (async_callback_wrapper_func)) {
810 13 : return async_callback_wrapper_func;
811 : }
812 :
813 6 : var function = new CCodeFunction (async_callback_wrapper_func, "void");
814 6 : function.modifiers = CCodeModifiers.STATIC;
815 :
816 6 : function.add_parameter (new CCodeParameter ("*source_object", "GObject"));
817 6 : function.add_parameter (new CCodeParameter ("*res", "GAsyncResult"));
818 6 : function.add_parameter (new CCodeParameter ("*user_data", "void"));
819 :
820 6 : push_function (function);
821 :
822 6 : var res_ref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
823 6 : res_ref.add_argument (new CCodeIdentifier ("res"));
824 :
825 6 : CCodeFunctionCall ccall = null;
826 :
827 : // store reference to async result of inner async function in out async result
828 6 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_pointer"));
829 6 : ccall.add_argument (new CCodeIdentifier ("user_data"));
830 6 : ccall.add_argument (res_ref);
831 6 : ccall.add_argument (new CCodeIdentifier ("g_object_unref"));
832 6 : ccode.add_expression (ccall);
833 :
834 : // free async result
835 6 : ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
836 6 : ccall.add_argument (new CCodeIdentifier ("user_data"));
837 6 : ccode.add_expression (ccall);
838 :
839 6 : pop_function ();
840 :
841 6 : cfile.add_function_declaration (function);
842 6 : cfile.add_function (function);
843 :
844 6 : return async_callback_wrapper_func;
845 : }
846 : }
|