3 * Copyright (C) 2008-2011 Jürg Billeter
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.
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.
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
20 * Jürg Billeter <j@bitron.ch>
26 * Code visitor generating .gir file for the public interface.
28 public class Vala
.GIRWriter
: CodeVisitor
{
29 private CodeContext context
;
30 private string directory
;
31 private string gir_namespace
;
32 private string gir_version
;
34 StringBuilder buffer
= new
StringBuilder();
36 Vala
.HashSet
<Namespace
> unannotated_namespaces
= new Vala
.HashSet
<Namespace
>();
37 Vala
.HashSet
<Namespace
> our_namespaces
= new Vala
.HashSet
<Namespace
>();
38 Vala
.ArrayList
<Vala
.Symbol
> hierarchy
= new Vala
.ArrayList
<Vala
.Symbol
>();
39 Vala
.ArrayList
<Vala
.CodeNode
> deferred
= new Vala
.ArrayList
<Vala
.CodeNode
>();
43 private TypeSymbol gobject_type
;
45 private struct GIRNamespace
{
46 public GIRNamespace (string ns
, string version
) {
47 this
.ns
= ns
; this
.version
= version
;
50 public string version
;
51 public bool equal (GIRNamespace g
) {
52 return ((ns
== g
.ns
) && (version
== g
.version
));
56 private ArrayList
<GIRNamespace?
> externals
= new ArrayList
<GIRNamespace?
> ((EqualFunc
) GIRNamespace
.equal
);
58 public void write_includes() {
59 foreach (var i
in externals
) {
60 write_indent_stream ();
61 stream
.printf ("<include name=\"%s\" version=\"%s\"/>\n", i
.ns
, i
.version
);
67 * Writes the public interface of the specified code context into the
70 * @param context a code context
71 * @param filename a relative or absolute filename
73 public void write_file (CodeContext context
, string directory
, string gir_namespace
, string gir_version
, string package
) {
74 this
.context
= context
;
75 this
.directory
= directory
;
76 this
.gir_namespace
= gir_namespace
;
77 this
.gir_version
= gir_version
;
79 var root_symbol
= context
.root
;
80 var glib_ns
= root_symbol
.scope
.lookup ("GLib");
81 gobject_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Object");
83 write_package (package
);
85 context
.accept (this
);
88 buffer
.append_printf ("</repository>\n");
90 string filename
= "%s%c%s-%s.gir".printf (directory
, Path
.DIR_SEPARATOR
, gir_namespace
, gir_version
);
91 stream
= FileStream
.open (filename
, "w");
93 Report
.error (null, "unable to open `%s' for writing".printf (filename
));
97 stream
.printf ("<?xml version=\"1.0\"?>\n");
99 stream
.printf ("<repository version=\"1.2\"");
100 stream
.printf (" xmlns=\"http://www.gtk.org/introspection/core/1.0\"");
101 stream
.printf (" xmlns:c=\"http://www.gtk.org/introspection/c/1.0\"");
102 stream
.printf (" xmlns:glib=\"http://www.gtk.org/introspection/glib/1.0\"");
103 stream
.printf (">\n");
109 stream
.puts (buffer
.str
);
112 foreach (var ns
in unannotated_namespaces
) {
113 if (!our_namespaces
.contains(ns
)) {
114 Report
.warning (ns
.source_reference
, "Namespace %s does not have a GIR namespace and version annotation".printf (ns
.name
));
117 foreach (var ns
in our_namespaces
) {
118 ns
.source_reference
.file
.gir_namespace
= gir_namespace
;
119 ns
.source_reference
.file
.gir_version
= gir_version
;
123 private void write_package (string package
) {
125 buffer
.append_printf ("<package name=\"%s\"/>\n", package
);
128 private void write_c_includes (Namespace ns
) {
129 // Collect C header filenames
130 Set
<string> header_filenames
= new HashSet
<string> (str_hash
, str_equal
);
131 foreach (string c_header_filename
in ns
.get_cheader_filenames ()) {
132 header_filenames
.add (c_header_filename
);
134 foreach (Symbol symbol
in ns
.scope
.get_symbol_table ().get_values ()) {
135 foreach (string c_header_filename
in symbol
.get_cheader_filenames ()) {
136 header_filenames
.add (c_header_filename
);
140 // Generate c:include tags
141 foreach (string c_header_filename
in header_filenames
) {
142 write_c_include (c_header_filename
);
146 private void write_c_include (string name
) {
148 buffer
.append_printf ("<c:include name=\"%s\"/>\n", name
);
151 public override void visit_namespace (Namespace ns
) {
152 if (ns
.external_package
) {
156 if (ns
.name
== null) {
158 hierarchy
.insert (0, ns
);
159 ns
.accept_children (this
);
160 hierarchy
.remove_at (0);
164 if (ns
.parent_symbol
.name
!= null) {
165 ns
.accept_children (this
);
169 write_c_includes (ns
);
172 buffer
.append_printf ("<namespace name=\"%s\" version=\"%s\"", gir_namespace
, gir_version
);
173 string? cprefix
= ns
.get_cprefix ();
174 if (cprefix
!= null) {
175 buffer
.append_printf (" c:prefix=\"%s\"", cprefix
);
177 buffer
.append_printf (">\n");
180 write_annotations (ns
);
182 hierarchy
.insert (0, ns
);
183 ns
.accept_children (this
);
184 hierarchy
.remove_at (0);
188 buffer
.append_printf ("</namespace>\n");
189 our_namespaces
.add(ns
);
194 private void write_symbol_attributes (Symbol symbol
) {
195 if (symbol
.deprecated
) {
196 buffer
.append_printf (" deprecated=\"%s\"", (symbol
.replacement
== null) ?
"" : "Use %s".printf (symbol
.replacement
));
197 if (symbol
.deprecated_since
!= null) {
198 buffer
.append_printf (" deprecated-version=\"%s\"", symbol
.deprecated_since
);
203 public override void visit_class (Class cl
) {
204 if (cl
.external_package
) {
208 if (!check_accessibility (cl
)) {
212 if (!(hierarchy
[0] is Namespace
)) {
217 if (cl
.is_subtype_of (gobject_type
)) {
218 string gtype_struct_name
= cl
.name
+ "Class";
221 buffer
.append_printf ("<class name=\"%s\"", get_gir_name (cl
));
222 write_gtype_attributes (cl
);
223 buffer
.append_printf (" glib:type-struct=\"%s\"", gtype_struct_name
);
224 buffer
.append_printf (" parent=\"%s\"", gi_type_name (cl
.base_class
));
225 if (cl
.is_abstract
) {
226 buffer
.append_printf (" abstract=\"1\"");
228 write_symbol_attributes (cl
);
229 buffer
.append_printf (">\n");
232 // write implemented interfaces
233 foreach (DataType base_type
in cl
.get_base_types ()) {
234 var object_type
= (ObjectType
) base_type
;
235 if (object_type
.type_symbol is Interface
) {
237 buffer
.append_printf ("<implements name=\"%s\"/>\n", gi_type_name (object_type
.type_symbol
));
241 write_annotations (cl
);
244 buffer
.append_printf ("<field name=\"parent_instance\">\n");
247 buffer
.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (cl
.base_class
), cl
.base_class
.get_cname ());
250 buffer
.append_printf("</field>\n");
253 buffer
.append_printf ("<field name=\"priv\">\n");
256 buffer
.append_printf ("<type name=\"%sPrivate\" c:type=\"%sPrivate*\"/>\n", cl
.name
, cl
.get_cname ());
259 buffer
.append_printf("</field>\n");
261 hierarchy
.insert (0, cl
);
262 cl
.accept_children (this
);
263 hierarchy
.remove_at (0);
267 buffer
.append_printf ("</class>\n");
270 buffer
.append_printf ("<record name=\"%s\"", gtype_struct_name
);
271 write_ctype_attributes (cl
, "Class");
272 buffer
.append_printf (" glib:is-gtype-struct-for=\"%s\"", cl
.name
);
273 buffer
.append_printf (">\n");
277 buffer
.append_printf ("<field name=\"parent_class\">\n");
280 buffer
.append_printf ("<type name=\"%sClass\" c:type=\"%sClass\"/>\n", gi_type_name (cl
.base_class
), cl
.base_class
.get_cname ());
283 buffer
.append_printf ("</field>\n");
285 foreach (Method m
in cl
.get_methods ()) {
286 if (m
.is_abstract
|| m
.is_virtual
) {
288 buffer
.append_printf("<field name=\"%s\">\n", m
.name
);
290 write_signature(m
, "callback", true);
293 buffer
.append_printf ("</field>\n");
297 foreach (Signal sig
in cl
.get_signals ()) {
298 if (sig
.default_handler
!= null) {
300 buffer
.append_printf ("<field name=\"%s\">\n", sig
.name
);
302 write_signature (sig
.default_handler
, "callback", true);
305 buffer
.append_printf ("</field>\n");
312 buffer
.append_printf ("</record>\n");
315 buffer
.append_printf ("<record name=\"%sPrivate\" c:type=\"%sPrivate\" disguised=\"1\"/>\n", cl
.name
, cl
.get_cname ());
318 buffer
.append_printf ("<record name=\"%s\"", get_gir_name (cl
));
319 write_symbol_attributes (cl
);
320 buffer
.append_printf (">\n");
323 write_annotations (cl
);
325 hierarchy
.insert (0, cl
);
326 cl
.accept_children (this
);
327 hierarchy
.remove_at (0);
331 buffer
.append_printf ("</record>\n");
337 public override void visit_struct (Struct st
) {
338 if (st
.external_package
) {
342 if (!check_accessibility (st
)) {
346 if (!(hierarchy
[0] is Namespace
)) {
352 buffer
.append_printf ("<record name=\"%s\"", get_gir_name (st
));
353 write_symbol_attributes (st
);
354 buffer
.append_printf (">\n");
357 write_annotations (st
);
359 hierarchy
.insert (0, st
);
360 st
.accept_children (this
);
361 hierarchy
.remove_at (0);
365 buffer
.append_printf ("</record>\n");
370 public override void visit_interface (Interface iface
) {
371 if (iface
.external_package
) {
375 if (!check_accessibility (iface
)) {
379 if (!(hierarchy
[0] is Namespace
)) {
380 deferred
.add (iface
);
384 string gtype_struct_name
= iface
.name
+ "Iface";
387 buffer
.append_printf ("<interface name=\"%s\"", get_gir_name (iface
));
388 write_gtype_attributes (iface
);
389 buffer
.append_printf (" glib:type-struct=\"%s\"", gtype_struct_name
);
390 write_symbol_attributes (iface
);
391 buffer
.append_printf (">\n");
394 // write prerequisites
395 if (iface
.get_prerequisites ().size
> 0) {
396 foreach (DataType base_type
in iface
.get_prerequisites ()) {
398 buffer
.append_printf ("<prerequisite name=\"%s\"/>\n", gi_type_name (((ObjectType
) base_type
).type_symbol
));
402 write_annotations (iface
);
404 hierarchy
.insert (0, iface
);
405 iface
.accept_children (this
);
406 hierarchy
.remove_at (0);
410 buffer
.append_printf ("</interface>\n");
413 buffer
.append_printf ("<record name=\"%s\"", gtype_struct_name
);
414 write_ctype_attributes (iface
, "Iface");
415 buffer
.append_printf (" glib:is-gtype-struct-for=\"%s\"", iface
.name
);
416 buffer
.append_printf (">\n");
420 buffer
.append_printf ("<field name=\"parent_iface\">\n");
423 buffer
.append_printf ("<type name=\"GObject.TypeInterface\" c:type=\"GTypeInterface\"/>\n");
426 buffer
.append_printf ("</field>\n");
428 foreach (Method m
in iface
.get_methods ()) {
429 if (m
.is_abstract
|| m
.is_virtual
) {
431 buffer
.append_printf("<field name=\"%s\">\n", m
.name
);
433 write_signature(m
, "callback", true);
436 buffer
.append_printf ("</field>\n");
442 buffer
.append_printf ("</record>\n");
447 private void visit_deferred () {
448 var nodes
= this
.deferred
;
449 this
.deferred
= new Vala
.ArrayList
<Vala
.CodeNode
>();
451 foreach (var node
in nodes
) {
456 private string?
get_gir_name (Symbol symbol
) {
457 string? gir_name
= null;
458 var h0
= hierarchy
[0];
460 for (Symbol? cur_sym
= symbol
; cur_sym
!= null ; cur_sym
= cur_sym
.parent_symbol
) {
465 gir_name
= cur_sym
.gir_name
.concat (gir_name
);
471 public override void visit_enum (Enum en
) {
472 if (en
.external_package
) {
476 if (!check_accessibility (en
)) {
480 if (!(hierarchy
[0] is Namespace
)) {
485 string element_name
= (en
.is_flags
) ?
"bitfield" : "enumeration";
488 buffer
.append_printf ("<%s name=\"%s\"", element_name
, get_gir_name (en
));
489 write_gtype_attributes (en
);
490 write_symbol_attributes (en
);
491 buffer
.append_printf (">\n");
494 write_annotations (en
);
497 hierarchy
.insert (0, en
);
498 en
.accept_children (this
);
499 hierarchy
.remove_at (0);
503 buffer
.append_printf ("</%s>\n", element_name
);
508 private int enum_value
;
510 public override void visit_enum_value (EnumValue ev
) {
512 var en
= (Enum
) hierarchy
[0];
513 buffer
.append_printf ("<member name=\"%s\" c:identifier=\"%s\"", ev
.name
.down (), ev
.get_cname ());
514 if (ev
.value
!= null) {
515 string value
= literal_expression_to_value_string (ev
.value
);
516 buffer
.append_printf (" value=\"%s\"", value
);
519 buffer
.append_printf (" value=\"%d\"", 1 << enum_value
++);
521 buffer
.append_printf (" value=\"%d\"", enum_value
++);
524 write_symbol_attributes (ev
);
525 buffer
.append_printf ("/>\n");
528 public override void visit_error_domain (ErrorDomain edomain
) {
529 if (edomain
.external_package
) {
533 if (!check_accessibility (edomain
)) {
538 buffer
.append_printf ("<errordomain name=\"%s\"", edomain
.name
);
539 buffer
.append_printf (" get-quark=\"%squark\"", edomain
.get_lower_case_cprefix ());
540 buffer
.append_printf (" codes=\"%s\"", edomain
.name
);
541 write_symbol_attributes (edomain
);
542 buffer
.append_printf (">\n");
544 write_annotations (edomain
);
546 buffer
.append_printf ("</errordomain>\n");
549 buffer
.append_printf ("<enumeration name=\"%s\"", edomain
.name
);
550 write_ctype_attributes (edomain
);
551 buffer
.append_printf (">\n");
555 hierarchy
.insert (0, edomain
);
556 edomain
.accept_children (this
);
557 hierarchy
.remove_at (0);
561 buffer
.append_printf ("</enumeration>\n");
566 public override void visit_error_code (ErrorCode ecode
) {
568 buffer
.append_printf ("<member name=\"%s\" c:identifier=\"%s\"", ecode
.name
.down (), ecode
.get_cname ());
569 if (ecode
.value
!= null) {
570 string value
= literal_expression_to_value_string (ecode
.value
);
571 buffer
.append_printf (" value=\"%s\"", value
);
573 buffer
.append_printf (" value=\"%d\"", enum_value
++);
575 write_symbol_attributes (ecode
);
576 buffer
.append_printf ("/>\n");
579 public override void visit_constant (Constant c
) {
580 if (c
.external_package
) {
584 if (!check_accessibility (c
)) {
588 //TODO Add better constant evaluation
589 var initializer
= c
.value
;
590 string value
= literal_expression_to_value_string (initializer
);
593 buffer
.append_printf ("<constant name=\"%s\" c:identifier=\"%s\"", c
.name
, c
.get_cname ());
594 buffer
.append_printf (" value=\"%s\"", value
);
595 write_symbol_attributes (c
);
596 buffer
.append_printf (">\n");
599 write_type (initializer
.value_type
);
603 buffer
.append_printf ("</constant>\n");
606 public override void visit_field (Field f
) {
607 if (f
.external_package
) {
611 if (!check_accessibility (f
)) {
616 buffer
.append_printf ("<field name=\"%s\"", f
.get_cname ());
617 if (f
.variable_type
.nullable
) {
618 buffer
.append_printf (" allow-none=\"1\"");
620 write_symbol_attributes (f
);
621 buffer
.append_printf (">\n");
624 write_annotations (f
);
626 write_type (f
.variable_type
);
630 buffer
.append_printf ("</field>\n");
633 private void write_implicit_params (DataType type
, ref int index
, bool has_array_length
, string name
, ParameterDirection direction
) {
634 if (type is ArrayType
&& has_array_length
) {
635 var int_type
= new
IntegerType (CodeContext
.get ().root
.scope
.lookup ("int") as Struct
);
636 write_param_or_return (int_type
, true, ref index
, has_array_length
, "%s_length1".printf (name
), direction
);
637 } else if (type is DelegateType
) {
638 var data_type
= new
PointerType (new
VoidType ());
639 write_param_or_return (data_type
, true, ref index
, false, "%s_target".printf (name
), direction
);
640 if (type
.value_owned
) {
641 var notify_type
= new
DelegateType (CodeContext
.get ().root
.scope
.lookup ("GLib").scope
.lookup ("DestroyNotify") as Delegate
);
642 write_param_or_return (notify_type
, true, ref index
, false, "%s_target_destroy_notify".printf (name
), direction
);
647 private void write_params_and_return (List
<Parameter
> params
, DataType? return_type
, bool return_array_length
, bool constructor
= false, DataType? instance_type
= null, bool user_data
= false) {
649 bool ret_is_struct
= return_type
!= null && return_type
.is_real_non_null_struct_type ();
650 if (params
.size
!= 0 || instance_type
!= null || (return_type is ArrayType
&& return_array_length
) || (return_type is DelegateType
) || ret_is_struct
) {
652 buffer
.append_printf ("<parameters>\n");
656 if (instance_type
!= null) {
657 write_param_or_return (instance_type
, true, ref index
, false, "self");
660 foreach (Parameter param
in params
) {
661 write_param_or_return (param
.variable_type
, true, ref index
, !param
.no_array_length
, param
.name
, param
.direction
);
663 write_implicit_params (param
.variable_type
, ref index
, !param
.no_array_length
, param
.name
, param
.direction
);
667 // struct returns are converted to parameters
668 write_param_or_return (return_type
, true, ref index
, false, "result", ParameterDirection
.OUT
, constructor
, true);
670 write_implicit_params (return_type
, ref index
, return_array_length
, "result", ParameterDirection
.OUT
);
673 last_index
= index
- 1;
677 buffer
.append_printf ("<parameter name=\"user_data\" transfer-ownership=\"none\" closure=\"%d\">\n", index
);
680 buffer
.append_printf ("<type name=\"gpointer\" c:type=\"void*\"/>\n");
683 buffer
.append_printf ("</parameter>\n");
688 buffer
.append_printf ("</parameters>\n");
691 if (return_type
!= null && !ret_is_struct
) {
692 write_param_or_return (return_type
, false, ref last_index
, return_array_length
, null, ParameterDirection
.IN
, constructor
);
693 } else if (ret_is_struct
) {
694 write_param_or_return (new
VoidType (), false, ref last_index
, false, null, ParameterDirection
.IN
);
698 public override void visit_delegate (Delegate cb
) {
699 if (cb
.external_package
) {
703 if (!check_accessibility (cb
)) {
708 buffer
.append_printf ("<callback name=\"%s\"", cb
.name
);
709 buffer
.append_printf (" c:type=\"%s\"", cb
.get_cname ());
710 if (cb
.tree_can_fail
) {
711 buffer
.append_printf (" throws=\"1\"");
713 write_symbol_attributes (cb
);
714 buffer
.append_printf (">\n");
717 write_annotations (cb
);
719 write_params_and_return (cb
.get_parameters (), cb
.return_type
, !cb
.no_array_length
, false, null, cb
.has_target
);
723 buffer
.append_printf ("</callback>\n");
726 public override void visit_method (Method m
) {
727 if (m
.external_package
) {
731 // don't write interface implementation unless it's an abstract or virtual method
732 if (!check_accessibility (m
) || m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
736 // check for unsupported types
737 if (!check_signature (m
)) {
741 string tag_name
= "method";
742 var parent
= this
.hierarchy
.get (0);
743 if (parent is Enum
) {
748 if (parent is Namespace
|| m
.binding
== MemberBinding
.STATIC
|| parent
!= m
.parent_symbol
) {
749 tag_name
= "function";
752 write_signature (m
, tag_name
);
754 if (m
.is_abstract
|| m
.is_virtual
) {
755 write_signature (m
, "virtual-method", false);
759 bool check_type (DataType type
) {
760 // gobject-introspection does not currently support va_list parameters
761 if (type
.get_cname () == "va_list") {
768 bool check_signature (Method m
) {
769 if (!check_type (m
.return_type
)) {
772 foreach (var param
in m
.get_parameters ()) {
773 if (param
.variable_type
== null || !check_type (param
.variable_type
)) {
780 private void write_signature (Method m
, string tag_name
, bool instance
= false) {
781 var parent
= this
.hierarchy
.get (0);
783 if (m
.parent_symbol
!= parent
) {
785 name
= m
.get_cname ();
786 var parent_prefix
= parent
.get_lower_case_cprefix ();
787 if (name
.has_prefix (parent_prefix
)) {
788 name
= name
.substring (parent_prefix
.length
);
795 string finish_name
= name
;
796 if (finish_name
.has_suffix ("_async")) {
797 finish_name
= finish_name
.substring (0, finish_name
.length
- "_async".length
);
799 finish_name
+= "_finish";
800 do_write_signature (m
, tag_name
, instance
, name
, m
.get_cname (), m
.get_async_begin_parameters (), new
VoidType (), false);
801 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
);
803 do_write_signature (m
, tag_name
, instance
, name
, m
.get_cname (), m
.get_parameters (), m
.return_type
, m
.tree_can_fail
);
807 private void do_write_signature (Method m
, string tag_name
, bool instance
, string name
, string cname
, List
<Vala
.Parameter
> params
, DataType return_type
, bool can_fail
) {
809 buffer
.append_printf ("<%s name=\"%s\"", tag_name
, name
);
810 if (tag_name
== "virtual-method") {
811 buffer
.append_printf (" invoker=\"%s\"", name
);
812 } else if (tag_name
== "callback") {
813 /* this is only used for vfuncs */
814 buffer
.append_printf (" c:type=\"%s\"", name
);
816 buffer
.append_printf (" c:identifier=\"%s\"", cname
);
819 buffer
.append_printf (" throws=\"1\"");
821 write_symbol_attributes (m
);
822 buffer
.append_printf (">\n");
825 write_annotations (m
);
827 DataType instance_type
= null;
829 instance_type
= CCodeBaseModule
.get_data_type_for_symbol ((TypeSymbol
) m
.parent_symbol
);
832 write_params_and_return (params
, return_type
, !m
.no_array_length
, false, instance_type
);
836 buffer
.append_printf ("</%s>\n", tag_name
);
839 public override void visit_creation_method (CreationMethod m
) {
840 if (m
.external_package
) {
844 if (!check_accessibility (m
)) {
850 bool is_struct
= m
.parent_symbol is Struct
;
851 // GI doesn't like constructors that return void type
852 string tag_name
= is_struct ?
"function" : "constructor";
854 if (m
.parent_symbol is Class
&& m
== ((Class
)m
.parent_symbol
).default_construction_method
||
855 m
.parent_symbol is Struct
&& m
== ((Struct
)m
.parent_symbol
).default_construction_method
) {
856 string m_name
= is_struct ?
"init" : "new";
857 buffer
.append_printf ("<%s name=\"%s\" c:identifier=\"%s\"", tag_name
, m_name
, m
.get_cname ());
859 buffer
.append_printf ("<%s name=\"%s\" c:identifier=\"%s\"", tag_name
, m
.name
, m
.get_cname ());
862 if (m
.tree_can_fail
) {
863 buffer
.append_printf (" throws=\"1\"");
865 buffer
.append_printf (">\n");
868 write_annotations (m
);
871 var datatype
= CCodeBaseModule
.get_data_type_for_symbol ((TypeSymbol
) m
.parent_symbol
);
872 write_params_and_return (m
.get_parameters (), datatype
, false, true);
876 buffer
.append_printf ("</%s>\n", tag_name
);
879 public override void visit_property (Property prop
) {
880 if (!check_accessibility (prop
) || prop
.overrides
|| (prop
.base_interface_property
!= null && !prop
.is_abstract
&& !prop
.is_virtual
)) {
885 buffer
.append_printf ("<property name=\"%s\"", prop
.get_canonical_name ());
886 if (prop
.get_accessor
== null) {
887 buffer
.append_printf (" readable=\"0\"");
889 if (prop
.set_accessor
!= null) {
890 buffer
.append_printf (" writable=\"1\"");
891 if (prop
.set_accessor
.construction
) {
892 if (!prop
.set_accessor
.writable
) {
893 buffer
.append_printf (" construct-only=\"1\"");
895 buffer
.append_printf (" construct=\"1\"");
899 write_symbol_attributes (prop
);
900 buffer
.append_printf (">\n");
903 write_annotations (prop
);
905 write_type (prop
.property_type
);
909 buffer
.append_printf ("</property>\n");
912 public override void visit_signal (Signal sig
) {
913 if (!check_accessibility (sig
)) {
918 buffer
.append_printf ("<glib:signal name=\"%s\"", sig
.get_cname ());
919 write_symbol_attributes (sig
);
920 buffer
.append_printf (">\n");
923 write_annotations (sig
);
925 write_params_and_return (sig
.get_parameters (), sig
.return_type
, false);
929 buffer
.append_printf ("</glib:signal>\n");
932 private void write_indent () {
935 for (i
= 0; i
< indent
; i
++) {
936 buffer
.append_c ('\t');
940 private void write_indent_stream () {
943 for (i
= 0; i
< indent
; i
++) {
949 private void write_param_or_return (DataType type
, bool is_parameter
, ref int index
, bool has_array_length
, string? name
= null, ParameterDirection direction
= ParameterDirection
.IN
, bool constructor
= false, bool caller_allocates
= false) {
951 string tag
= is_parameter ?
"parameter" : "return-value";
952 buffer
.append_printf ("<%s", tag
);
954 buffer
.append_printf (" name=\"%s\"", name
);
956 if (direction
== ParameterDirection
.REF
) {
957 buffer
.append_printf (" direction=\"inout\"");
958 } else if (direction
== ParameterDirection
.OUT
) {
959 buffer
.append_printf (" direction=\"out\"");
962 DelegateType delegate_type
= type as DelegateType
;
964 if ((type
.value_owned
&& delegate_type
== null) || constructor
) {
965 buffer
.append_printf (" transfer-ownership=\"full\"");
967 buffer
.append_printf (" transfer-ownership=\"none\"");
969 if (caller_allocates
) {
970 buffer
.append_printf (" caller-allocates=\"1\"");
973 buffer
.append_printf (" allow-none=\"1\"");
976 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
977 int closure_index
= is_parameter ?
978 index
+ 1 : (type
.value_owned ? index
- 1 : index
);
979 buffer
.append_printf (" closure=\"%i\"", closure_index
);
980 if (type
.value_owned
) {
981 buffer
.append_printf (" destroy=\"%i\"", closure_index
+ 1);
984 if (delegate_type
.is_called_once
) {
985 buffer
.append (" scope=\"async\"");
989 buffer
.append_printf (">\n");
992 int length_param_index
= -1;
993 if (has_array_length
) {
994 length_param_index
= is_parameter ? index
+ 1 : index
;
996 write_type (type
, length_param_index
);
1000 buffer
.append_printf ("</%s>\n", tag
);
1004 private void write_ctype_attributes (TypeSymbol symbol
, string suffix
= "") {
1005 buffer
.append_printf (" c:type=\"%s%s\"", symbol
.get_cname (), suffix
);
1008 private void write_gtype_attributes (TypeSymbol symbol
) {
1009 write_ctype_attributes(symbol
);
1010 buffer
.append_printf (" glib:type-name=\"%s\"", symbol
.get_cname ());
1011 buffer
.append_printf (" glib:get-type=\"%sget_type\"", symbol
.get_lower_case_cprefix ());
1014 private void write_type (DataType type
, int index
= -1) {
1015 if (type is ArrayType
) {
1016 var array_type
= (ArrayType
) type
;
1019 buffer
.append_printf ("<array");
1020 if (array_type
.fixed_length
) {
1021 buffer
.append_printf (" fixed-size=\"%i\"", array_type
.length
);
1022 } else if (index
!= -1) {
1023 buffer
.append_printf (" length=\"%i\"", index
);
1025 buffer
.append_printf (">\n");
1028 write_type (array_type
.element_type
);
1032 buffer
.append_printf ("</array>\n");
1033 } else if (type is VoidType
) {
1035 buffer
.append_printf ("<type name=\"none\"/>\n");
1036 } else if (type is PointerType
) {
1038 buffer
.append_printf ("<type name=\"gpointer\" c:type=\"%s\"/>\n", type
.get_cname ());
1039 } else if (type
.data_type
!= null) {
1041 buffer
.append_printf ("<type name=\"%s\" c:type=\"%s\"", gi_type_name (type
.data_type
), type
.get_cname ());
1043 List
<DataType
> type_arguments
= type
.get_type_arguments ();
1044 if (type_arguments
.size
== 0) {
1045 buffer
.append_printf ("/>\n");
1047 buffer
.append_printf (">\n");
1050 foreach (DataType type_argument
in type_arguments
) {
1051 write_type (type_argument
);
1056 buffer
.append_printf ("</type>\n");
1058 } else if (type is DelegateType
) {
1059 var deleg_type
= (DelegateType
) type
;
1061 buffer
.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (deleg_type
.delegate_symbol
), type
.get_cname ());
1062 } else if (type is GenericType
) {
1063 // generic type parameters not supported in GIR
1065 buffer
.append ("<type name=\"gpointer\" c:type=\"gpointer\"/>\n");
1068 buffer
.append_printf ("<type name=\"%s\"/>\n", type
.to_string ());
1072 private void write_annotations (CodeNode node
) {
1073 foreach (Attribute attr
in node
.attributes
) {
1074 string name
= camel_case_to_canonical (attr
.name
);
1075 foreach (string arg_name
in attr
.args
.get_keys ()) {
1076 string value
= attr
.args
.get (arg_name
);
1077 if (value
.has_prefix ("\"")) {
1079 value
= attr
.get_string (arg_name
);
1083 buffer
.append_printf ("<annotation key=\"%s.%s\" value=\"%s\"/>\n",
1084 name
, camel_case_to_canonical (arg_name
), value
);
1089 private string gi_type_name (TypeSymbol type_symbol
) {
1090 Symbol parent
= type_symbol
.parent_symbol
;
1091 if (parent is Namespace
) {
1092 Namespace ns
= parent as Namespace
;
1093 if (ns
.gir_name
!= null) {
1094 if (type_symbol
.source_reference
.file
.gir_namespace
!= null) {
1095 GIRNamespace external
= GIRNamespace (type_symbol
.source_reference
.file
.gir_namespace
, type_symbol
.source_reference
.file
.gir_version
);
1096 if (!externals
.contains (external
)) {
1097 externals
.add (external
);
1099 return "%s.%s".printf (type_symbol
.source_reference
.file
.gir_namespace
, type_symbol
.gir_name
);
1101 unannotated_namespaces
.add(ns
);
1106 return type_symbol
.get_full_gir_name();
1109 private string?
literal_expression_to_value_string (Expression literal
) {
1110 if (literal is StringLiteral
) {
1111 var lit
= literal as StringLiteral
;
1113 return Markup
.escape_text (lit
.eval ());
1115 } else if (literal is CharacterLiteral
) {
1116 return "%c".printf ((char) ((CharacterLiteral
) literal
).get_char ());
1117 } else if (literal is BooleanLiteral
) {
1118 return ((BooleanLiteral
) literal
).value ?
"true" : "false";
1119 } else if (literal is RealLiteral
) {
1120 return ((RealLiteral
) literal
).value
;
1121 } else if (literal is IntegerLiteral
) {
1122 return ((IntegerLiteral
) literal
).value
;
1123 } else if (literal is UnaryExpression
) {
1124 var unary
= (UnaryExpression
) literal
;
1125 if (unary
.operator
== UnaryOperator
.MINUS
) {
1126 if (unary
.inner is RealLiteral
) {
1127 return "-" + ((RealLiteral
) unary
.inner
).value
;
1128 } else if (unary
.inner is IntegerLiteral
) {
1129 return "-" + ((IntegerLiteral
) unary
.inner
).value
;
1136 private string camel_case_to_canonical (string name
) {
1137 string[] parts
= Symbol
.camel_case_to_lower_case (name
).split ("_");
1138 return string.joinv ("-", parts
);
1141 private bool check_accessibility (Symbol sym
) {
1142 if (sym
.access
== SymbolAccessibility
.PUBLIC
||
1143 sym
.access
== SymbolAccessibility
.PROTECTED
) {