~ubuntu-branches/ubuntu/quantal/vala/quantal

« back to all changes in this revision

Viewing changes to .pc/90_revert_use_new_gir_version.patch/vala/valagirparser.vala

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-09-20 19:57:26 UTC
  • mfrom: (1.5.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20100920195726-cbxb3q400aj1hoqr
Tags: 0.10.0-0ubuntu1
* New upstream release
* debian/patches/90_revert_use_new_gir_version.patch:
  - don't build with new GIR

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* valagirparser.vala
 
2
 *
 
3
 * Copyright (C) 2008-2009  Jürg Billeter
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2.1 of the License, or (at your option) any later version.
 
9
 
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 
 
15
 * You should have received a copy of the GNU Lesser General Public
 
16
 * License along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 
18
 *
 
19
 * Author:
 
20
 *      Jürg Billeter <j@bitron.ch>
 
21
 */
 
22
 
 
23
using GLib;
 
24
 
 
25
/**
 
26
 * Code visitor parsing all Vala source files.
 
27
 */
 
28
public class Vala.GirParser : CodeVisitor {
 
29
        MarkupReader reader;
 
30
 
 
31
        CodeContext context;
 
32
        Namespace glib_ns;
 
33
 
 
34
        SourceFile current_source_file;
 
35
        SourceLocation begin;
 
36
        SourceLocation end;
 
37
        MarkupTokenType current_token;
 
38
 
 
39
        string[] cheader_filenames;
 
40
        string[] package_names;
 
41
 
 
42
        HashMap<string,string> attributes_map = new HashMap<string,string> (str_hash, str_equal);
 
43
 
 
44
        HashMap<string,ArrayList<Method>> gtype_callbacks = new HashMap<string,ArrayList<Method>> (str_hash, str_equal);
 
45
 
 
46
        /**
 
47
         * Parses all .gir source files in the specified code
 
48
         * context and builds a code tree.
 
49
         *
 
50
         * @param context a code context
 
51
         */
 
52
        public void parse (CodeContext context) {
 
53
                this.context = context;
 
54
                glib_ns = context.root.scope.lookup ("GLib") as Namespace;
 
55
                context.accept (this);
 
56
        }
 
57
 
 
58
        public override void visit_source_file (SourceFile source_file) {
 
59
                if (source_file.filename.has_suffix (".gir")) {
 
60
                        parse_file (source_file);
 
61
                }
 
62
        }
 
63
 
 
64
        public void parse_file (SourceFile source_file) {
 
65
                this.current_source_file = source_file;
 
66
                reader = new MarkupReader (source_file.filename);
 
67
 
 
68
                // xml prolog
 
69
                next ();
 
70
                next ();
 
71
 
 
72
                next ();
 
73
                parse_repository ();
 
74
 
 
75
                var remove_queue = new ArrayList<CodeNode> ();
 
76
 
 
77
                foreach (CodeNode node in source_file.get_nodes ()) {
 
78
                        if (node is Class) {
 
79
                                var cl = (Class) node;
 
80
                                var ns = cl.parent_symbol as Namespace;
 
81
                                // remove Class records
 
82
                                var class_struct = ns.scope.lookup (cl.name + "Class") as Struct;
 
83
                                if (class_struct != null) {
 
84
                                        ns.remove_struct ((Struct) class_struct);
 
85
                                        remove_queue.add (class_struct);
 
86
                                }
 
87
                        } else if (node is Interface) {
 
88
                                var iface = (Interface) node;
 
89
                                var ns = iface.parent_symbol as Namespace;
 
90
                                // remove Iface records
 
91
                                var iface_struct = ns.scope.lookup (iface.name + "Iface") as Struct;
 
92
                                if (iface_struct != null) {
 
93
                                        ns.remove_struct ((Struct) iface_struct);
 
94
                                        remove_queue.add (iface_struct);
 
95
                                }
 
96
                        }
 
97
                }
 
98
 
 
99
                foreach (CodeNode node in remove_queue) {
 
100
                        source_file.remove_node (node);
 
101
                }
 
102
 
 
103
                reader = null;
 
104
                this.current_source_file = null;
 
105
        }
 
106
 
 
107
        void next () {
 
108
                current_token = reader.read_token (out begin, out end);
 
109
 
 
110
                // Skip *all* <doc> tags
 
111
                if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "doc")
 
112
                        skip_element();
 
113
        }
 
114
 
 
115
        void start_element (string name) {
 
116
                if (current_token != MarkupTokenType.START_ELEMENT || reader.name != name) {
 
117
                        // error
 
118
                        Report.error (get_current_src (), "expected start element of `%s'".printf (name));
 
119
                }
 
120
        }
 
121
 
 
122
        void end_element (string name) {
 
123
                if (current_token != MarkupTokenType.END_ELEMENT || reader.name != name) {
 
124
                        // error
 
125
                        Report.error (get_current_src (), "expected end element of `%s'".printf (name));
 
126
                }
 
127
                next ();
 
128
        }
 
129
 
 
130
        SourceReference get_current_src () {
 
131
                return new SourceReference (this.current_source_file, begin.line, begin.column, end.line, end.column);
 
132
        }
 
133
 
 
134
        const string GIR_VERSION = "1.2";
 
135
 
 
136
        void parse_repository () {
 
137
                start_element ("repository");
 
138
                if (reader.get_attribute ("version") != GIR_VERSION) {
 
139
                        Report.error (get_current_src (), "unsupported GIR version %s (supported: %s)".printf (reader.get_attribute ("version"), GIR_VERSION));
 
140
                        return;
 
141
                }
 
142
                next ();
 
143
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
144
                        if (reader.name == "namespace") {
 
145
                                var ns = parse_namespace ();
 
146
                                if (ns != null) {
 
147
                                        context.root.add_namespace (ns);
 
148
                                }
 
149
                        } else if (reader.name == "include") {
 
150
                                parse_include ();
 
151
                        } else if (reader.name == "package") {
 
152
                                parse_package ();
 
153
                        } else if (reader.name == "c:include") {
 
154
                                parse_c_include ();
 
155
                        } else {
 
156
                                // error
 
157
                                Report.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader.name));
 
158
                                break;
 
159
                        }
 
160
                }
 
161
                end_element ("repository");
 
162
        }
 
163
 
 
164
        void parse_include () {
 
165
                start_element ("include");
 
166
                next ();
 
167
                end_element ("include");
 
168
        }
 
169
 
 
170
        void parse_package () {
 
171
                start_element ("package");
 
172
                add_package_name (reader.get_attribute ("name"));
 
173
                next ();
 
174
                end_element ("package");
 
175
        }
 
176
 
 
177
        void parse_c_include () {
 
178
                start_element ("c:include");
 
179
                cheader_filenames += reader.get_attribute ("name");
 
180
                next ();
 
181
                end_element ("c:include");
 
182
        }
 
183
 
 
184
        void skip_element () {
 
185
                next ();
 
186
 
 
187
                int level = 1;
 
188
                while (level > 0) {
 
189
                        if (current_token == MarkupTokenType.START_ELEMENT) {
 
190
                                level++;
 
191
                        } else if (current_token == MarkupTokenType.END_ELEMENT) {
 
192
                                level--;
 
193
                        } else if (current_token == MarkupTokenType.EOF) {
 
194
                                Report.error (get_current_src (), "unexpected end of file");
 
195
                                break;
 
196
                        }
 
197
                        next ();
 
198
                }
 
199
        }
 
