Line data Source code
1 : /* valaccodemethodmodule.vala
2 : *
3 : * Copyright (C) 2007-2010 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 : * Raffaele Sandrini <raffaele@sandrini.ch>
22 : */
23 :
24 : using GLib;
25 :
26 : /**
27 : * The link between a method and generated code.
28 : */
29 4395 : public abstract class Vala.CCodeMethodModule : CCodeStructModule {
30 :
31 1465 : private bool ellipses_to_valist = false;
32 :
33 17085 : string get_creturn_type (Method m, string default_value) {
34 17085 : string type = get_ccode_type (m);
35 17085 : if (type == null) {
36 34164 : return default_value;
37 : }
38 17085 : return type;
39 : }
40 :
41 25476 : bool is_gtypeinstance_creation_method (Method m) {
42 25476 : bool result = false;
43 :
44 39642 : var cl = m.parent_symbol as Class;
45 25476 : if (m is CreationMethod && cl != null && !cl.is_compact) {
46 25476 : result = true;
47 : }
48 :
49 25476 : return result;
50 : }
51 :
52 51252 : public virtual void generate_method_result_declaration (Method m, CCodeFile decl_space, CCodeFunction cfunc, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
53 17084 : var creturn_type = get_callable_creturn_type (m);
54 17084 : cfunc.return_type = get_creturn_type (m, get_ccode_name (creturn_type));
55 :
56 17084 : generate_type_declaration (m.return_type, decl_space);
57 :
58 17151 : if (m.return_type.is_real_non_null_struct_type ()) {
59 : // structs are returned via out parameter
60 67 : var cparam = new CCodeParameter ("result", get_ccode_name (m.return_type) + "*");
61 67 : cparam_map.set (get_param_pos (-3), cparam);
62 67 : if (carg_map != null) {
63 38 : carg_map.set (get_param_pos (-3), get_cexpression ("result"));
64 : }
65 17271 : } else if (get_ccode_array_length (m) && m.return_type is ArrayType) {
66 : // return array length if appropriate
67 254 : var array_type = (ArrayType) m.return_type;
68 254 : var length_ctype = get_ccode_array_length_type (m) + "*";
69 :
70 846 : for (int dim = 1; dim <= array_type.rank; dim++) {
71 296 : var cparam = new CCodeParameter (get_array_length_cname ("result", dim), length_ctype);
72 296 : cparam_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), cparam);
73 296 : if (carg_map != null) {
74 170 : carg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), get_cexpression (cparam.name));
75 : }
76 : }
77 16803 : } else if (get_ccode_delegate_target (m) && m.return_type is DelegateType) {
78 : // return delegate target if appropriate
79 40 : var deleg_type = (DelegateType) m.return_type;
80 80 : if (deleg_type.delegate_symbol.has_target) {
81 40 : var cparam = new CCodeParameter (get_delegate_target_cname ("result"), get_ccode_name (delegate_target_type) + "*");
82 40 : cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), cparam);
83 40 : if (carg_map != null) {
84 22 : carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), get_cexpression (cparam.name));
85 : }
86 40 : if (deleg_type.is_disposable ()) {
87 23 : cparam = new CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), get_ccode_name (delegate_target_destroy_type) + "*");
88 23 : cparam_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), cparam);
89 23 : if (carg_map != null) {
90 15 : carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), get_cexpression (cparam.name));
91 : }
92 : }
93 : }
94 : }
95 :
96 18269 : if (m.has_error_type_parameter ()) {
97 1185 : var error_types = new ArrayList<DataType> ();
98 1185 : m.get_error_types (error_types);
99 3699 : foreach (DataType error_type in error_types) {
100 1257 : generate_type_declaration (error_type, decl_space);
101 : }
102 :
103 1185 : var cparam = new CCodeParameter ("error", "GError**");
104 1185 : cparam_map.set (get_param_pos (get_ccode_error_pos (m)), cparam);
105 1185 : if (carg_map != null) {
106 582 : carg_map.set (get_param_pos (get_ccode_error_pos (m)), new CCodeIdentifier (cparam.name));
107 : }
108 : }
109 : }
110 :
111 252 : public void complete_async () {
112 126 : var data_var = new CCodeIdentifier ("_data_");
113 126 : var async_result_expr = new CCodeMemberAccess.pointer (data_var, "_async_result");
114 :
115 126 : var finish_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_pointer"));
116 126 : finish_call.add_argument (async_result_expr);
117 126 : finish_call.add_argument (data_var);
118 126 : finish_call.add_argument (new CCodeConstant ("NULL"));
119 126 : ccode.add_expression (finish_call);
120 :
121 : // Preserve the "complete now" behavior if state != 0, do so by
122 : // iterating the GTask's main context till the task is complete.
123 126 : var state = new CCodeMemberAccess.pointer (data_var, "_state_");
124 126 : var zero = new CCodeConstant ("0");
125 126 : var state_is_not_zero = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, state, zero);
126 126 : ccode.open_if (state_is_not_zero);
127 :
128 : CCodeExpression task_is_complete;
129 :
130 126 : var task_complete = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_completed"));
131 126 : task_complete.add_argument (async_result_expr);
132 126 : task_is_complete = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, task_complete);
133 :
134 126 : ccode.open_while (task_is_complete);
135 126 : var task_context = new CCodeFunctionCall (new CCodeIdentifier ("g_task_get_context"));
136 126 : task_context.add_argument (async_result_expr);
137 126 : var iterate_context = new CCodeFunctionCall (new CCodeIdentifier ("g_main_context_iteration"));
138 126 : iterate_context.add_argument (task_context);
139 126 : iterate_context.add_argument (new CCodeConstant ("TRUE"));
140 126 : ccode.add_expression (iterate_context);
141 126 : ccode.close ();
142 :
143 126 : ccode.close ();
144 :
145 126 : var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
146 126 : unref.add_argument (async_result_expr);
147 126 : ccode.add_expression (unref);
148 :
149 126 : ccode.add_return (new CCodeConstant ("FALSE"));
150 : }
151 :
152 28476 : public override bool generate_method_declaration (Method m, CCodeFile decl_space) {
153 28476 : if (m.is_async_callback) {
154 21100 : return false;
155 : }
156 28457 : if ((m.is_abstract || m.is_virtual) && get_ccode_no_wrapper (m)) {
157 21100 : return false;
158 : }
159 28414 : if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
160 21100 : return false;
161 : }
162 :
163 7376 : generate_type_declaration (new MethodType (m), decl_space);
164 :
165 7376 : var function = new CCodeFunction (get_ccode_name (m));
166 :
167 7376 : if (m.is_private_symbol () && !m.external) {
168 879 : function.modifiers |= CCodeModifiers.STATIC;
169 879 : if (m.is_inline) {
170 43 : function.modifiers |= CCodeModifiers.INLINE;
171 : }
172 6497 : } else if (context.hide_internal && m.is_internal_symbol () && !m.external) {
173 168 : function.modifiers |= CCodeModifiers.INTERNAL;
174 6329 : } else if (!m.entry_point && !m.external) {
175 4495 : function.modifiers |= CCodeModifiers.EXTERN;
176 4495 : requires_vala_extern = true;
177 : }
178 :
179 7376 : if (m.entry_point) {
180 1828 : function.modifiers |= CCodeModifiers.STATIC;
181 : }
182 :
183 7376 : if (m.version.deprecated) {
184 16 : if (context.profile == Profile.GOBJECT) {
185 16 : decl_space.add_include ("glib.h");
186 : }
187 16 : function.modifiers |= CCodeModifiers.DEPRECATED;
188 : }
189 :
190 7376 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
191 7376 : var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
192 :
193 7376 : var cl = m.parent_symbol as Class;
194 :
195 : // do not generate _new functions for creation methods of abstract classes
196 7376 : if (!(m is CreationMethod && cl != null && cl.is_abstract && !cl.is_compact)) {
197 7286 : bool etv_tmp = ellipses_to_valist;
198 7286 : ellipses_to_valist = false;
199 7286 : generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
200 7286 : ellipses_to_valist = etv_tmp;
201 :
202 7286 : decl_space.add_function_declaration (function);
203 : }
204 :
205 7376 : if (is_gtypeinstance_creation_method (m)) {
206 : // _construct function
207 1638 : function = new CCodeFunction (get_ccode_real_name (m));
208 :
209 1638 : if (m.is_private_symbol ()) {
210 17 : function.modifiers |= CCodeModifiers.STATIC;
211 1621 : } else if (context.hide_internal && m.is_internal_symbol ()) {
212 112 : function.modifiers |= CCodeModifiers.INTERNAL;
213 : } else {
214 1509 : function.modifiers |= CCodeModifiers.EXTERN;
215 1509 : requires_vala_extern = true;
216 : }
217 :
218 1638 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
219 1638 : bool etv_tmp = ellipses_to_valist;
220 1638 : ellipses_to_valist = false;
221 1638 : generate_cparameters (m, decl_space, cparam_map, function);
222 1638 : ellipses_to_valist = etv_tmp;
223 :
224 1638 : decl_space.add_function_declaration (function);
225 :
226 1638 : if (m.is_variadic ()) {
227 : // _constructv function
228 31 : function = new CCodeFunction (get_ccode_constructv_name ((CreationMethod) m));
229 :
230 31 : if (!m.is_private_symbol ()) {
231 31 : function.modifiers |= CCodeModifiers.EXTERN;
232 31 : requires_vala_extern = true;
233 : }
234 :
235 31 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
236 31 : generate_cparameters (m, decl_space, cparam_map, function);
237 :
238 31 : decl_space.add_function_declaration (function);
239 : }
240 : }
241 :
242 7376 : return true;
243 : }
244 :
245 636 : void register_plugin_types (Symbol sym, Set<Symbol> registered_types) {
246 318 : var ns = sym as Namespace;
247 318 : var cl = sym as Class;
248 318 : var iface = sym as Interface;
249 318 : if (ns != null) {
250 127 : foreach (var ns_ns in ns.get_namespaces ()) {
251 42 : register_plugin_types (ns_ns, registered_types);
252 : }
253 517 : foreach (var ns_cl in ns.get_classes ()) {
254 237 : register_plugin_types (ns_cl, registered_types);
255 : }
256 119 : foreach (var ns_iface in ns.get_interfaces ()) {
257 38 : register_plugin_types (ns_iface, registered_types);
258 : }
259 275 : } else if (cl != null) {
260 237 : register_plugin_type (cl, registered_types);
261 237 : foreach (var cl_cl in cl.get_classes ()) {
262 0 : register_plugin_types (cl_cl, registered_types);
263 : }
264 38 : } else if (iface != null) {
265 38 : register_plugin_type (iface, registered_types);
266 38 : foreach (var iface_cl in iface.get_classes ()) {
267 0 : register_plugin_types (iface_cl, registered_types);
268 : }
269 : }
270 : }
271 :
272 277 : void register_plugin_type (ObjectTypeSymbol type_symbol, Set<Symbol> registered_types) {
273 276 : if (type_symbol.external_package) {
274 : return;
275 : }
276 :
277 1 : if (!registered_types.add (type_symbol)) {
278 : // already registered
279 : return;
280 : }
281 :
282 1 : var cl = type_symbol as Class;
283 1 : if (cl != null) {
284 1 : if (cl.is_compact) {
285 0 : return;
286 : }
287 :
288 : // register base types first
289 3 : foreach (var base_type in cl.get_base_types ()) {
290 1 : register_plugin_type ((ObjectTypeSymbol) base_type.type_symbol, registered_types);
291 : }
292 : }
293 :
294 1 : unowned Interface? iface = type_symbol as Interface;
295 0 : bool is_dbus_interface = false;
296 0 : if (iface != null) {
297 0 : is_dbus_interface = GDBusModule.get_dbus_name (type_symbol) != null;
298 : }
299 :
300 : // Add function prototypes for required register-type-calls which are likely external
301 1 : if (type_symbol.source_reference.file != cfile.file) {
302 : // TODO Duplicated source with TypeRegisterFunction.init_from_type()
303 0 : var register_func = new CCodeFunction ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null)), "GType");
304 0 : register_func.add_parameter (new CCodeParameter ("module", "GTypeModule *"));
305 0 : register_func.is_declaration = true;
306 0 : cfile.add_function_declaration (register_func);
307 :
308 : // TODO Duplicated source with GDBusClientModule.generate_interface_declaration()
309 0 : if (is_dbus_interface) {
310 0 : var proxy_register_type = new CCodeFunction ("%sproxy_register_dynamic_type".printf (get_ccode_lower_case_prefix (iface)));
311 0 : proxy_register_type.add_parameter (new CCodeParameter ("module", "GTypeModule*"));
312 0 : proxy_register_type.modifiers |= CCodeModifiers.EXTERN;
313 0 : cfile.add_function_declaration (proxy_register_type);
314 0 : requires_vala_extern = true;
315 : }
316 : }
317 :
318 1 : var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null))));
319 1 : register_call.add_argument (new CCodeIdentifier (module_init_param_name));
320 1 : ccode.add_expression (register_call);
321 :
322 1 : if (is_dbus_interface) {
323 0 : string proxy_cname = get_ccode_lower_case_prefix (type_symbol) + "proxy";
324 0 : var register_proxy = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_dynamic_type".printf (proxy_cname)));
325 0 : register_proxy.add_argument (new CCodeIdentifier (module_init_param_name));
326 0 : ccode.add_expression (register_proxy);
327 : }
328 : }
329 :
330 : /**
331 : * This function generates the code the given method. If the method is
332 : * a constructor, _construct is generated, unless it's variadic, in which
333 : * case _constructv is generated (and _construct is generated together
334 : * with _new in visit_creation_method).
335 : */
336 10202 : public override void visit_method (Method m) {
337 5101 : push_context (new EmitContext (m));
338 5101 : push_line (m.source_reference);
339 :
340 5101 : bool in_gobject_creation_method = false;
341 5101 : bool in_fundamental_creation_method = false;
342 :
343 5101 : bool profile = m.has_attribute ("Profile");
344 :
345 5101 : string real_name = get_ccode_real_name (m);
346 :
347 5101 : if (m is CreationMethod) {
348 845 : unowned Class? cl = m.parent_symbol as Class;
349 814 : if (cl != null && !cl.is_compact) {
350 767 : if (cl.base_class == null) {
351 845 : in_fundamental_creation_method = true;
352 497 : } else if (gobject_type != null && cl.is_subtype_of (gobject_type)) {
353 845 : in_gobject_creation_method = true;
354 : }
355 : }
356 845 : if (cl != null && !cl.is_compact && m.is_variadic ()) {
357 14 : real_name = get_ccode_constructv_name ((CreationMethod) m);
358 : }
359 : }
360 :
361 5101 : var creturn_type = get_callable_creturn_type (m);
362 :
363 12113 : foreach (Parameter param in m.get_parameters ()) {
364 3506 : param.accept (this);
365 : }
366 :
367 : // do not declare overriding methods and interface implementations
368 5101 : if ((m.is_abstract || m.is_virtual
369 4820 : || (m.base_method == null && m.base_interface_method == null))
370 4401 : && m.signal_reference == null) {
371 4390 : generate_method_declaration (m, cfile);
372 :
373 4390 : if (!m.is_internal_symbol ()) {
374 1043 : generate_method_declaration (m, header_file);
375 : }
376 4390 : if (!m.is_private_symbol ()) {
377 3316 : generate_method_declaration (m, internal_header_file);
378 : }
379 : }
380 :
381 5103 : if (profile) {
382 2 : string prefix = "_vala_prof_%s".printf (real_name);
383 :
384 2 : cfile.add_include ("stdio.h");
385 :
386 2 : var counter = new CCodeIdentifier (prefix + "_counter");
387 2 : var counter_decl = new CCodeDeclaration (get_ccode_name (int_type));
388 2 : counter_decl.add_declarator (new CCodeVariableDeclarator (counter.name));
389 2 : counter_decl.modifiers = CCodeModifiers.STATIC;
390 2 : cfile.add_type_member_declaration (counter_decl);
391 :
392 : // nesting level for recursive functions
393 2 : var level = new CCodeIdentifier (prefix + "_level");
394 2 : var level_decl = new CCodeDeclaration (get_ccode_name (int_type));
395 2 : level_decl.add_declarator (new CCodeVariableDeclarator (level.name));
396 2 : level_decl.modifiers = CCodeModifiers.STATIC;
397 2 : cfile.add_type_member_declaration (level_decl);
398 :
399 2 : var timer = new CCodeIdentifier (prefix + "_timer");
400 2 : var timer_decl = new CCodeDeclaration ("GTimer *");
401 2 : timer_decl.add_declarator (new CCodeVariableDeclarator (timer.name));
402 2 : timer_decl.modifiers = CCodeModifiers.STATIC;
403 2 : cfile.add_type_member_declaration (timer_decl);
404 :
405 2 : var constructor = new CCodeFunction (prefix + "_init");
406 2 : constructor.modifiers = CCodeModifiers.STATIC | CCodeModifiers.CONSTRUCTOR;
407 2 : cfile.add_function_declaration (constructor);
408 2 : push_function (constructor);
409 :
410 2 : ccode.add_assignment (timer, new CCodeFunctionCall (new CCodeIdentifier ("g_timer_new")));
411 :
412 2 : var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
413 2 : stop_call.add_argument (timer);
414 2 : ccode.add_expression (stop_call);
415 :
416 2 : pop_function ();
417 2 : cfile.add_function (constructor);
418 :
419 :
420 2 : var destructor = new CCodeFunction (prefix + "_exit");
421 2 : destructor.modifiers = CCodeModifiers.STATIC | CCodeModifiers.DESTRUCTOR;
422 2 : cfile.add_function_declaration (destructor);
423 2 : push_function (destructor);
424 :
425 2 : var elapsed_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_elapsed"));
426 2 : elapsed_call.add_argument (timer);
427 2 : elapsed_call.add_argument (new CCodeConstant ("NULL"));
428 :
429 2 : var print_call = new CCodeFunctionCall (new CCodeIdentifier ("fprintf"));
430 2 : print_call.add_argument (new CCodeIdentifier ("stderr"));
431 2 : print_call.add_argument (new CCodeConstant ("\"%s: %%gs (%%d calls)\\n\"".printf (m.get_full_name ())));
432 2 : print_call.add_argument (elapsed_call);
433 2 : print_call.add_argument (counter);
434 2 : ccode.add_expression (print_call);
435 :
436 2 : pop_function ();
437 2 : cfile.add_function (destructor);
438 : }
439 :
440 : CCodeFunction function;
441 5101 : function = new CCodeFunction (real_name);
442 :
443 5101 : if (m.is_inline) {
444 49 : function.modifiers |= CCodeModifiers.INLINE;
445 : }
446 :
447 5101 : if (m.entry_point) {
448 877 : function.modifiers |= CCodeModifiers.STATIC;
449 : }
450 :
451 5101 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
452 :
453 5101 : generate_cparameters (m, cfile, cparam_map, function);
454 :
455 : // generate *_real_* functions for virtual methods
456 : // also generate them for abstract methods of classes to prevent faulty subclassing
457 5101 : if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
458 5010 : if (!m.coroutine) {
459 4883 : if (m.base_method != null || m.base_interface_method != null) {
460 : // declare *_real_* function
461 860 : function.modifiers |= CCodeModifiers.STATIC;
462 860 : cfile.add_function_declaration (function);
463 4023 : } else if (m.is_private_symbol ()) {
464 1071 : function.modifiers |= CCodeModifiers.STATIC;
465 2952 : } else if (context.hide_internal && m.is_internal_symbol ()) {
466 48 : function.modifiers |= CCodeModifiers.INTERNAL;
467 : }
468 : } else {
469 127 : if (m.body != null) {
470 127 : function = new CCodeFunction (real_name + "_co", get_ccode_name (bool_type));
471 :
472 : // data struct to hold parameters, local variables, and the return value
473 127 : function.add_parameter (new CCodeParameter ("_data_", Symbol.lower_case_to_camel_case (get_ccode_const_name (m)) + "Data*"));
474 127 : function.modifiers |= CCodeModifiers.STATIC;
475 127 : cfile.add_function_declaration (function);
476 : }
477 : }
478 : }
479 :
480 5101 : if (m.comment != null) {
481 360 : cfile.add_type_member_definition (new CCodeComment (m.comment.content));
482 : }
483 :
484 5101 : push_function (function);
485 :
486 5101 : unowned CCodeBlock? co_switch_block = null;
487 :
488 : // generate *_real_* functions for virtual methods
489 : // also generate them for abstract methods of classes to prevent faulty subclassing
490 5101 : if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
491 5010 : if (m.body != null) {
492 4952 : if (m.coroutine) {
493 127 : ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"));
494 :
495 : // initial coroutine state
496 127 : ccode.add_case (new CCodeConstant ("0"));
497 127 : ccode.add_goto ("_state_0");
498 :
499 127 : co_switch_block = ccode.current_block;
500 :
501 127 : ccode.close ();
502 :
503 : // coroutine body
504 127 : ccode.add_label ("_state_0");
505 : }
506 :
507 5046 : if (m.closure) {
508 : // add variables for parent closure blocks
509 : // as closures only have one parameter for the innermost closure block
510 94 : var closure_block = current_closure_block;
511 94 : int block_id = get_block_id (closure_block);
512 95 : while (true) {
513 95 : var parent_closure_block = next_closure_block (closure_block.parent_symbol);
514 1 : if (parent_closure_block == null) {
515 94 : break;
516 : }
517 1 : int parent_block_id = get_block_id (parent_closure_block);
518 :
519 1 : var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id));
520 1 : ccode.add_declaration ("Block%dData*".printf (parent_block_id), new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id)));
521 1 : ccode.add_assignment (new CCodeIdentifier ("_data%d_".printf (parent_block_id)), parent_data);
522 :
523 1 : closure_block = parent_closure_block;
524 1 : block_id = parent_block_id;
525 : }
526 :
527 : // add self variable for closures
528 : // as closures have block data parameter
529 123 : if (m.binding == MemberBinding.INSTANCE) {
530 29 : var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self");
531 29 : ccode.add_declaration (get_ccode_name (SemanticAnalyzer.get_data_type_for_symbol (current_type_symbol)), new CCodeVariableDeclarator ("self"));
532 29 : ccode.add_assignment (new CCodeIdentifier ("self"), cself);
533 : }
534 :
535 : // allow capturing generic type parameters
536 94 : var data_var = get_variable_cexpression ("_data%d_".printf (block_id));
537 100 : foreach (var type_param in m.get_type_parameters ()) {
538 3 : var type = get_ccode_type_id (type_param);
539 3 : var dup_func = get_ccode_copy_function (type_param);
540 3 : var destroy_func = get_ccode_destroy_function (type_param);
541 3 : ccode.add_declaration ("GType", new CCodeVariableDeclarator (type));
542 3 : ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (dup_func));
543 3 : ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (destroy_func));
544 3 : ccode.add_assignment (new CCodeIdentifier (type), new CCodeMemberAccess.pointer (data_var, type));
545 3 : ccode.add_assignment (new CCodeIdentifier (dup_func), new CCodeMemberAccess.pointer (data_var, dup_func));
546 3 : ccode.add_assignment (new CCodeIdentifier (destroy_func), new CCodeMemberAccess.pointer (data_var, destroy_func));
547 : }
548 7756 : } else if (m.parent_symbol is Class && !m.coroutine) {
549 2898 : var cl = (Class) m.parent_symbol;
550 3583 : if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
551 : Method base_method;
552 : ReferenceType base_expression_type;
553 685 : if (m.overrides && m.base_method != null) {
554 614 : base_method = m.base_method;
555 614 : base_expression_type = new ObjectType ((Class) base_method.parent_symbol);
556 : } else {
557 71 : base_method = m.base_interface_method;
558 71 : base_expression_type = new ObjectType ((Interface) base_method.parent_symbol);
559 : }
560 685 : var self_target_type = new ObjectType (cl);
561 988 : CCodeExpression cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
562 :
563 685 : ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
564 685 : ccode.add_assignment (new CCodeIdentifier ("self"), cself);
565 2213 : } else if (m.binding == MemberBinding.INSTANCE
566 2089 : && !(m is CreationMethod)
567 1285 : && m.base_method == null && m.base_interface_method == null) {
568 1167 : create_method_type_check_statement (m, creturn_type, cl, true, "self");
569 : }
570 : }
571 :
572 11592 : foreach (Parameter param in m.get_parameters ()) {
573 3390 : if (param.ellipsis || param.params_array) {
574 70 : if (param.params_array) {
575 22 : append_params_array (m);
576 : }
577 70 : break;
578 : }
579 :
580 3320 : if (param.direction != ParameterDirection.OUT) {
581 3209 : unowned TypeSymbol? t = param.variable_type.type_symbol;
582 5406 : if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) {
583 2197 : var cname = get_ccode_name (param);
584 2197 : if (param.direction == ParameterDirection.REF && !param.variable_type.is_real_struct_type ()) {
585 15 : cname = "*"+cname;
586 : }
587 2197 : create_method_type_check_statement (m, creturn_type, t, !param.variable_type.nullable, cname);
588 : }
589 212 : } else if (!m.coroutine) {
590 : // declare local variable for out parameter to allow assignment even when caller passes NULL
591 101 : var vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_name (param)), default_value_for_type (param.variable_type, true), get_ccode_declarator_suffix (param.variable_type));
592 101 : ccode.add_declaration (get_ccode_name (param.variable_type), vardecl);
593 :
594 127 : if (param.variable_type is ArrayType) {
595 : // create variables to store array dimensions
596 26 : var array_type = (ArrayType) param.variable_type;
597 :
598 50 : if (!array_type.fixed_length) {
599 24 : var length_ctype = get_ccode_array_length_type (param);
600 52 : for (int dim = 1; dim <= array_type.rank; dim++) {
601 28 : vardecl = new CCodeVariableDeclarator.zero (get_array_length_cname ("_vala_%s".printf (get_ccode_name (param)), dim), new CCodeConstant ("0"));
602 28 : ccode.add_declaration (length_ctype, vardecl);
603 : }
604 : }
605 77 : } else if (param.variable_type is DelegateType) {
606 2 : var deleg_type = (DelegateType) param.variable_type;
607 2 : if (deleg_type.delegate_symbol.has_target) {
608 : // create variable to store delegate target
609 2 : vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_delegate_target_name (param)), new CCodeConstant ("NULL"));
610 2 : ccode.add_declaration (get_ccode_name (delegate_target_type), vardecl);
611 :
612 2 : if (deleg_type.is_disposable ()) {
613 2 : vardecl = new CCodeVariableDeclarator.zero ("_vala_%s".printf (get_ccode_delegate_target_destroy_notify_name (param)), new CCodeConstant ("NULL"));
614 2 : ccode.add_declaration (get_ccode_name (delegate_target_destroy_type), vardecl);
615 : }
616 : }
617 : }
618 : }
619 : }
620 :
621 4952 : if (m is CreationMethod) {
622 844 : if (in_gobject_creation_method) {
623 440 : if (!m.coroutine) {
624 438 : ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
625 : }
626 731 : } else if (is_gtypeinstance_creation_method (m)) {
627 327 : var cl = (Class) m.parent_symbol;
628 327 : ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
629 :
630 594 : if (cl.is_fundamental () && !((CreationMethod) m).chain_up) {
631 267 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
632 267 : ccall.add_argument (get_variable_cexpression ("object_type"));
633 267 : ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (cl) + "*"));
634 :
635 : /* type, dup func, and destroy func fields for generic types */
636 267 : var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
637 339 : foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
638 36 : var type = get_ccode_type_id (type_param);
639 36 : var dup_func = get_ccode_copy_function (type_param);
640 36 : var destroy_func = get_ccode_destroy_function (type_param);
641 36 : ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, type), new CCodeIdentifier (type));
642 36 : ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, dup_func), new CCodeIdentifier (dup_func));
643 36 : ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, destroy_func), new CCodeIdentifier (destroy_func));
644 : }
645 : }
646 123 : } else if (current_type_symbol is Class) {
647 46 : var cl = (Class) m.parent_symbol;
648 46 : if (!m.coroutine) {
649 46 : ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator ("self"));
650 : }
651 :
652 79 : if (!((CreationMethod) m).chain_up) {
653 : // TODO implicitly chain up to base class as in add_object_creation
654 : // g_slice_new0 needs glib.h
655 33 : cfile.add_include ("glib.h");
656 33 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
657 33 : ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
658 33 : ccode.add_assignment (get_this_cexpression (), ccall);
659 : }
660 :
661 79 : if (cl.base_class == null && !(((CreationMethod) m).chain_up && cl.is_compact)) {
662 33 : var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null))));
663 33 : cinitcall.add_argument (get_this_cexpression ());
664 33 : if (!cl.is_compact) {
665 0 : cinitcall.add_argument (new CCodeConstant ("NULL"));
666 : }
667 33 : ccode.add_expression (cinitcall);
668 : }
669 31 : } else if (m.parent_symbol is Struct) {
670 31 : unowned Struct st = (Struct) m.parent_symbol;
671 32 : if (st.is_simple_type ()) {
672 1 : var vardecl = new CCodeVariableDeclarator ("self", default_value_for_type (creturn_type, true));
673 1 : vardecl.init0 = true;
674 1 : ccode.add_declaration (get_ccode_name (creturn_type), vardecl);
675 56 : } else if (!((CreationMethod) m).chain_up) {
676 : // memset needs string.h
677 26 : cfile.add_include ("string.h");
678 26 : var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
679 26 : czero.add_argument (new CCodeIdentifier ("self"));
680 26 : czero.add_argument (new CCodeConstant ("0"));
681 26 : czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (st))));
682 26 : ccode.add_expression (czero);
683 : }
684 : } else {
685 0 : Report.error (m.source_reference, "internal: creation method not supported in `%s'", m.parent_symbol.get_full_name ());
686 : }
687 : }
688 :
689 4952 : if (context.module_init_method == m && in_plugin) {
690 : // GTypeModule-based plug-in, register types
691 1 : register_plugin_types (context.root, new HashSet<Symbol> ());
692 : }
693 :
694 4978 : foreach (Expression precondition in m.get_preconditions ()) {
695 13 : create_precondition_statement (m, creturn_type, precondition);
696 : }
697 : }
698 : }
699 :
700 5103 : if (profile) {
701 2 : string prefix = "_vala_prof_%s".printf (real_name);
702 :
703 2 : var level = new CCodeIdentifier (prefix + "_level");
704 2 : ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, level)));
705 :
706 2 : var counter = new CCodeIdentifier (prefix + "_counter");
707 2 : ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, counter));
708 :
709 2 : var timer = new CCodeIdentifier (prefix + "_timer");
710 2 : var cont_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_continue"));
711 2 : cont_call.add_argument (timer);
712 2 : ccode.add_expression (cont_call);
713 :
714 2 : ccode.close ();
715 : }
716 :
717 5101 : if (m.body != null) {
718 4952 : m.body.emit (this);
719 :
720 5079 : if (co_switch_block != null) {
721 : // after counting the number of yields for coroutines, append the case statements to the switch
722 127 : var old_block = ccode.current_block;
723 127 : ccode.current_block = co_switch_block;
724 :
725 196 : for (int state = 1; state < emit_context.next_coroutine_state; state++) {
726 69 : ccode.add_case (new CCodeConstant (state.to_string ()));
727 69 : ccode.add_goto ("_state_%d".printf (state));
728 : }
729 :
730 : // let gcc know that this can't happen
731 127 : ccode.add_default ();
732 127 : ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
733 :
734 127 : ccode.current_block = old_block;
735 127 : co_switch_block = null;
736 : }
737 : }
738 :
739 : // we generate the same code if we see a return statement, this handles the case without returns
740 5102 : if (profile && m.return_type is VoidType) {
741 1 : string prefix = "_vala_prof_%s".printf (real_name);
742 :
743 1 : var level = new CCodeIdentifier (prefix + "_level");
744 1 : ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
745 :
746 1 : var timer = new CCodeIdentifier (prefix + "_timer");
747 :
748 1 : var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
749 1 : stop_call.add_argument (timer);
750 1 : ccode.add_expression (stop_call);
751 :
752 1 : ccode.close ();
753 : }
754 :
755 : // generate *_real_* functions for virtual methods
756 : // also generate them for abstract methods of classes to prevent faulty subclassing
757 5101 : if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
758 : /* Methods imported from a plain C file don't
759 : * have a body, e.g. Vala.Parser.parse_file () */
760 5010 : if (m.body != null) {
761 4952 : if (current_method_inner_error) {
762 275 : cfile.add_include ("glib.h");
763 : /* always separate error parameter and inner_error local variable
764 : * as error may be set to NULL but we're always interested in inner errors
765 : */
766 275 : if (m.coroutine) {
767 : // no initialization necessary, closure struct is zeroed
768 25 : closure_struct.add_field ("GError*", "_inner_error%d_".printf (current_inner_error_id));
769 : } else {
770 250 : ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
771 : }
772 : }
773 :
774 : // For non-void return-types GAsyncModule.visit_return_statement () will take care of this
775 4952 : if (m.return_type is VoidType && m.coroutine) {
776 : // epilogue
777 96 : complete_async ();
778 : }
779 :
780 4952 : if (m is CreationMethod) {
781 1648 : if (current_type_symbol is Class && !m.coroutine) {
782 804 : CCodeExpression cresult = new CCodeIdentifier ("self");
783 804 : if (get_ccode_type (m) != null) {
784 0 : cresult = new CCodeCastExpression (cresult, get_ccode_type (m));
785 : }
786 :
787 804 : ccode.add_return (cresult);
788 40 : } else if (current_type_symbol is Struct && ((Struct) current_type_symbol).is_simple_type ()) {
789 : // constructors return simple type structs by value
790 1 : ccode.add_return (new CCodeIdentifier ("self"));
791 : }
792 : }
793 :
794 4952 : cfile.add_function (ccode);
795 : }
796 : }
797 :
798 5146 : if (m.is_abstract && current_type_symbol is Class) {
799 : // generate helpful error message if a sublcass does not implement an abstract method.
800 : // This is only meaningful for subclasses implemented in C since the vala compiler would
801 : // complain during compile time of such en error.
802 :
803 : // add critical warning that this method should not have been called
804 45 : var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
805 89 : if (!((Class) current_type_symbol).is_compact) {
806 44 : var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
807 44 : type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
808 :
809 44 : var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
810 44 : type_name_call.add_argument (type_from_instance_call);
811 :
812 44 : cerrorcall.add_argument (new CCodeConstant ("\"Type `%%s' does not implement abstract method `%s'\"".printf (get_ccode_name (m))));
813 44 : cerrorcall.add_argument (type_name_call);
814 : } else {
815 1 : cerrorcall.add_argument (new CCodeConstant ("\"Abstract method `%s' is not implemented\"".printf (get_ccode_name (m))));
816 : }
817 :
818 45 : ccode.add_expression (cerrorcall);
819 :
820 : // add return statement
821 45 : return_default_value (creturn_type);
822 :
823 45 : cfile.add_function (ccode);
824 : }
825 :
826 6470 : if (current_method_return && !(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
827 : CCodeVariableDeclarator vardecl;
828 1369 : if (m.is_abstract) {
829 0 : vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
830 0 : vardecl.init0 = true;
831 : } else {
832 1369 : vardecl = new CCodeVariableDeclarator ("result");
833 : }
834 1369 : ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
835 : }
836 :
837 5101 : pop_context ();
838 :
839 5348 : if ((m.is_abstract || m.is_virtual) && !m.coroutine
840 266 : && !get_ccode_no_wrapper (m)
841 : // If the method is a signal handler, the declaration is not needed.
842 : // the name should be reserved for the emitter!
843 256 : && m.signal_reference == null) {
844 :
845 247 : cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
846 247 : var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
847 :
848 247 : generate_vfunc (m, creturn_type, cparam_map, carg_map);
849 : }
850 :
851 5978 : if (m.entry_point) {
852 : // m is possible entry point, add appropriate startup code
853 :
854 882 : if (m.coroutine) {
855 : // add callback for async main
856 5 : var asyncmain_callback = new CCodeFunction (real_name + "_callback");
857 5 : asyncmain_callback.add_parameter (new CCodeParameter ("source_object", "GObject*"));
858 5 : asyncmain_callback.add_parameter (new CCodeParameter ("res", "GAsyncResult*"));
859 5 : asyncmain_callback.add_parameter (new CCodeParameter ("user_data", "gpointer"));
860 5 : asyncmain_callback.modifiers |= CCodeModifiers.STATIC;
861 :
862 5 : push_function (asyncmain_callback);
863 5 : ccode.add_declaration ("GMainLoop*", new CCodeVariableDeclarator.zero ("loop", new CCodeIdentifier ("user_data")));
864 :
865 : // get the return value
866 5 : var finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_real_name (m)));
867 5 : finish_call.add_argument (new CCodeIdentifier ("res"));
868 6 : if (m.return_type is VoidType) {
869 4 : ccode.add_expression (finish_call);
870 : } else {
871 : // save the return value
872 1 : var asyncmain_result = new CCodeIdentifier (real_name + "_result");
873 1 : var asyncmain_result_decl = new CCodeDeclaration (get_ccode_name (int_type));
874 1 : asyncmain_result_decl.add_declarator (new CCodeVariableDeclarator (asyncmain_result.name));
875 1 : asyncmain_result_decl.modifiers = CCodeModifiers.STATIC;
876 1 : cfile.add_type_member_declaration (asyncmain_result_decl);
877 1 : ccode.add_assignment (asyncmain_result, finish_call);
878 : }
879 :
880 : // quit the main loop
881 5 : var loop_quit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_main_loop_quit"));
882 5 : loop_quit_call.add_argument (new CCodeIdentifier ("loop"));
883 5 : ccode.add_expression (loop_quit_call);
884 :
885 5 : pop_function ();
886 5 : cfile.add_function (asyncmain_callback);
887 : }
888 :
889 877 : var cmain = new CCodeFunction ("main", "int");
890 877 : cmain.line = function.line;
891 877 : cmain.add_parameter (new CCodeParameter ("argc", "int"));
892 877 : cmain.add_parameter (new CCodeParameter ("argv", "char **"));
893 877 : push_function (cmain);
894 :
895 877 : if (context.profile == Profile.GOBJECT) {
896 869 : if (context.mem_profiler) {
897 0 : var mem_profiler_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_mem_set_vtable"));
898 0 : mem_profiler_init_call.line = cmain.line;
899 0 : mem_profiler_init_call.add_argument (new CCodeConstant ("glib_mem_profiler_table"));
900 0 : ccode.add_expression (mem_profiler_init_call);
901 : }
902 : }
903 :
904 877 : var main_call = new CCodeFunctionCall (new CCodeIdentifier (m.coroutine ? real_name : function.name));
905 877 : if (m.get_parameters ().size == 1) {
906 91 : main_call.add_argument (new CCodeIdentifier ("argv"));
907 91 : main_call.add_argument (new CCodeIdentifier ("argc"));
908 : }
909 :
910 882 : if (m.coroutine) {
911 : // main method is asynchronous, so we have to setup GMainLoop and run it
912 5 : var main_loop_new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_main_loop_new"));
913 5 : main_loop_new_call.add_argument (new CCodeConstantIdentifier ("NULL"));
914 5 : main_loop_new_call.add_argument (new CCodeConstantIdentifier ("FALSE"));
915 5 : ccode.add_declaration ("GMainLoop*", new CCodeVariableDeclarator.zero ("loop", main_loop_new_call));
916 :
917 : // add some more arguments to main_call
918 5 : main_call.add_argument (new CCodeIdentifier (real_name + "_callback"));
919 5 : main_call.add_argument (new CCodeIdentifier ("loop"));
920 5 : ccode.add_expression (main_call);
921 :
922 5 : var main_loop_run_call = new CCodeFunctionCall (new CCodeIdentifier ("g_main_loop_run"));
923 5 : main_loop_run_call.add_argument (new CCodeIdentifier ("loop"));
924 5 : ccode.add_expression (main_loop_run_call);
925 :
926 5 : var main_loop_unref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_main_loop_unref"));
927 5 : main_loop_unref_call.add_argument (new CCodeIdentifier ("loop"));
928 5 : ccode.add_expression (main_loop_unref_call);
929 :
930 5 : if (m.return_type is VoidType) {
931 : // method returns void, always use 0 as exit code
932 4 : ccode.add_return (new CCodeConstant ("0"));
933 : } else {
934 : // get the saved return value
935 1 : ccode.add_return (new CCodeIdentifier (real_name + "_result"));
936 : }
937 : } else {
938 872 : if (m.return_type is VoidType) {
939 : // method returns void, always use 0 as exit code
940 853 : ccode.add_expression (main_call);
941 853 : ccode.add_return (new CCodeConstant ("0"));
942 : } else {
943 19 : ccode.add_return (main_call);
944 : }
945 : }
946 877 : pop_function ();
947 877 : cfile.add_function (cmain);
948 : }
949 :
950 5101 : pop_line ();
951 : }
952 :
953 13499 : public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
954 : CCodeParameter cparam;
955 5932 : if (!param.ellipsis && !param.params_array) {
956 2649 : generate_type_declaration (param.variable_type, decl_space);
957 :
958 2649 : string? ctypename = get_ccode_type (param);
959 2649 : if (ctypename == null) {
960 2646 : ctypename = get_ccode_name (param.variable_type);
961 :
962 : // pass non-simple structs always by reference
963 2646 : unowned Struct? st = param.variable_type.type_symbol as Struct;
964 2034 : if (st != null) {
965 2034 : if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
966 165 : if (st.is_immutable && !param.variable_type.value_owned) {
967 0 : ctypename = "const " + ctypename;
968 : }
969 :
970 165 : if (!param.variable_type.nullable) {
971 133 : ctypename += "*";
972 : }
973 : }
974 : }
975 :
976 2646 : if (param.direction != ParameterDirection.IN) {
977 202 : ctypename += "*";
978 : }
979 : }
980 :
981 2649 : cparam = new CCodeParameter (get_ccode_name (param), ctypename);
982 2649 : if (param.format_arg) {
983 0 : cparam.modifiers = CCodeModifiers.FORMAT_ARG;
984 : }
985 : } else {
986 317 : var va_list_name = "_vala_va_list";
987 :
988 : // Add _first_* parameter for the params array parameter
989 425 : if (param.params_array) {
990 108 : var param_type = ((ArrayType) param.variable_type).element_type;
991 108 : string ctypename = get_ccode_name (param_type);
992 :
993 108 : generate_type_declaration (param_type, decl_space);
994 :
995 : // pass non-simple structs always by reference
996 159 : if (param_type.type_symbol is Struct) {
997 51 : var st = (Struct) param_type.type_symbol;
998 51 : if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
999 34 : if (st.is_immutable && !param.variable_type.value_owned) {
1000 0 : ctypename = "const " + ctypename;
1001 : }
1002 :
1003 34 : if (!param_type.nullable) {
1004 0 : ctypename += "*";
1005 : }
1006 : }
1007 : }
1008 :
1009 108 : cparam = new CCodeParameter ("_first_%s".printf (get_ccode_name (param)), ctypename);
1010 108 : cparam_map.set (get_param_pos (get_ccode_pos (param) - 0.1, true), cparam);
1011 :
1012 108 : va_list_name = "_va_list_%s".printf (get_ccode_name (param));
1013 : }
1014 :
1015 317 : if (ellipses_to_valist) {
1016 45 : cparam = new CCodeParameter (va_list_name, "va_list");
1017 : } else {
1018 272 : cparam = new CCodeParameter.with_ellipsis ();
1019 : }
1020 : }
1021 :
1022 2966 : cparam_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis || param.params_array), cparam);
1023 2966 : if (carg_map != null && !param.ellipsis && !param.params_array) {
1024 1187 : carg_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis || param.params_array), get_parameter_cexpression (param));
1025 : }
1026 :
1027 : return cparam;
1028 : }
1029 :
1030 35392 : 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) {
1031 17882 : if (m.closure) {
1032 186 : var closure_block = current_closure_block;
1033 186 : int block_id = get_block_id (closure_block);
1034 186 : var instance_param = new CCodeParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
1035 186 : cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
1036 22488 : } else if (m.parent_symbol is Class && m is CreationMethod) {
1037 4978 : var cl = (Class) m.parent_symbol;
1038 4978 : if (!cl.is_compact && vcall == null && (direction & 1) == 1) {
1039 2465 : cfile.add_include ("glib-object.h");
1040 2465 : cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
1041 : }
1042 26729 : } else if (m.binding == MemberBinding.INSTANCE && (direction != 2 || get_ccode_finish_instance (m))) {
1043 7100 : var this_type = SemanticAnalyzer.get_this_type (m);
1044 :
1045 7100 : generate_type_declaration (this_type, decl_space);
1046 :
1047 7100 : CCodeParameter instance_param = null;
1048 7186 : if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
1049 86 : var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
1050 86 : instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
1051 7658 : } else if (m.overrides) {
1052 644 : var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
1053 644 : instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
1054 : } else {
1055 6370 : unowned Struct? st = m.parent_symbol as Struct;
1056 6370 : if (st != null && !st.is_simple_type ()) {
1057 160 : instance_param = new CCodeParameter ("*self", get_ccode_name (this_type));
1058 6210 : } else if (st != null && st.is_simple_type () && m is CreationMethod) {
1059 : // constructors return simple type structs by value
1060 : } else {
1061 6207 : instance_param = new CCodeParameter ("self", get_ccode_name (this_type));
1062 : }
1063 : }
1064 14197 : if (instance_param != null) {
1065 7097 : cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
1066 : }
1067 5439 : } else if (m.binding == MemberBinding.CLASS) {
1068 7 : var this_type = SemanticAnalyzer.get_this_type (m);
1069 7 : var class_param = new CCodeParameter ("klass", get_ccode_name (this_type));
1070 7 : cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), class_param);
1071 : }
1072 :
1073 : // memory management for generic types
1074 17696 : List<TypeParameter>? type_parameters = null;
1075 17696 : if (is_gtypeinstance_creation_method (m) && (direction & 1) == 1) {
1076 16898 : type_parameters = ((Class) m.parent_symbol).get_type_parameters ();
1077 12925 : } else if (!m.closure && (direction & 1) == 1) {
1078 12127 : type_parameters = m.get_type_parameters ();
1079 : }
1080 16898 : if (type_parameters != null) {
1081 16898 : int type_param_index = 0;
1082 18006 : foreach (var type_param in type_parameters) {
1083 554 : cfile.add_include ("glib-object.h");
1084 554 : var type = get_ccode_type_id (type_param);
1085 554 : var dup_func = get_ccode_copy_function (type_param);
1086 554 : var destroy_func = get_ccode_destroy_function (type_param);
1087 554 : cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter (type, "GType"));
1088 554 : cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter (dup_func, "GBoxedCopyFunc"));
1089 554 : cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter (destroy_func, "GDestroyNotify"));
1090 554 : if (carg_map != null) {
1091 299 : carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier (type));
1092 299 : carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (dup_func));
1093 299 : carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier (destroy_func));
1094 : }
1095 554 : type_param_index++;
1096 : }
1097 : }
1098 :
1099 17696 : var needs_format_arg = m.get_format_arg_index () < 0 && (m.printf_format || m.scanf_format);
1100 :
1101 17696 : CCodeParameter? prev_cparam = null;
1102 37792 : foreach (Parameter param in m.get_parameters ()) {
1103 10183 : if (param.direction != ParameterDirection.OUT) {
1104 9716 : if ((direction & 1) == 0) {
1105 : // no in parameters
1106 204 : continue;
1107 : }
1108 : } else {
1109 467 : if ((direction & 2) == 0) {
1110 : // no out parameters
1111 66 : continue;
1112 : }
1113 : }
1114 :
1115 9913 : var cparam = generate_parameter (param, decl_space, cparam_map, carg_map);
1116 :
1117 : // if there is no explicit FormatArg annotation while this method throws an error
1118 : // it is required to mark the parameter located right before ellipsis as format-arg
1119 : // to account for the parameter shifting caused by the inserted GError parameter
1120 9913 : if (needs_format_arg) {
1121 176 : if (prev_cparam != null && cparam.ellipsis) {
1122 34 : prev_cparam.modifiers |= CCodeModifiers.FORMAT_ARG;
1123 : }
1124 352 : prev_cparam = cparam;
1125 : }
1126 : }
1127 :
1128 17696 : if ((direction & 2) != 0) {
1129 17084 : generate_method_result_declaration (m, decl_space, func, cparam_map, carg_map);
1130 : }
1131 :
1132 : // append C parameters in the right order
1133 : int last_pos = -1;
1134 : int min_pos;
1135 43698 : while (true) {
1136 43698 : min_pos = -1;
1137 188772 : foreach (int pos in cparam_map.get_keys ()) {
1138 101376 : if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
1139 37288 : min_pos = pos;
1140 : }
1141 : }
1142 43698 : if (min_pos == -1) {
1143 : break;
1144 : }
1145 26002 : func.add_parameter (cparam_map.get (min_pos));
1146 26002 : if (vdeclarator != null) {
1147 3611 : vdeclarator.add_parameter (cparam_map.get (min_pos));
1148 : }
1149 33975 : if (vcall != null) {
1150 10815 : var arg = carg_map.get (min_pos);
1151 10815 : if (arg != null) {
1152 7973 : vcall.add_argument (arg);
1153 : }
1154 : }
1155 : last_pos = min_pos;
1156 : }
1157 :
1158 17696 : if (m.printf_format) {
1159 56 : func.modifiers |= CCodeModifiers.PRINTF;
1160 17640 : } else if (m.scanf_format) {
1161 16 : func.modifiers |= CCodeModifiers.SCANF;
1162 : }
1163 :
1164 17696 : if (m.version.deprecated) {
1165 37 : func.modifiers |= CCodeModifiers.DEPRECATED;
1166 : }
1167 : }
1168 :
1169 638 : public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) {
1170 319 : push_context (new EmitContext ());
1171 :
1172 : CCodeFunction vfunc;
1173 319 : if (suffix == "_finish") {
1174 36 : vfunc = new CCodeFunction (get_ccode_finish_name (m));
1175 : } else {
1176 283 : vfunc = new CCodeFunction (get_ccode_name (m));
1177 : }
1178 :
1179 : CCodeExpression vcast;
1180 495 : if (m.parent_symbol is Interface) {
1181 143 : vcast = new CCodeIdentifier ("_iface_");
1182 : } else {
1183 176 : var cl = (Class) m.parent_symbol;
1184 176 : if (!cl.is_compact) {
1185 174 : vcast = new CCodeIdentifier ("_klass_");
1186 : } else {
1187 2 : vcast = new CCodeIdentifier ("self");
1188 : }
1189 : }
1190 :
1191 : CCodeFunctionCall vcall;
1192 319 : if (suffix == "_finish") {
1193 36 : vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m)));
1194 : } else {
1195 283 : vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m)));
1196 : }
1197 :
1198 319 : carg_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeIdentifier ("self"));
1199 :
1200 319 : generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, direction);
1201 :
1202 319 : push_function (vfunc);
1203 :
1204 320 : if (m.return_type.is_non_null_simple_type () && default_value_for_type (m.return_type, false) == null) {
1205 : // the type check will use the result variable
1206 : CCodeVariableDeclarator vardecl;
1207 1 : if (m.is_abstract) {
1208 1 : vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
1209 1 : vardecl.init0 = true;
1210 : } else {
1211 0 : vardecl = new CCodeVariableDeclarator ("result");
1212 : }
1213 1 : ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
1214 : }
1215 :
1216 : // add a typecheck statement for "self"
1217 319 : create_method_type_check_statement (m, return_type, (TypeSymbol) m.parent_symbol, true, "self");
1218 :
1219 321 : foreach (Expression precondition in m.get_preconditions ()) {
1220 1 : create_precondition_statement (m, return_type, precondition);
1221 : }
1222 :
1223 638 : if (m.parent_symbol is Interface) {
1224 143 : var iface = (Interface) m.parent_symbol;
1225 :
1226 143 : var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (iface)));
1227 143 : ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1228 143 : ccode.add_declaration ("%s*".printf (get_ccode_type_name (iface)), new CCodeVariableDeclarator ("_iface_"));
1229 143 : ccode.add_assignment (vcast, vcastcall);
1230 : } else {
1231 176 : var cl = (Class) m.parent_symbol;
1232 350 : if (!cl.is_compact) {
1233 174 : var vcastcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
1234 174 : ((CCodeFunctionCall) vcastcall).add_argument (new CCodeIdentifier ("self"));
1235 174 : ccode.add_declaration ("%s*".printf (get_ccode_type_name (cl)), new CCodeVariableDeclarator ("_klass_"));
1236 174 : ccode.add_assignment (vcast, vcastcall);
1237 : }
1238 : }
1239 :
1240 : // check if vfunc pointer is properly set
1241 319 : ccode.open_if (vcall.call);
1242 :
1243 319 : if (return_type is VoidType || return_type.is_real_non_null_struct_type ()) {
1244 194 : ccode.add_expression (vcall);
1245 125 : } else if (m.get_postconditions ().size == 0) {
1246 : /* pass method return value */
1247 124 : ccode.add_return (vcall);
1248 : } else {
1249 : /* store method return value for postconditions */
1250 1 : ccode.add_declaration (get_creturn_type (m, get_ccode_name (return_type)), new CCodeVariableDeclarator ("result"));
1251 1 : ccode.add_assignment (new CCodeIdentifier ("result"), vcall);
1252 : }
1253 :
1254 319 : if (m.get_postconditions ().size > 0) {
1255 3 : foreach (Expression postcondition in m.get_postconditions ()) {
1256 1 : create_postcondition_statement (postcondition);
1257 : }
1258 :
1259 1 : if (!(return_type is VoidType)) {
1260 1 : ccode.add_return (new CCodeIdentifier ("result"));
1261 : }
1262 : }
1263 :
1264 319 : ccode.close ();
1265 :
1266 319 : if (m.return_type.is_non_null_simple_type () && default_value_for_type (m.return_type, false) == null) {
1267 1 : ccode.add_return (new CCodeIdentifier ("result"));
1268 318 : } else if (!(return_type is VoidType)) {
1269 124 : ccode.add_return (default_value_for_type (return_type, false, true));
1270 : }
1271 :
1272 319 : if (m.printf_format) {
1273 0 : vfunc.modifiers |= CCodeModifiers.PRINTF;
1274 319 : } else if (m.scanf_format) {
1275 0 : vfunc.modifiers |= CCodeModifiers.SCANF;
1276 : }
1277 :
1278 319 : if (m.version.deprecated) {
1279 3 : vfunc.modifiers |= CCodeModifiers.DEPRECATED;
1280 : }
1281 :
1282 319 : cfile.add_function (vfunc);
1283 :
1284 319 : pop_context ();
1285 : }
1286 :
1287 3683 : private void create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) {
1288 3683 : if (!m.coroutine) {
1289 3599 : create_type_check_statement (m, return_type, t, non_null, var_name);
1290 : }
1291 : }
1292 :
1293 28 : private void create_precondition_statement (Method m, DataType ret_type, Expression precondition) {
1294 14 : is_in_method_precondition = true;
1295 :
1296 14 : var ccheck = new CCodeFunctionCall ();
1297 :
1298 14 : precondition.emit (this);
1299 :
1300 14 : ccheck.add_argument (get_cvalue (precondition));
1301 :
1302 14 : string message = ((string) precondition.source_reference.begin.pos).substring (0, (int) (precondition.source_reference.end.pos - precondition.source_reference.begin.pos));
1303 14 : ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
1304 14 : requires_assert = true;
1305 :
1306 14 : if (m is CreationMethod) {
1307 2 : if (m.parent_symbol is Class) {
1308 1 : ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1309 1 : ccheck.add_argument (new CCodeConstant ("NULL"));
1310 : } else {
1311 : // creation method of struct
1312 1 : ccheck.call = new CCodeIdentifier ("_vala_return_if_fail");
1313 : }
1314 12 : } else if (m.coroutine) {
1315 : // _co function
1316 1 : ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1317 1 : ccheck.add_argument (new CCodeConstant ("FALSE"));
1318 17 : } else if (ret_type is VoidType) {
1319 : /* void function */
1320 5 : ccheck.call = new CCodeIdentifier ("_vala_return_if_fail");
1321 : } else {
1322 6 : ccheck.call = new CCodeIdentifier ("_vala_return_val_if_fail");
1323 :
1324 6 : var cdefault = default_value_for_type (ret_type, false);
1325 6 : if (cdefault != null) {
1326 6 : ccheck.add_argument (cdefault);
1327 : } else {
1328 0 : return;
1329 : }
1330 : }
1331 :
1332 14 : ccode.add_expression (ccheck);
1333 :
1334 14 : current_method_return = true;
1335 14 : is_in_method_precondition = false;
1336 : }
1337 :
1338 836 : public override void visit_creation_method (CreationMethod m) {
1339 836 : push_line (m.source_reference);
1340 :
1341 836 : unowned Class? cl = m.parent_symbol as Class;
1342 805 : if (cl != null && !cl.is_compact) {
1343 758 : ellipses_to_valist = true;
1344 : } else {
1345 78 : ellipses_to_valist = false;
1346 : }
1347 836 : visit_method (m);
1348 836 : ellipses_to_valist = false;
1349 :
1350 836 : if ((!m.external && m.external_package) || m.source_type == SourceFileType.FAST) {
1351 0 : pop_line ();
1352 0 : return;
1353 : }
1354 :
1355 : // do not generate _new functions for creation methods of abstract classes
1356 836 : if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
1357 : // _new function
1358 719 : create_aux_constructor (m, get_ccode_name (m), false);
1359 :
1360 : // _construct function (if visit_method generated _constructv)
1361 719 : if (m.is_variadic ()) {
1362 14 : create_aux_constructor (m, get_ccode_real_name (m), true);
1363 : }
1364 : }
1365 :
1366 836 : pop_line ();
1367 : }
1368 :
1369 1466 : private void create_aux_constructor (CreationMethod m, string func_name, bool self_as_first_parameter) {
1370 733 : var vfunc = new CCodeFunction (func_name);
1371 733 : if (m.is_private_symbol ()) {
1372 17 : vfunc.modifiers |= CCodeModifiers.STATIC;
1373 716 : } else if (context.hide_internal && m.is_internal_symbol ()) {
1374 27 : vfunc.modifiers |= CCodeModifiers.INTERNAL;
1375 : }
1376 :
1377 733 : var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
1378 733 : var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
1379 :
1380 733 : push_function (vfunc);
1381 :
1382 733 : string constructor = (m.is_variadic ()) ? get_ccode_constructv_name (m) : get_ccode_real_name (m);
1383 733 : var vcall = new CCodeFunctionCall (new CCodeIdentifier (constructor));
1384 :
1385 733 : if (self_as_first_parameter) {
1386 14 : cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
1387 14 : vcall.add_argument (get_variable_cexpression ("object_type"));
1388 : } else {
1389 719 : vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
1390 : }
1391 :
1392 :
1393 733 : generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
1394 :
1395 761 : if (m.is_variadic ()) {
1396 28 : int last_pos = -1;
1397 28 : int second_last_pos = -1;
1398 128 : foreach (int pos in cparam_map.get_keys ()) {
1399 72 : if (pos > last_pos) {
1400 : second_last_pos = last_pos;
1401 : last_pos = pos;
1402 18 : } else if (pos > second_last_pos) {
1403 : second_last_pos = pos;
1404 : }
1405 : }
1406 :
1407 28 : var carg = carg_map.get (second_last_pos);
1408 28 : if (carg == null) {
1409 : // params arrays have an implicit first argument, refer to the cparameter name
1410 10 : carg = new CCodeIdentifier (cparam_map.get (second_last_pos).name);
1411 10 : vcall.add_argument (carg);
1412 : }
1413 :
1414 28 : var vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1415 28 : vastart.add_argument (new CCodeIdentifier ("_vala_va_list_obj"));
1416 28 : vastart.add_argument (carg);
1417 :
1418 28 : ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_vala_va_list_obj"));
1419 28 : ccode.add_expression (vastart);
1420 :
1421 28 : vcall.add_argument (new CCodeIdentifier("_vala_va_list_obj"));
1422 : }
1423 :
1424 733 : ccode.add_return (vcall);
1425 :
1426 733 : pop_function ();
1427 :
1428 733 : cfile.add_function (vfunc);
1429 : }
1430 : }
1431 :
1432 : // vim:sw=8 noet
|