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

« back to all changes in this revision

Viewing changes to .pc/90_revert_use_new_gir_version.patch/codegen/valagirwriter.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
/* valagirwriter.vala
 
2
 *
 
3
 * Copyright (C) 2008-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
 */
 
22
 
 
23
using GLib;
 
24
 
 
25
/**
 
26
 * Code visitor generating .gir file for the public interface.
 
27
 */
 
28
public class Vala.GIRWriter : CodeVisitor {
 
29
        private CodeContext context;
 
30
        private string directory;
 
31
        private string gir_namespace;
 
32
        private string gir_version;
 
33
 
 
34
        StringBuilder buffer = new StringBuilder();
 
35
        FileStream stream;
 
36
        Vala.HashSet<Namespace> unannotated_namespaces = new Vala.HashSet<Namespace>();
 
37
        Vala.HashSet<Namespace> our_namespaces = new Vala.HashSet<Namespace>();
 
38
 
 
39
        int indent;
 
40
 
 
41
        private TypeSymbol gobject_type;
 
42
 
 
43
        private struct GIRNamespace {
 
44
                public GIRNamespace (string ns, string version) {
 
45
                        this.ns = ns; this.version = version;
 
46
                }
 
47
                public string ns;
 
48
                public string version;
 
49
                public bool equal (GIRNamespace g) {
 
50
                        return ((ns == g.ns) && (version == g.version));
 
51
                }
 
52
        }
 
53
 
 
54
        private ArrayList<GIRNamespace?> externals = new ArrayList<GIRNamespace?> ((EqualFunc) GIRNamespace.equal);
 
55
 
 
56
        public void write_includes() {
 
57
                foreach (var i in externals) {
 
58
                        write_indent_stream ();
 
59
                        stream.printf ("<include name=\"%s\" version=\"%s\"/>\n", i.ns, i.version);
 
60
                }
 
61
        }
 
62
 
 
63
 
 
64
        /**
 
65
         * Writes the public interface of the specified code context into the
 
66
         * specified file.
 
67
         *
 
68
         * @param context  a code context
 
69
         * @param filename a relative or absolute filename
 
70
         */
 
71
        public void write_file (CodeContext context, string directory, string gir_namespace, string gir_version, string package) {
 
72
                this.context = context;
 
73
                this.directory = directory;
 
74
                this.gir_namespace = gir_namespace;
 
75
                this.gir_version = gir_version;
 
76
 
 
77
                var root_symbol = context.root;
 
78
                var glib_ns = root_symbol.scope.lookup ("GLib");
 
79
                gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
 
80
 
 
81
                write_package (package);
 
82
 
 
83
                context.accept (this);
 
84
 
 
85
                indent--;
 
86
                buffer.append_printf ("</repository>\n");
 
87
 
 
88
                string filename = "%s%c%s-%s.gir".printf (directory, Path.DIR_SEPARATOR, gir_namespace, gir_version);
 
89
                stream = FileStream.open (filename, "w");
 
90
                if (stream == null) {
 
91
                        Report.error (null, "unable to open `%s' for writing".printf (filename));
 
92
                        return;
 
93
                }
 
94
 
 
95
                stream.printf ("<?xml version=\"1.0\"?>\n");
 
96
 
 
97
                stream.printf ("<repository version=\"1.2\"");
 
98
                stream.printf (" xmlns=\"http://www.gtk.org/introspection/core/1.0\"");
 
99
                stream.printf (" xmlns:c=\"http://www.gtk.org/introspection/c/1.0\"");
 
100
                stream.printf (" xmlns:glib=\"http://www.gtk.org/introspection/glib/1.0\"");
 
101
                stream.printf (">\n");
 
102
                indent++;
 
103
 
 
104
                write_includes();
 
105
                indent--;
 
106
 
 
107
                stream.puts (buffer.str);
 
108
                stream = null;
 
109
 
 
110
                foreach (var ns in unannotated_namespaces) {
 
111
                        if (!our_namespaces.contains(ns)) {
 
112
                                Report.warning (ns.source_reference, "Namespace %s does not have a GIR namespace and version annotation".printf (ns.name));
 
113
                        }
 
114
                }
 
115
                foreach (var ns in our_namespaces) {
 
116
                        ns.source_reference.file.gir_namespace = gir_namespace;
 
117
                        ns.source_reference.file.gir_version = gir_version;
 
118
                }
 
119
        }
 
120
 
 
121
        private void write_package (string package) {
 
122
                write_indent ();
 
123
                buffer.append_printf ("<package name=\"%s\"/>\n", package);
 
124
        }
 
125
 
 
126
        private void write_c_includes (Namespace ns) {
 
127
                // Collect C header filenames
 
128
                Set<string> header_filenames = new HashSet<string> (str_hash, str_equal);
 
129
                foreach (string c_header_filename in ns.get_cheader_filenames ()) {
 
130
                        header_filenames.add (c_header_filename);
 
131
                }
 
132
                foreach (Symbol symbol in ns.scope.get_symbol_table ().get_values ()) {
 
133
                        foreach (string c_header_filename in symbol.get_cheader_filenames ()) {
 
134
                                header_filenames.add (c_header_filename);
 
135
                        }
 
136
                }
 
137
 
 
138
                // Generate c:include tags
 
139
                foreach (string c_header_filename in header_filenames) {
 
140
                        write_c_include (c_header_filename);
 
141
                }
 
142
        }
 
143
 
 
144
        private void write_c_include (string name) {
 
145
                write_indent ();
 
146
                buffer.append_printf ("<c:include name=\"%s\"/>\n", name);
 
147
        }
 
148
 
 
149
        public override void visit_namespace (Namespace ns) {
 
150
                if (ns.external_package) {
 
151
                        return;
 
152
                }
 
153
 
 
154
                if (ns.name == null)  {
 
155
                        // global namespace
 
156
                        ns.accept_children (this);
 
157
                        return;
 
158
                }
 
159
 
 
160
                if (ns.parent_symbol.name != null) {
 
161
                        // nested namespace
 
162
                        // not supported in GIR at the moment
 
163
                        return;
 
164
                }
 
165
 
 
166
                write_c_includes (ns);
 
167
 
 
168
                write_indent ();
 
169
                buffer.append_printf ("<namespace name=\"%s\" version=\"%s\"", gir_namespace, gir_version);
 
170
                string? cprefix = ns.get_cprefix ();
 
171
                if (cprefix != null) {
 
172
                        buffer.append_printf (" c:prefix=\"%s\"", cprefix);
 
173
                }
 
174
                buffer.append_printf (">\n");
 
175
                indent++;
 
176
 
 
177
                write_annotations (ns);
 
178
 
 
179
                ns.accept_children (this);
 
180
 
 
181
                indent--;
 
182
                write_indent ();
 
183
                buffer.append_printf ("</namespace>\n");
 
184
                our_namespaces.add(ns);
 
185
        }
 
186
 
 
187
        public override void visit_class (Class cl) {
 
188
                if (cl.external_package) {
 
189
                        return;
 
190
                }
 
191
 
 
192
                if (!check_accessibility (cl)) {
 
193
                        return;
 
194
                }
 
195
 
 
196
                if (cl.is_subtype_of (gobject_type)) {
 
197
                        string gtype_struct_name = cl.name + "Class";
 
198
 
 
199
                        write_indent ();
 
200
                        buffer.append_printf ("<class name=\"%s\"", cl.name);
 
201
                        write_gtype_attributes (cl);
 
202
                        buffer.append_printf (" glib:type-struct=\"%s\"", gtype_struct_name);
 
203
                        buffer.append_printf (" parent=\"%s\"", gi_type_name (cl.base_class));
 
204
                        if (cl.is_abstract) {
 
205
                                buffer.append_printf (" abstract=\"1\"");
 
206
                        }
 
207
                        buffer.append_printf (">\n");
 
208
                        indent++;
 
209
 
 
210
                        // write implemented interfaces
 
211
                        foreach (DataType base_type in cl.get_base_types ()) {
 
212
                                var object_type = (ObjectType) base_type;
 
213
                                if (object_type.type_symbol is Interface) {
 
214
                                        write_indent ();
 
215
                                        buffer.append_printf ("<implements name=\"%s\"/>\n", gi_type_name (object_type.type_symbol));
 
216
                                }
 
217
                        }
 
218
 
 
219
                        write_annotations (cl);
 
220
 
 
221
                        write_indent ();
 
222
                        buffer.append_printf ("<field name=\"parent_instance\">\n");
 
223
                        indent++;
 
224
                        write_indent ();
 
225
                        buffer.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (cl.base_class), cl.base_class.get_cname ());
 
226
                        indent--;
 
227
                        write_indent ();
 
228
                        buffer.append_printf("</field>\n");
 
229
 
 
230
                        write_indent ();
 
231
                        buffer.append_printf ("<field name=\"priv\">\n");
 
232
                        indent++;
 
233
                        write_indent ();
 
234
                        buffer.append_printf ("<type name=\"%sPrivate\" c:type=\"%sPrivate*\"/>\n", cl.name, cl.get_cname ());
 
235
                        indent--;
 
236
                        write_indent ();
 
237
                        buffer.append_printf("</field>\n");
 
238
 
 
239
                        cl.accept_children (this);
 
240
 
 
241
                        indent--;
 
242
                        write_indent ();
 
243
                        buffer.append_printf ("</class>\n");
 
244
 
 
245
                        write_indent ();
 
246
                        buffer.append_printf ("<record name=\"%s\"", gtype_struct_name);
 
247
                        write_ctype_attributes (cl, "Class");
 
248
                        buffer.append_printf (" glib:is-gtype-struct-for=\"%s\"", cl.name);
 
249
                        buffer.append_printf (">\n");
 
250
                        indent++;
 
251
 
 
252
                        write_indent ();
 
253
                        buffer.append_printf ("<field name=\"parent_class\">\n");
 
254
                        indent++;
 
255
                        write_indent ();
 
256
                        buffer.append_printf ("<type name=\"%sClass\" c:type=\"%sClass\"/>\n", gi_type_name (cl.base_class), cl.base_class.get_cname ());
 
257
                        indent--;
 
258
                        write_indent ();
 
259
                        buffer.append_printf ("</field>\n");
 
260
 
 
261
                        foreach (Method m in cl.get_methods ()) {
 
262
                                if (m.is_abstract || m.is_virtual) {
 
263
                                        write_indent ();
 
264
                                        buffer.append_printf("<field name=\"%s\">\n", m.name);
 
265
                                        indent++;
 
266
                                        write_signature(m, "callback", true);
 
267
                                        indent--;
 
268
                                        write_indent ();
 
269
                                        buffer.append_printf ("</field>\n");
 
270
                                }
 
271
                        }
 
272
 
 
273
                        foreach (Signal sig in cl.get_signals ()) {
 
274
                                if (sig.default_handler != null) {
 
275
                                        write_indent ();
 
276
                                        buffer.append_printf ("<field name=\"%s\">\n", sig.name);
 
277
                                        indent++;
 
278
                                        write_signature (sig.default_handler, "callback", true);
 
279
                                        indent--;
 
280
                                        write_indent ();
 
281
                                        buffer.append_printf ("</field>\n");
 
282
                                }
 
283
                        }
 
284
 
 
285
 
 
286
                        indent--;
 
287
                        write_indent ();
 
288
                        buffer.append_printf ("</record>\n");
 
289
 
 
290
                        write_indent ();
 
291
                        buffer.append_printf ("<record name=\"%sPrivate\" c:type=\"%sPrivate\" disguised=\"1\"/>\n", cl.name, cl.get_cname ());
 
292
                } else {
 
293
                        write_indent ();
 
294
                        buffer.append_printf ("<record name=\"%s\"", cl.name);
 
295
                        buffer.append_printf (">\n");
 
296
                        indent++;
 
297
 
 
298
                        write_annotations (cl);
 
299
 
 
300
                        cl.accept_children (this);
 
301
 
 
302
                        indent--;
 
303
                        write_indent ();
 
304
                        buffer.append_printf ("</record>\n");
 
305
                }
 
306
        }
 