200
 
 
201
        Namespace? parse_namespace () {
 
202
                start_element ("namespace");
 
203
 
 
204
                bool new_namespace = false;
 
205
                string namespace_name = transform_namespace_name (reader.get_attribute ("name"));
 
206
                var ns = context.root.scope.lookup (namespace_name) as Namespace;
 
207
                if (ns == null) {
 
208
                        ns = new Namespace (namespace_name, get_current_src ());
 
209
                        new_namespace = true;
 
210
                } else {
 
211
                        if (ns.external_package) {
 
212
                                ns.attributes = null;
 
213
                                ns.source_reference = get_current_src ();
 
214
                        }
 
215
                }
 
216
 
 
217
                string? cprefix = reader.get_attribute ("c:identifier-prefixes");
 
218
                if (cprefix != null) {
 
219
                        ns.add_cprefix (cprefix);
 
220
                        ns.set_lower_case_cprefix (Symbol.camel_case_to_lower_case (cprefix) + "_");
 
221
                }
 
222
 
 
223
                foreach (string c_header in cheader_filenames) {
 
224
                        ns.add_cheader_filename (c_header);
 
225
                }
 
226
                next ();
 
227
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
228
                        if (reader.get_attribute ("introspectable") == "0") {
 
229
                                skip_element ();
 
230
                                continue;
 
231
                        }
 
232
 
 
233
                        Symbol sym = null;
 
234
                        if (reader.name == "alias") {
 
235
                                sym = parse_alias ();
 
236
                        } else if (reader.name == "enumeration") {
 
237
                                if (reader.get_attribute ("glib:error-quark") != null) {
 
238
                                        sym = parse_error_domain ();
 
239
                                } else {
 
240
                                        sym = parse_enumeration ();
 
241
                                }
 
242
                        } else if (reader.name == "bitfield") {
 
243
                                sym = parse_bitfield ();
 
244
                        } else if (reader.name == "function") {
 
245
                                sym = parse_method ("function");
 
246
                        } else if (reader.name == "callback") {
 
247
                                sym = parse_callback ();
 
248
                        } else if (reader.name == "record") {
 
249
                                if (reader.get_attribute ("glib:get-type") != null) {
 
250
                                        sym = parse_boxed ();
 
251
                                } else {
 
252
                                        sym = parse_record ();
 
253
                                }
 
254
                        } else if (reader.name == "class") {
 
255
                                sym = parse_class ();
 
256
                        } else if (reader.name == "interface") {
 
257
                                sym = parse_interface ();
 
258
                        } else if (reader.name == "glib:boxed") {
 
259
                                sym = parse_boxed ();
 
260
                        } else if (reader.name == "union") {
 
261
                                sym = parse_union ();
 
262
                        } else if (reader.name == "constant") {
 
263
                                sym = parse_constant ();
 
264
                        } else {
 
265
                                // error
 
266
                                Report.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader.name));
 
267
                                break;
 
268
                        }
 
269
 
 
270
                        if (sym is Class) {
 
271
                                ns.add_class ((Class) sym);
 
272
                        } else if (sym is Interface) {
 
273
                                ns.add_interface ((Interface) sym);
 
274
                        } else if (sym is Struct) {
 
275
                                ns.add_struct ((Struct) sym);
 
276
                        } else if (sym is Enum) {
 
277
                                ns.add_enum ((Enum) sym);
 
278
                        } else if (sym is ErrorDomain) {
 
279
                                ns.add_error_domain ((ErrorDomain) sym);
 
280
                        } else if (sym is Delegate) {
 
281
                                ns.add_delegate ((Delegate) sym);
 
282
                        } else if (sym is Method) {
 
283
                                ns.add_method ((Method) sym);
 
284
                        } else if (sym is Constant) {
 
285
                                ns.add_constant ((Constant) sym);
 
286
                        } else if (sym == null) {
 
287
                                continue;
 
288
                        }
 
289
                        current_source_file.add_node (sym);
 
290
                }
 
291
                end_element ("namespace");
 
292
 
 
293
                postprocess_gtype_callbacks (ns);
 
294
 
 
295
                if (!new_namespace) {
 
296
                        ns = null;
 
297
                }
 
298
 
 
299
                return ns;
 
300
        }
 
301
 
 
302
        Struct parse_alias () {
 
303
                start_element ("alias");
 
304
                var st = new Struct (reader.get_attribute ("name"), get_current_src ());
 
305
                st.access = SymbolAccessibility.PUBLIC;
 
306
                st.external = true;
 
307
                next ();
 
308
 
 
309
                st.base_type = parse_type (null, null, true);
 
310
 
 
311
                end_element ("alias");
 
312
                return st;
 
313
        }
 
314
 
 
315
        private void calculate_common_prefix (ref string common_prefix, string cname) {
 
316
                if (common_prefix == null) {
 
317
                        common_prefix = cname;
 
318
                        while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
 
319
                                // FIXME: could easily be made faster
 
320
                                common_prefix = common_prefix.ndup (common_prefix.size () - 1);
 
321
                        }
 
322
                } else {
 
323
                        while (!cname.has_prefix (common_prefix)) {
 
324
                                common_prefix = common_prefix.ndup (common_prefix.size () - 1);
 
325
                        }
 
326
                }
 
327
                while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
 
328
                       (cname.offset (common_prefix.length).get_char ().isdigit ()) && (cname.length - common_prefix.length) <= 1)) {
 
329
                        // enum values may not consist solely of digits
 
330
                        common_prefix = common_prefix.ndup (common_prefix.size () - 1);
 
331
                }
 
332
        }
 
333
 
 
334
        Enum parse_enumeration () {
 
335
                start_element ("enumeration");
 
336
                var en = new Enum (reader.get_attribute ("name"), get_current_src ());
 
337
                en.access = SymbolAccessibility.PUBLIC;
 
338
 
 
339
                string enum_cname = reader.get_attribute ("c:type");
 
340
                if (enum_cname != null) {
 
341
                        en.set_cname (enum_cname);
 
342
                }
 
343
 
 
344
                next ();
 
345
 
 
346
                string common_prefix = null;
 
347
                
 
348
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
349
                        if (reader.get_attribute ("introspectable") == "0") {
 
350
                                skip_element ();
 
351
                                continue;
 
352
                        }
 
353
 
 
354
                        if (reader.name == "member") {
 
355
                                var ev = parse_enumeration_member ();
 
356
                                en.add_value (ev);
 
357
                                calculate_common_prefix (ref common_prefix, ev.get_cname ());
 
358
                        } else {
 
359
                                // error
 
360
                                break;
 
361
                        }
 
362
                }
 
363
 
 
364
                en.set_cprefix (common_prefix);
 
365
 
 
366
                end_element ("enumeration");
 
367
                return en;
 
368
        }
 
369
 
 
370
        ErrorDomain parse_error_domain () {
 
371
                start_element ("enumeration");
 
372
 
 
373
                var ed = new ErrorDomain (reader.get_attribute ("name"), get_current_src ());
 
374
                ed.access = SymbolAccessibility.PUBLIC;
 
375
 
 
376
                string enum_cname = reader.get_attribute ("c:type");
 
377
                if (enum_cname != null) {
 
378
                        ed.set_cname (enum_cname);
 
379
                }
 
380
 
 
381
                next ();
 
382
 
 
383
                string common_prefix = null;
 
384
 
 
385
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
386
                        if (reader.get_attribute ("introspectable") == "0") {
 
387
                                skip_element ();
 
388
                                continue;
 
389
                        }
 
390
 
 
391
                        if (reader.name == "member") {
 
392
                                ErrorCode ec = parse_error_member ();
 
393
                                ed.add_code (ec);
 
394
                                calculate_common_prefix (ref common_prefix, ec.get_cname ());
 
395
                        } else {
 
396
                                // error
 
397
                                break;
 
398
                        }
 
399
                }
 
