3 * Copyright (C) 2008-2010 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
>();
41 private TypeSymbol gobject_type
;
43 private struct GIRNamespace
{
44 public GIRNamespace (string ns
, string version
) {
45 this
.ns
= ns
; this
.version
= version
;
48 public string version
;
49 public bool equal (GIRNamespace g
) {
50 return ((ns
== g
.ns
) && (version
== g
.version
));
54 private ArrayList
<GIRNamespace?
> externals
= new ArrayList
<GIRNamespace?
> ((EqualFunc
) GIRNamespace
.equal
);
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
);
65 * Writes the public interface of the specified code context into the
68 * @param context a code context
69 * @param filename a relative or absolute filename
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
;
77 var root_symbol
= context
.root
;
78 var glib_ns
= root_symbol
.scope
.lookup ("GLib");
79 gobject_type
= (TypeSymbol
) glib_ns
.scope
.lookup ("Object");
81 write_package (package
);
83 context
.accept (this
);
86 buffer
.append_printf ("</repository>\n");
88 string filename
= "%s%c%s-%s.gir".printf (directory
, Path
.DIR_SEPARATOR
, gir_namespace
, gir_version
);
89 stream
= FileStream
.open (filename
, "w");
91 Report
.error (null, "unable to open `%s' for writing".printf (filename
));
95 stream
.printf ("<?xml version=\"1.0\"?>\n");
97 stream
.printf ("<repository version=\"1.1\"");
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");
107 stream
.puts (buffer
.str
);
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
));
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
;
121 private void write_package (string package
) {
123 buffer
.append_printf ("<package name=\"%s\"/>\n", package
);
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
);
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
);
138 // Generate c:include tags
139 foreach (string c_header_filename
in header_filenames
) {
140 write_c_include (c_header_filename
);
144 private void write_c_include (string name
) {
146 buffer
.append_printf ("<c:include name=\"%s\"/>\n", name
);
149 public override void visit_namespace (Namespace ns
) {
150 if (ns
.external_package
) {
154 if (ns
.name
== null) {
156 ns
.accept_children (this
);
160 if (ns
.parent_symbol
.name
!= null) {
162 // not supported in GIR at the moment
166 write_c_includes (ns
);
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
);
174 buffer
.append_printf (">\n");
177 write_annotations (ns
);
179 ns
.accept_children (this
);
183 buffer
.append_printf ("</namespace>\n");
184 our_namespaces
.add(ns
);
187 public override void visit_class (Class cl
) {
188 if (cl
.external_package
) {
192 if (!check_accessibility (cl
)) {
196 if (cl
.is_subtype_of (gobject_type
)) {
197 string gtype_struct_name
= cl
.name
+ "Class";
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\"");
207 buffer
.append_printf (">\n");
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
) {
215 buffer
.append_printf ("<implements name=\"%s\"/>\n", gi_type_name (object_type
.type_symbol
));
219 write_annotations (cl
);
222 buffer
.append_printf ("<field name=\"parent_instance\">\n");
225 buffer
.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (cl
.base_class
), cl
.base_class
.get_cname ());
228 buffer
.append_printf("</field>\n");
231 buffer
.append_printf ("<field name=\"priv\">\n");
234 buffer
.append_printf ("<type name=\"any\" c:type=\"%sPrivate*\"/>\n", cl
.get_cname ());
237 buffer
.append_printf("</field>\n");
239 cl
.accept_children (this
);
243 buffer
.append_printf ("</class>\n");
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");
253 buffer
.append_printf ("<field name=\"parent_class\">\n");
256 buffer
.append_printf ("<type name=\"%sClass\" c:type=\"%sClass\"/>\n", gi_type_name (cl
.base_class
), cl
.base_class
.get_cname ());
259 buffer
.append_printf ("</field>\n");
261 foreach (Method m
in cl
.get_methods ()) {
262 if (m
.is_abstract
|| m
.is_virtual
) {
264 buffer
.append_printf("<field name=\"%s\">\n", m
.name
);
266 write_signature(m
, "callback", true);
269 buffer
.append_printf ("</field>\n");
273 foreach (Signal sig
in cl
.get_signals ()) {
274 if (sig
.default_handler
!= null) {
276 buffer
.append_printf ("<field name=\"%s\">\n", sig
.name
);
278 write_signature (sig
.default_handler
, "callback", true);
281 buffer
.append_printf ("</field>\n");
288 buffer
.append_printf ("</record>\n");
291 buffer
.append_printf ("<record name=\"%s\"", cl
.name
);
292 buffer
.append_printf (">\n");
295 write_annotations (cl
);
297 cl
.accept_children (this
);
301 buffer
.append_printf ("</record>\n");
305 public override void visit_struct (Struct st
) {
306 if (st
.external_package
) {
310 if (!check_accessibility (st
)) {
315 buffer
.append_printf ("<record name=\"%s\"", st
.name
);
316 buffer
.append_printf (">\n");
319 write_annotations (st
);
321 st
.accept_children (this
);
325 buffer
.append_printf ("</record>\n");
328 public override void visit_interface (Interface iface
) {
329 if (iface
.external_package
) {
333 if (!check_accessibility (iface
)) {
337 string gtype_struct_name
= iface
.name
+ "Iface";
340 buffer
.append_printf ("<interface name=\"%s\"", iface
.name
);
341 write_gtype_attributes (iface
);
342 buffer
.append_printf (" glib:type-struct=\"%s\"", gtype_struct_name
);
343 buffer
.append_printf (">\n");
346 // write prerequisites
347 if (iface
.get_prerequisites ().size
> 0) {
349 buffer
.append_printf ("<requires>\n");
352 foreach (DataType base_type
in iface
.get_prerequisites ()) {
353 var object_type
= (ObjectType
) base_type
;
354 if (object_type
.type_symbol is Class
) {
356 buffer
.append_printf ("<object name=\"%s\"/>\n", gi_type_name (object_type
.type_symbol
));
357 } else if (object_type
.type_symbol is Interface
) {
359 buffer
.append_printf ("<interface name=\"%s\"/>\n", gi_type_name (object_type
.type_symbol
));
361 assert_not_reached ();
367 buffer
.append_printf ("</requires>\n");
370 write_annotations (iface
);
372 iface
.accept_children (this
);
376 buffer
.append_printf ("</interface>\n");
379 buffer
.append_printf ("<record name=\"%s\"", gtype_struct_name
);
380 write_ctype_attributes (iface
, "Iface");
381 buffer
.append_printf (" glib:is-gtype-struct-for=\"%s\"", iface
.name
);
382 buffer
.append_printf (">\n");
385 foreach (Method m
in iface
.get_methods ()) {
386 if (m
.is_abstract
|| m
.is_virtual
) {
387 write_signature(m
, "callback", true);
393 buffer
.append_printf ("</record>\n");
396 public override void visit_enum (Enum en
) {
397 if (en
.external_package
) {
401 if (!check_accessibility (en
)) {
406 buffer
.append_printf ("<enumeration name=\"%s\"", en
.name
);
407 write_gtype_attributes (en
);
408 buffer
.append_printf (">\n");
411 write_annotations (en
);
414 en
.accept_children (this
);
418 buffer
.append_printf ("</enumeration>\n");
421 private int enum_value
;
423 public override void visit_enum_value (EnumValue ev
) {
425 buffer
.append_printf ("<member name=\"%s\" c:identifier=\"%s\"", ev
.name
.down (), ev
.get_cname ());
426 if (ev
.value
!= null) {
427 string value
= literal_expression_to_value_string (ev
.value
);
428 buffer
.append_printf (" value=\"%s\"", value
);
430 buffer
.append_printf (" value=\"%d\"", enum_value
++);
432 buffer
.append_printf ("/>\n");
435 public override void visit_error_domain (ErrorDomain edomain
) {
436 if (edomain
.external_package
) {
440 if (!check_accessibility (edomain
)) {
445 buffer
.append_printf ("<errordomain name=\"%s\"", edomain
.name
);
446 buffer
.append_printf (" get-quark=\"%squark\"", edomain
.get_lower_case_cprefix ());
447 buffer
.append_printf (" codes=\"%s\"", edomain
.name
);
448 buffer
.append_printf (">\n");
450 write_annotations (edomain
);
452 buffer
.append_printf ("</errordomain>\n");
455 buffer
.append_printf ("<enumeration name=\"%s\"", edomain
.name
);
456 write_ctype_attributes (edomain
);
457 buffer
.append_printf (">\n");
461 edomain
.accept_children (this
);
465 buffer
.append_printf ("</enumeration>\n");
468 public override void visit_error_code (ErrorCode ecode
) {
470 buffer
.append_printf ("<member name=\"%s\" c:identifier=\"%s\"", ecode
.name
.down (), ecode
.get_cname ());
471 if (ecode
.value
!= null) {
472 string value
= literal_expression_to_value_string (ecode
.value
);
473 buffer
.append_printf (" value=\"%s\"", value
);
475 buffer
.append_printf (" value=\"%d\"", enum_value
++);
477 buffer
.append_printf ("/>\n");
480 public override void visit_constant (Constant c
) {
481 if (c
.external_package
) {
485 if (!check_accessibility (c
)) {
489 //TODO Add better constant evaluation
490 var initializer
= c
.value
;
491 string value
= literal_expression_to_value_string (initializer
);
494 buffer
.append_printf ("<constant name=\"%s\" c:identifier=\"%s\"", c
.name
, c
.get_cname ());
495 buffer
.append_printf (" value=\"%s\"", value
);
496 buffer
.append_printf (">\n");
499 write_type (initializer
.value_type
);
503 buffer
.append_printf ("</constant>\n");
506 public override void visit_field (Field f
) {
507 if (f
.external_package
) {
511 if (!check_accessibility (f
)) {
516 buffer
.append_printf ("<field name=\"%s\"", f
.get_cname ());
517 if (f
.variable_type
.nullable
) {
518 buffer
.append_printf (" allow-none=\"1\"");
520 buffer
.append_printf (">\n");
523 write_annotations (f
);
525 write_type (f
.variable_type
);
529 buffer
.append_printf ("</field>\n");
532 private void write_implicit_params (DataType type
, ref int index
, bool has_array_length
, string name
, ParameterDirection direction
) {
533 if (type is ArrayType
&& has_array_length
) {
534 var int_type
= new
IntegerType (CodeContext
.get ().root
.scope
.lookup ("int") as Struct
);
535 write_param_or_return (int_type
, "parameter", ref index
, has_array_length
, "%s_length1".printf (name
), direction
);
536 } else if (type is DelegateType
) {
537 var data_type
= new
PointerType (new
VoidType ());
538 write_param_or_return (data_type
, "parameter", ref index
, false, "%s_target".printf (name
), direction
);
539 if (type
.value_owned
) {
540 var notify_type
= new
DelegateType (CodeContext
.get ().root
.scope
.lookup ("GLib").scope
.lookup ("DestroyNotify") as Delegate
);
541 write_param_or_return (notify_type
, "parameter", ref index
, false, "%s_target_destroy_notify".printf (name
), direction
);
546 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) {
548 if (params
.size
!= 0 || instance_type
!= null || (return_type is ArrayType
&& return_array_length
) || (return_type is DelegateType
)) {
550 buffer
.append_printf ("<parameters>\n");
554 if (instance_type
!= null) {
555 write_param_or_return (instance_type
, "parameter", ref index
, false, "self");
558 foreach (FormalParameter param
in params
) {
559 write_param_or_return (param
.variable_type
, "parameter", ref index
, !param
.no_array_length
, param
.name
, param
.direction
);
561 write_implicit_params (param
.variable_type
, ref index
, !param
.no_array_length
, param
.name
, param
.direction
);
564 last_index
= index
- 1;
565 write_implicit_params (return_type
, ref index
, return_array_length
, "result", ParameterDirection
.OUT
);
569 buffer
.append_printf ("<parameter name=\"user_data\" transfer-ownership=\"none\" closure=\"%d\">\n", index
);
572 buffer
.append_printf ("<type name=\"any\" c:type=\"void*\"/>\n");
575 buffer
.append_printf ("</parameter>\n");
580 buffer
.append_printf ("</parameters>\n");
583 if (return_type
!= null) {
584 write_param_or_return (return_type
, "return-value", ref last_index
, return_array_length
, null, ParameterDirection
.IN
, constructor
);
588 public override void visit_delegate (Delegate cb
) {
589 if (cb
.external_package
) {
593 if (!check_accessibility (cb
)) {
598 buffer
.append_printf ("<callback name=\"%s\"", cb
.name
);
599 buffer
.append_printf (" c:type=\"%s\"", cb
.get_cname ());
600 if (cb
.tree_can_fail
) {
601 buffer
.append_printf (" throws=\"1\"");
603 buffer
.append_printf (">\n");
606 write_annotations (cb
);
608 write_params_and_return (cb
.get_parameters (), cb
.return_type
, !cb
.no_array_length
, false, null, cb
.has_target
);
612 buffer
.append_printf ("</callback>\n");
615 public override void visit_method (Method m
) {
616 if (m
.external_package
) {
620 // don't write interface implementation unless it's an abstract or virtual method
621 if (!check_accessibility (m
) || m
.overrides
|| (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
625 string tag_name
= "method";
626 var parent
= m
.parent_symbol
;
627 if (parent is Namespace
|| m
.binding
== MemberBinding
.STATIC
) {
628 tag_name
= "function";
631 write_signature (m
, tag_name
);
633 if (m
.is_abstract
|| m
.is_virtual
) {
634 write_signature (m
, "virtual-method", false);
638 private void write_signature (Method m
, string tag_name
, bool instance
= false) {
640 string finish_name
= m
.name
;
641 if (finish_name
.has_suffix ("_async")) {
642 finish_name
= finish_name
.substring (0, finish_name
.length
- "_async".length
);
644 finish_name
+= "_finish";
645 do_write_signature (m
, tag_name
, instance
, m
.name
, m
.get_cname (), m
.get_async_begin_parameters (), new
VoidType (), false);
646 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
);
648 do_write_signature (m
, tag_name
, instance
, m
.name
, m
.get_cname (), m
.get_parameters (), m
.return_type
, m
.tree_can_fail
);
652 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
) {
654 buffer
.append_printf ("<%s name=\"%s\"", tag_name
, name
);
655 if (tag_name
== "virtual-method") {
656 buffer
.append_printf (" invoker=\"%s\"", name
);
657 } else if (tag_name
== "callback") {
658 /* this is only used for vfuncs */
659 buffer
.append_printf (" c:type=\"%s\"", name
);
661 buffer
.append_printf (" c:identifier=\"%s\"", cname
);
664 buffer
.append_printf (" throws=\"1\"");
666 buffer
.append_printf (">\n");
669 write_annotations (m
);
671 DataType instance_type
= null;
673 instance_type
= CCodeBaseModule
.get_data_type_for_symbol ((TypeSymbol
) m
.parent_symbol
);
676 write_params_and_return (params
, return_type
, !m
.no_array_length
, false, instance_type
);
680 buffer
.append_printf ("</%s>\n", tag_name
);
683 public override void visit_creation_method (CreationMethod m
) {
684 if (m
.external_package
) {
688 if (!check_accessibility (m
)) {
694 if (m
.parent_symbol is Class
&& m
== ((Class
)m
.parent_symbol
).default_construction_method
||
695 m
.parent_symbol is Struct
&& m
== ((Struct
)m
.parent_symbol
).default_construction_method
) {
696 buffer
.append_printf ("<constructor name=\"new\" c:identifier=\"%s\"", m
.get_cname ());
698 buffer
.append_printf ("<constructor name=\"%s\" c:identifier=\"%s\"", m
.name
, m
.get_cname ());
701 if (m
.tree_can_fail
) {
702 buffer
.append_printf (" throws=\"1\"");
704 buffer
.append_printf (">\n");
707 write_annotations (m
);
710 var datatype
= CCodeBaseModule
.get_data_type_for_symbol ((TypeSymbol
) m
.parent_symbol
);
711 write_params_and_return (m
.get_parameters (), datatype
, false, true);
715 buffer
.append_printf ("</constructor>\n");
718 public override void visit_property (Property prop
) {
719 if (!check_accessibility (prop
) || prop
.overrides
|| (prop
.base_interface_property
!= null && !prop
.is_abstract
&& !prop
.is_virtual
)) {
724 buffer
.append_printf ("<property name=\"%s\"", prop
.get_canonical_name ());
725 if (prop
.get_accessor
== null) {
726 buffer
.append_printf (" readable=\"0\"");
728 if (prop
.set_accessor
!= null) {
729 buffer
.append_printf (" writable=\"1\"");
730 if (prop
.set_accessor
.construction
) {
731 if (!prop
.set_accessor
.writable
) {
732 buffer
.append_printf (" construct-only=\"1\"");
734 buffer
.append_printf (" construct=\"1\"");
738 buffer
.append_printf (">\n");
741 write_annotations (prop
);
743 write_type (prop
.property_type
);
747 buffer
.append_printf ("</property>\n");
750 public override void visit_signal (Signal sig
) {
751 if (!check_accessibility (sig
)) {
756 buffer
.append_printf ("<glib:signal name=\"%s\"", sig
.get_cname ());
757 buffer
.append_printf (">\n");
760 write_annotations (sig
);
762 write_params_and_return (sig
.get_parameters (), sig
.return_type
, false);
766 buffer
.append_printf ("</glib:signal>\n");
769 private void write_indent () {
772 for (i
= 0; i
< indent
; i
++) {
773 buffer
.append_c ('\t');
777 private void write_indent_stream () {
780 for (i
= 0; i
< indent
; i
++) {
786 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) {
788 buffer
.append_printf ("<%s", tag
);
790 buffer
.append_printf (" name=\"%s\"", name
);
792 if (direction
== ParameterDirection
.REF
) {
793 buffer
.append_printf (" direction=\"inout\"");
794 } else if (direction
== ParameterDirection
.OUT
) {
795 buffer
.append_printf (" direction=\"out\"");
798 DelegateType delegate_type
= type as DelegateType
;
800 if ((type
.value_owned
&& delegate_type
== null) || constructor
) {
801 buffer
.append_printf (" transfer-ownership=\"full\"");
803 buffer
.append_printf (" transfer-ownership=\"none\"");
806 buffer
.append_printf (" allow-none=\"1\"");
809 if (delegate_type
!= null && delegate_type
.delegate_symbol
.has_target
) {
810 buffer
.append_printf (" closure=\"%i\"", index
+ 1);
811 if (type
.value_owned
) {
812 buffer
.append_printf (" destroy=\"%i\"", index
+ 2);
816 buffer
.append_printf (">\n");
819 write_type (type
, has_array_length ? index
: -1);
823 buffer
.append_printf ("</%s>\n", tag
);
827 private void write_ctype_attributes (TypeSymbol symbol
, string suffix
= "") {
828 buffer
.append_printf (" c:type=\"%s%s\"", symbol
.get_cname (), suffix
);
831 private void write_gtype_attributes (TypeSymbol symbol
) {
832 write_ctype_attributes(symbol
);
833 buffer
.append_printf (" glib:type-name=\"%s\"", symbol
.get_cname ());
834 buffer
.append_printf (" glib:get-type=\"%sget_type\"", symbol
.get_lower_case_cprefix ());
837 private void write_type (DataType type
, int index
= -1) {
838 if (type is ArrayType
) {
839 var array_type
= (ArrayType
) type
;
842 buffer
.append_printf ("<array");
843 if (array_type
.fixed_length
) {
844 buffer
.append_printf (" fixed-length\"%i\"", array_type
.length
);
845 } else if (index
!= -1) {
846 buffer
.append_printf (" length=\"%i\"", index
+ 1);
848 buffer
.append_printf (">\n");
851 write_type (array_type
.element_type
);
855 buffer
.append_printf ("</array>\n");
856 } else if (type is VoidType
) {
858 buffer
.append_printf ("<type name=\"none\"/>\n");
859 } else if (type is PointerType
) {
861 buffer
.append_printf ("<type name=\"any\" c:type=\"%s\"/>\n", type
.get_cname ());
862 } else if (type
.data_type
!= null) {
864 buffer
.append_printf ("<type name=\"%s\" c:type=\"%s\"", gi_type_name (type
.data_type
), type
.get_cname ());
866 List
<DataType
> type_arguments
= type
.get_type_arguments ();
867 if (type_arguments
.size
== 0) {
868 buffer
.append_printf ("/>\n");
870 buffer
.append_printf (">\n");
873 foreach (DataType type_argument
in type_arguments
) {
874 write_type (type_argument
);
879 buffer
.append_printf ("</type>\n");
881 } else if (type is DelegateType
) {
882 var deleg_type
= (DelegateType
) type
;
884 buffer
.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (deleg_type
.delegate_symbol
), type
.get_cname ());
885 } else if (type is GenericType
) {
886 // generic type parameters not supported in GIR
888 buffer
.append ("<type name=\"any\" c:type=\"gpointer\"/>\n");
891 buffer
.append_printf ("<type name=\"%s\"/>\n", type
.to_string ());
895 private void write_annotations (CodeNode node
) {
896 foreach (Attribute attr
in node
.attributes
) {
897 string name
= camel_case_to_canonical (attr
.name
);
898 foreach (string arg_name
in attr
.args
.get_keys ()) {
899 var arg
= attr
.args
.get (arg_name
);
901 string value
= literal_expression_to_value_string ((Literal
) arg
);
905 buffer
.append_printf ("<annotation key=\"%s.%s\" value=\"%s\"/>\n",
906 name
, camel_case_to_canonical (arg_name
), value
);
912 private string gi_type_name (TypeSymbol type_symbol
) {
913 Symbol parent
= type_symbol
.parent_symbol
;
914 if (parent is Namespace
) {
915 Namespace ns
= parent as Namespace
;
916 if (ns
.name
!= null) {
917 if (type_symbol
.source_reference
.file
.gir_namespace
!= null) {
918 GIRNamespace external
= GIRNamespace (type_symbol
.source_reference
.file
.gir_namespace
, type_symbol
.source_reference
.file
.gir_version
);
919 if (!externals
.contains (external
)) {
920 externals
.add (external
);
922 return "%s.%s".printf (type_symbol
.source_reference
.file
.gir_namespace
, type_symbol
.name
);
924 unannotated_namespaces
.add(ns
);
929 return vala_to_gi_type_name (type_symbol
.get_full_name());
932 private string vala_to_gi_type_name (string name
) {
933 if (name
== "bool") {
935 } else if (name
== "string") {
937 } else if (!name
.contains (".")) {
940 string[] split_name
= name
.split (".");
942 StringBuilder type_name
= new
StringBuilder ();
943 type_name
.append (split_name
[0]);
944 type_name
.append_unichar ('.');
945 for (int i
= 1; i
< split_name
.length
; i
++) {
946 type_name
.append (split_name
[i
]);
948 return type_name
.str
;
952 private string?
literal_expression_to_value_string (Expression literal
) {
953 if (literal is StringLiteral
) {
954 var lit
= literal as StringLiteral
;
956 return Markup
.escape_text (lit
.eval ());
958 } else if (literal is CharacterLiteral
) {
959 return "%c".printf ((char) ((CharacterLiteral
) literal
).get_char ());
960 } else if (literal is BooleanLiteral
) {
961 return ((BooleanLiteral
) literal
).value ?
"true" : "false";
962 } else if (literal is RealLiteral
) {
963 return ((RealLiteral
) literal
).value
;
964 } else if (literal is IntegerLiteral
) {
965 return ((IntegerLiteral
) literal
).value
;
966 } else if (literal is UnaryExpression
) {
967 var unary
= (UnaryExpression
) literal
;
968 if (unary
.operator
== UnaryOperator
.MINUS
) {
969 if (unary
.inner is RealLiteral
) {
970 return "-" + ((RealLiteral
) unary
.inner
).value
;
971 } else if (unary
.inner is IntegerLiteral
) {
972 return "-" + ((IntegerLiteral
) unary
.inner
).value
;
979 private string camel_case_to_canonical (string name
) {
980 string[] parts
= Symbol
.camel_case_to_lower_case (name
).split ("_");
981 return string.joinv ("-", parts
);
984 private bool check_accessibility (Symbol sym
) {
985 if (sym
.access
== SymbolAccessibility
.PUBLIC
||
986 sym
.access
== SymbolAccessibility
.PROTECTED
) {