307
 
 
308
        public override void visit_struct (Struct st) {
 
309
                if (st.external_package) {
 
310
                        return;
 
311
                }
 
312
 
 
313
                if (!check_accessibility (st)) {
 
314
                        return;
 
315
                }
 
316
 
 
317
                write_indent ();
 
318
                buffer.append_printf ("<record name=\"%s\"", st.name);
 
319
                buffer.append_printf (">\n");
 
320
                indent++;
 
321
 
 
322
                write_annotations (st);
 
323
 
 
324
                st.accept_children (this);
 
325
 
 
326
                indent--;
 
327
                write_indent ();
 
328
                buffer.append_printf ("</record>\n");
 
329
        }
 
330
 
 
331
        public override void visit_interface (Interface iface) {
 
332
                if (iface.external_package) {
 
333
                        return;
 
334
                }
 
335
 
 
336
                if (!check_accessibility (iface)) {
 
337
                        return;
 
338
                }
 
339
 
 
340
                string gtype_struct_name = iface.name + "Iface";
 
341
 
 
342
                write_indent ();
 
343
                buffer.append_printf ("<interface name=\"%s\"", iface.name);
 
344
                write_gtype_attributes (iface);
 
345
                buffer.append_printf (" glib:type-struct=\"%s\"", gtype_struct_name);
 
346
                buffer.append_printf (">\n");
 
347
                indent++;
 
348
 
 
349
                // write prerequisites
 
350
                if (iface.get_prerequisites ().size > 0) {
 
351
                        foreach (DataType base_type in iface.get_prerequisites ()) {
 
352
                                write_indent ();
 
353
                                buffer.append_printf ("<prerequisite name=\"%s\"/>\n", gi_type_name (((ObjectType) base_type).type_symbol));
 
354
                        }
 
355
                }
 
356
 
 
357
                write_annotations (iface);
 
358
                iface.accept_children (this);
 
359
 
 
360
                indent--;
 
361
                write_indent ();
 
362
                buffer.append_printf ("</interface>\n");
 
363
 
 
364
                write_indent ();
 
365
                buffer.append_printf ("<record name=\"%s\"", gtype_struct_name);
 
366
                write_ctype_attributes (iface, "Iface");
 
367
                buffer.append_printf (" glib:is-gtype-struct-for=\"%s\"", iface.name);
 
368
                buffer.append_printf (">\n");
 
369
                indent++;
 
370
 
 
371
                foreach (Method m in iface.get_methods ()) {
 
372
                        if (m.is_abstract || m.is_virtual) {
 
373
                                write_signature(m, "callback", true);
 
374
                        }
 
375
                }
 
376
 
 
377
                indent--;
 
378
                write_indent ();
 
379
                buffer.append_printf ("</record>\n");
 
380
        }
 