400
 
 
401
                ed.set_cprefix (common_prefix);
 
402
 
 
403
                end_element ("enumeration");
 
404
                return ed;
 
405
        }
 
406
 
 
407
        Enum parse_bitfield () {
 
408
                start_element ("bitfield");
 
409
                var en = new Enum (reader.get_attribute ("name"), get_current_src ());
 
410
                en.access = SymbolAccessibility.PUBLIC;
 
411
                next ();
 
412
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
413
                        if (reader.get_attribute ("introspectable") == "0") {
 
414
                                skip_element ();
 
415
                                continue;
 
416
                        }
 
417
 
 
418
                        if (reader.name == "member") {
 
419
                                en.add_value (parse_enumeration_member ());
 
420
                        } else {
 
421
                                // error
 
422
                                break;
 
423
                        }
 
424
                }
 
425
                end_element ("bitfield");
 
426
                return en;
 
427
        }
 
428
 
 
429
        EnumValue parse_enumeration_member () {
 
430
                start_element ("member");
 
431
                var ev = new EnumValue (string.joinv ("_", reader.get_attribute ("name").up ().split ("-")), null);
 
432
                ev.set_cname (reader.get_attribute ("c:identifier"));
 
433
                next ();
 
434
                end_element ("member");
 
435
                return ev;
 
436
        }
 
437
 
 
438
        ErrorCode parse_error_member () {
 
439
                start_element ("member");
 
440
 
 
441
                ErrorCode ec;
 
442
                string name = string.joinv ("_", reader.get_attribute ("name").up ().split ("-"));
 
443
                string value = reader.get_attribute ("value");
 
444
                if (value != null) {
 
445
                        ec = new ErrorCode.with_value (name, new IntegerLiteral (value));
 
446
                } else {
 
447
                        ec = new ErrorCode (name);
 
448
                }
 
449
 
 
450
                next ();
 
451
                end_element ("member");
 
452
                return ec;
 
453
        }
 
454
 
 
455
        DataType parse_return_value (out string? ctype = null) {
 
456
                start_element ("return-value");
 
457
                string transfer = reader.get_attribute ("transfer-ownership");
 
458
                string allow_none = reader.get_attribute ("allow-none");
 
459
                next ();
 
460
                var transfer_elements = transfer == "full";
 
461
                var type = &ctype != null ? parse_type(out ctype, null, transfer_elements) : parse_type (null, null, transfer_elements);
 
462
                if (transfer == "full" || transfer == "container") {
 
463
                        type.value_owned = true;
 
464
                }
 
465
                if (allow_none == "1") {
 
466
                        type.nullable = true;
 
467
                }
 
468
                end_element ("return-value");
 
469
                return type;
 
470
        }
 
471
 
 
472
        FormalParameter parse_parameter (out int array_length_idx = null, out int closure_idx = null, out int destroy_idx = null, out string? scope = null) {
 
473
                FormalParameter param;
 
474
 
 
475
                if (&array_length_idx != null) {
 
476
                        array_length_idx = -1;
 
477
                }
 
478
                if (&closure_idx != null) {
 
479
                        closure_idx = -1;
 
480
                }
 
481
                if (&destroy_idx != null) {
 
482
                        destroy_idx = -1;
 
483
                }
 
484
 
 
485
                start_element ("parameter");
 
486
                string name = reader.get_attribute ("name");
 
487
                string direction = reader.get_attribute ("direction");
 
488
                string transfer = reader.get_attribute ("transfer-ownership");
 
489
                string allow_none = reader.get_attribute ("allow-none");
 
490
 
 
491
                if (&scope != null) {
 
492
                        scope = reader.get_attribute ("scope");
 
493
                }
 
494
 
 
495
                string closure = reader.get_attribute ("closure");
 
496
                string destroy = reader.get_attribute ("destroy");
 
497
                if (closure != null && &closure_idx != null) {
 
498
                        closure_idx = closure.to_int ();
 
499
                }
 
500
                if (destroy != null && &destroy_idx != null) {
 
501
                        destroy_idx = destroy.to_int ();
 
502
                }
 
503
 
 
504
                next ();
 
505
                if (reader.name == "varargs") {
 
506
                        start_element ("varargs");
 
507
                        next ();
 
508
                        param = new FormalParameter.with_ellipsis (get_current_src ());
 
509
                        end_element ("varargs");
 
510
                } else {
 
511
                        var type = parse_type (null, out array_length_idx, transfer == "full");
 
512
                        if (transfer == "full" || transfer == "container" || destroy != null) {
 
513
                                type.value_owned = true;
 
514
                        }
 
515
                        if (allow_none == "1") {
 
516
                                type.nullable = true;
 
517
                        }
 
518
                        param = new FormalParameter (name, type, get_current_src ());
 
519
                        if (direction == "out") {
 
520
                                param.direction = ParameterDirection.OUT;
 
521
                        } else if (direction == "inout") {
 
522
                                param.direction = ParameterDirection.REF;
 
523
                        }
 
524
                }
 
525
                end_element ("parameter");
 
526
                return param;
 
527
        }
 
528
 
 
529
        DataType parse_type (out string? ctype = null, out int array_length_index = null, bool transfer_elements = false) {
 
530
                bool is_array = false;
 
531
                string type_name = reader.get_attribute ("name");
 
532
 
 
533
                if (reader.name == "array") {
 
534
                        is_array = true;
 
535
                        start_element ("array");
 
536
 
 
537
                        if (!(type_name == "GLib.Array" || type_name == "GLib.PtrArray")) {
 
538
                                if (reader.get_attribute ("length") != null
 
539
                                    && &array_length_index != null) {
 
540
                                        array_length_index = reader.get_attribute ("length").to_int ();
 
541
                                }
 
542
                                next ();
 
543
                                var element_type = parse_type ();
 
544
                                end_element ("array");
 
545
                                return new ArrayType (element_type, 1, null);
 
546
                        }
 
547
                } else if (reader.name == "callback"){
 
548
                        var callback = parse_callback ();
 
549
                        return new DelegateType (callback);
 
550
                } else {
 
551
                        start_element ("type");
 
552
                }
 
553
 
 
554
                if (&ctype != null) {
 
555
                        ctype = reader.get_attribute("c:type");
 
556
                }
 
557
 
 
558
                next ();
 
559
 
 
560
                if (type_name == "GLib.PtrArray"
 
561
                    && current_token == MarkupTokenType.START_ELEMENT) {
 
562
                        type_name = "GLib.GenericArray";
 
563
                }
 
564
 
 
565
                DataType type = parse_type_from_name (type_name);
 
566
 
 
567
                // type arguments / element types
 
568
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
569
                        var element_type = parse_type ();
 
570
                        element_type.value_owned = transfer_elements;
 
571
                        type.add_type_argument (element_type);
 
572
                }
 
573
 
 
574
                end_element (is_array ? "array" : "type");
 
575
                return type;
 
576
        }
 
