~ubuntu-branches/ubuntu/raring/vala-0.20/raring-proposed

« back to all changes in this revision

Viewing changes to codegen/valaccodemethodmodule.vala

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher
  • Date: 2013-04-05 13:45:05 UTC
  • Revision ID: package-import@ubuntu.com-20130405134505-yyk3rec9904i7p8o
Tags: upstream-0.20.1
ImportĀ upstreamĀ versionĀ 0.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        public override bool method_has_wrapper (Method method) {
 
34
                return (method.get_attribute ("NoWrapper") == null);
 
35
        }
 
36
 
 
37
        string get_creturn_type (Method m, string default_value) {
 
38
                string type = get_ccode_type (m);
 
39
                if (type == null) {
 
40
                        return default_value;
 
41
                }
 
42
                return type;
 
43
        }
 
44
 
 
45
        bool is_gtypeinstance_creation_method (Method m) {
 
46
                bool result = false;
 
47
 
 
48
                var cl = m.parent_symbol as Class;
 
49
                if (m is CreationMethod && cl != null && !cl.is_compact) {
 
50
                        result = true;
 
51
                }
 
52
 
 
53
                return result;
 
54
        }
 
55
 
 
56
        public virtual void generate_method_result_declaration (Method m, CCodeFile decl_space, CCodeFunction cfunc, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
 
57
                var creturn_type = m.return_type;
 
58
                if (m is CreationMethod) {
 
59
                        var cl = m.parent_symbol as Class;
 
60
                        if (cl != null) {
 
61
                                // object creation methods return the new object in C
 
62
                                // in Vala they have no return type
 
63
                                creturn_type = new ObjectType (cl);
 
64
                        }
 
65
                } else if (m.return_type.is_real_non_null_struct_type ()) {
 
66
                        // structs are returned via out parameter
 
67
                        creturn_type = new VoidType ();
 
68
                }
 
69
                cfunc.return_type = get_creturn_type (m, get_ccode_name (creturn_type));
 
70
 
 
71
                generate_type_declaration (m.return_type, decl_space);
 
72
 
 
73
                if (m.return_type.is_real_non_null_struct_type ()) {
 
74
                        // structs are returned via out parameter
 
75
                        var cparam = new CCodeParameter ("result", get_ccode_name (m.return_type) + "*");
 
76
                        cparam_map.set (get_param_pos (-3), cparam);
 
77
                        if (carg_map != null) {
 
78
                                carg_map.set (get_param_pos (-3), get_result_cexpression ());
 
79
                        }
 
80
                } else if (get_ccode_array_length (m) && m.return_type is ArrayType) {
 
81
                        // return array length if appropriate
 
82
                        var array_type = (ArrayType) m.return_type;
 
83
                        var array_length_type = get_ccode_array_length_type (m) != null ? get_ccode_array_length_type (m) : "int";
 
84
                        array_length_type += "*";
 
85
 
 
86
                        for (int dim = 1; dim <= array_type.rank; dim++) {
 
87
                                var cparam = new CCodeParameter (get_array_length_cname ("result", dim), array_length_type);
 
88
                                cparam_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), cparam);
 
89
                                if (carg_map != null) {
 
90
                                        carg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), get_variable_cexpression (cparam.name));
 
91
                                }
 
92
                        }
 
93
                } else if (m.return_type is DelegateType) {
 
94
                        // return delegate target if appropriate
 
95
                        var deleg_type = (DelegateType) m.return_type;
 
96
                        var d = deleg_type.delegate_symbol;
 
97
                        if (d.has_target) {
 
98
                                var cparam = new CCodeParameter (get_delegate_target_cname ("result"), "void**");
 
99
                                cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), cparam);
 
100
                                if (carg_map != null) {
 
101
                                        carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), get_variable_cexpression (cparam.name));
 
102
                                }
 
103
                                if (deleg_type.value_owned) {
 
104
                                        cparam = new CCodeParameter (get_delegate_target_destroy_notify_cname ("result"), "GDestroyNotify*");
 
105
                                        cparam_map.set (get_param_pos (get_ccode_delegate_target_pos (m) + 0.01), cparam);
 
106
                                        if (carg_map != null) {
 
107
                                                carg_map.set (get_param_pos (get_ccode_delegate_target_pos (m) + 0.01), get_variable_cexpression (cparam.name));
 
108
                                        }
 
109
                                }
 
110
                        }
 
111
                }
 
112
 
 
113
                if (m.get_error_types ().size > 0 || (m.base_method != null && m.base_method.get_error_types ().size > 0) || (m.base_interface_method != null && m.base_interface_method.get_error_types ().size > 0)) {
 
114
                        foreach (DataType error_type in m.get_error_types ()) {
 
115
                                generate_type_declaration (error_type, decl_space);
 
116
                        }
 
117
 
 
118
                        var cparam = new CCodeParameter ("error", "GError**");
 
119
                        cparam_map.set (get_param_pos (-1), cparam);
 
120
                        if (carg_map != null) {
 
121
                                carg_map.set (get_param_pos (-1), new CCodeIdentifier (cparam.name));
 
122
                        }
 
123
                }
 
124
        }
 
125
 
 
126
        public void complete_async () {
 
127
                var state = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_");
 
128
                var zero = new CCodeConstant ("0");
 
129
                var state_is_zero = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, state, zero);
 
130
                ccode.open_if (state_is_zero);
 
131
 
 
132
                var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_async_result");
 
133
 
 
134
                var idle_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete_in_idle"));
 
135
                idle_call.add_argument (async_result_expr);
 
136
                ccode.add_expression (idle_call);
 
137
 
 
138
                ccode.add_else ();
 
139
 
 
140
                var direct_call = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
 
141
                direct_call.add_argument (async_result_expr);
 
142
                ccode.add_expression (direct_call);
 
143
 
 
144
                ccode.close ();
 
145
 
 
146
                var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
 
147
                unref.add_argument (async_result_expr);
 
148
                ccode.add_expression (unref);
 
149
 
 
150
                ccode.add_return (new CCodeConstant ("FALSE"));
 
151
        }
 
152
 
 
153
        public override void generate_method_declaration (Method m, CCodeFile decl_space) {
 
154
                if (m.is_async_callback) {
 
155
                        return;
 
156
                }
 
157
                if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
 
158
                        return;
 
159
                }
 
160
 
 
161
                var function = new CCodeFunction (get_ccode_name (m));
 
162
 
 
163
                if (m.is_private_symbol () && !m.external) {
 
164
                        function.modifiers |= CCodeModifiers.STATIC;
 
165
                        if (m.is_inline) {
 
166
                                function.modifiers |= CCodeModifiers.INLINE;
 
167
                        }
 
168
                }
 
169
 
 
170
                if (m.deprecated) {
 
171
                        function.modifiers |= CCodeModifiers.DEPRECATED;
 
172
                }
 
173
 
 
174
                var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
 
175
                var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
 