381
 
 
382
        public override void visit_enum (Enum en) {
 
383
                if (en.external_package) {
 
384
                        return;
 
385
                }
 
386
 
 
387
                if (!check_accessibility (en)) {
 
388
                        return;
 
389
                }
 
390
 
 
391
                write_indent ();
 
392
                buffer.append_printf ("<enumeration name=\"%s\"", en.name);
 
393
                write_gtype_attributes (en);
 
394
                buffer.append_printf (">\n");
 
395
                indent++;
 
396
 
 
397
                write_annotations (en);
 
398
 
 
399
                enum_value = 0;
 
400
                en.accept_children (this);
 
401
 
 
402
                indent--;
 
403
                write_indent ();
 
404
                buffer.append_printf ("</enumeration>\n");
 
405
        }
 
406
 
 
407
        private int enum_value;
 
408
 
 
409
        public override void visit_enum_value (EnumValue ev) {
 
410
                write_indent ();
 
411
                buffer.append_printf ("<member name=\"%s\" c:identifier=\"%s\"", ev.name.down (), ev.get_cname ());
 
412
                if (ev.value != null) {
 
413
                        string value = literal_expression_to_value_string (ev.value);
 
414
                        buffer.append_printf (" value=\"%s\"", value);
 
415
                } else {
 
416
                        buffer.append_printf (" value=\"%d\"", enum_value++);
 
417
                }
 
418
                buffer.append_printf ("/>\n");
 
419
        }
 