577
 
 
578
        DataType parse_type_from_name (string type_name) {
 
579
                DataType type;
 
580
                if (type_name == "none") {
 
581
                        type = new VoidType ();
 
582
                } else if (type_name == "gpointer") {
 
583
                        type = new PointerType (new VoidType ());
 
584
                } else if (type_name == "GObject.Strv") {
 
585
                        type = new ArrayType (new UnresolvedType.from_symbol (new UnresolvedSymbol (null, "string")), 1, null);
 
586
                } else {
 
587
                        if (type_name == "utf8") {
 
588
                                type_name = "string";
 
589
                        } else if (type_name == "gboolean") {
 
590
                                type_name = "bool";
 
591
                        } else if (type_name == "gchar") {
 
592
                                type_name = "char";
 
593
                        } else if (type_name == "gshort") {
 
594
                                type_name = "short";
 
595
                        } else if (type_name == "gushort") {
 
596
                                type_name = "ushort";
 
597
                        } else if (type_name == "gint") {
 
598
                                type_name = "int";
 
599
                        } else if (type_name == "guint") {
 
600
                                type_name = "uint";
 
601
                        } else if (type_name == "glong") {
 
602
                                type_name = "long";
 
603
                        } else if (type_name == "gulong") {
 
604
                                type_name = "ulong";
 
605
                        } else if (type_name == "gint8") {
 
606
                                type_name = "int8";
 
607
                        } else if (type_name == "guint8") {
 
608
                                type_name = "uint8";
 
609
                        } else if (type_name == "gint16") {
 
610
                                type_name = "int16";
 
611
                        } else if (type_name == "guint16") {
 
612
                                type_name = "uint16";
 
613
                        } else if (type_name == "gint32") {
 
614
                                type_name = "int32";
 
615
                        } else if (type_name == "guint32") {
 
616
                                type_name = "uint32";
 
617
                        } else if (type_name == "gint64") {
 
618
                                type_name = "int64";
 
619
                        } else if (type_name == "guint64") {
 
620
                                type_name = "uint64";
 
621
                        } else if (type_name == "gfloat") {
 
622
                                type_name = "float";
 
623
                        } else if (type_name == "gdouble") {
 
624
                                type_name = "double";
 
625
                        } else if (type_name == "filename") {
 
626
                                type_name = "string";
 
627
                        } else if (type_name == "GLib.offset") {
 
628
                                type_name = "int64";
 
629
                        } else if (type_name == "gsize") {
 
630
                                type_name = "size_t";
 
631
                        } else if (type_name == "gssize") {
 
632
                                type_name = "ssize_t";
 
633
                        } else if (type_name == "GType") {
 
634
                                type_name = "GLib.Type";
 
635
                        } else if (type_name == "GLib.String") {
 
636
                                type_name = "GLib.StringBuilder";
 
637
                        } else if (type_name == "GObject.Class") {
 
638
                                type_name = "GLib.ObjectClass";
 
639
                        } else if (type_name == "GLib.unichar") {
 
640
                                type_name = "unichar";
 
641
                        } else if (type_name == "GLib.Data") {
 
642
                                type_name = "GLib.Datalist";
 
643
                        } else if (type_name == "Atk.ImplementorIface") {
 
644
                                type_name = "Atk.Implementor";
 
645
                        }
 
646
                        string[] type_components = type_name.split (".");
 
647
                        if (type_components[1] != null) {
 
648
                                // namespaced name
 
649
                                string namespace_name = transform_namespace_name (type_components[0]);
 
650
                                string transformed_type_name = type_components[1];
 
651
                                type = new UnresolvedType.from_symbol (new UnresolvedSymbol (new UnresolvedSymbol (null, namespace_name), transformed_type_name));
 
652
                        } else {
 
653
                                type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, type_name));
 
654
                        }
 
655
                }
 
656
 
 
657
                return type;
 
658
        }
 
659
 
 
660
        string transform_namespace_name (string gir_module_name) {
 
661
                if (gir_module_name == "GObject") {
 
662
                        return "GLib";
 
663
                } else if (gir_module_name == "Gio") {
 
664
                        return "GLib";
 
665
                } else if (gir_module_name == "GModule") {
 
666
                        return "GLib";
 
667
                }
 
668
                return gir_module_name;
 
669
        }
 
670
 
 
671
        Struct parse_record () {
 
672
                start_element ("record");
 
673
                var st = new Struct (reader.get_attribute ("name"), get_current_src ());
 
674
                st.external = true;
 
675
 
 
676
                string glib_is_gtype_struct_for = reader.get_attribute ("glib:is-gtype-struct-for");
 
677
 
 
678
                st.access = SymbolAccessibility.PUBLIC;
 
679
                next ();
 
680
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
681
                        if (reader.get_attribute ("introspectable") == "0") {
 
682
                                skip_element ();
 
683
                                continue;
 
684
                        }
 
685
 
 
686
                        if (reader.name == "field") {
 
687
                                st.add_field (parse_field ());
 
688
                        } else if (reader.name == "callback") {
 
689
                                if (glib_is_gtype_struct_for != null) {
 
690
                                        ArrayList<Method> callbacks = gtype_callbacks.get (glib_is_gtype_struct_for);
 
691
                                        if (callbacks == null) {
 
692
                                                callbacks = new ArrayList<Method> ();
 
693
                                                gtype_callbacks.set (glib_is_gtype_struct_for, callbacks);
 
694
                                        }
 
695
                                        callbacks.add (parse_method ("callback"));
 
696
                                } else {
 
697
                                        parse_callback ();
 
698
                                }
 
699
                        } else if (reader.name == "constructor") {
 
700
                                parse_constructor ();
 
701
                        } else if (reader.name == "method") {
 
702
                                st.add_method (parse_method ("method"));
 
703
                        } else if (reader.name == "union") {
 
704
                                Struct s = parse_union ();
 
705
                                var s_fields = s.get_fields ();
 
706
                                foreach (var f in s_fields) {
 
707
                                        f.set_cname (s.get_cname () + "." + f.get_cname ());
 
708
                                        f.name = s.name + "_" + f.name;
 
709
                                        st.add_field (f);
 
710
                                }
 
711
                        } else {
 
712
                                // error
 
713
                                Report.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader.name));
 
714
                                break;
 
715
                        }
 
716
                }
 
717
                end_element ("record");
 
718
                return st;
 
719
        }
 
720
 
 
721
        void postprocess_gtype_callbacks (Namespace ns) {
 
722
                foreach (string gtype_name in gtype_callbacks.get_keys ()) {
 
723
                        var gtype = ns.scope.lookup (gtype_name) as ObjectTypeSymbol;
 
724
                        ArrayList<Method> callbacks = gtype_callbacks.get (gtype_name);
 
725
                        foreach (Method m in callbacks) {
 
726
                                var symbol = gtype.scope.lookup (m.name);
 
727
                                if (symbol == null) {
 
728
                                        continue;
 
729
                                } else if (symbol is Method)  {
 
730
                                        var meth = (Method) symbol;
 
731
                                        if (gtype is Class) {
 
732
                                                meth.is_virtual = true;
 
733
                                        } else if (gtype is Interface) {
 
734
                                                meth.is_abstract = true;
 
735
                                        }
 
736
                                } else if (symbol is Signal) {
 
737
                                        var sig = (Signal) symbol;
 
738
                                        sig.is_virtual = true;
 
739
                                } else {
 
740
                                        Report.error (get_current_src (), "unknown member type `%s' in `%s'".printf (m.name, gtype.name));
 
741
                                }
 
742
                        }
 
743
                }
 
744
        }
 