176
 
 
177
                var cl = m.parent_symbol as Class;
 
178
 
 
179
                // do not generate _new functions for creation methods of abstract classes
 
180
                if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
 
181
                        bool etv_tmp = ellipses_to_valist;
 
182
                        ellipses_to_valist = false;
 
183
                        generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
 
184
                        ellipses_to_valist = etv_tmp;
 
185
 
 
186
                        decl_space.add_function_declaration (function);
 
187
                }
 
188
 
 
189
                if (m is CreationMethod && cl != null) {
 
190
                        // _construct function
 
191
                        function = new CCodeFunction (get_ccode_real_name (m));
 
192
 
 
193
                        if (m.is_private_symbol ()) {
 
194
                                function.modifiers |= CCodeModifiers.STATIC;
 
195
                        }
 
196
 
 
197
                        cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
 
198
                        bool etv_tmp = ellipses_to_valist;
 
199
                        ellipses_to_valist = false;
 
200
                        generate_cparameters (m, decl_space, cparam_map, function);
 
201
                        ellipses_to_valist = etv_tmp;
 
202
 
 
203
                        decl_space.add_function_declaration (function);
 
204
 
 
205
                        if (m.is_variadic ()) {
 
206
                                // _constructv function
 
207
                                function = new CCodeFunction (get_constructv_name ((CreationMethod) m));
 
208
                                function.modifiers |= CCodeModifiers.STATIC;
 
209
 
 
210
                                cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
 
211
                                generate_cparameters (m, decl_space, cparam_map, function);
 
212
 
 
213
                                decl_space.add_function_declaration (function);
 
214
                        }
 
215
                }
 
216
        }
 
217
 
 
218
        private string get_constructv_name (CreationMethod m) {
 
219
                const string infix = "constructv";
 
220
 
 
221
                var parent = m.parent_symbol as Class;
 
222
 
 
223
                if (m.name == ".new") {
 
224
                        return "%s%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (parent), infix);
 
225
                } else {
 
226
                        return "%s%s_%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (parent), infix, m.name);
 
227
                }
 
228
        }
 
229
 
 
230
        void register_plugin_types (Symbol sym, Set<Symbol> registered_types) {
 
231
                var ns = sym as Namespace;
 
232
                var cl = sym as Class;
 
233
                var iface = sym as Interface;
 
234
                if (ns != null) {
 
235
                        foreach (var ns_ns in ns.get_namespaces ()) {
 
236
                                register_plugin_types (ns_ns, registered_types);
 
237
                        }
 
238
                        foreach (var ns_cl in ns.get_classes ()) {
 
239
                                register_plugin_types (ns_cl, registered_types);
 
240
                        }
 
241
                        foreach (var ns_iface in ns.get_interfaces ()) {
 
242
                                register_plugin_types (ns_iface, registered_types);
 
243
                        }
 
244
                } else if (cl != null) {
 
245
                        register_plugin_type (cl, registered_types);
 
246
                        foreach (var cl_cl in cl.get_classes ()) {
 
247
                                register_plugin_types (cl_cl, registered_types);
 
248
                        }
 
249
                } else if (iface != null) {
 
250
                        register_plugin_type (iface, registered_types);
 
251
                        foreach (var iface_cl in iface.get_classes ()) {
 
252
                                register_plugin_types (iface_cl, registered_types);
 
253
                        }
 
254
                }
 
255
        }
 
256
 
 
257
        void register_plugin_type (ObjectTypeSymbol type_symbol, Set<Symbol> registered_types) {
 
258
                if (type_symbol.external_package) {
 
259
                        return;
 
260
                }
 
261
 
 
262
                if (!registered_types.add (type_symbol)) {
 
263
                        // already registered
 
264
                        return;
 
265
                }
 
266
 
 
267
                var cl = type_symbol as Class;
 
268
                if (cl != null) {
 
269
                        if (cl.is_compact) {
 
270
                                return;
 
271
                        }
 
272
 
 
273
                        // register base types first
 
274
                        foreach (var base_type in cl.get_base_types ()) {
 
275
                                register_plugin_type ((ObjectTypeSymbol) base_type.data_type, registered_types);
 
276
                        }
 
277
                }
 
278
 
 
279
                var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (get_ccode_lower_case_name (type_symbol, null))));
 
280
                register_call.add_argument (new CCodeIdentifier (module_init_param_name));
 
281
                ccode.add_expression (register_call);
 
282
        }
 
283
 
 
284
        /**
 
285
         * This function generates the code the given method. If the method is
 
286
         * a constructor, _construct is generated, unless it's variadic, in which
 
287
         * case _constructv is generated (and _construct is generated together
 
288
         * with _new in visit_creation_method).
 
289
         */
 