420
 
 
421
        public override void visit_error_domain (ErrorDomain edomain) {
 
422
                if (edomain.external_package) {
 
423
                        return;
 
424
                }
 
425
 
 
426
                if (!check_accessibility (edomain)) {
 
427
                        return;
 
428
                }
 
429
 
 
430
                write_indent ();
 
431
                buffer.append_printf ("<errordomain name=\"%s\"", edomain.name);
 
432
                buffer.append_printf (" get-quark=\"%squark\"", edomain.get_lower_case_cprefix ());
 
433
                buffer.append_printf (" codes=\"%s\"", edomain.name);
 
434
                buffer.append_printf (">\n");
 
435
 
 
436
                write_annotations (edomain);
 
437
 
 
438
                buffer.append_printf ("</errordomain>\n");
 
439
 
 
440
                write_indent ();
 
441
                buffer.append_printf ("<enumeration name=\"%s\"", edomain.name);
 
442
                write_ctype_attributes (edomain);
 
443
                buffer.append_printf (">\n");
 
444
                indent++;
 
445
 
 
446
                enum_value = 0;
 
447
                edomain.accept_children (this);
 
448
 
 
449
                indent--;
 
450
                write_indent ();
 
451
                buffer.append_printf ("</enumeration>\n");
 
452
        }
 
453
 
 
454
        public override void visit_error_code (ErrorCode ecode) {
 
455
                write_indent ();
 
456
                buffer.append_printf ("<member name=\"%s\" c:identifier=\"%s\"", ecode.name.down (), ecode.get_cname ());
 
457
                if (ecode.value != null) {
 
458
                        string value = literal_expression_to_value_string (ecode.value);
 
459
                        buffer.append_printf (" value=\"%s\"", value);
 
460
                } else {
 
461
                        buffer.append_printf (" value=\"%d\"", enum_value++);
 
462
                }
 
463
                buffer.append_printf ("/>\n");
 
464
        }
 
465
 
 
466
        public override void visit_constant (Constant c) {
 
467
                if (c.external_package) {
 
468
                        return;
 
469
                }
 
470
 
 
471
                if (!check_accessibility (c)) {
 
472
                        return;
 
473
                }
 
474
 
 
475
                //TODO Add better constant evaluation
 
476
                var initializer = c.value;
 
477
                string value = literal_expression_to_value_string (initializer);
 
478
 
 
479
                write_indent ();
 
480
                buffer.append_printf ("<constant name=\"%s\" c:identifier=\"%s\"", c.name, c.get_cname ());
 
481
                buffer.append_printf (" value=\"%s\"", value);
 
482
                buffer.append_printf (">\n");
 
483
                indent++;
 
484
 
 
485
                write_type (initializer.value_type);
 
486
 
 
487
                indent--;
 
488
                write_indent ();
 
489
                buffer.append_printf ("</constant>\n");
 
490
        }
 
491
 
 
492
        public override void visit_field (Field f) {
 
493
                if (f.external_package) {
 
494
                        return;
 
495
                }
 
496
 
 
497
                if (!check_accessibility (f)) {
 
498
                        return;
 
499
                }
 
500
 
 
501
                write_indent ();
 
502
                buffer.append_printf ("<field name=\"%s\"", f.get_cname ());
 
503
                if (f.variable_type.nullable) {
 
504
                        buffer.append_printf (" allow-none=\"1\"");
 
505
                }
 
506
                buffer.append_printf (">\n");
 
507
                indent++;
 
508
 
 
509
                write_annotations (f);
 
510
 
 
511
                write_type (f.variable_type);
 
512
 
 
513
                indent--;
 
514
                write_indent ();
 
515
                buffer.append_printf ("</field>\n");
 
516
        }
 