745
 
 
746
        Class parse_class () {
 
747
                start_element ("class");
 
748
                var cl = new Class (reader.get_attribute ("name"), get_current_src ());
 
749
                cl.access = SymbolAccessibility.PUBLIC;
 
750
                cl.external = true;
 
751
 
 
752
                string cname = reader.get_attribute ("c:type");
 
753
                if (cname != null) {
 
754
                        cl.set_cname (cname);
 
755
                }
 
756
 
 
757
                string parent = reader.get_attribute ("parent");
 
758
                if (parent != null) {
 
759
                        cl.add_base_type (parse_type_from_name (parent));
 
760
                }
 
761
 
 
762
                next ();
 
763
                var signals = new ArrayList<Signal> ();
 
764
                var methods = new ArrayList<Method> ();
 
765
                var vmethods = new ArrayList<Method> ();
 
766
                var fields = new ArrayList<Field> ();
 
767
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
768
                        if (reader.get_attribute ("introspectable") == "0") {
 
769
                                skip_element ();
 
770
                                continue;
 
771
                        }
 
772
 
 
773
                        if (reader.name == "implements") {
 
774
                                start_element ("implements");
 
775
                                cl.add_base_type (parse_type_from_name (reader.get_attribute ("name")));
 
776
                                next ();
 
777
                                end_element ("implements");
 
778
                        } else if (reader.name == "constant") {
 
779
                                cl.add_constant (parse_constant ());
 
780
                        } else if (reader.name == "field") {
 
781
                                fields.add (parse_field ());
 
782
                        } else if (reader.name == "property") {
 
783
                                cl.add_property (parse_property ());
 
784
                        } else if (reader.name == "constructor") {
 
785
                                cl.add_method (parse_constructor (cname));
 
786
                        } else if (reader.name == "function") {
 
787
                                methods.add (parse_method ("function"));
 
788
                        } else if (reader.name == "method") {
 
789
                                methods.add (parse_method ("method"));
 
790
                        } else if (reader.name == "virtual-method") {
 
791
                                vmethods.add (parse_method ("virtual-method"));
 
792
                        } else if (reader.name == "union") {
 
793
                                Struct s = parse_union ();
 
794
                                var s_fields = s.get_fields ();
 
795
                                foreach (var f in s_fields) {
 
796
                                        f.set_cname (s.get_cname () + "." + f.get_cname ());
 
797
                                        f.name = s.name + "_" + f.name;
 
798
                                        fields.add (f);
 
799
                                }
 
800
                        } else if (reader.name == "glib:signal") {
 
801
                                signals.add (parse_signal ());
 
802
                        } else {
 
803
                                // error
 
804
                                Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
 
805
                                break;
 
806
                        }
 
807
                }
 
808
 
 
809
                // signal merging
 
810
                foreach (Signal sig in signals) {
 
811
                        var symbol = cl.scope.lookup (sig.name);
 
812
                        if (symbol == null) {
 
813
                                cl.add_signal (sig);
 
814
                        } else if (symbol is Property) {
 
815
                                // properties take precedence
 
816
                        } else {
 
817
                                Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (sig.name, cl.name));
 
818
                        }
 
819
                }
 
820
 
 
821
                // virtual method merging
 
822
                foreach (Method m in vmethods) {
 
823
                        var symbol = cl.scope.lookup (m.name);
 
824
                        if (symbol == null) {
 
825
                                cl.add_method (m);
 
826
                        } else if (symbol is Signal) {
 
827
                                var sig = (Signal) symbol;
 
828
                                sig.is_virtual = true;
 
829
                        } else if (symbol is Property || symbol is Field) {
 
830
                                // assume method is getter for property/field ignore method
 
831
                        } else {
 
832
                                Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, cl.name));
 
833
                        }
 
834
                }
 
835
 
 
836
                // method merging
 
837
                foreach (Method m in methods) {
 
838
                        var symbol = cl.scope.lookup (m.name);
 
839
                        if (symbol == null) {
 
840
                                cl.add_method (m);
 
841
                        } else if (symbol is Signal) {
 
842
                                var sig = (Signal) symbol;
 
843
                                sig.has_emitter = true;
 
844
                        } else if (symbol is Property || symbol is Field) {
 
845
                                // assume method is getter for property/field ignore method
 
846
                        } else if (symbol is Method) {
 
847
                                // assume method is wrapper for virtual method
 
848
                        } else {
 
849
                                Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, cl.name));
 
850
                        }
 
851
                }
 
852
 
 
853
                // fields have lowest priority
 
854
                foreach (Field f in fields) {
 
855
                        var symbol = cl.scope.lookup (f.name);
 
856
                        if (symbol == null) {
 
857
                                cl.add_field (f);
 
858
                        }
 
859
                }
 
860
 
 
861
                handle_async_methods (cl);
 
862
 
 
863
                end_element ("class");
 
864
                return cl;
 
865
        }
 
866
 
 
867
        Interface parse_interface () {
 
868
                start_element ("interface");
 
869
                var iface = new Interface (reader.get_attribute ("name"), get_current_src ());
 
870
                iface.access = SymbolAccessibility.PUBLIC;
 
871
                iface.external = true;
 
872
 
 
873
                string cname = reader.get_attribute ("c:type");
 
874
                if (cname != null) {
 
875
                        iface.set_cname (cname);
 
876
                }
 
877
 
 
878
                next ();
 
879
                var methods = new ArrayList<Method> ();
 
880
                var vmethods = new ArrayList<Method> ();
 
881
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
882
                        if (reader.get_attribute ("introspectable") == "0") {
 
883
                                skip_element ();
 
884
                                continue;
 
885
                        }
 
886
 
 
887
                        if (reader.name == "prerequisite") {
 
888
                                start_element ("prerequisite");
 
889
                                iface.add_prerequisite (parse_type_from_name (reader.get_attribute ("name")));
 
890
                                next ();
 
891
                                end_element ("prerequisite");
 
892
                        } else if (reader.name == "field") {
 
893
                                parse_field ();
 
894
                        } else if (reader.name == "property") {
 
895
                                iface.add_property (parse_property ());
 
896
                        } else if (reader.name == "virtual-method") {
 
897
                                vmethods.add (parse_method ("virtual-method"));
 
898
                        } else if (reader.name == "function") {
 
899
                                methods.add (parse_method ("function"));
 
900
                        } else if (reader.name == "method") {
 
901
                                methods.add (parse_method ("method"));
 
902
                        } else if (reader.name == "glib:signal") {
 
903
                                iface.add_signal (parse_signal ());
 
904
                        } else {
 
905
                                // error
 
906
                                Report.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader.name));
 
907
                                break;
 
908
                        }
 
909
                }
 
910
 
 
911
                // ensure we have at least one instantiable prerequisite (GLib.Object)
 
912
                bool has_instantiable_prereq = false;
 
913
                foreach (DataType prereq in iface.get_prerequisites ()) {
 
914
                        if (prereq.data_type is Class) {
 
915
                                has_instantiable_prereq = true;
 
916
                                break;
 
917
                        }
 
918
                }
 
919
 
 
920
                if (!has_instantiable_prereq)
 
921
                        iface.add_prerequisite (new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("Object")));
 
922
 
 
923
                // virtual method merging
 
