Fix wrapper for delegates returning arrays, fixes bug 564474
[vala-lang.git] / gobject / valagirwriter.vala
blobc3b5328f2e6f335984dea74bdfd935203c8eea20
1 /* valagirwriter.vala
3 * Copyright (C) 2008 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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
24 using Gee;
26 /**
27 * Code visitor generating .gir file for the public interface.
29 public class Vala.GIRWriter : CodeVisitor {
30 private CodeContext context;
32 FileStream stream;
34 int indent;
36 private TypeSymbol gobject_type;
38 /**
39 * Writes the public interface of the specified code context into the
40 * specified file.
42 * @param context a code context
43 * @param filename a relative or absolute filename
45 public void write_file (CodeContext context, string filename) {
46 this.context = context;
48 var root_symbol = context.root;
49 var glib_ns = root_symbol.scope.lookup ("GLib");
50 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
52 stream = FileStream.open (filename, "w");
54 stream.printf ("<?xml version=\"1.0\"?>\n");
56 stream.printf ("<repository version=\"1.0\">\n");
58 context.accept (this);
60 stream.printf ("</repository>\n");
62 stream = null;
65 public override void visit_namespace (Namespace ns) {
66 if (ns.external_package) {
67 return;
70 if (ns.name == null) {
71 // global namespace
72 ns.accept_children (this);
73 return;
76 if (ns.parent_symbol.name != null) {
77 // nested namespace
78 // not supported in GIR at the moment
79 return;
82 write_indent ();
83 stream.printf ("<namespace name=\"%s\" version=\"1.0\">\n", ns.name);
84 indent++;
86 ns.accept_children (this);
88 indent--;
89 write_indent ();
90 stream.printf ("</namespace>\n");
93 public override void visit_class (Class cl) {
94 if (cl.external_package) {
95 return;
98 if (!check_accessibility (cl)) {
99 return;
102 if (cl.is_subtype_of (gobject_type)) {
103 write_indent ();
104 stream.printf ("<class name=\"%s\"", cl.name);
105 stream.printf (" parent=\"%s\"", cl.base_class.get_full_name ());
106 stream.printf (" glib:type-name=\"%s\"", cl.get_cname ());
107 stream.printf (" glib:get-type=\"%sget_type\"", cl.get_lower_case_cprefix ());
108 stream.printf (">\n");
109 indent++;
111 // write implemented interfaces
112 bool first = true;
113 foreach (DataType base_type in cl.get_base_types ()) {
114 var object_type = (ObjectType) base_type;
115 if (object_type.type_symbol is Interface) {
116 if (first) {
117 write_indent ();
118 stream.printf ("<implements>\n");
119 indent++;
120 first = false;
122 write_indent ();
123 stream.printf ("<interface name=\"%s\"/>\n", object_type.type_symbol.get_full_name ());
126 if (!first) {
127 indent--;
128 write_indent ();
129 stream.printf ("</implements>\n");
132 cl.accept_children (this);
134 indent--;
135 write_indent ();
136 stream.printf ("</class>\n");
137 } else {
138 write_indent ();
139 stream.printf ("<record name=\"%s\"", cl.name);
140 stream.printf (">\n");
141 indent++;
143 cl.accept_children (this);
145 indent--;
146 write_indent ();
147 stream.printf ("</record>\n");
151 public override void visit_struct (Struct st) {
152 if (st.external_package) {
153 return;
156 if (!check_accessibility (st)) {
157 return;
160 write_indent ();
161 stream.printf ("<record name=\"%s\"", st.name);
162 stream.printf (">\n");
163 indent++;
165 st.accept_children (this);
167 indent--;
168 write_indent ();
169 stream.printf ("</record>\n");
172 public override void visit_interface (Interface iface) {
173 if (iface.external_package) {
174 return;
177 if (!check_accessibility (iface)) {
178 return;
181 write_indent ();
182 stream.printf ("<interface name=\"%s\"", iface.name);
183 stream.printf (" glib:get-type=\"%sget_type\"", iface.get_lower_case_cprefix ());
184 stream.printf (">\n");
185 indent++;
187 // write prerequisites
188 if (iface.get_prerequisites ().size > 0) {
189 write_indent ();
190 stream.printf ("<requires>\n");
191 indent++;
193 foreach (DataType base_type in iface.get_prerequisites ()) {
194 var object_type = (ObjectType) base_type;
195 if (object_type.type_symbol is Class) {
196 write_indent ();
197 stream.printf ("<object name=\"%s\"/>\n", object_type.type_symbol.get_full_name ());
198 } else if (object_type.type_symbol is Interface) {
199 write_indent ();
200 stream.printf ("<interface name=\"%s\"/>\n", object_type.type_symbol.get_full_name ());
201 } else {
202 assert_not_reached ();
206 indent--;
207 write_indent ();
208 stream.printf ("</requires>\n");
211 iface.accept_children (this);
213 indent--;
214 write_indent ();
215 stream.printf ("</interface>\n");
218 public override void visit_enum (Enum en) {
219 if (en.external_package) {
220 return;
223 if (!check_accessibility (en)) {
224 return;
227 write_indent ();
228 stream.printf ("<enumeration name=\"%s\"", en.name);
229 stream.printf (" c:type=\"%s\"", en.get_cname ());
230 stream.printf (" glib:get-type=\"%sget_type\"", en.get_lower_case_cprefix ());
231 stream.printf (">\n");
232 indent++;
234 en.accept_children (this);
236 indent--;
237 write_indent ();
238 stream.printf ("</enumeration>\n");
241 public override void visit_enum_value (EnumValue ev) {
242 write_indent ();
243 stream.printf ("<member name=\"%s\"/>\n", string.joinv ("-", ev.name.down ().split ("_")));
246 public override void visit_error_domain (ErrorDomain edomain) {
247 if (edomain.external_package) {
248 return;
251 if (!check_accessibility (edomain)) {
252 return;
255 write_indent ();
256 stream.printf ("<errordomain name=\"%s\"", edomain.get_cname ());
257 stream.printf (">\n");
258 indent++;
260 edomain.accept_children (this);
262 indent--;
263 write_indent ();
264 stream.printf ("</errordomain>\n");
267 public override void visit_error_code (ErrorCode ecode) {
268 write_indent ();
269 stream.printf ("<member name=\"%s\"/>\n", ecode.get_cname ());
272 public override void visit_constant (Constant c) {
273 if (c.external_package) {
274 return;
277 if (!check_accessibility (c)) {
278 return;
281 write_indent ();
282 stream.printf ("<constant name=\"%s\"/>\n", c.get_cname ());
285 public override void visit_field (Field f) {
286 if (f.external_package) {
287 return;
290 if (!check_accessibility (f)) {
291 return;
294 write_indent ();
295 stream.printf ("<field name=\"%s\">\n", f.get_cname ());
296 indent++;
298 write_type (f.field_type);
300 indent--;
301 write_indent ();
302 stream.printf ("</field>\n");
305 private void write_params (Gee.List<FormalParameter> params, DataType? instance_type = null) {
306 write_indent ();
307 stream.printf ("<parameters>\n");
308 indent++;
310 if (instance_type != null) {
311 write_indent ();
312 stream.printf ("<parameter name=\"self\">\n");
313 indent++;
315 write_type (instance_type);
317 indent--;
318 write_indent ();
319 stream.printf ("</parameter>\n");
322 foreach (FormalParameter param in params) {
323 write_indent ();
324 stream.printf ("<parameter name=\"%s\"", param.name);
325 if (param.direction == ParameterDirection.REF) {
326 stream.printf (" direction=\"inout\"");
327 // in/out paramter
328 if (param.parameter_type.value_owned) {
329 stream.printf (" transfer-ownership=\"full\"");
331 } else if (param.direction == ParameterDirection.OUT) {
332 // out paramter
333 stream.printf (" direction=\"out\"");
334 if (param.parameter_type.value_owned) {
335 stream.printf (" transfer-ownership=\"full\"");
337 } else {
338 // normal in paramter
339 if (param.parameter_type.value_owned) {
340 stream.printf (" transfer-ownership=\"full\"");
343 stream.printf (">\n");
344 indent++;
346 write_type (param.parameter_type);
348 indent--;
349 write_indent ();
350 stream.printf ("</parameter>\n");
353 indent--;
354 write_indent ();
355 stream.printf ("</parameters>\n");
358 public override void visit_delegate (Delegate cb) {
359 if (cb.external_package) {
360 return;
363 if (!check_accessibility (cb)) {
364 return;
367 write_indent ();
368 stream.printf ("<callback name=\"%s\"", cb.get_cname ());
369 stream.printf (">\n");
370 indent++;
372 write_params (cb.get_parameters ());
374 write_return_type (cb.return_type);
376 indent--;
377 write_indent ();
378 stream.printf ("</callback>\n");
381 public override void visit_method (Method m) {
382 if (m.external_package) {
383 return;
386 // don't write interface implementation unless it's an abstract or virtual method
387 if (!check_accessibility (m) || m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
388 return;
391 write_indent ();
392 stream.printf ("<method name=\"%s\" c:identifier=\"%s\"", m.name, m.get_cname ());
393 stream.printf (">\n");
394 indent++;
396 DataType instance_type = null;
397 if (m.binding == MemberBinding.INSTANCE) {
398 instance_type = CCodeBaseModule.get_data_type_for_symbol ((TypeSymbol) m.parent_symbol);
401 write_params (m.get_parameters (), instance_type);
403 write_return_type (m.return_type);
405 indent--;
406 write_indent ();
407 stream.printf ("</method>\n");
410 public override void visit_creation_method (CreationMethod m) {
411 if (m.external_package) {
412 return;
415 if (!check_accessibility (m)) {
416 return;
419 write_indent ();
420 stream.printf ("<constructor name=\"%s\" c:identifier=\"%s\"", m.name, m.get_cname ());
421 stream.printf (">\n");
422 indent++;
424 write_params (m.get_parameters ());
426 write_return_type (CCodeBaseModule.get_data_type_for_symbol ((TypeSymbol) m.parent_symbol));
428 indent--;
429 write_indent ();
430 stream.printf ("</constructor>\n");
433 public override void visit_property (Property prop) {
434 if (!check_accessibility (prop) || prop.overrides || (prop.base_interface_property != null && !prop.is_abstract && !prop.is_virtual)) {
435 return;
438 write_indent ();
439 stream.printf ("<property name=\"%s\"", prop.name);
440 if (prop.get_accessor != null) {
441 stream.printf (" readable=\"1\"");
443 if (prop.set_accessor != null) {
444 stream.printf (" writable=\"1\"");
446 stream.printf (">\n");
447 indent++;
449 write_type (prop.property_type);
451 indent--;
452 write_indent ();
453 stream.printf ("</property>\n");
456 public override void visit_signal (Signal sig) {
457 if (!check_accessibility (sig)) {
458 return;
461 write_indent ();
462 stream.printf ("<glib:signal name=\"%s\"", sig.get_cname ());
463 stream.printf (">\n");
464 indent++;
466 write_params (sig.get_parameters ());
468 write_return_type (sig.return_type);
470 indent--;
471 write_indent ();
472 stream.printf ("</glib:signal>\n");
475 private void write_indent () {
476 int i;
478 for (i = 0; i < indent; i++) {
479 stream.putc ('\t');
483 private void write_return_type (DataType type) {
484 write_indent ();
485 stream.printf ("<return-value");
486 if (type.value_owned) {
487 stream.printf (" transfer-ownership=\"full\"");
489 stream.printf (">\n");
490 indent++;
492 write_type (type);
494 indent--;
495 write_indent ();
496 stream.printf ("</return-value>\n");
499 private void write_type (DataType type) {
500 if (type is ArrayType) {
501 var array_type = (ArrayType) type;
503 write_indent ();
504 stream.printf ("<array>\n");
505 indent++;
507 write_type (array_type.element_type);
509 indent--;
510 write_indent ();
511 stream.printf ("</array>\n");
512 } else if (type is VoidType) {
513 write_indent ();
514 stream.printf ("<type name=\"none\"/>\n");
515 } else {
516 write_indent ();
517 stream.printf ("<type name=\"%s\"/>\n", type.to_string ());
521 private bool check_accessibility (Symbol sym) {
522 if (sym.access == SymbolAccessibility.PUBLIC ||
523 sym.access == SymbolAccessibility.PROTECTED) {
524 return true;
527 return false;