517
 
 
518
        private void write_implicit_params (DataType type, ref int index, bool has_array_length, string name, ParameterDirection direction) {
 
519
                if (type is ArrayType && has_array_length) {
 
520
                        var int_type = new IntegerType (CodeContext.get ().root.scope.lookup ("int") as Struct);
 
521
                        write_param_or_return (int_type, "parameter", ref index, has_array_length, "%s_length1".printf (name), direction);
 
522
                } else if (type is DelegateType) {
 
523
                        var data_type = new PointerType (new VoidType ());
 
524
                        write_param_or_return (data_type, "parameter", ref index, false, "%s_target".printf (name), direction);
 
525
                        if (type.value_owned) {
 
526
                                var notify_type = new DelegateType (CodeContext.get ().root.scope.lookup ("GLib").scope.lookup ("DestroyNotify") as Delegate);
 
527
                                write_param_or_return (notify_type, "parameter", ref index, false, "%s_target_destroy_notify".printf (name), direction);
 
528
                        }
 
529
                }
 
530
        }
 
531
 
 
532
        private void write_params_and_return (List<FormalParameter> params, DataType? return_type, bool return_array_length, bool constructor = false, DataType? instance_type = null, bool user_data = false) {
 
533
                int last_index = 0;
 
534
                if (params.size != 0 || instance_type != null || (return_type is ArrayType && return_array_length) || (return_type is DelegateType)) {
 
535
                        write_indent ();
 
536
                        buffer.append_printf ("<parameters>\n");
 
537
                        indent++;
 
538
                        int index = 1;
 
539
 
 
540
                        if (instance_type != null) {
 
541
                                write_param_or_return (instance_type, "parameter", ref index, false, "self");
 
542
                        }
 
543
 
 
544
                        foreach (FormalParameter param in params) {
 
545
                                write_param_or_return (param.variable_type, "parameter", ref index, !param.no_array_length, param.name, param.direction);
 
546
 
 
547
                                write_implicit_params (param.variable_type, ref index, !param.no_array_length, param.name, param.direction);
 
548
                        }
 
549
 
 
550
                        last_index = index - 1;
 
551
                        write_implicit_params (return_type, ref index, return_array_length, "result", ParameterDirection.OUT);
 
552
 
 
553
                        if (user_data) {
 
554
                                write_indent ();
 
555
                                buffer.append_printf ("<parameter name=\"user_data\" transfer-ownership=\"none\" closure=\"%d\">\n", index);
 
556
                                indent++;
 
557
                                write_indent ();
 
558
                                buffer.append_printf ("<type name=\"gpointer\" c:type=\"void*\"/>\n");
 
559
                                indent--;
 
560
                                write_indent ();
 
561
                                buffer.append_printf ("</parameter>\n");
 
562
                        }
 
563
 
 
564
                        indent--;
 
565
                        write_indent ();
 
566
                        buffer.append_printf ("</parameters>\n");
 
567
                }
 
568
 
 
569
                if (return_type != null) {
 
570
                        write_param_or_return (return_type, "return-value", ref last_index, return_array_length, null, ParameterDirection.IN, constructor);
 
571
                }
 
572
        }
 
573
 
 
574
        public override void visit_delegate (Delegate cb) {
 
575
                if (cb.external_package) {
 
576
                        return;
 
577
                }
 
578
 
 
579
                if (!check_accessibility (cb)) {
 
580
                        return;
 
581
                }
 
582
 
 
583
                write_indent ();
 
584
                buffer.append_printf ("<callback name=\"%s\"", cb.name);
 
585
                buffer.append_printf (" c:type=\"%s\"", cb.get_cname ());
 
586
                if (cb.tree_can_fail) {
 
587
                        buffer.append_printf (" throws=\"1\"");
 
588
                }
 
589
                buffer.append_printf (">\n");
 
590
                indent++;
 
591
 
 
592
                write_annotations (cb);
 
593
 
 
594
                write_params_and_return (cb.get_parameters (), cb.return_type, !cb.no_array_length, false, null, cb.has_target);
 
595
 
 
596
                indent--;
 
597
                write_indent ();
 
598
                buffer.append_printf ("</callback>\n");
 
599
        }
 
600
 
 
601
        public override void visit_method (Method m) {
 
602
                if (m.external_package) {
 
603
                        return;
 
604
                }
 
605
 
 
606
                // don't write interface implementation unless it's an abstract or virtual method
 
607
                if (!check_accessibility (m) || m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
 
608
                        return;
 
609
                }
 
610
 
 
611
                string tag_name = "method";
 
612
                var parent = m.parent_symbol;
 
613
                if (parent is Namespace || m.binding == MemberBinding.STATIC) {
 
614
                        tag_name = "function";
 
615
                }
 
616
 
 
617
                write_signature (m, tag_name);
 
618
 
 
619
                if (m.is_abstract || m.is_virtual) {
 
620
                        write_signature (m, "virtual-method", false);
 
621
                }
 
622
        }
 