290
        public override void visit_method (Method m) {
 
291
                string real_name = get_ccode_real_name (m);
 
292
                if (m is CreationMethod && m.is_variadic ()) {
 
293
                        real_name = get_constructv_name ((CreationMethod) m);
 
294
                }
 
295
 
 
296
                push_context (new EmitContext (m));
 
297
                push_line (m.source_reference);
 
298
 
 
299
                bool in_gobject_creation_method = false;
 
300
                bool in_fundamental_creation_method = false;
 
301
 
 
302
                check_type (m.return_type);
 
303
 
 
304
                bool profile = m.get_attribute ("Profile") != null;
 
305
 
 
306
                if (m.get_attribute ("NoArrayLength") != null) {
 
307
                        Report.deprecated (m.source_reference, "NoArrayLength attribute is deprecated, use [CCode (array_length = false)] instead.");
 
308
                }
 
309
 
 
310
                if (m is CreationMethod) {
 
311
                        var cl = current_type_symbol as Class;
 
312
                        if (cl != null && !cl.is_compact) {
 
313
                                if (cl.base_class == null) {
 
314
                                        in_fundamental_creation_method = true;
 
315
                                } else if (gobject_type != null && cl.is_subtype_of (gobject_type)) {
 
316
                                        in_gobject_creation_method = true;
 
317
                                }
 
318
                        }
 
319
                }
 
320
 
 
321
                if (m.coroutine) {
 
322
                        next_coroutine_state = 1;
 
323
                }
 
324
 
 
325
                var creturn_type = m.return_type;
 
326
                if (m.return_type.is_real_non_null_struct_type ()) {
 
327
                        // structs are returned via out parameter
 
328
                        creturn_type = new VoidType ();
 
329
                }
 
330
 
 
331
                foreach (Parameter param in m.get_parameters ()) {
 
332
                        param.accept (this);
 
333
                }
 
334
 
 
335
                // do not declare overriding methods and interface implementations
 
336
                if ((m.is_abstract || m.is_virtual
 
337
                         || (m.base_method == null && m.base_interface_method == null)) && m.signal_reference == null) {
 
338
                        generate_method_declaration (m, cfile);
 
339
 
 
340
                        if (!m.is_internal_symbol ()) {
 
341
                                generate_method_declaration (m, header_file);
 
342
                        }
 
343
                        if (!m.is_private_symbol ()) {
 
344
                                generate_method_declaration (m, internal_header_file);
 
345
                        }
 
346
                }
 
347
 
 
348
                if (profile) {
 
349
                        string prefix = "_vala_prof_%s".printf (real_name);
 
350
 
 
351
                        cfile.add_include ("stdio.h");
 
352
 
 
353
                        var counter = new CCodeIdentifier (prefix + "_counter");
 
354
                        var counter_decl = new CCodeDeclaration ("gint");
 
355
                        counter_decl.add_declarator (new CCodeVariableDeclarator (counter.name));
 
356
                        counter_decl.modifiers = CCodeModifiers.STATIC;
 
357
                        cfile.add_type_member_declaration (counter_decl);
 
358
 
 
359
                        // nesting level for recursive functions
 
360
                        var level = new CCodeIdentifier (prefix + "_level");
 
361
                        var level_decl = new CCodeDeclaration ("gint");
 
362
                        level_decl.add_declarator (new CCodeVariableDeclarator (level.name));
 
363
                        level_decl.modifiers = CCodeModifiers.STATIC;
 
364
                        cfile.add_type_member_declaration (level_decl);
 
365
 
 
366
                        var timer = new CCodeIdentifier (prefix + "_timer");
 
367
                        var timer_decl = new CCodeDeclaration ("GTimer *");
 
368
                        timer_decl.add_declarator (new CCodeVariableDeclarator (timer.name));
 
369
                        timer_decl.modifiers = CCodeModifiers.STATIC;
 
370
                        cfile.add_type_member_declaration (timer_decl);
 
371
 
 
372
                        var constructor = new CCodeFunction (prefix + "_init");
 
373
                        constructor.modifiers = CCodeModifiers.STATIC;
 
374
                        constructor.attributes = "__attribute__((constructor))";
 
375
                        cfile.add_function_declaration (constructor);
 
376
                        push_function (constructor);
 
377
 
 
378
                        ccode.add_assignment (timer, new CCodeFunctionCall (new CCodeIdentifier ("g_timer_new")));
 
379
 
 
380
                        var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
 
381
                        stop_call.add_argument (timer);
 
382
                        ccode.add_expression (stop_call);
 
383
 
 
384
                        pop_function ();
 
385
                        cfile.add_function (constructor);
 
386
 
 
387
 
 
388
                        var destructor = new CCodeFunction (prefix + "_exit");
 
389
                        destructor.modifiers = CCodeModifiers.STATIC;
 
390
                        destructor.attributes = "__attribute__((destructor))";
 
391
                        cfile.add_function_declaration (destructor);
 
392
                        push_function (destructor);
 
393
 
 
394
                        var elapsed_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_elapsed"));
 
395
                        elapsed_call.add_argument (timer);
 
396
                        elapsed_call.add_argument (new CCodeConstant ("NULL"));
 
397
 
 
398
                        var print_call = new CCodeFunctionCall (new CCodeIdentifier ("fprintf"));
 
399
                        print_call.add_argument (new CCodeIdentifier ("stderr"));
 
400
                        print_call.add_argument (new CCodeConstant ("\"%s: %%gs (%%d calls)\\n\"".printf (m.get_full_name ())));
 
401
                        print_call.add_argument (elapsed_call);
 
402
                        print_call.add_argument (counter);
 
403
                        ccode.add_expression (print_call);
 
404
 
 
405
                        pop_function ();
 
406
                        cfile.add_function (destructor);
 
407
                }
 
408
 
 
409
                CCodeFunction function;
 
410
                function = new CCodeFunction (real_name);
 
411
 
 
412
                if (m.is_inline) {
 
413
                        function.modifiers |= CCodeModifiers.INLINE;
 
414
                }
 
415
 
 
416
                if (m is CreationMethod && m.is_variadic ()) {
 
417
                        function.modifiers |= CCodeModifiers.STATIC;
 
418
                }
 
419
 
 
420
                var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
 
421
 
 
422
                generate_cparameters (m, cfile, cparam_map, function);
 
423
 
 
424
                // generate *_real_* functions for virtual methods
 
425
                // also generate them for abstract methods of classes to prevent faulty subclassing
 
426
                if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
 
427
                        if (!m.coroutine) {
 
428
                                if (m.base_method != null || m.base_interface_method != null) {
 
429
                                        // declare *_real_* function
 
430
                                        function.modifiers |= CCodeModifiers.STATIC;
 
431
                                        cfile.add_function_declaration (function);
 
432
                                } else if (m.is_private_symbol ()) {
 
433
                                        function.modifiers |= CCodeModifiers.STATIC;
 
434
                                }
 
435
                        } else {
 
436
                                if (m.body != null) {
 
437
                                        function = new CCodeFunction (real_name + "_co", "gboolean");
 
438
 
 
439
                                        // data struct to hold parameters, local variables, and the return value
 
440
                                        function.add_parameter (new CCodeParameter ("_data_", Symbol.lower_case_to_camel_case (get_ccode_const_name (m)) + "Data*"));
 
441
                                        function.modifiers |= CCodeModifiers.STATIC;
 
442
                                        cfile.add_function_declaration (function);
 
443
                                }
 
444
                        }
 
445
                }
 
446
 
 
447
                if (m.comment != null) {
 
448
                        cfile.add_type_member_definition (new CCodeComment (m.comment.content));
 
449
                }
 
450
 
 
451
                push_function (function);
 
452
 
 
453
                // generate *_real_* functions for virtual methods
 
454
                // also generate them for abstract methods of classes to prevent faulty subclassing
 
455
                if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
 
