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