623
 
 
624
        private void write_signature (Method m, string tag_name, bool instance = false) {
 
625
                if (m.coroutine) {
 
626
                        string finish_name = m.name;
 
627
                        if (finish_name.has_suffix ("_async")) {
 
628
                                finish_name = finish_name.substring (0, finish_name.length - "_async".length);
 
629
                        }
 
630
                        finish_name += "_finish";
 
631
                        do_write_signature (m, tag_name, instance, m.name, m.get_cname (), m.get_async_begin_parameters (), new VoidType (), false);
 
632
                        do_write_signature (m, tag_name, instance, finish_name, m.get_finish_cname (), m.get_async_end_parameters (), m.return_type, m.tree_can_fail);
 
633
                } else {
 
634
                        do_write_signature (m, tag_name, instance, m.name, m.get_cname (), m.get_parameters (), m.return_type, m.tree_can_fail);
 
635
                }
 
636
        }
 
637
 
 
638
        private void do_write_signature (Method m, string tag_name, bool instance, string name, string cname, List<Vala.FormalParameter> params, DataType return_type, bool can_fail) {
 
639
                write_indent ();
 
640
                buffer.append_printf ("<%s name=\"%s\"", tag_name, name);
 
641
                if (tag_name == "virtual-method") {
 
642
                        buffer.append_printf (" invoker=\"%s\"", name);
 
643
                } else if (tag_name == "callback") {
 
644
                        /* this is only used for vfuncs */
 
645
                        buffer.append_printf (" c:type=\"%s\"", name);
 
646
                } else {
 
647
                        buffer.append_printf (" c:identifier=\"%s\"", cname);
 
648
                }
 
649
                if (can_fail) {
 
650
                        buffer.append_printf (" throws=\"1\"");
 
651
                }
 
652
                buffer.append_printf (">\n");
 
653
                indent++;
 
654
 
 
655
                write_annotations (m);
 
656
 
 
657
                DataType instance_type = null;
 
658
                if (instance) {
 
659
                        instance_type = CCodeBaseModule.get_data_type_for_symbol ((TypeSymbol) m.parent_symbol);
 
660
                }
 
661
 
 
662
                write_params_and_return (params, return_type, !m.no_array_length, false, instance_type);
 
663
 
 
664
                indent--;
 
665
                write_indent ();
 
666
                buffer.append_printf ("</%s>\n", tag_name);
 
667
        }
 
668
        
 
669
        public override void visit_creation_method (CreationMethod m) {
 
670
                if (m.external_package) {
 
671
                        return;
 
672
                }
 
673
 
 
674
                if (!check_accessibility (m)) {
 
675
                        return;
 
676
                }
 
677
 
 
678
                write_indent ();
 
679
 
 
680
                if (m.parent_symbol is Class && m == ((Class)m.parent_symbol).default_construction_method ||
 
681
                        m.parent_symbol is Struct && m == ((Struct)m.parent_symbol).default_construction_method) {
 
682
                        buffer.append_printf ("<constructor name=\"new\" c:identifier=\"%s\"", m.get_cname ());
 
683
                } else {
 
684
                        buffer.append_printf ("<constructor name=\"%s\" c:identifier=\"%s\"", m.name, m.get_cname ());
 
685
                }
 
686
 
 
687
                if (m.tree_can_fail) {
 
688
                        buffer.append_printf (" throws=\"1\"");
 
689
                }
 
690
                buffer.append_printf (">\n");
 
691
                indent++;
 
692
 
 
693
                write_annotations (m);
 
694
 
 
695
 
 
696
                var datatype = CCodeBaseModule.get_data_type_for_symbol ((TypeSymbol) m.parent_symbol);
 
697
                write_params_and_return (m.get_parameters (), datatype, false, true);
 
698
 
 
699
                indent--;
 
700
                write_indent ();
 
701
                buffer.append_printf ("</constructor>\n");
 
702
        }
 
703
 
 
704
        public override void visit_property (Property prop) {
 
705
                if (!check_accessibility (prop) || prop.overrides || (prop.base_interface_property != null && !prop.is_abstract && !prop.is_virtual)) {
 
706
                        return;
 
707
                }
 
708
 
 
709
                write_indent ();
 
710
                buffer.append_printf ("<property name=\"%s\"", prop.get_canonical_name ());
 
711
                if (prop.get_accessor == null) {
 
712
                        buffer.append_printf (" readable=\"0\"");
 
713
                }
 
714
                if (prop.set_accessor != null) {
 
715
                        buffer.append_printf (" writable=\"1\"");
 
716
                        if (prop.set_accessor.construction) {
 
717
                                if (!prop.set_accessor.writable) {
 
718
                                        buffer.append_printf (" construct-only=\"1\"");
 
719
                                } else {
 
720
                                        buffer.append_printf (" construct=\"1\"");
 
721
                                }
 
722
                        }
 
723
                }
 
724
                buffer.append_printf (">\n");
 
725
                indent++;
 
726
 
 
727
                write_annotations (prop);
 
728
 
 
729
                write_type (prop.property_type);
 
730
 
 
731
                indent--;
 
732
                write_indent ();
 
733
                buffer.append_printf ("</property>\n");
 
734
        }
 