456
                        if (m.body != null) {
 
457
                                if (m.coroutine) {
 
458
                                        ccode.open_switch (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"));
 
459
 
 
460
                                        // initial coroutine state
 
461
                                        ccode.add_case (new CCodeConstant ("0"));
 
462
                                        ccode.add_goto ("_state_0");
 
463
 
 
464
                                        for (int state = 1; state <= m.yield_count; state++) {
 
465
                                                ccode.add_case (new CCodeConstant (state.to_string ()));
 
466
                                                ccode.add_goto ("_state_%d".printf (state));
 
467
                                        }
 
468
 
 
469
 
 
470
                                        // let gcc know that this can't happen
 
471
                                        ccode.add_default ();
 
472
                                        ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_assert_not_reached")));
 
473
 
 
474
                                        ccode.close ();
 
475
 
 
476
                                        // coroutine body
 
477
                                        ccode.add_label ("_state_0");
 
478
                                }
 
479
 
 
480
                                if (m.closure) {
 
481
                                        // add variables for parent closure blocks
 
482
                                        // as closures only have one parameter for the innermost closure block
 
483
                                        var closure_block = current_closure_block;
 
484
                                        int block_id = get_block_id (closure_block);
 
485
                                        while (true) {
 
486
                                                var parent_closure_block = next_closure_block (closure_block.parent_symbol);
 
487
                                                if (parent_closure_block == null) {
 
488
                                                        break;
 
489
                                                }
 
490
                                                int parent_block_id = get_block_id (parent_closure_block);
 
491
 
 
492
                                                var parent_data = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "_data%d_".printf (parent_block_id));
 
493
                                                ccode.add_declaration ("Block%dData*".printf (parent_block_id), new CCodeVariableDeclarator ("_data%d_".printf (parent_block_id)));
 
494
                                                ccode.add_assignment (new CCodeIdentifier ("_data%d_".printf (parent_block_id)), parent_data);
 
495
 
 
496
                                                closure_block = parent_closure_block;
 
497
                                                block_id = parent_block_id;
 
498
                                        }
 
499
 
 
500
                                        // add self variable for closures
 
501
                                        // as closures have block data parameter
 
502
                                        if (m.binding == MemberBinding.INSTANCE) {
 
503
                                                var cself = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data%d_".printf (block_id)), "self");
 
504
                                                ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator ("self"));
 
505
                                                ccode.add_assignment (new CCodeIdentifier ("self"), cself);
 
506
                                        }
 
507
 
 
508
                                        // allow capturing generic type parameters
 
509
                                        foreach (var type_param in m.get_type_parameters ()) {
 
510
                                                string func_name;
 
511
 
 
512
                                                func_name = "%s_type".printf (type_param.name.down ());
 
513
                                                ccode.add_declaration ("GType", new CCodeVariableDeclarator (func_name));
 
514
                                                ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
 
515
 
 
516
                                                func_name = "%s_dup_func".printf (type_param.name.down ());
 
517
                                                ccode.add_declaration ("GBoxedCopyFunc", new CCodeVariableDeclarator (func_name));
 
518
                                                ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
 
519
 
 
520
                                                func_name = "%s_destroy_func".printf (type_param.name.down ());
 
521
                                                ccode.add_declaration ("GDestroyNotify", new CCodeVariableDeclarator (func_name));
 
522
                                                ccode.add_assignment (new CCodeIdentifier (func_name), new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (block_id)), func_name));
 
523
                                        }
 
524
                                } else if (m.parent_symbol is Class && !m.coroutine) {
 
525
                                        var cl = (Class) m.parent_symbol;
 
526
                                        if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
 
527
                                                Method base_method;
 
528
                                                ReferenceType base_expression_type;
 
529
                                                if (m.overrides) {
 
530
                                                        base_method = m.base_method;
 
531
                                                        base_expression_type = new ObjectType ((Class) base_method.parent_symbol);
 
532
                                                } else {
 
533
                                                        base_method = m.base_interface_method;
 
534
                                                        base_expression_type = new ObjectType ((Interface) base_method.parent_symbol);
 
535
                                                }
 
536
                                                var self_target_type = new ObjectType (cl);
 
537
                                                CCodeExpression cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
 
538
 
 
539
                                                ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
 
540
                                                ccode.add_assignment (new CCodeIdentifier ("self"), cself);
 
541
                                        } else if (m.binding == MemberBinding.INSTANCE
 
542
                                                           && !(m is CreationMethod)
 
543
                                                           && m.base_method == null && m.base_interface_method == null) {
 
544
                                                create_method_type_check_statement (m, creturn_type, cl, true, "self");
 
545
                                        }
 
546
                                }
 
547
 
 
548
                                foreach (Parameter param in m.get_parameters ()) {
 
549
                                        if (param.ellipsis) {
 
550
                                                break;
 
551
                                        }
 
552
 
 
553
                                        if (param.direction != ParameterDirection.OUT) {
 
554
                                                var t = param.variable_type.data_type;
 
555
                                                if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) {
 
556
                                                        var cname = get_variable_cname (param.name);
 
557
                                                        if (param.direction == ParameterDirection.REF && !param.variable_type.is_real_struct_type ()) {
 
558
                                                                cname = "*"+cname;
 
559
                                                        }
 
560
                                                        create_method_type_check_statement (m, creturn_type, t, !param.variable_type.nullable, cname);
 
561
                                                }
 
562
                                        } else if (!m.coroutine) {
 
563
                                                // declare local variable for out parameter to allow assignment even when caller passes NULL
 
564
                                                var vardecl = new CCodeVariableDeclarator.zero (get_variable_cname ("_vala_" + param.name), default_value_for_type (param.variable_type, true));
 
565
                                                ccode.add_declaration (get_ccode_name (param.variable_type), vardecl);
 
566
 
 
567
                                                if (param.variable_type is ArrayType) {
 
568
                                                        // create variables to store array dimensions
 
569
                                                        var array_type = (ArrayType) param.variable_type;
 
570
 
 
571
                                                        if (!array_type.fixed_length) {
 
572
                                                                for (int dim = 1; dim <= array_type.rank; dim++) {
 
573
                                                                        vardecl = new CCodeVariableDeclarator.zero (get_array_length_cname (get_variable_cname ("_vala_" + param.name), dim), new CCodeConstant ("0"));
 
574
                                                                        ccode.add_declaration ("int", vardecl);
 
575
                                                                }
 
576
                                                        }
 
577
                                                } else if (param.variable_type is DelegateType) {
 
578
                                                        var deleg_type = (DelegateType) param.variable_type;
 
579
                                                        var d = deleg_type.delegate_symbol;
 
580
                                                        if (d.has_target) {
 
581
                                                                // create variable to store delegate target
 
582
                                                                vardecl = new CCodeVariableDeclarator.zero ("_vala_" + get_ccode_delegate_target_name (param), new CCodeConstant ("NULL"));
 
583
                                                                ccode.add_declaration ("void *", vardecl);
 
584
 
 
585
                                                                if (deleg_type.value_owned) {
 
586
                                                                        vardecl = new CCodeVariableDeclarator.zero (get_delegate_target_destroy_notify_cname (get_variable_cname ("_vala_" + param.name)), new CCodeConstant ("NULL"));
 
587
                                                                        ccode.add_declaration ("GDestroyNotify", vardecl);
 
588
                                                                }
 
589
                                                        }
 
590
                                                }
 
591
                                        }
 
592
                                }
 
593
 
 
594
                                if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
 
595
                                        var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
 
596
                                        vardecl.init0 = true;
 
597
                                        ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
 
598
                                }
 