924
                foreach (Method m in vmethods) {
 
925
                        var symbol = iface.scope.lookup (m.name);
 
926
                        if (symbol == null) {
 
927
                                iface.add_method (m);
 
928
                        } else if (symbol is Signal) {
 
929
                                var sig = (Signal) symbol;
 
930
                                sig.is_virtual = true;
 
931
                        } else {
 
932
                                Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, iface.name));
 
933
                        }
 
934
                }
 
935
 
 
936
                // method merging
 
937
                foreach (Method m in methods) {
 
938
                        var symbol = iface.scope.lookup (m.name);
 
939
                        if (symbol == null) {
 
940
                                iface.add_method (m);
 
941
                        } else if (symbol is Signal) {
 
942
                                var sig = (Signal) symbol;
 
943
                                sig.has_emitter = true;
 
944
                        } else if (symbol is Method) {
 
945
                                // assume method is wrapper for virtual method
 
946
                        } else {
 
947
                                Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, iface.name));
 
948
                        }
 
949
                }
 
950
 
 
951
                handle_async_methods (iface);
 
952
 
 
953
                end_element ("interface");
 
954
                return iface;
 
955
        }
 
956
 
 
957
        void handle_async_methods (ObjectTypeSymbol type_symbol) {
 
958
                var methods = type_symbol.get_methods ();
 
959
                for (int method_n = 0 ; method_n < methods.size ; method_n++) {
 
960
                        var m = methods.get (method_n);
 
961
 
 
962
                        if (m.coroutine) {
 
963
                                string finish_method_base;
 
964
                                if (m.name.has_suffix ("_async")) {
 
965
                                        finish_method_base = m.name.substring (0, m.name.length - "_async".length);
 
966
                                } else {
 
967
                                        finish_method_base = m.name;
 
968
                                }
 
969
                                var finish_method = type_symbol.scope.lookup (finish_method_base + "_finish") as Method;
 
970
 
 
971
                                // check if the method is using non-standard finish method name
 
972
                                if (finish_method == null) {
 
973
                                        var method_cname = m.get_finish_cname ();
 
974
                                        foreach (Method method in type_symbol.get_methods ()) {
 
975
                                                if (method.get_cname () == method_cname) {
 
976
                                                        finish_method = method;
 
977
                                                        break;
 
978
                                                }
 
979
                                        }
 
980
                                }
 
981
 
 
982
                                if (finish_method != null) {
 
983
                                        m.return_type = finish_method.return_type.copy ();
 
984
                                        m.no_array_length = finish_method.no_array_length;
 
985
                                        m.array_null_terminated = finish_method.array_null_terminated;
 
986
                                        foreach (var param in finish_method.get_parameters ()) {
 
987
                                                if (param.direction == ParameterDirection.OUT) {
 
988
                                                        var async_param = param.copy ();
 
989
                                                        if (m.scope.lookup (param.name) != null) {
 
990
                                                                // parameter name conflict
 
991
                                                                async_param.name += "_out";
 
992
                                                        }
 
993
                                                        m.add_parameter (async_param);
 
994
                                                }
 
995
                                        }
 
996
                                        foreach (DataType error_type in finish_method.get_error_types ()) {
 
997
                                                m.add_error_type (error_type.copy ());
 
998
                                        }
 
999
                                        if (methods.index_of (finish_method) < method_n) {
 
1000
                                                method_n--;
 
1001
                                        }
 
1002
                                        type_symbol.scope.remove (finish_method.name);
 
1003
                                        methods.remove (finish_method);
 
1004
                                }
 
1005
                        }
 
1006
                }
 
1007
        }
 
1008
 
 
1009
        Field parse_field () {
 
1010
                start_element ("field");
 
1011
                string name = reader.get_attribute ("name");
 
1012
                string allow_none = reader.get_attribute ("allow-none");
 
1013
                next ();
 
1014
                var type = parse_type ();
 
1015
                var field = new Field (name, type, null, get_current_src ());
 
1016
                field.access = SymbolAccessibility.PUBLIC;
 
1017
                if (allow_none == "1") {
 
1018
                        type.nullable = true;
 
1019
                }
 
1020
                end_element ("field");
 
1021
                return field;
 
1022
        }
 
1023
 
 
1024
        Property parse_property () {
 
1025
                start_element ("property");
 
1026
                string name = string.joinv ("_", reader.get_attribute ("name").split ("-"));
 
1027
                string readable = reader.get_attribute ("readable");
 
1028
                string writable = reader.get_attribute ("writable");
 
1029
                string construct_ = reader.get_attribute ("construct");
 
1030
                string construct_only = reader.get_attribute ("construct-only");
 
1031
                next ();
 
1032
                var type = parse_type ();
 
1033
                var prop = new Property (name, type, null, null, get_current_src ());
 
1034
                prop.access = SymbolAccessibility.PUBLIC;
 
1035
                if (readable != "0") {
 
1036
                        prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
 
1037
                }
 
1038
                if (writable == "1" || construct_only == "1") {
 
1039
                        prop.set_accessor = new PropertyAccessor (false, (construct_only != "1") && (writable == "1"), (construct_only == "1") || (construct_ == "1"), prop.property_type.copy (), null, null);
 
1040
                }
 
1041
                end_element ("property");
 
1042
                return prop;
 
1043
        }
 
1044
 
 
1045
        Delegate parse_callback () {
 
1046
                return this.parse_function ("callback") as Delegate;
 
1047
        }
 
1048
 
 
1049
        Method parse_constructor (string? parent_ctype = null) {
 
1050
                start_element ("constructor");
 
1051
                string name = reader.get_attribute ("name");
 
1052
                string throws_string = reader.get_attribute ("throws");
 
1053
                string cname = reader.get_attribute ("c:identifier");
 
1054
                next ();
 
1055
 
 
1056
                string? ctype;
 
1057
                parse_return_value (out ctype);
 
1058
 
 
1059
                var m = new CreationMethod (null, name, get_current_src ());
 
1060
                m.access = SymbolAccessibility.PUBLIC;
 
1061
                m.has_construct_function = false;
 
1062
                if (ctype != null && (parent_ctype == null || ctype != parent_ctype + "*")) {
 
1063
                        m.custom_return_type_cname = ctype;
 
1064
                }
 
1065
                if (m.name == "new") {
 
1066
                        m.name = null;
 
1067
                } else if (m.name.has_prefix ("new_")) {
 
1068
                        m.name = m.name.offset ("new_".length);
 
1069
                }
 
1070
                if (cname != null) {
 
1071
                        m.set_cname (cname);
 
1072
                }
 
1073
                if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
 
1074
                        start_element ("parameters");
 
1075
                        next ();
 
1076
                        while (current_token == MarkupTokenType.START_ELEMENT) {
 
1077
                                m.add_parameter (parse_parameter ());
 
1078
                        }
 
1079
                        end_element ("parameters");
 
1080
                }
 
1081
 
 
1082
                if (throws_string == "1") {
 
1083
                        m.add_error_type (new ErrorType (null, null));
 
1084
                }
 
1085
                end_element ("constructor");
 
1086
                return m;
 
1087
        }
 