735
 
 
736
        public override void visit_signal (Signal sig) {
 
737
                if (!check_accessibility (sig)) {
 
738
                        return;
 
739
                }
 
740
                
 
741
                write_indent ();
 
742
                buffer.append_printf ("<glib:signal name=\"%s\"", sig.get_cname ());
 
743
                buffer.append_printf (">\n");
 
744
                indent++;
 
745
 
 
746
                write_annotations (sig);
 
747
 
 
748
                write_params_and_return (sig.get_parameters (), sig.return_type, false);
 
749
 
 
750
                indent--;
 
751
                write_indent ();
 
752
                buffer.append_printf ("</glib:signal>\n");
 
753
        }
 
754
 
 
755
        private void write_indent () {
 
756
                int i;
 
757
                
 
758
                for (i = 0; i < indent; i++) {
 
759
                        buffer.append_c ('\t');
 
760
                }
 
761
        }
 
762
 
 
763
        private void write_indent_stream () {
 
764
                int i;
 
765
 
 
766
                for (i = 0; i < indent; i++) {
 
767
                        stream.putc ('\t');
 
768
                }
 
769
        }
 
770
 
 
771
 
 
772
        private void write_param_or_return (DataType type, string tag, ref int index, bool has_array_length, string? name = null, ParameterDirection direction = ParameterDirection.IN, bool constructor = false) {
 
773
                write_indent ();
 
774
                buffer.append_printf ("<%s", tag);
 
775
                if (name != null) {
 
776
                        buffer.append_printf (" name=\"%s\"", name);
 
777
                }
 
778
                if (direction == ParameterDirection.REF) {
 
779
                        buffer.append_printf (" direction=\"inout\"");
 
780
                } else if (direction == ParameterDirection.OUT) {
 
781
                        buffer.append_printf (" direction=\"out\"");
 
782
                }
 
783
 
 
784
                DelegateType delegate_type = type as DelegateType;
 
785
 
 
786
                if ((type.value_owned && delegate_type == null) || constructor) {
 
787
                        buffer.append_printf (" transfer-ownership=\"full\"");
 
788
                } else {
 
789
                        buffer.append_printf (" transfer-ownership=\"none\"");
 
790
                }
 
791
                if (type.nullable) {
 
792
                        buffer.append_printf (" allow-none=\"1\"");
 
793
                }
 
794
 
 
795
                if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
 
796
                        buffer.append_printf (" closure=\"%i\"", index + 1);
 
797
                        if (type.value_owned) {
 
798
                                buffer.append_printf (" destroy=\"%i\"", index + 2);
 
799
                        }
 
800
                }
 
801
 
 
802
                buffer.append_printf (">\n");
 
803
                indent++;
 
804
 
 
805
                write_type (type, has_array_length ? index : -1);
 
806
 
 
807
                indent--;
 
808
                write_indent ();
 
809
                buffer.append_printf ("</%s>\n", tag);
 
810
                index++;
 
811
        }
 
812
 
 
813
        private void write_ctype_attributes (TypeSymbol symbol, string suffix = "") {
 
814
                buffer.append_printf (" c:type=\"%s%s\"", symbol.get_cname (), suffix);
 
815
        }
 
816
 
 
817
        private void write_gtype_attributes (TypeSymbol symbol) {
 
818
                write_ctype_attributes(symbol);
 
819
                buffer.append_printf (" glib:type-name=\"%s\"", symbol.get_cname ());
 
820
                buffer.append_printf (" glib:get-type=\"%sget_type\"", symbol.get_lower_case_cprefix ());
 
821
        }
 
822
 
 
823
        private void write_type (DataType type, int index = -1) {
 
824
                if (type is ArrayType) {
 
825
                        var array_type = (ArrayType) type;
 
826
 
 
827
                        write_indent ();
 
828
                        buffer.append_printf ("<array");
 
829
                        if (array_type.fixed_length) {
 
830
                                buffer.append_printf (" fixed-length\"%i\"", array_type.length);
 
831
                        } else if (index != -1) {
 
832
                                buffer.append_printf (" length=\"%i\"", index + 1);
 
833
                        }
 
834
                        buffer.append_printf (">\n");
 
835
                        indent++;
 
836
 
 
837
                        write_type (array_type.element_type);
 
838
 
 
839
                        indent--;
 
840
                        write_indent ();
 
841
                        buffer.append_printf ("</array>\n");
 
842
                } else if (type is VoidType) {
 
843
                        write_indent ();
 
844
                        buffer.append_printf ("<type name=\"none\"/>\n");
 
845
                } else if (type is PointerType) {
 
846
                        write_indent ();
 
847
                        buffer.append_printf ("<type name=\"gpointer\" c:type=\"%s\"/>\n", type.get_cname ());
 
848
                } else if (type.data_type != null) {
 
849
                        write_indent ();
 
850
                        buffer.append_printf ("<type name=\"%s\" c:type=\"%s\"", gi_type_name (type.data_type), type.get_cname ());
 
851
 
 
852
                        List<DataType> type_arguments = type.get_type_arguments ();
 
853
                        if (type_arguments.size == 0) {
 
854
                                buffer.append_printf ("/>\n");
 
855
                        } else {
 
856
                                buffer.append_printf (">\n");
 
857
                                indent++;
 
858
 
 
859
                                foreach (DataType type_argument in type_arguments) {
 
860
                                        write_type (type_argument);
 
861
                                }
 
862
 
 
863
                                indent--;
 
864
                                write_indent ();
 
865
                                buffer.append_printf ("</type>\n");
 
866
                        }
 
867
                } else if (type is DelegateType) {
 
868
                        var deleg_type = (DelegateType) type;
 
869
                        write_indent ();
 
870
                        buffer.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (deleg_type.delegate_symbol), type.get_cname ());
 
871
                } else if (type is GenericType) {
 
872
                        // generic type parameters not supported in GIR
 
873
                        write_indent ();
 
874
                        buffer.append ("<type name=\"gpointer\" c:type=\"gpointer\"/>\n");
 
875
                } else {
 
876
                        write_indent ();
 
877
                        buffer.append_printf ("<type name=\"%s\"/>\n", type.to_string ());
 
878
                }
 