599
 
 
600
                                if (m is CreationMethod) {
 
601
                                        if (in_gobject_creation_method) {
 
602
                                                if (!m.coroutine) {
 
603
                                                        ccode.add_declaration ("%s *".printf (get_ccode_name (current_type_symbol)), new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
 
604
                                                }
 
605
                                        } else if (is_gtypeinstance_creation_method (m)) {
 
606
                                                var cl = (Class) m.parent_symbol;
 
607
                                                ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator.zero ("self", new CCodeConstant ("NULL")));
 
608
 
 
609
                                                if (cl.is_fundamental () && !((CreationMethod) m).chain_up) {
 
610
                                                        var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_create_instance"));
 
611
                                                        ccall.add_argument (get_variable_cexpression ("object_type"));
 
612
                                                        ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (cl) + "*"));
 
613
 
 
614
                                                        /* type, dup func, and destroy func fields for generic types */
 
615
                                                        foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
 
616
                                                                CCodeIdentifier param_name;
 
617
                                                                CCodeAssignment assign;
 
618
 
 
619
                                                                var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
 
620
 
 
621
                                                                param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
 
622
                                                                assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
 
623
                                                                ccode.add_expression (assign);
 
624
 
 
625
                                                                param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
 
626
                                                                assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
 
627
                                                                ccode.add_expression (assign);
 
628
 
 
629
                                                                param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
 
630
                                                                assign = new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name);
 
631
                                                                ccode.add_expression (assign);
 
632
                                                        }
 
633
                                                }
 
634
                                        } else if (current_type_symbol is Class) {
 
635
                                                var cl = (Class) m.parent_symbol;
 
636
                                                if (!m.coroutine) {
 
637
                                                        ccode.add_declaration (get_ccode_name (cl) + "*", new CCodeVariableDeclarator ("self"));
 
638
                                                }
 
639
 
 
640
                                                if (!((CreationMethod) m).chain_up) {
 
641
                                                        // TODO implicitly chain up to base class as in add_object_creation
 
642
                                                        var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
 
643
                                                        ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
 
644
                                                        ccode.add_assignment (get_this_cexpression (), ccall);
 
645
                                                }
 
646
 
 
647
                                                if (cl.base_class == null) {
 
648
                                                        // derived compact classes do not have fields
 
649
                                                        var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null))));
 
650
                                                        cinitcall.add_argument (get_this_cexpression ());
 
651
                                                        ccode.add_expression (cinitcall);
 
652
                                                }
 
653
                                        } else {
 
654
                                                var st = (Struct) m.parent_symbol;
 
655
 
 
656
                                                // memset needs string.h
 
657
                                                cfile.add_include ("string.h");
 
658
                                                var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
 
659
                                                czero.add_argument (new CCodeIdentifier ("self"));
 
660
                                                czero.add_argument (new CCodeConstant ("0"));
 
661
                                                czero.add_argument (new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (st))));
 
662
                                                ccode.add_expression (czero);
 
663
                                        }
 
664
                                }
 
665
 
 
666
                                if (context.module_init_method == m && in_plugin) {
 
667
                                        // GTypeModule-based plug-in, register types
 
668
                                        register_plugin_types (context.root, new HashSet<Symbol> ());
 
669
                                }
 
670
 
 
671
                                foreach (Expression precondition in m.get_preconditions ()) {
 
672
                                        create_precondition_statement (m, creturn_type, precondition);
 
673
                                }
 
674
                        }
 
675
                }
 
676
 
 
677
                if (profile) {
 
678
                        string prefix = "_vala_prof_%s".printf (real_name);
 
679
 
 
680
                        var level = new CCodeIdentifier (prefix + "_level");
 
681
                        ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, level)));
 
682
 
 
683
                        var counter = new CCodeIdentifier (prefix + "_counter");
 
684
                        ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, counter));
 
685
 
 
686
                        var timer = new CCodeIdentifier (prefix + "_timer");
 
687
                        var cont_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_continue"));
 
688
                        cont_call.add_argument (timer);
 
689
                        ccode.add_expression (cont_call);
 
690
 
 
691
                        ccode.close ();
 
692
                }
 
693
 
 
694
                if (m.body != null) {
 
695
                        m.body.emit (this);
 
696
                }
 
697
 
 
698
                if (profile) {
 
699
                        string prefix = "_vala_prof_%s".printf (real_name);
 
700
 
 
701
                        var level = new CCodeIdentifier (prefix + "_level");
 
702
                        ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
 
703
 
 
704
                        var timer = new CCodeIdentifier (prefix + "_timer");
 
705
 
 
706
                        var stop_call = new CCodeFunctionCall (new CCodeIdentifier ("g_timer_stop"));
 
707
                        stop_call.add_argument (timer);
 
708
                        ccode.add_expression (stop_call);
 
709
 
 
710
                        ccode.close ();
 
711
                }
 
712
 
 
713
                // generate *_real_* functions for virtual methods
 
714
                // also generate them for abstract methods of classes to prevent faulty subclassing
 
715
                if (!m.is_abstract || (m.is_abstract && current_type_symbol is Class)) {
 
716
                        /* Methods imported from a plain C file don't
 
717
                         * have a body, e.g. Vala.Parser.parse_file () */
 
718
                        if (m.body != null) {
 
719
                                if (current_method_inner_error) {
 
720
                                        /* always separate error parameter and inner_error local variable
 
721
                                         * as error may be set to NULL but we're always interested in inner errors
 
722
                                         */
 
723
                                        if (m.coroutine) {
 
724
                                                closure_struct.add_field ("GError *", "_inner_error_");
 
725
 
 
726
                                                // no initialization necessary, closure struct is zeroed
 
727
                                        } else {
 
728
                                                ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
 
729
                                        }
 
730
                                }
 
731
 
 
732
                                if (m.coroutine) {
 
733
                                        // epilogue
 
734
                                        complete_async ();
 
735
                                }
 
736
 
 
737
                                if (!(m.return_type is VoidType) && !m.return_type.is_real_non_null_struct_type () && !m.coroutine) {
 
738
                                        // add dummy return if exit block is known to be unreachable to silence C compiler
 
739
                                        if (m.return_block != null && m.return_block.get_predecessors ().size == 0) {
 
740
                                                ccode.add_return (new CCodeIdentifier ("result"));
 
741
                                        }
 
742
                                }
 
743
 
 
744
                                if (m is CreationMethod) {
 
745
                                        if (current_type_symbol is Class) {
 
746
                                                creturn_type = new ObjectType (current_class);
 
747
                                        } else {
 
748
                                                creturn_type = new VoidType ();
 
749
                                        }
 
750
 
 
751
 
 
752
                                        if (current_type_symbol is Class && gobject_type != null && current_class.is_subtype_of (gobject_type)
 
753
                                            && current_class.get_type_parameters ().size > 0
 
754
                                            && !((CreationMethod) m).chain_up) {
 
755
                                                var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, new CCodeIdentifier ("__params_it"), new CCodeIdentifier ("__params"));
 
756
                                                ccode.open_while (ccond);
 
757
                                                ccode.add_expression (new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, new CCodeIdentifier ("__params_it")));
 
758
                                                var cunsetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_unset"));
 
759
                                                cunsetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("__params_it"), "value")));
 
760
                                                ccode.add_expression (cunsetcall);
 
761
                                                ccode.close ();
 
762
 
 
763
                                                var cfreeparams = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
 
764
                                                cfreeparams.add_argument (new CCodeIdentifier ("__params"));
 