1088
 
 
1089
        class MethodInfo {
 
1090
                public MethodInfo (FormalParameter param, int array_length_idx, int closure_idx, int destroy_idx) {
 
1091
                        this.param = param;
 
1092
                        this.array_length_idx = array_length_idx;
 
1093
                        this.closure_idx = closure_idx;
 
1094
                        this.destroy_idx = destroy_idx;
 
1095
                        this.vala_idx = 0.0F;
 
1096
                        this.keep = true;
 
1097
                }
 
1098
 
 
1099
                public FormalParameter param;
 
1100
                public float vala_idx;
 
1101
                public int array_length_idx;
 
1102
                public int closure_idx;
 
1103
                public int destroy_idx;
 
1104
                public bool keep;
 
1105
        }
 
1106
 
 
1107
        Symbol parse_function (string element_name) {
 
1108
                start_element (element_name);
 
1109
                string name = reader.get_attribute ("name");
 
1110
                string cname = reader.get_attribute ("c:identifier");
 
1111
                string throws_string = reader.get_attribute ("throws");
 
1112
                string invoker = reader.get_attribute ("invoker");
 
1113
                next ();
 
1114
                DataType return_type;
 
1115
                if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
 
1116
                        return_type = parse_return_value ();
 
1117
                } else {
 
1118
                        return_type = new VoidType ();
 
1119
                }
 
1120
 
 
1121
                Symbol s;
 
1122
 
 
1123
                if (element_name == "callback") {
 
1124
                        s = new Delegate (name, return_type, get_current_src ());
 
1125
                } else {
 
1126
                        s = new Method (name, return_type, get_current_src ());
 
1127
                }
 
1128
 
 
1129
                s.access = SymbolAccessibility.PUBLIC;
 
1130
                if (cname != null) {
 
1131
                        if (s is Method) {
 
1132
                                ((Method) s).set_cname (cname);
 
1133
                        } else {
 
1134
                                ((Delegate) s).set_cname (cname);
 
1135
                        }
 
1136
                }
 
1137
 
 
1138
                if (element_name == "virtual-method" || element_name == "callback") {
 
1139
                        if (s is Method) {
 
1140
                                ((Method) s).is_virtual = true;
 
1141
                        }
 
1142
 
 
1143
                        if (invoker != null){
 
1144
                                s.name = invoker;
 
1145
                        }
 
1146
                } else if (element_name == "function") {
 
1147
                        ((Method) s).binding = MemberBinding.STATIC;
 
1148
                }
 
1149
 
 
1150
                var parameters = new ArrayList<MethodInfo> ();
 
1151
                var array_length_parameters = new ArrayList<int> ();
 
1152
                var closure_parameters = new ArrayList<int> ();
 
1153
                var destroy_parameters = new ArrayList<int> ();
 
1154
                if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
 
1155
                        start_element ("parameters");
 
1156
                        next ();
 
1157
 
 
1158
                        while (current_token == MarkupTokenType.START_ELEMENT) {
 
1159
                                int array_length_idx, closure_idx, destroy_idx;
 
1160
                                string scope;
 
1161
                                var param = parse_parameter (out array_length_idx, out closure_idx, out destroy_idx, out scope);
 
1162
                                if (array_length_idx != -1) {
 
1163
                                        array_length_parameters.add (array_length_idx);
 
1164
                                }
 
1165
                                if (closure_idx != -1) {
 
1166
                                        closure_parameters.add (closure_idx);
 
1167
                                }
 
1168
                                if (destroy_idx != -1) {
 
1169
                                        destroy_parameters.add (destroy_idx);
 
1170
                                }
 
1171
 
 
1172
                                var info = new MethodInfo(param, array_length_idx, closure_idx, destroy_idx);
 
1173
 
 
1174
                                if (s is Method && scope == "async") {
 
1175
                                        var unresolved_type = param.variable_type as UnresolvedType;
 
1176
                                        if (unresolved_type != null && unresolved_type.unresolved_symbol.name == "AsyncReadyCallback") {
 
1177
                                                // GAsync-style method
 
1178
                                                ((Method) s).coroutine = true;
 
1179
                                                info.keep = false;
 
1180
                                        }
 
1181
                                }
 
1182
 
 
1183
                                parameters.add (info);
 
1184
                        }
 
1185
                        end_element ("parameters");
 
1186
                }
 
1187
                int i = 0, j=1;
 
1188
 
 
1189
                int last = -1;
 
1190
                foreach (MethodInfo info in parameters) {
 
1191
                        if (s is Delegate && info.closure_idx == i) {
 
1192
                                var d = (Delegate) s;
 
1193
                                d.has_target = true;
 
1194
                                d.cinstance_parameter_position = (float) j - 0.1;
 
1195
                                info.keep = false;
 
1196
                        } else if (info.keep
 
1197
                            && !array_length_parameters.contains (i)
 
1198
                            && !closure_parameters.contains (i)
 
1199
                            && !destroy_parameters.contains (i)) {
 
1200
                                info.vala_idx = (float) j;
 
1201
                                info.keep = true;
 
1202
 
 
1203
                                /* interpolate for vala_idx between this and last*/
 
1204
                                float last_idx = 0.0F;
 
1205
                                if (last != -1) {
 
1206
                                        last_idx = parameters[last].vala_idx;
 
1207
                                }
 
1208
                                for (int k=last+1; k < i; k++) {
 
1209
                                        parameters[k].vala_idx =  last_idx + (((j - last_idx) / (i-last)) * (k-last));
 
1210
                                }
 
1211
                                last = i;
 
1212
                                j++;
 
1213
                        } else {
 
1214
                                info.keep = false;
 
1215
                                // make sure that vala_idx is always set
 
1216
                                // the above if branch does not set vala_idx for
 
1217
                                // hidden parameters at the end of the parameter list
 
1218
                                info.vala_idx = (j - 1) + (i - last) * 0.1F;
 
1219
                        }
 
1220
                        i++;
 
1221
                }
 
1222
 
 
1223
                foreach (MethodInfo info in parameters) {
 
1224
                        if (info.keep) {
 
1225
 
 
1226
                                /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
 
1227
                                 so do it first*/
 
1228
                                if (s is Method) {
 
1229
                                        ((Method) s).add_parameter (info.param);
 
1230
                                } else {
 
1231
                                        ((Delegate) s).add_parameter (info.param);
 
1232
                                }
 
1233
 
 
1234
                                if (info.array_length_idx != -1) {
 
1235
                                        if ((info.array_length_idx) >= parameters.size) {
 
1236
                                                Report.error (get_current_src (), "invalid array_length index");
 
1237
                                                continue;
 
1238
                                        }
 
1239
                                        info.param.carray_length_parameter_position = parameters[info.array_length_idx].vala_idx;
 
1240
                                        info.param.set_array_length_cname (parameters[info.array_length_idx].param.name);
 
1241
                                }
 
1242
                                if (info.param.variable_type is ArrayType && info.array_length_idx == -1) {
 
1243
                                        info.param.no_array_length = true;
 
1244
                                }
 
1245
 
 
1246
                                if (info.closure_idx != -1) {
 
1247
                                        if ((info.closure_idx) >= parameters.size) {
 
1248
                                                Report.error (get_current_src (), "invalid closure index");
 
1249
                                                continue;
 
1250
                                        }
 
1251
                                        info.param.cdelegate_target_parameter_position = parameters[info.closure_idx].vala_idx;
 
1252
                                }
 
1253
                                if (info.destroy_idx != -1) {
 
1254
                                        if (info.destroy_idx >= parameters.size) {
 
1255
                                                Report.error (get_current_src (), "invalid destroy index");
 
1256
                                                continue;
 
1257
                                        }
 
1258
                                        info.param.cdestroy_notify_parameter_position = parameters[info.destroy_idx].vala_idx;
 
1259
                                }
 
1260
                        }
 
1261
                }
 