879
        }
 
880
 
 
881
        private void write_annotations (CodeNode node) {
 
882
                foreach (Attribute attr in node.attributes) {
 
883
                        string name = camel_case_to_canonical (attr.name);
 
884
                        foreach (string arg_name in attr.args.get_keys ()) {
 
885
                                var arg = attr.args.get (arg_name);
 
886
 
 
887
                                string value = literal_expression_to_value_string ((Literal) arg);
 
888
 
 
889
                                if (value != null) {
 
890
                                        write_indent ();
 
891
                                        buffer.append_printf ("<annotation key=\"%s.%s\" value=\"%s\"/>\n",
 
892
                                                name, camel_case_to_canonical (arg_name), value);
 
893
                                }
 
894
                        }
 
895
                }
 
896
        }
 
897
 
 
898
        private string gi_type_name (TypeSymbol type_symbol) {
 
899
                Symbol parent = type_symbol.parent_symbol;
 
900
                if (parent is Namespace) {
 
901
                        Namespace ns = parent as Namespace;
 
902
                        if (ns.gir_name != null) {
 
903
                                if (type_symbol.source_reference.file.gir_namespace != null) {
 
904
                                        GIRNamespace external = GIRNamespace (type_symbol.source_reference.file.gir_namespace, type_symbol.source_reference.file.gir_version);
 
905
                                        if (!externals.contains (external)) {
 
906
                                                externals.add (external);
 
907
                                        }
 
908
                                        return "%s.%s".printf (type_symbol.source_reference.file.gir_namespace, type_symbol.gir_name);
 
909
                                } else {
 
910
                                        unannotated_namespaces.add(ns);
 
911
                                }
 
912
                        }
 
913
                }
 
914
 
 
915
                return type_symbol.get_full_gir_name();
 
916
        }
 
917
 
 
918
        private string? literal_expression_to_value_string (Expression literal) {
 
919
                if (literal is StringLiteral) {
 
920
                        var lit = literal as StringLiteral;
 
921
                        if (lit != null) {
 
922
                                return Markup.escape_text (lit.eval ());
 
923
                        }
 
924
                } else if (literal is CharacterLiteral) {
 
925
                        return "%c".printf ((char) ((CharacterLiteral) literal).get_char ());
 
926
                } else if (literal is BooleanLiteral) {
 
927
                        return ((BooleanLiteral) literal).value ? "true" : "false";
 
928
                } else if (literal is RealLiteral) {
 
929
                        return ((RealLiteral) literal).value;
 
930
                } else if (literal is IntegerLiteral) {
 
931
                        return ((IntegerLiteral) literal).value;
 
932
                } else if (literal is UnaryExpression) {
 
933
                        var unary = (UnaryExpression) literal;
 
934
                        if (unary.operator == UnaryOperator.MINUS) {
 
935
                                if (unary.inner is RealLiteral) {
 
936
                                        return "-" + ((RealLiteral) unary.inner).value;
 
937
                                } else if (unary.inner is IntegerLiteral) {
 
938
                                        return "-" + ((IntegerLiteral) unary.inner).value;
 
939
                                }
 
940
                        }
 
941
                }
 
942
                return null;
 
943
        }
 
944
 
 
945
        private string camel_case_to_canonical (string name) {
 
946
                string[] parts = Symbol.camel_case_to_lower_case (name).split ("_");
 
947
                return string.joinv ("-", parts);
 
948
        }
 
949
 
 
950
        private bool check_accessibility (Symbol sym) {
 
951
                if (sym.access == SymbolAccessibility.PUBLIC ||
 
952
                    sym.access == SymbolAccessibility.PROTECTED) {
 
953
                        return true;
 
954
                }
 
955
 
 
956
                return false;
 
957
        }
 
958
}