765
                                                ccode.add_expression (cfreeparams);
 
766
                                        }
 
767
 
 
768
                                        if (current_type_symbol is Class && !m.coroutine) {
 
769
                                                CCodeExpression cresult = new CCodeIdentifier ("self");
 
770
                                                if (get_ccode_type (m) != null) {
 
771
                                                        cresult = new CCodeCastExpression (cresult, get_ccode_type (m));
 
772
                                                }
 
773
 
 
774
                                                ccode.add_return (cresult);
 
775
                                        }
 
776
                                }
 
777
 
 
778
                                cfile.add_function (ccode);
 
779
                        }
 
780
                }
 
781
 
 
782
                if (m.is_abstract && current_type_symbol is Class) {
 
783
                        // generate helpful error message if a sublcass does not implement an abstract method.
 
784
                        // This is only meaningful for subclasses implemented in C since the vala compiler would
 
785
                        // complain during compile time of such en error.
 
786
 
 
787
                        // add critical warning that this method should not have been called
 
788
                        var type_from_instance_call = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
 
789
                        type_from_instance_call.add_argument (new CCodeIdentifier ("self"));
 
790
 
 
791
                        var type_name_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
 
792
                        type_name_call.add_argument (type_from_instance_call);
 
793
 
 
794
                        var error_string = "\"Type `%%s' does not implement abstract method `%s'\"".printf (get_ccode_name (m));
 
795
 
 
796
                        var cerrorcall = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
 
797
                        cerrorcall.add_argument (new CCodeConstant (error_string));
 
798
                        cerrorcall.add_argument (type_name_call);
 
799
 
 
800
                        ccode.add_expression (cerrorcall);
 
801
 
 
802
                        // add return statement
 
803
                        return_default_value (creturn_type);
 
804
 
 
805
                        cfile.add_function (ccode);
 
806
                }
 
807
 
 
808
                pop_context ();
 
809
 
 
810
                if ((m.is_abstract || m.is_virtual) && !m.coroutine &&
 
811
                /* If the method is a signal handler, the declaration
 
812
                 * is not needed. -- the name should be reserved for the
 
813
                 * emitter! */
 
814
                            m.signal_reference == null) {
 
815
 
 
816
                        cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
 
817
                        var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
 
818
 
 
819
                        generate_vfunc (m, creturn_type, cparam_map, carg_map);
 
820
                }
 
821
 
 
822
                if (m.entry_point) {
 
823
                        // m is possible entry point, add appropriate startup code
 
824
                        var cmain = new CCodeFunction ("main", "int");
 
825
                        cmain.line = function.line;
 
826
                        cmain.add_parameter (new CCodeParameter ("argc", "int"));
 
827
                        cmain.add_parameter (new CCodeParameter ("argv", "char **"));
 
828
                        push_function (cmain);
 
829
 
 
830
                        if (context.mem_profiler) {
 
831
                                var mem_profiler_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_mem_set_vtable"));
 
832
                                mem_profiler_init_call.line = cmain.line;
 
833
                                mem_profiler_init_call.add_argument (new CCodeConstant ("glib_mem_profiler_table"));
 
834
                                ccode.add_expression (mem_profiler_init_call);
 
835
                        }
 
836
 
 
837
                        if (context.thread && !context.require_glib_version (2, 32)) {
 
838
                                var thread_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_thread_init"));
 
839
                                thread_init_call.line = cmain.line;
 
840
                                thread_init_call.add_argument (new CCodeConstant ("NULL"));
 
841
                                ccode.add_expression (thread_init_call);
 
842
                        }
 
843
 
 
844
                        if (!context.require_glib_version (2, 36)) {
 
845
                                ccode.add_expression (new CCodeFunctionCall (new CCodeIdentifier ("g_type_init")));
 
846
                        }
 
847
 
 
848
                        var main_call = new CCodeFunctionCall (new CCodeIdentifier (function.name));
 
849
                        if (m.get_parameters ().size == 1) {
 
850
                                main_call.add_argument (new CCodeIdentifier ("argv"));
 
851
                                main_call.add_argument (new CCodeIdentifier ("argc"));
 
852
                        }
 
853
                        if (m.return_type is VoidType) {
 
854
                                // method returns void, always use 0 as exit code
 
855
                                ccode.add_expression (main_call);
 
856
                                ccode.add_return (new CCodeConstant ("0"));
 
857
                        } else {
 
858
                                ccode.add_return (main_call);
 
859
                        }
 
860
                        pop_function ();
 
861
                        cfile.add_function (cmain);
 
862
                }
 
863
 
 
864
                pop_line ();
 
865
        }
 
866
 
 
867
        public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
 
868
                CCodeParameter cparam;
 
869
                if (!param.ellipsis) {
 
870
                        string ctypename = get_ccode_name (param.variable_type);
 
871
 
 
872
                        generate_type_declaration (param.variable_type, decl_space);
 
873
 
 
874
                        // pass non-simple structs always by reference
 
875
                        if (param.variable_type.data_type is Struct) {
 
876
                                var st = (Struct) param.variable_type.data_type;
 
877
                                if (!st.is_simple_type () && param.direction == ParameterDirection.IN) {
 
878
                                        if (st.is_immutable && !param.variable_type.value_owned) {
 
879
                                                ctypename = "const " + ctypename;
 
880
                                        }
 
881
 
 
882
                                        if (!param.variable_type.nullable) {
 
883
                                                ctypename += "*";
 
884
                                        }
 
885
                                }
 
886
                        }
 
887
 
 
888
                        if (param.direction != ParameterDirection.IN) {
 
889
                                ctypename += "*";
 
890
                        }
 
891
 
 
892
                        cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
 
893
                } else if (ellipses_to_valist) {
 
894
                        cparam = new CCodeParameter ("_vala_va_list", "va_list");
 
895
                } else {
 
896
                        cparam = new CCodeParameter.with_ellipsis ();
 
897
                }
 
898
 
 
899
                cparam_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis), cparam);
 
900
                if (carg_map != null && !param.ellipsis) {
 
901
                        carg_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis), get_variable_cexpression (param.name));
 
902
                }
 
903
 
 
904
                return cparam;
 
905
        }
 