1262
 
 
1263
                if (throws_string == "1") {
 
1264
                        s.add_error_type (new ErrorType (null, null));
 
1265
                }
 
1266
                end_element (element_name);
 
1267
                return s;
 
1268
        }
 
1269
 
 
1270
        Method parse_method (string element_name) {
 
1271
                return this.parse_function (element_name) as Method;
 
1272
        }
 
1273
 
 
1274
        Signal parse_signal () {
 
1275
                start_element ("glib:signal");
 
1276
                string name = string.joinv ("_", reader.get_attribute ("name").split ("-"));
 
1277
                next ();
 
1278
                DataType return_type;
 
1279
                if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
 
1280
                        return_type = parse_return_value ();
 
1281
                } else {
 
1282
                        return_type = new VoidType ();
 
1283
                }
 
1284
                var sig = new Signal (name, return_type);
 
1285
                sig.access = SymbolAccessibility.PUBLIC;
 
1286
                sig.external = true;
 
1287
                if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
 
1288
                        start_element ("parameters");
 
1289
                        next ();
 
1290
                        while (current_token == MarkupTokenType.START_ELEMENT) {
 
1291
                                sig.add_parameter (parse_parameter ());
 
1292
                        }
 
1293
                        end_element ("parameters");
 
1294
                }
 
1295
                end_element ("glib:signal");
 
1296
                return sig;
 
1297
        }
 
1298
 
 
1299
        Class parse_boxed () {
 
1300
                string name = reader.get_attribute ("name");
 
1301
                if (name == null) {
 
1302
                        name = reader.get_attribute ("glib:name");
 
1303
                }
 
1304
                var cl = new Class (name);
 
1305
                cl.access = SymbolAccessibility.PUBLIC;
 
1306
                cl.external = true;
 
1307
                cl.is_compact = true;
 
1308
 
 
1309
                string cname = reader.get_attribute ("c:type");
 
1310
                if (cname != null) {
 
1311
                        cl.set_cname (cname);
 
1312
                }
 
1313
 
 
1314
                cl.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
 
1315
                cl.set_free_function ("g_boxed_free");
 
1316
                cl.set_dup_function ("g_boxed_copy");
 
1317
 
 
1318
                next ();
 
1319
 
 
1320
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
1321
                        if (reader.get_attribute ("introspectable") == "0") {
 
1322
                                skip_element ();
 
1323
                                continue;
 
1324
                        }
 
1325
 
 
1326
                        if (reader.name == "field") {
 
1327
                                cl.add_field (parse_field ());
 
1328
                        } else if (reader.name == "constructor") {
 
1329
                                parse_constructor ();
 
1330
                        } else if (reader.name == "method") {
 
1331
                                cl.add_method (parse_method ("method"));
 
1332
                        } else {
 
1333
                                // error
 
1334
                                Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
 
1335
                                break;
 
1336
                        }
 
1337
                }
 
1338
 
 
1339
                if (current_token != MarkupTokenType.END_ELEMENT) {
 
1340
                        // error
 
1341
                        Report.error (get_current_src (), "expected end element");
 
1342
                }
 
1343
                next ();
 
1344
                return cl;
 
1345
        }
 
1346
 
 
1347
        Struct parse_union () {
 
1348
                start_element ("union");
 
1349
                var st = new Struct (reader.get_attribute ("name"));
 
1350
                st.access = SymbolAccessibility.PUBLIC;
 
1351
                st.external = true;
 
1352
                next ();
 
1353
 
 
1354
                while (current_token == MarkupTokenType.START_ELEMENT) {
 
1355
                        if (reader.get_attribute ("introspectable") == "0") {
 
1356
                                skip_element ();
 
1357
                                continue;
 
1358
                        }
 
1359
 
 
1360
                        if (reader.name == "field") {
 
1361
                                st.add_field (parse_field ());
 
1362
                        } else if (reader.name == "constructor") {
 
1363
                                parse_constructor ();
 
1364
                        } else if (reader.name == "method") {
 
1365
                                st.add_method (parse_method ("method"));
 
1366
                        } else if (reader.name == "record") {
 
1367
                                Struct s = parse_record ();
 
1368
                                var fs = s.get_fields ();
 
1369
                                foreach (var f in fs) {
 
1370
                                        f.set_cname (s.get_cname () + "." + f.get_cname ());
 
1371
                                        f.name = s.name + "_" + f.name;
 
1372
                                        st.add_field (f);
 
1373
                                }
 
1374
                        } else {
 
1375
                                // error
 
1376
                                Report.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader.name));
 
1377
                                break;
 
1378
                        }
 
1379
                }
 
1380
 
 
1381
                end_element ("union");
 
1382
                return st;
 
1383
        }
 
1384
 
 
1385
        Constant parse_constant () {
 
1386
                start_element ("constant");
 
1387
                string name = reader.get_attribute ("name");
 
1388
                next ();
 
1389
                var type = parse_type ();
 
1390
                var c = new Constant (name, type, null, get_current_src ());
 
1391
                c.access = SymbolAccessibility.PUBLIC;
 
1392
                c.external = true;
 
1393
                end_element ("constant");
 
1394
                return c;
 
1395
        }
 
1396
 
 
1397
        public void parse_metadata (string metadata_filename) {
 
1398
                if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
 
1399
                        try {
 
1400
                                string metadata;
 
1401
                                FileUtils.get_contents (metadata_filename, out metadata, null);
 
1402
                                
 
1403
                                foreach (string line in metadata.split ("\n")) {
 
1404
                                        if (line.has_prefix ("#")) {
 
1405
                                                // ignore comment lines
 
1406
                                                continue;
 
1407
                                        }
 
1408
 
 
1409
                                        string[] tokens = line.split (" ", 2);
 
1410
 
 
1411
                                        if (null == tokens[0]) {
 
1412
                                                continue;
 
1413
                                        }
 
1414
 
 
1415
                                        foreach (string attribute in tokens[1].split (" ")) {
 
1416
                                                string[] pair = attribute.split ("=", 2);
 
1417
                                                if (pair[0] == null || pair[1] == null) {
 
1418
                                                        continue;
 
1419
                                                }
 
1420
 
 
1421
                                                string key = "%s/@%s".printf (tokens[0], pair[0]);
 
1422
                                                attributes_map.set (key, pair[1].substring (1, pair[1].length - 2));
 
1423
                                        }
 
1424
                                }
 
1425
                        } catch (FileError e) {
 
1426
                                Report.error (null, "Unable to read metadata file: %s".printf (e.message));
 
1427
                        }
 
1428
                } else {
 
1429
                        Report.error (null, "Metadata file `%s' not found".printf (metadata_filename));
 
1430
                }
 
1431
        }
 
1432
 
 
1433
        void add_package_name (string name) {
 
1434
                if (package_names == null) {
 
1435
                        package_names = new string[0];
 
1436
                }
 
1437
 
 
1438
                foreach (var existing in package_names) {
 
1439
                        if (name == existing) {
 
1440
                                return;
 
1441
                        }
 
1442
                }
 
1443
 
 
1444
                package_names += name;
 
1445
        }
 
1446
 
 
1447
        public string[]? get_package_names () {
 
1448
                return package_names;
 
1449
        }
 
1450
}
 
1451