Release 0.7.8
[vala-lang.git] / vala / valacodewriter.vala
blob1f28ea7410c0c6d9c27e05ce7167253a95fb4c9e
1 /* valacodewriter.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 /**
27 * Code visitor generating Vala API file for the public interface.
29 public class Vala.CodeWriter : CodeVisitor {
30 private CodeContext context;
32 FileStream stream;
34 int indent;
35 /* at begin of line */
36 bool bol = true;
38 Scope current_scope;
40 bool dump_tree;
41 bool emit_internal;
43 string? override_header = null;
44 string? header_to_override = null;
46 public CodeWriter (bool dump_tree = false, bool emit_internal = false) {
47 this.dump_tree = dump_tree;
48 this.emit_internal = emit_internal;
51 /**
52 * Allows overriding of a specific cheader in the output
53 * @param original orignal cheader to override
54 * @param replacement cheader to replace original with
56 public void set_cheader_override (string original, string replacement)
58 header_to_override = original;
59 override_header = replacement;
62 /**
63 * Writes the public interface of the specified code context into the
64 * specified file.
66 * @param context a code context
67 * @param filename a relative or absolute filename
69 public void write_file (CodeContext context, string filename) {
70 this.context = context;
72 stream = FileStream.open (filename, "w");
74 write_string ("/* %s generated by %s, do not modify. */".printf (Path.get_basename (filename), Environment.get_prgname ()));
75 write_newline ();
76 write_newline ();
78 current_scope = context.root.scope;
80 context.accept (this);
82 current_scope = null;
84 stream = null;
87 public override void visit_namespace (Namespace ns) {
88 if (ns.external_package) {
89 return;
92 if (ns.name == null) {
93 ns.accept_children (this);
94 return;
97 write_indent ();
98 write_string ("[CCode (cprefix = \"%s\", lower_case_cprefix = \"%s\")]".printf (ns.get_cprefix (), ns.get_lower_case_cprefix ()));
99 write_newline ();
101 write_attributes (ns);
103 write_indent ();
104 write_string ("namespace ");
105 write_identifier (ns.name);
106 write_begin_block ();
108 current_scope = ns.scope;
110 visit_sorted (ns.get_namespaces ());
111 visit_sorted (ns.get_classes ());
112 visit_sorted (ns.get_interfaces ());
113 visit_sorted (ns.get_structs ());
114 visit_sorted (ns.get_enums ());
115 visit_sorted (ns.get_error_domains ());
116 visit_sorted (ns.get_delegates ());
117 visit_sorted (ns.get_fields ());
118 visit_sorted (ns.get_constants ());
119 visit_sorted (ns.get_methods ());
121 current_scope = current_scope.parent_scope;
123 write_end_block ();
124 write_newline ();
127 private string get_cheaders (Symbol cl) {
128 bool first = true;
129 string cheaders = "";
130 foreach (string cheader in cl.get_cheader_filenames ()) {
131 if (header_to_override != null &&
132 cheader == header_to_override) {
133 cheader = override_header;
135 if (first) {
136 cheaders = cheader;
137 first = false;
138 } else {
139 cheaders = "%s,%s".printf (cheaders, cheader);
142 return cheaders;
145 public override void visit_class (Class cl) {
146 if (cl.external_package) {
147 return;
150 if (!check_accessibility (cl)) {
151 return;
154 if (cl.is_compact) {
155 write_indent ();
156 write_string ("[Compact]");
157 write_newline ();
160 if (cl.is_immutable) {
161 write_indent ();
162 write_string ("[Immutable]");
163 write_newline ();
166 write_indent ();
168 write_string ("[CCode (");
170 if (cl.is_reference_counting ()) {
171 if (cl.base_class == null || cl.base_class.get_ref_function () == null || cl.base_class.get_ref_function () != cl.get_ref_function ()) {
172 write_string ("ref_function = \"%s\", ".printf (cl.get_ref_function ()));
173 if (cl.ref_function_void) {
174 write_string ("ref_function_void = true, ");
177 if (cl.base_class == null || cl.base_class.get_unref_function () == null || cl.base_class.get_unref_function () != cl.get_unref_function ()) {
178 write_string ("unref_function = \"%s\", ".printf (cl.get_unref_function ()));
180 } else {
181 if (cl.get_dup_function () != null) {
182 write_string ("copy_function = \"%s\", ".printf (cl.get_dup_function ()));
184 if (cl.get_free_function () != cl.get_default_free_function ()) {
185 write_string ("free_function = \"%s\", ".printf (cl.get_free_function ()));
189 if (cl.get_cname () != cl.get_default_cname ()) {
190 write_string ("cname = \"%s\", ".printf (cl.get_cname ()));
192 if (cl.const_cname != null) {
193 write_string ("const_cname = \"%s\", ".printf (cl.const_cname));
196 if (cl.type_check_function != null) {
197 write_string ("type_check_function = \"%s\", ".printf (cl.type_check_function ));
200 if (cl.is_compact && cl.get_type_id () != "G_TYPE_POINTER") {
201 write_string ("type_id = \"%s\", ".printf (cl.get_type_id ()));
204 if (cl.get_param_spec_function () != cl.get_default_param_spec_function ()) {
205 write_string ("param_spec_function = \"%s\", ".printf (cl.get_param_spec_function ()));
208 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(cl)));
209 write_newline ();
211 write_attributes (cl);
213 write_indent ();
214 write_accessibility (cl);
215 if (cl.is_abstract) {
216 write_string ("abstract ");
218 write_string ("class ");
219 write_identifier (cl.name);
221 var type_params = cl.get_type_parameters ();
222 if (type_params.size > 0) {
223 write_string ("<");
224 bool first = true;
225 foreach (TypeParameter type_param in type_params) {
226 if (first) {
227 first = false;
228 } else {
229 write_string (",");
231 write_identifier (type_param.name);
233 write_string (">");
236 var base_types = cl.get_base_types ();
237 if (base_types.size > 0) {
238 write_string (" : ");
240 bool first = true;
241 foreach (DataType base_type in base_types) {
242 if (!first) {
243 write_string (", ");
244 } else {
245 first = false;
247 write_type (base_type);
250 write_begin_block ();
252 current_scope = cl.scope;
254 visit_sorted (cl.get_classes ());
255 visit_sorted (cl.get_structs ());
256 visit_sorted (cl.get_enums ());
257 visit_sorted (cl.get_delegates ());
258 visit_sorted (cl.get_fields ());
259 visit_sorted (cl.get_constants ());
260 visit_sorted (cl.get_methods ());
261 visit_sorted (cl.get_properties ());
262 visit_sorted (cl.get_signals ());
264 if (cl.constructor != null) {
265 cl.constructor.accept (this);
268 current_scope = current_scope.parent_scope;
270 write_end_block ();
271 write_newline ();
274 void visit_sorted (List<Symbol> symbols) {
275 var sorted_symbols = new ArrayList<Symbol> ();
276 foreach (Symbol sym in symbols) {
277 int left = 0;
278 int right = sorted_symbols.size - 1;
279 if (left > right || sym.name < sorted_symbols[left].name) {
280 sorted_symbols.insert (0, sym);
281 } else if (sym.name > sorted_symbols[right].name) {
282 sorted_symbols.add (sym);
283 } else {
284 while (right - left > 1) {
285 int i = (right + left) / 2;
286 if (sym.name > sorted_symbols[i].name) {
287 left = i;
288 } else {
289 right = i;
292 sorted_symbols.insert (left + 1, sym);
295 foreach (Symbol sym in sorted_symbols) {
296 sym.accept (this);
300 public override void visit_struct (Struct st) {
301 if (st.external_package) {
302 return;
305 if (!check_accessibility (st)) {
306 return;
309 if (st.is_immutable) {
310 write_indent ();
311 write_string ("[Immutable]");
312 write_newline ();
315 write_indent ();
317 write_string ("[CCode (");
319 if (st.get_cname () != st.get_default_cname ()) {
320 write_string ("cname = \"%s\", ".printf (st.get_cname ()));
323 if (!st.is_simple_type () && st.get_type_id () != "G_TYPE_POINTER") {
324 write_string ("type_id = \"%s\", ".printf (st.get_type_id ()));
327 if (!st.has_copy_function) {
328 write_string ("has_copy_function = false, ");
331 if (!st.has_destroy_function) {
332 write_string ("has_destroy_function = false, ");
335 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(st)));
336 write_newline ();
338 if (st.is_simple_type ()) {
339 write_indent ();
340 write_string ("[SimpleType]");
341 write_newline ();
344 if (st.is_integer_type ()) {
345 write_indent ();
346 write_string ("[IntegerType (rank = %d)]".printf (st.get_rank ()));
347 write_newline ();
350 if (st.is_floating_type ()) {
351 write_indent ();
352 write_string ("[FloatingType (rank = %d)]".printf (st.get_rank ()));
353 write_newline ();
356 write_attributes (st);
358 write_indent ();
359 write_accessibility (st);
360 write_string ("struct ");
361 write_identifier (st.name);
363 if (st.base_type != null) {
364 write_string (" : ");
365 write_type (st.base_type);
368 write_begin_block ();
370 current_scope = st.scope;
372 foreach (Field field in st.get_fields ()) {
373 field.accept (this);
375 visit_sorted (st.get_constants ());
376 visit_sorted (st.get_methods ());
377 visit_sorted (st.get_properties ());
379 current_scope = current_scope.parent_scope;
381 write_end_block ();
382 write_newline ();
385 public override void visit_interface (Interface iface) {
386 if (iface.external_package) {
387 return;
390 if (!check_accessibility (iface)) {
391 return;
394 write_indent ();
396 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(iface)));
397 if (iface.get_lower_case_csuffix () != iface.get_default_lower_case_csuffix ())
398 write_string (", lower_case_csuffix = \"%s\"".printf (iface.get_lower_case_csuffix ()));
400 write_string (")]");
401 write_newline ();
403 write_attributes (iface);
405 write_indent ();
406 write_accessibility (iface);
407 write_string ("interface ");
408 write_identifier (iface.name);
410 var type_params = iface.get_type_parameters ();
411 if (type_params.size > 0) {
412 write_string ("<");
413 bool first = true;
414 foreach (TypeParameter type_param in type_params) {
415 if (first) {
416 first = false;
417 } else {
418 write_string (",");
420 write_identifier (type_param.name);
422 write_string (">");
425 var prerequisites = iface.get_prerequisites ();
426 if (prerequisites.size > 0) {
427 write_string (" : ");
429 bool first = true;
430 foreach (DataType prerequisite in prerequisites) {
431 if (!first) {
432 write_string (", ");
433 } else {
434 first = false;
436 write_type (prerequisite);
439 write_begin_block ();
441 current_scope = iface.scope;
443 visit_sorted (iface.get_classes ());
444 visit_sorted (iface.get_structs ());
445 visit_sorted (iface.get_enums ());
446 visit_sorted (iface.get_delegates ());
447 visit_sorted (iface.get_fields ());
448 visit_sorted (iface.get_constants ());
449 visit_sorted (iface.get_methods ());
450 visit_sorted (iface.get_properties ());
451 visit_sorted (iface.get_signals ());
453 current_scope = current_scope.parent_scope;
455 write_end_block ();
456 write_newline ();
459 public override void visit_enum (Enum en) {
460 if (en.external_package) {
461 return;
464 if (!check_accessibility (en)) {
465 return;
468 write_indent ();
470 write_string ("[CCode (cprefix = \"%s\", ".printf (en.get_cprefix ()));
472 if (!en.has_type_id) {
473 write_string ("has_type_id = \"%d\", ".printf (en.has_type_id ? 1 : 0));
476 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(en)));
478 if (en.is_flags) {
479 write_indent ();
480 write_string ("[Flags]");
483 write_attributes (en);
485 write_indent ();
486 write_accessibility (en);
487 write_string ("enum ");
488 write_identifier (en.name);
489 write_begin_block ();
491 bool first = true;
492 foreach (EnumValue ev in en.get_values ()) {
493 if (first) {
494 first = false;
495 } else {
496 write_string (",");
497 write_newline ();
500 if (ev.get_cname () != ev.get_default_cname ()) {
501 write_indent ();
502 write_string ("[CCode (cname = \"%s\")]".printf (ev.get_cname ()));
504 write_indent ();
505 write_identifier (ev.name);
508 if (!first) {
509 if (en.get_methods ().size > 0) {
510 write_string (";");
512 write_newline ();
515 current_scope = en.scope;
516 foreach (Method m in en.get_methods ()) {
517 m.accept (this);
519 current_scope = current_scope.parent_scope;
521 write_end_block ();
522 write_newline ();
525 public override void visit_error_domain (ErrorDomain edomain) {
526 if (edomain.external_package) {
527 return;
530 if (!check_accessibility (edomain)) {
531 return;
534 write_indent ();
536 write_string ("[CCode (cprefix = \"%s\", cheader_filename = \"%s\")]".printf (edomain.get_cprefix (), get_cheaders(edomain)));
538 write_attributes (edomain);
540 write_indent ();
541 write_accessibility (edomain);
542 write_string ("errordomain ");
543 write_identifier (edomain.name);
544 write_begin_block ();
546 edomain.accept_children (this);
548 write_end_block ();
549 write_newline ();
552 public override void visit_error_code (ErrorCode ecode) {
553 write_indent ();
554 write_identifier (ecode.name);
555 write_string (",");
556 write_newline ();
559 public override void visit_constant (Constant c) {
560 if (c.external_package) {
561 return;
564 if (!check_accessibility (c)) {
565 return;
568 bool custom_cname = (c.get_cname () != c.get_default_cname ());
569 bool custom_cheaders = (c.parent_symbol is Namespace);
570 if (custom_cname || custom_cheaders) {
571 write_indent ();
572 write_string ("[CCode (");
574 if (custom_cname) {
575 write_string ("cname = \"%s\"".printf (c.get_cname ()));
578 if (custom_cheaders) {
579 if (custom_cname) {
580 write_string (", ");
583 write_string ("cheader_filename = \"%s\"".printf (get_cheaders(c)));
586 write_string (")]");
589 write_indent ();
590 write_accessibility (c);
591 write_string ("const ");
593 write_type (c.type_reference);
595 write_string (" ");
596 write_identifier (c.name);
597 write_string (";");
598 write_newline ();
601 public override void visit_field (Field f) {
602 if (f.external_package) {
603 return;
606 if (!check_accessibility (f)) {
607 return;
610 bool custom_cname = (f.get_cname () != f.get_default_cname ());
611 bool custom_ctype = (f.get_ctype () != null);
612 bool custom_cheaders = (f.parent_symbol is Namespace);
613 if (custom_cname || custom_ctype || custom_cheaders || (f.no_array_length && f.field_type is ArrayType)) {
614 write_indent ();
615 write_string ("[CCode (");
617 if (custom_cname) {
618 write_string ("cname = \"%s\"".printf (f.get_cname ()));
621 if (custom_ctype) {
622 if (custom_cname) {
623 write_string (", ");
626 write_string ("type = \"%s\"".printf (f.get_ctype ()));
629 if (custom_cheaders) {
630 if (custom_cname || custom_ctype) {
631 write_string (", ");
634 write_string ("cheader_filename = \"%s\"".printf (get_cheaders(f)));
637 if (f.no_array_length && f.field_type is ArrayType) {
638 if (custom_cname || custom_ctype || custom_cheaders) {
639 write_string (", ");
642 write_string ("array_length = false");
644 if (f.array_null_terminated) {
645 write_string (", array_null_terminated = true");
649 write_string (")]");
652 write_indent ();
653 write_accessibility (f);
655 if (f.binding == MemberBinding.STATIC) {
656 write_string ("static ");
657 } else if (f.binding == MemberBinding.CLASS) {
658 write_string ("class ");
661 if (is_weak (f.field_type)) {
662 write_string ("weak ");
665 write_type (f.field_type);
667 write_string (" ");
668 write_identifier (f.name);
669 write_string (";");
670 write_newline ();
673 private void write_error_domains (List<DataType> error_domains) {
674 if (error_domains.size > 0) {
675 write_string (" throws ");
677 bool first = true;
678 foreach (DataType type in error_domains) {
679 if (!first) {
680 write_string (", ");
681 } else {
682 first = false;
685 write_type (type);
690 // equality comparison with 3 digit precision
691 private bool float_equal (double d1, double d2) {
692 return ((int) (d1 * 1000)) == ((int) (d2 * 1000));
695 private void write_params (List<FormalParameter> params) {
696 write_string ("(");
698 int i = 1;
699 foreach (FormalParameter param in params) {
700 if (i > 1) {
701 write_string (", ");
704 if (param.ellipsis) {
705 write_string ("...");
706 continue;
710 var ccode_params = new StringBuilder ();
711 var separator = "";
713 if (param.ctype != null) {
714 ccode_params.append_printf ("%stype = \"%s\"", separator, param.ctype);
715 separator = ", ";
717 if (param.no_array_length && param.parameter_type is ArrayType) {
718 ccode_params.append_printf ("%sarray_length = false", separator);
719 separator = ", ";
721 if (!float_equal (param.carray_length_parameter_position, i + 0.1)) {
722 ccode_params.append_printf ("%sarray_length_pos = %g", separator, param.carray_length_parameter_position);
723 separator = ", ";
725 if (!float_equal (param.cdelegate_target_parameter_position, i + 0.1)) {
726 ccode_params.append_printf ("%sdelegate_target_pos = %g", separator, param.cdelegate_target_parameter_position);
727 separator = ", ";
730 if (ccode_params.len > 0) {
731 write_string ("[CCode (%s)] ".printf (ccode_params.str));
734 if (param.params_array) {
735 write_string ("params ");
738 if (param.direction == ParameterDirection.IN) {
739 if (param.parameter_type.value_owned) {
740 write_string ("owned ");
742 } else {
743 if (param.direction == ParameterDirection.REF) {
744 write_string ("ref ");
745 } else if (param.direction == ParameterDirection.OUT) {
746 write_string ("out ");
748 if (is_weak (param.parameter_type)) {
749 write_string ("unowned ");
753 write_type (param.parameter_type);
755 write_string (" ");
756 write_identifier (param.name);
758 if (param.default_expression != null) {
759 write_string (" = ");
760 write_string (param.default_expression.to_string ());
763 i++;
766 write_string (")");
769 public override void visit_delegate (Delegate cb) {
770 if (cb.external_package) {
771 return;
774 if (!check_accessibility (cb)) {
775 return;
778 write_indent ();
780 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(cb)));
782 if (!cb.has_target) {
783 write_string (", has_target = false");
786 write_string (")]");
788 write_indent ();
790 write_accessibility (cb);
791 write_string ("delegate ");
793 write_return_type (cb.return_type);
795 write_string (" ");
796 write_identifier (cb.name);
798 write_string (" ");
800 write_params (cb.get_parameters ());
802 write_string (";");
804 write_newline ();
807 public override void visit_constructor (Constructor c) {
808 if (!dump_tree) {
809 return;
812 write_indent ();
813 write_string ("construct");
814 write_code_block (c.body);
815 write_newline ();
818 public override void visit_method (Method m) {
819 if (m.external_package) {
820 return;
823 // don't write interface implementation unless it's an abstract or virtual method
824 if (!check_accessibility (m) || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
825 if (!dump_tree) {
826 return;
830 if (m.get_attribute ("NoWrapper") != null) {
831 write_indent ();
832 write_string ("[NoWrapper]");
834 if (m.returns_modified_pointer) {
835 write_indent ();
836 write_string ("[ReturnsModifiedPointer]");
838 if (m.printf_format) {
839 write_indent ();
840 write_string ("[PrintfFormat]");
842 if (m.scanf_format) {
843 write_indent ();
844 write_string ("[ScanfFormat]");
847 var ccode_params = new StringBuilder ();
848 var separator = "";
850 if (m.get_cname () != m.get_default_cname ()) {
851 ccode_params.append_printf ("%scname = \"%s\"", separator, m.get_cname ());
852 separator = ", ";
854 if (m.parent_symbol is Namespace) {
855 ccode_params.append_printf ("%scheader_filename = \"%s\"", separator, get_cheaders(m));
856 separator = ", ";
858 if (!float_equal (m.cinstance_parameter_position, 0)) {
859 ccode_params.append_printf ("%sinstance_pos = %g", separator, m.cinstance_parameter_position);
860 separator = ", ";
862 if (m.no_array_length && m.return_type is ArrayType) {
863 ccode_params.append_printf ("%sarray_length = false", separator);
864 separator = ", ";
866 if (!float_equal (m.carray_length_parameter_position, -3)) {
867 ccode_params.append_printf ("%sarray_length_pos = %g", separator, m.carray_length_parameter_position);
868 separator = ", ";
870 if (m.array_null_terminated && m.return_type is ArrayType) {
871 ccode_params.append_printf ("%sarray_null_terminated = true", separator);
872 separator = ", ";
874 if (!float_equal (m.cdelegate_target_parameter_position, -3)) {
875 ccode_params.append_printf ("%sdelegate_target_pos = %g", separator, m.cdelegate_target_parameter_position);
876 separator = ", ";
878 if (m.vfunc_name != m.name) {
879 ccode_params.append_printf ("%svfunc_name = \"%s\"", separator, m.vfunc_name);
880 separator = ", ";
882 if (m.sentinel != m.DEFAULT_SENTINEL) {
883 ccode_params.append_printf ("%ssentinel = \"%s\"", separator, m.sentinel);
884 separator = ", ";
886 if (m is CreationMethod && ((CreationMethod)m).custom_return_type_cname != null) {
887 ccode_params.append_printf ("%stype = \"%s\"", separator, ((CreationMethod)m).custom_return_type_cname);
888 separator = ", ";
890 if (m is CreationMethod && !m.has_construct_function) {
891 ccode_params.append_printf ("%shas_construct_function = false", separator);
892 separator = ", ";
895 if (ccode_params.len > 0) {
896 write_indent ();
897 write_string ("[CCode (%s)]".printf (ccode_params.str));
900 write_indent ();
901 write_accessibility (m);
903 if (m is CreationMethod) {
904 var datatype = (TypeSymbol) m.parent_symbol;
905 write_identifier (datatype.name);
906 if (m.name != ".new") {
907 write_string (".");
908 write_identifier (m.name);
910 write_string (" ");
911 } else if (m.binding == MemberBinding.STATIC) {
912 write_string ("static ");
913 } else if (m.binding == MemberBinding.CLASS) {
914 write_string ("class ");
915 } else if (m.is_abstract) {
916 write_string ("abstract ");
917 } else if (m.is_virtual) {
918 write_string ("virtual ");
919 } else if (m.overrides) {
920 write_string ("override ");
923 if (m.coroutine) {
924 write_string ("async ");
927 if (!(m is CreationMethod)) {
928 write_return_type (m.return_type);
929 write_string (" ");
931 write_identifier (m.name);
933 var type_params = m.get_type_parameters ();
934 if (type_params.size > 0) {
935 write_string ("<");
936 bool first = true;
937 foreach (TypeParameter type_param in type_params) {
938 if (first) {
939 first = false;
940 } else {
941 write_string (",");
943 write_identifier (type_param.name);
945 write_string (">");
948 write_string (" ");
951 write_params (m.get_parameters ());
952 write_error_domains (m.get_error_types ());
954 write_code_block (m.body);
956 write_newline ();
959 public override void visit_creation_method (CreationMethod m) {
960 visit_method (m);
963 public override void visit_property (Property prop) {
964 if (!check_accessibility (prop) || (prop.base_interface_property != null && !prop.is_abstract && !prop.is_virtual)) {
965 return;
968 if (prop.no_accessor_method) {
969 write_indent ();
970 write_string ("[NoAccessorMethod]");
972 if (prop.property_type is ArrayType && prop.no_array_length) {
973 write_indent ();
974 write_string ("[CCode (array_length = false");
976 if (prop.array_null_terminated) {
977 write_string (", array_null_terminated = true");
980 write_string (")]");
983 write_indent ();
984 write_accessibility (prop);
986 if (prop.binding == MemberBinding.STATIC) {
987 write_string ("static ");
988 } else if (prop.is_abstract) {
989 write_string ("abstract ");
990 } else if (prop.is_virtual) {
991 write_string ("virtual ");
992 } else if (prop.overrides) {
993 write_string ("override ");
996 write_type (prop.property_type);
998 write_string (" ");
999 write_identifier (prop.name);
1000 write_string (" {");
1001 if (prop.get_accessor != null) {
1002 if (prop.get_accessor.value_type.is_disposable ()) {
1003 write_string (" owned");
1006 write_string (" get");
1007 write_code_block (prop.get_accessor.body);
1009 if (prop.set_accessor != null) {
1010 if (prop.set_accessor.value_type.value_owned) {
1011 write_string ("owned ");
1014 if (prop.set_accessor.writable) {
1015 write_string (" set");
1017 if (prop.set_accessor.construction) {
1018 write_string (" construct");
1020 write_code_block (prop.set_accessor.body);
1022 write_string (" }");
1023 write_newline ();
1026 public override void visit_signal (Signal sig) {
1027 if (!check_accessibility (sig)) {
1028 return;
1031 if (sig.has_emitter) {
1032 write_indent ();
1033 write_string ("[HasEmitter]");
1036 write_indent ();
1037 write_accessibility (sig);
1039 if (sig.is_virtual) {
1040 write_string ("virtual ");
1043 write_string ("signal ");
1045 write_return_type (sig.return_type);
1047 write_string (" ");
1048 write_identifier (sig.name);
1050 write_string (" ");
1052 write_params (sig.get_parameters ());
1054 write_string (";");
1056 write_newline ();
1059 public override void visit_block (Block b) {
1060 write_begin_block ();
1062 foreach (Statement stmt in b.get_statements ()) {
1063 stmt.accept (this);
1066 write_end_block ();
1069 public override void visit_empty_statement (EmptyStatement stmt) {
1072 public override void visit_declaration_statement (DeclarationStatement stmt) {
1073 write_indent ();
1074 stmt.declaration.accept (this);
1075 write_string (";");
1076 write_newline ();
1079 public override void visit_local_variable (LocalVariable local) {
1080 write_type (local.variable_type);
1081 write_string (" ");
1082 write_identifier (local.name);
1083 if (local.initializer != null) {
1084 write_string (" = ");
1085 local.initializer.accept (this);
1089 public override void visit_initializer_list (InitializerList list) {
1090 write_string ("{");
1092 bool first = true;
1093 foreach (Expression initializer in list.get_initializers ()) {
1094 if (!first) {
1095 write_string (", ");
1096 } else {
1097 write_string (" ");
1099 first = false;
1100 initializer.accept (this);
1102 write_string (" }");
1105 public override void visit_expression_statement (ExpressionStatement stmt) {
1106 write_indent ();
1107 stmt.expression.accept (this);
1108 write_string (";");
1109 write_newline ();
1112 public override void visit_if_statement (IfStatement stmt) {
1113 write_indent ();
1114 write_string ("if (");
1115 stmt.condition.accept (this);
1116 write_string (")");
1117 stmt.true_statement.accept (this);
1118 if (stmt.false_statement != null) {
1119 write_string (" else");
1120 stmt.false_statement.accept (this);
1122 write_newline ();
1125 public override void visit_switch_statement (SwitchStatement stmt) {
1126 write_indent ();
1127 write_string ("switch (");
1128 stmt.expression.accept (this);
1129 write_string (") {");
1130 write_newline ();
1132 foreach (SwitchSection section in stmt.get_sections ()) {
1133 section.accept (this);
1136 write_indent ();
1137 write_string ("}");
1138 write_newline ();
1141 public override void visit_switch_section (SwitchSection section) {
1142 foreach (SwitchLabel label in section.get_labels ()) {
1143 label.accept (this);
1146 visit_block (section);
1149 public override void visit_switch_label (SwitchLabel label) {
1150 if (label.expression != null) {
1151 write_indent ();
1152 write_string ("case ");
1153 label.expression.accept (this);
1154 write_string (":");
1155 write_newline ();
1156 } else {
1157 write_indent ();
1158 write_string ("default:");
1159 write_newline ();
1163 public override void visit_loop (Loop stmt) {
1164 write_indent ();
1165 write_string ("loop");
1166 stmt.body.accept (this);
1167 write_newline ();
1170 public override void visit_while_statement (WhileStatement stmt) {
1171 write_indent ();
1172 write_string ("while (");
1173 stmt.condition.accept (this);
1174 write_string (")");
1175 stmt.body.accept (this);
1176 write_newline ();
1179 public override void visit_do_statement (DoStatement stmt) {
1180 write_indent ();
1181 write_string ("do");
1182 stmt.body.accept (this);
1183 write_string ("while (");
1184 stmt.condition.accept (this);
1185 write_string (");");
1186 write_newline ();
1189 public override void visit_for_statement (ForStatement stmt) {
1190 write_indent ();
1191 write_string ("for (");
1193 bool first = true;
1194 foreach (Expression initializer in stmt.get_initializer ()) {
1195 if (!first) {
1196 write_string (", ");
1198 first = false;
1199 initializer.accept (this);
1201 write_string ("; ");
1203 stmt.condition.accept (this);
1204 write_string ("; ");
1206 first = true;
1207 foreach (Expression iterator in stmt.get_iterator ()) {
1208 if (!first) {
1209 write_string (", ");
1211 first = false;
1212 iterator.accept (this);
1215 write_string (")");
1216 stmt.body.accept (this);
1217 write_newline ();
1220 public override void visit_foreach_statement (ForeachStatement stmt) {
1223 public override void visit_break_statement (BreakStatement stmt) {
1224 write_indent ();
1225 write_string ("break;");
1226 write_newline ();
1229 public override void visit_continue_statement (ContinueStatement stmt) {
1230 write_indent ();
1231 write_string ("continue;");
1232 write_newline ();
1235 public override void visit_return_statement (ReturnStatement stmt) {
1236 write_indent ();
1237 write_string ("return");
1238 if (stmt.return_expression != null) {
1239 write_string (" ");
1240 stmt.return_expression.accept (this);
1242 write_string (";");
1243 write_newline ();
1246 public override void visit_yield_statement (YieldStatement y) {
1247 write_indent ();
1248 write_string ("yield");
1249 if (y.yield_expression != null) {
1250 write_string (" ");
1251 y.yield_expression.accept (this);
1253 write_string (";");
1254 write_newline ();
1257 public override void visit_throw_statement (ThrowStatement stmt) {
1258 write_indent ();
1259 write_string ("throw");
1260 if (stmt.error_expression != null) {
1261 write_string (" ");
1262 stmt.error_expression.accept (this);
1264 write_string (";");
1265 write_newline ();
1268 public override void visit_try_statement (TryStatement stmt) {
1269 write_indent ();
1270 write_string ("try");
1271 stmt.body.accept (this);
1272 write_newline ();
1275 public override void visit_catch_clause (CatchClause clause) {
1278 public override void visit_lock_statement (LockStatement stmt) {
1281 public override void visit_delete_statement (DeleteStatement stmt) {
1284 public override void visit_array_creation_expression (ArrayCreationExpression expr) {
1285 write_string ("new ");
1286 write_type (expr.element_type);
1287 write_string ("[");
1289 bool first = true;
1290 foreach (Expression size in expr.get_sizes ()) {
1291 if (!first) {
1292 write_string (", ");
1294 first = false;
1296 size.accept (this);
1299 write_string ("]");
1301 if (expr.initializer_list != null) {
1302 write_string (" ");
1303 expr.initializer_list.accept (this);
1307 public override void visit_boolean_literal (BooleanLiteral lit) {
1308 write_string (lit.value.to_string ());
1311 public override void visit_character_literal (CharacterLiteral lit) {
1312 write_string (lit.value);
1315 public override void visit_integer_literal (IntegerLiteral lit) {
1316 write_string (lit.value);
1319 public override void visit_real_literal (RealLiteral lit) {
1320 write_string (lit.value);
1323 public override void visit_string_literal (StringLiteral lit) {
1324 write_string (lit.value);
1327 public override void visit_null_literal (NullLiteral lit) {
1328 write_string ("null");
1331 public override void visit_member_access (MemberAccess expr) {
1332 if (expr.inner != null) {
1333 expr.inner.accept (this);
1334 write_string (".");
1336 write_identifier (expr.member_name);
1339 public override void visit_method_call (MethodCall expr) {
1340 expr.call.accept (this);
1341 write_string (" (");
1343 bool first = true;
1344 foreach (Expression arg in expr.get_argument_list ()) {
1345 if (!first) {
1346 write_string (", ");
1348 first = false;
1350 arg.accept (this);
1353 write_string (")");
1356 public override void visit_element_access (ElementAccess expr) {
1357 expr.container.accept (this);
1358 write_string ("[");
1360 bool first = true;
1361 foreach (Expression index in expr.get_indices ()) {
1362 if (!first) {
1363 write_string (", ");
1365 first = false;
1367 index.accept (this);
1370 write_string ("]");
1373 public override void visit_base_access (BaseAccess expr) {
1374 write_string ("base");
1377 public override void visit_postfix_expression (PostfixExpression expr) {
1378 expr.inner.accept (this);
1379 if (expr.increment) {
1380 write_string ("++");
1381 } else {
1382 write_string ("--");
1386 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
1387 write_string ("new ");
1388 write_type (expr.type_reference);
1389 write_string (" (");
1391 bool first = true;
1392 foreach (Expression arg in expr.get_argument_list ()) {
1393 if (!first) {
1394 write_string (", ");
1396 first = false;
1398 arg.accept (this);
1401 write_string (")");
1404 public override void visit_sizeof_expression (SizeofExpression expr) {
1405 write_string ("sizeof (");
1406 write_type (expr.type_reference);
1407 write_string (")");
1410 public override void visit_typeof_expression (TypeofExpression expr) {
1411 write_string ("typeof (");
1412 write_type (expr.type_reference);
1413 write_string (")");
1416 public override void visit_unary_expression (UnaryExpression expr) {
1417 switch (expr.operator) {
1418 case UnaryOperator.PLUS:
1419 write_string ("+");
1420 break;
1421 case UnaryOperator.MINUS:
1422 write_string ("-");
1423 break;
1424 case UnaryOperator.LOGICAL_NEGATION:
1425 write_string ("!");
1426 break;
1427 case UnaryOperator.BITWISE_COMPLEMENT:
1428 write_string ("~");
1429 break;
1430 case UnaryOperator.INCREMENT:
1431 write_string ("++");
1432 break;
1433 case UnaryOperator.DECREMENT:
1434 write_string ("--");
1435 break;
1436 case UnaryOperator.REF:
1437 write_string ("ref ");
1438 break;
1439 case UnaryOperator.OUT:
1440 write_string ("out ");
1441 break;
1442 default:
1443 assert_not_reached ();
1445 expr.inner.accept (this);
1448 public override void visit_cast_expression (CastExpression expr) {
1449 if (expr.is_non_null_cast) {
1450 write_string ("(!) ");
1451 expr.inner.accept (this);
1452 return;
1455 if (!expr.is_silent_cast) {
1456 write_string ("(");
1457 write_type (expr.type_reference);
1458 write_string (") ");
1461 expr.inner.accept (this);
1463 if (expr.is_silent_cast) {
1464 write_string (" as ");
1465 write_type (expr.type_reference);
1469 public override void visit_pointer_indirection (PointerIndirection expr) {
1470 write_string ("*");
1471 expr.inner.accept (this);
1474 public override void visit_addressof_expression (AddressofExpression expr) {
1475 write_string ("&");
1476 expr.inner.accept (this);
1479 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
1480 write_string ("(owned) ");
1481 expr.inner.accept (this);
1484 public override void visit_binary_expression (BinaryExpression expr) {
1485 expr.left.accept (this);
1487 switch (expr.operator) {
1488 case BinaryOperator.PLUS:
1489 write_string (" + ");
1490 break;
1491 case BinaryOperator.MINUS:
1492 write_string (" - ");
1493 break;
1494 case BinaryOperator.MUL:
1495 write_string (" * ");
1496 break;
1497 case BinaryOperator.DIV:
1498 write_string (" / ");
1499 break;
1500 case BinaryOperator.MOD:
1501 write_string (" % ");
1502 break;
1503 case BinaryOperator.SHIFT_LEFT:
1504 write_string (" << ");
1505 break;
1506 case BinaryOperator.SHIFT_RIGHT:
1507 write_string (" >> ");
1508 break;
1509 case BinaryOperator.LESS_THAN:
1510 write_string (" < ");
1511 break;
1512 case BinaryOperator.GREATER_THAN:
1513 write_string (" > ");
1514 break;
1515 case BinaryOperator.LESS_THAN_OR_EQUAL:
1516 write_string (" <= ");
1517 break;
1518 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1519 write_string (" >= ");
1520 break;
1521 case BinaryOperator.EQUALITY:
1522 write_string (" == ");
1523 break;
1524 case BinaryOperator.INEQUALITY:
1525 write_string (" != ");
1526 break;
1527 case BinaryOperator.BITWISE_AND:
1528 write_string (" & ");
1529 break;
1530 case BinaryOperator.BITWISE_OR:
1531 write_string (" | ");
1532 break;
1533 case BinaryOperator.BITWISE_XOR:
1534 write_string (" ^ ");
1535 break;
1536 case BinaryOperator.AND:
1537 write_string (" && ");
1538 break;
1539 case BinaryOperator.OR:
1540 write_string (" || ");
1541 break;
1542 case BinaryOperator.IN:
1543 write_string (" in ");
1544 break;
1545 default:
1546 assert_not_reached ();
1549 expr.right.accept (this);
1552 public override void visit_type_check (TypeCheck expr) {
1553 expr.expression.accept (this);
1554 write_string (" is ");
1555 write_type (expr.type_reference);
1558 public override void visit_conditional_expression (ConditionalExpression expr) {
1559 expr.condition.accept (this);
1560 write_string ("?");
1561 expr.true_expression.accept (this);
1562 write_string (":");
1563 expr.false_expression.accept (this);
1566 public override void visit_lambda_expression (LambdaExpression expr) {
1569 public override void visit_assignment (Assignment a) {
1570 a.left.accept (this);
1571 write_string (" = ");
1572 a.right.accept (this);
1575 private void write_indent () {
1576 int i;
1578 if (!bol) {
1579 stream.putc ('\n');
1582 for (i = 0; i < indent; i++) {
1583 stream.putc ('\t');
1586 bol = false;
1589 private void write_identifier (string s) {
1590 char* id = (char*)s;
1591 int id_length = (int)s.length;
1592 if ( Vala.Scanner.get_identifier_or_keyword (id, id_length) != Vala.TokenType.IDENTIFIER ||
1593 s.get_char ().isdigit ()) {
1594 stream.putc ('@');
1596 write_string (s);
1599 private void write_return_type (DataType type) {
1600 if (is_weak (type)) {
1601 write_string ("unowned ");
1604 write_type (type);
1607 private bool is_weak (DataType type) {
1608 if (type.value_owned) {
1609 return false;
1610 } else if (type is VoidType || type is PointerType) {
1611 return false;
1612 } else if (type is ValueType) {
1613 if (type.nullable) {
1614 // nullable structs are heap allocated
1615 return true;
1618 // TODO return true for structs with destroy
1619 return false;
1622 return true;
1625 private void write_type (DataType type) {
1626 write_string (type.to_qualified_string (current_scope));
1629 private void write_string (string s) {
1630 stream.printf ("%s", s);
1631 bol = false;
1634 private void write_newline () {
1635 stream.putc ('\n');
1636 bol = true;
1639 void write_code_block (Block? block) {
1640 if (block == null || !dump_tree) {
1641 write_string (";");
1642 return;
1645 block.accept (this);
1648 private void write_begin_block () {
1649 if (!bol) {
1650 stream.putc (' ');
1651 } else {
1652 write_indent ();
1654 stream.putc ('{');
1655 write_newline ();
1656 indent++;
1659 private void write_end_block () {
1660 indent--;
1661 write_indent ();
1662 stream.printf ("}");
1665 private bool check_accessibility (Symbol sym) {
1666 if (dump_tree) {
1667 return true;
1668 } else {
1669 if (!emit_internal &&
1670 ( sym.access == SymbolAccessibility.PUBLIC ||
1671 sym.access == SymbolAccessibility.PROTECTED)) {
1672 return true;
1673 } else if (emit_internal &&
1674 ( sym.access == SymbolAccessibility.INTERNAL ||
1675 sym.access == SymbolAccessibility.PUBLIC ||
1676 sym.access == SymbolAccessibility.PROTECTED)) {
1677 return true;
1681 return false;
1684 private void write_attributes (CodeNode node) {
1685 foreach (Attribute attr in node.attributes) {
1686 if (!filter_attribute (attr)) {
1687 write_indent ();
1688 stream.printf ("[%s", attr.name);
1690 var keys = attr.args.get_keys ();
1691 if (keys.size != 0) {
1692 stream.printf (" (");
1694 string separator = "";
1695 foreach (string arg_name in keys) {
1696 stream.printf ("%s%s = ", separator, arg_name);
1697 var expr = attr.args.get (arg_name);
1698 expr.accept (this);
1699 separator = ", ";
1702 stream.printf (")");
1704 stream.printf ("]");
1705 write_newline ();
1710 private bool filter_attribute (Attribute attr) {
1711 if (attr.name == "CCode"
1712 || attr.name == "Compact" || attr.name == "Immutable"
1713 || attr.name == "SimpleType" || attr.name == "IntegerType" || attr.name == "FloatingType"
1714 || attr.name == "Flags") {
1715 return true;
1717 return false;
1720 private void write_accessibility (Symbol sym) {
1721 if (sym.access == SymbolAccessibility.PUBLIC) {
1722 write_string ("public ");
1723 } else if (sym.access == SymbolAccessibility.PROTECTED) {
1724 write_string ("protected ");
1725 } else if (sym.access == SymbolAccessibility.INTERNAL) {
1726 write_string ("internal ");
1727 } else if (sym.access == SymbolAccessibility.PRIVATE) {
1728 write_string ("private ");