906
 
 
907
        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) {
 
908
                if (m.closure) {
 
909
                        var closure_block = current_closure_block;
 
910
                        int block_id = get_block_id (closure_block);
 
911
                        var instance_param = new CCodeParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
 
912
                        cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
 
913
                } else if (m.parent_symbol is Class && m is CreationMethod) {
 
914
                        var cl = (Class) m.parent_symbol;
 
915
                        if (!cl.is_compact && vcall == null && (direction & 1) == 1) {
 
916
                                cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
 
917
                        }
 
918
                } else if (m.binding == MemberBinding.INSTANCE || (m.parent_symbol is Struct && m is CreationMethod)) {
 
919
                        TypeSymbol parent_type = find_parent_type (m);
 
920
                        DataType this_type;
 
921
                        if (parent_type is Class) {
 
922
                                this_type = new ObjectType ((Class) parent_type);
 
923
                        } else if (parent_type is Interface) {
 
924
                                this_type = new ObjectType ((Interface) parent_type);
 
925
                        } else if (parent_type is Struct) {
 
926
                                this_type = new StructValueType ((Struct) parent_type);
 
927
                        } else if (parent_type is Enum) {
 
928
                                this_type = new EnumValueType ((Enum) parent_type);
 
929
                        } else {
 
930
                                assert_not_reached ();
 
931
                        }
 
932
 
 
933
                        generate_type_declaration (this_type, decl_space);
 
934
 
 
935
                        CCodeParameter instance_param = null;
 
936
                        if (m.base_interface_method != null && !m.is_abstract && !m.is_virtual) {
 
937
                                var base_type = new ObjectType ((Interface) m.base_interface_method.parent_symbol);
 
938
                                instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
 
939
                        } else if (m.overrides) {
 
940
                                var base_type = new ObjectType ((Class) m.base_method.parent_symbol);
 
941
                                instance_param = new CCodeParameter ("base", get_ccode_name (base_type));
 
942
                        } else {
 
943
                                if (m.parent_symbol is Struct && !((Struct) m.parent_symbol).is_simple_type ()) {
 
944
                                        instance_param = new CCodeParameter ("*self", get_ccode_name (this_type));
 
945
                                } else {
 
946
                                        instance_param = new CCodeParameter ("self", get_ccode_name (this_type));
 
947
                                }
 
948
                        }
 
949
                        cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), instance_param);
 
950
                } else if (m.binding == MemberBinding.CLASS) {
 
951
                        TypeSymbol parent_type = find_parent_type (m);
 
952
                        DataType this_type;
 
953
                        this_type = new ClassType ((Class) parent_type);
 
954
                        var class_param = new CCodeParameter ("klass", get_ccode_name (this_type));
 
955
                        cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), class_param);
 
956
                }
 
957
 
 
958
                if (is_gtypeinstance_creation_method (m)) {
 
959
                        // memory management for generic types
 
960
                        int type_param_index = 0;
 
961
                        var cl = (Class) m.parent_symbol;
 
962
                        foreach (TypeParameter type_param in cl.get_type_parameters ()) {
 
963
                                cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
 
964
                                cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
 
965
                                cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
 
966
                                if (carg_map != null) {
 
967
                                        carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
 
968
                                        carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
 
969
                                        carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
 
970
                                }
 
971
                                type_param_index++;
 
972
                        }
 
973
                } else if (!m.closure && (direction & 1) == 1) {
 
974
                        int type_param_index = 0;
 
975
                        foreach (var type_param in m.get_type_parameters ()) {
 
976
                                cparam_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeParameter ("%s_type".printf (type_param.name.down ()), "GType"));
 
977
                                cparam_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
 
978
                                cparam_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
 
979
                                if (carg_map != null) {
 
980
                                        carg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
 
981
                                        carg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
 
982
                                        carg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
 
983
                                }
 
984
                                type_param_index++;
 
985
                        }
 
986
                }
 
987
 
 
988
                foreach (Parameter param in m.get_parameters ()) {
 
989
                        if (param.direction != ParameterDirection.OUT) {
 
990
                                if ((direction & 1) == 0) {
 
991
                                        // no in paramters
 
992
                                        continue;
 
993
                                }
 
994
                        } else {
 
995
                                if ((direction & 2) == 0) {
 
996
                                        // no out paramters
 
997
                                        continue;
 
998
                                }
 
999
                        }
 
1000
 
 
1001
                        generate_parameter (param, decl_space, cparam_map, carg_map);
 
1002
                }
 
1003
 
 
1004
                if ((direction & 2) != 0) {
 
1005
                        generate_method_result_declaration (m, decl_space, func, cparam_map, carg_map);
 
1006
                }
 
1007
 
 
1008
                // append C parameters in the right order
 
1009
                int last_pos = -1;
 
1010
                int min_pos;
 
1011
                while (true) {
 
1012
                        min_pos = -1;
 
1013
                        foreach (int pos in cparam_map.get_keys ()) {
 
1014
                                if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
 
1015
                                        min_pos = pos;
 
1016
                                }
 
1017
                        }
 
1018
                        if (min_pos == -1) {
 
1019
                                break;
 
1020
                        }
 
1021
                        func.add_parameter (cparam_map.get (min_pos));
 
1022
                        if (vdeclarator != null) {
 
1023
                                vdeclarator.add_parameter (cparam_map.get (min_pos));
 
1024
                        }
 
1025
                        if (vcall != null) {
 
1026
                                var arg = carg_map.get (min_pos);
 
1027
                                if (arg != null) {
 
1028
                                        vcall.add_argument (arg);
 
1029
                                }
 
1030
                        }
 
1031
                        last_pos = min_pos;
 
1032
                }
 
1033
        }
 
1034
 
 
1035
        public void generate_vfunc (Method m, DataType return_type, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression> carg_map, string suffix = "", int direction = 3) {
 
1036
                push_context (new EmitContext ());
 
1037
 
 
1038
                string cname = get_ccode_name (m);
 
1039
                if (suffix == "_finish" && cname.has_suffix ("_async")) {
 
1040
                        cname = cname.substring (0, cname.length - "_async".length);
 
1041
                }
 
1042
                var vfunc = new CCodeFunction (cname + suffix);
 
1043
 
 
1044
                CCodeFunctionCall vcast = null;
 
1045
                if (m.parent_symbol is Interface) {
 
1046
                        var iface = (Interface) m.parent_symbol;
 
1047
 
 
1048
                        vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_INTERFACE".printf (get_ccode_upper_case_name (iface))));
 
1049
                } else {
 
1050
                        var cl = (Class) m.parent_symbol;
 
1051
 
 
1052
                        vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (cl))));
 
1053
                }
 
1054
                vcast.add_argument (new CCodeIdentifier ("self"));
 
1055
        
 
1056
                cname = get_ccode_vfunc_name (m);
 
1057
                if (suffix == "_finish" && cname.has_suffix ("_async")) {
 
1058
                        cname = cname.substring (0, cname.length - "_async".length);
 
1059
                }
 
1060
                var vcall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, cname + suffix));
 
1061
                carg_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeIdentifier ("self"));
 
1062
 
 
1063
                generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, direction);
 
1064
 
 
1065
                push_function (vfunc);
 
1066
 
 
1067
                if (context.assert && m.return_type.data_type is Struct && ((Struct) m.return_type.data_type).is_simple_type () && default_value_for_type (m.return_type, false) == null) {
 
1068
                        // the type check will use the result variable
 
1069
                        var vardecl = new CCodeVariableDeclarator ("result", default_value_for_type (m.return_type, true));
 
1070
                        vardecl.init0 = true;
 
1071
                        ccode.add_declaration (get_ccode_name (m.return_type), vardecl);
 
1072
                }
 
1073
 
 
1074
                // add a typecheck statement for "self"
 
1075
                create_method_type_check_statement (m, return_type, (TypeSymbol) m.parent_symbol, true, "self");
 
1076
 
 
1077
                foreach (Expression precondition in m.get_preconditions ()) {
 
1078
                        create_precondition_statement (m, return_type, precondition);
 
1079
                }
 
1080
 
 
1081
                if (return_type is VoidType || return_type.is_real_non_null_struct_type ()) {
 
1082
                        ccode.add_expression (vcall);
 
1083
                } else if (m.get_postconditions ().size == 0) {
 
1084
                        /* pass method return value */
 
1085
                        ccode.add_return (vcall);
 
1086
                } else {
 
1087
                        /* store method return value for postconditions */
 
1088
                        ccode.add_declaration (get_creturn_type (m, get_ccode_name (return_type)), new CCodeVariableDeclarator ("result"));
 
1089
                        ccode.add_assignment (new CCodeIdentifier ("result"), vcall);
 
1090
                }
 
1091
 
 
1092
                if (m.get_postconditions ().size > 0) {
 
1093
                        foreach (Expression postcondition in m.get_postconditions ()) {
 
1094
                                create_postcondition_statement (postcondition);
 
1095
                        }
 
1096
 
 
1097
                        if (!(return_type is VoidType)) {
 
1098
                                ccode.add_return (new CCodeIdentifier ("result"));
 
1099
                        }
 
1100
                }
 
1101
 
 
1102
                cfile.add_function (vfunc);
 
1103
 
 
1104
                pop_context ();
 
1105
        }
 
1106
 
 
1107
        private void create_method_type_check_statement (Method m, DataType return_type, TypeSymbol t, bool non_null, string var_name) {
 
1108
                if (!m.coroutine) {
 
1109
                        create_type_check_statement (m, return_type, t, non_null, var_name);
 
1110
                }
 
1111
        }
 
1112
 
 
1113
        private void create_precondition_statement (CodeNode method_node, DataType ret_type, Expression precondition) {
 
1114
                var ccheck = new CCodeFunctionCall ();
 
1115
 
 
1116
                precondition.emit (this);
 
1117
 
 
1118
                ccheck.add_argument (get_cvalue (precondition));
 
1119
 
 
1120
                if (method_node is CreationMethod) {
 
1121
                        ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
 
1122
                        ccheck.add_argument (new CCodeConstant ("NULL"));
 
1123
                } else if (method_node is Method && ((Method) method_node).coroutine) {
 
1124
                        // _co function
 
1125
                        ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
 
1126
                        ccheck.add_argument (new CCodeConstant ("FALSE"));
 
1127
                } else if (ret_type is VoidType) {
 
1128
                        /* void function */
 
1129
                        ccheck.call = new CCodeIdentifier ("g_return_if_fail");
 
1130
                } else {
 
1131
                        ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
 
1132
 
 
1133
                        var cdefault = default_value_for_type (ret_type, false);
 
1134
                        if (cdefault != null) {
 
1135
                                ccheck.add_argument (cdefault);
 
1136
                        } else {
 
1137
                                return;
 
1138
                        }
 
1139
                }
 
1140
                
 
1141
                ccode.add_expression (ccheck);
 
1142
        }
 
1143
 
 
1144
        private TypeSymbol? find_parent_type (Symbol sym) {
 
1145
                while (sym != null) {
 
1146
                        if (sym is TypeSymbol) {
 
1147
                                return (TypeSymbol) sym;
 
1148
                        }
 
1149
                        sym = sym.parent_symbol;
 
1150
                }
 
1151
                return null;
 
1152
        }
 
1153
 
 
1154
        public override void visit_creation_method (CreationMethod m) {
 
1155
                push_line (m.source_reference);
 
1156
 
 
1157
                ellipses_to_valist = true;
 
1158
                visit_method (m);
 
1159
                ellipses_to_valist = false;
 
1160
 
 
1161
                if (m.source_type == SourceFileType.FAST) {
 
1162
                        return;
 
1163
                }
 
1164
 
 
1165
                // do not generate _new functions for creation methods of abstract classes
 
1166
                if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
 
1167
                        // _new function
 
1168
                        create_aux_constructor (m, get_ccode_name (m), false);
 
1169
 
 
1170
                        // _construct function (if visit_method generated _constructv)
 
1171
                        if (m.is_variadic ()) {
 
1172
                                create_aux_constructor (m, get_ccode_real_name (m), true);
 
1173
                        }
 
1174
                }
 
1175
 
 
1176
                pop_line ();
 
1177
        }
 
1178
 
 
1179
        private void create_aux_constructor (CreationMethod m, string func_name, bool self_as_first_parameter) {
 
1180
                var vfunc = new CCodeFunction (func_name);
 
1181
                if (m.is_private_symbol ()) {
 
1182
                        vfunc.modifiers |= CCodeModifiers.STATIC;
 
1183
                }
 
1184
 
 
1185
                var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
 
1186
                var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
 
1187
 
 
1188
                push_function (vfunc);
 
1189
 
 
1190
                string constructor = (m.is_variadic ()) ? get_constructv_name (m) : get_ccode_real_name (m);
 
1191
                var vcall = new CCodeFunctionCall (new CCodeIdentifier (constructor));
 
1192
 
 
1193
                if (self_as_first_parameter) {
 
1194
                        cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
 
1195
                        vcall.add_argument (get_variable_cexpression ("object_type"));
 
1196
                } else {
 
1197
                        vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
 
1198
                }
 
1199
 
 
1200
 
 
1201
                generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
 
1202
 
 
1203
                if (m.is_variadic ()) {
 
1204
                        int last_pos = -1;
 
1205
                        int second_last_pos = -1;
 
1206
                        foreach (int pos in cparam_map.get_keys ()) {
 
1207
                                if (pos > last_pos) {
 
1208
                                        second_last_pos = last_pos;
 
1209
                                        last_pos = pos;
 
1210
                                } else if (pos > second_last_pos) {
 
1211
                                        second_last_pos = pos;
 
1212
                                }
 
1213
                        }
 
1214
 
 
1215
                        var va_start = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
 
1216
                        va_start.add_argument (new CCodeIdentifier ("_vala_va_list_obj"));
 
1217
                        va_start.add_argument (carg_map.get (second_last_pos));
 
1218
 
 
1219
                        ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_vala_va_list_obj"));
 
1220
                        ccode.add_expression (va_start);
 
1221
 
 
1222
                        vcall.add_argument (new CCodeIdentifier("_vala_va_list_obj"));
 
1223
                }
 
1224
 
 
1225
                ccode.add_return (vcall);
 
1226
 
 
1227
                pop_function ();
 
1228
 
 
1229
                cfile.add_function (vfunc);
 
1230
        }
 
1231
}
 
1232
 
 
1233
// vim:sw=8 noet