Use `internal' accessibility for namespace members by default
[vala-lang.git] / vala / valacodewriter.vala
blob248b3b3da2db2efda5393177bda6031250300ce5
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>
25 using Gee;
27 /**
28 * Code visitor generating Vala API file for the public interface.
30 public class Vala.CodeWriter : CodeVisitor {
31 private CodeContext context;
33 FileStream stream;
35 int indent;
36 /* at begin of line */
37 bool bol = true;
39 Scope current_scope;
41 bool dump_tree;
43 public CodeWriter (bool dump_tree = false) {
44 this.dump_tree = dump_tree;
47 /**
48 * Writes the public interface of the specified code context into the
49 * specified file.
51 * @param context a code context
52 * @param filename a relative or absolute filename
54 public void write_file (CodeContext context, string filename) {
55 this.context = context;
57 stream = FileStream.open (filename, "w");
59 write_string ("/* %s generated by %s, do not modify. */".printf (Path.get_basename (filename), Environment.get_prgname ()));
60 write_newline ();
61 write_newline ();
63 current_scope = context.root.scope;
65 context.accept (this);
67 current_scope = null;
69 stream = null;
72 public override void visit_namespace (Namespace ns) {
73 if (ns.external_package) {
74 return;
77 if (ns.name == null) {
78 ns.accept_children (this);
79 return;
82 write_indent ();
83 write_string ("[CCode (cprefix = \"%s\", lower_case_cprefix = \"%s\")]".printf (ns.get_cprefix (), ns.get_lower_case_cprefix ()));
84 write_newline ();
86 write_indent ();
87 write_string ("namespace ");
88 write_identifier (ns.name);
89 write_begin_block ();
91 current_scope = ns.scope;
93 visit_sorted (ns.get_namespaces ());
94 visit_sorted (ns.get_classes ());
95 visit_sorted (ns.get_interfaces ());
96 visit_sorted (ns.get_structs ());
97 visit_sorted (ns.get_enums ());
98 visit_sorted (ns.get_error_types ());
99 visit_sorted (ns.get_delegates ());
100 visit_sorted (ns.get_fields ());
101 visit_sorted (ns.get_constants ());
102 visit_sorted (ns.get_methods ());
104 current_scope = current_scope.parent_scope;
106 write_end_block ();
107 write_newline ();
110 public override void visit_class (Class cl) {
111 if (cl.external_package) {
112 return;
115 if (!check_accessibility (cl)) {
116 return;
119 if (cl.is_compact) {
120 write_indent ();
121 write_string ("[Compact]");
122 write_newline ();
125 if (cl.is_immutable) {
126 write_indent ();
127 write_string ("[Immutable]");
128 write_newline ();
131 write_indent ();
133 write_string ("[CCode (");
135 if (cl.is_reference_counting ()) {
136 if (cl.base_class == null || cl.base_class.get_ref_function () == null || cl.base_class.get_ref_function () != cl.get_ref_function ()) {
137 write_string ("ref_function = \"%s\", ".printf (cl.get_ref_function ()));
139 if (cl.base_class == null || cl.base_class.get_unref_function () == null || cl.base_class.get_unref_function () != cl.get_unref_function ()) {
140 write_string ("unref_function = \"%s\", ".printf (cl.get_unref_function ()));
142 } else {
143 if (cl.get_dup_function () != null) {
144 write_string ("copy_function = \"%s\", ".printf (cl.get_dup_function ()));
146 if (cl.get_free_function () != cl.get_default_free_function ()) {
147 write_string ("free_function = \"%s\", ".printf (cl.get_free_function ()));
151 if (cl.get_cname () != cl.get_default_cname ()) {
152 write_string ("cname = \"%s\", ".printf (cl.get_cname ()));
155 if (cl.type_check_function != null) {
156 write_string ("type_check_function = \"%s\", ".printf (cl.type_check_function ));
159 if (cl.get_param_spec_function () != null
160 && (cl.base_class == null || cl.get_param_spec_function () != cl.base_class.get_param_spec_function ())) {
161 write_string ("param_spec_function = \"%s\", ".printf (cl.get_param_spec_function ()));
164 bool first = true;
165 string cheaders = "";
166 foreach (string cheader in cl.get_cheader_filenames ()) {
167 if (first) {
168 cheaders = cheader;
169 first = false;
170 } else {
171 cheaders = "%s,%s".printf (cheaders, cheader);
174 write_string ("cheader_filename = \"%s\")]".printf (cheaders));
175 write_newline ();
177 write_indent ();
178 write_accessibility (cl);
179 if (cl.is_abstract) {
180 write_string ("abstract ");
182 write_string ("class ");
183 write_identifier (cl.name);
185 var type_params = cl.get_type_parameters ();
186 if (type_params.size > 0) {
187 write_string ("<");
188 first = true;
189 foreach (TypeParameter type_param in type_params) {
190 if (first) {
191 first = false;
192 } else {
193 write_string (",");
195 write_identifier (type_param.name);
197 write_string (">");
200 var base_types = cl.get_base_types ();
201 if (base_types.size > 0) {
202 write_string (" : ");
204 first = true;
205 foreach (DataType base_type in base_types) {
206 if (!first) {
207 write_string (", ");
208 } else {
209 first = false;
211 write_type (base_type);
214 write_begin_block ();
216 current_scope = cl.scope;
218 visit_sorted (cl.get_classes ());
219 visit_sorted (cl.get_structs ());
220 visit_sorted (cl.get_enums ());
221 visit_sorted (cl.get_delegates ());
222 visit_sorted (cl.get_fields ());
223 visit_sorted (cl.get_constants ());
224 visit_sorted (cl.get_methods ());
225 visit_sorted (cl.get_properties ());
226 visit_sorted (cl.get_signals ());
228 current_scope = current_scope.parent_scope;
230 write_end_block ();
231 write_newline ();
234 void visit_sorted (Gee.List<Symbol> symbols) {
235 var sorted_symbols = new Gee.ArrayList<Symbol> ();
236 foreach (Symbol sym in symbols) {
237 int left = 0;
238 int right = sorted_symbols.size - 1;
239 if (left > right || sym.name < sorted_symbols[left].name) {
240 sorted_symbols.insert (0, sym);
241 } else if (sym.name > sorted_symbols[right].name) {
242 sorted_symbols.add (sym);
243 } else {
244 while (right - left > 1) {
245 int i = (right + left) / 2;
246 if (sym.name > sorted_symbols[i].name) {
247 left = i;
248 } else {
249 right = i;
252 sorted_symbols.insert (left + 1, sym);
255 foreach (Symbol sym in sorted_symbols) {
256 sym.accept (this);
260 public override void visit_struct (Struct st) {
261 if (st.external_package) {
262 return;
265 if (!check_accessibility (st)) {
266 return;
269 write_indent ();
271 write_string ("[CCode (");
273 if (st.get_cname () != st.get_default_cname ()) {
274 write_string ("cname = \"%s\", ".printf (st.get_cname ()));
277 if (!st.is_simple_type () && st.get_type_id () != "G_TYPE_POINTER") {
278 write_string ("type_id = \"%s\", ".printf (st.get_type_id ()));
281 bool first = true;
282 string cheaders = "";
283 foreach (string cheader in st.get_cheader_filenames ()) {
284 if (first) {
285 cheaders = cheader;
286 first = false;
287 } else {
288 cheaders = "%s,%s".printf (cheaders, cheader);
291 write_string ("cheader_filename = \"%s\")]".printf (cheaders));
292 write_newline ();
294 if (st.is_simple_type ()) {
295 write_indent ();
296 write_string ("[SimpleType]");
297 write_newline ();
300 if (st.is_integer_type ()) {
301 write_indent ();
302 write_string ("[IntegerType (rank = %d)]".printf (st.get_rank ()));
303 write_newline ();
306 if (st.is_floating_type ()) {
307 write_indent ();
308 write_string ("[FloatingType (rank = %d)]".printf (st.get_rank ()));
309 write_newline ();
312 write_indent ();
313 write_accessibility (st);
314 write_string ("struct ");
315 write_identifier (st.name);
317 var base_types = st.get_base_types ();
318 if (base_types.size > 0) {
319 write_string (" : ");
321 first = true;
322 foreach (DataType base_type in base_types) {
323 if (!first) {
324 write_string (", ");
325 } else {
326 first = false;
328 write_type (base_type);
332 write_begin_block ();
334 current_scope = st.scope;
336 foreach (Field field in st.get_fields ()) {
337 field.accept (this);
339 visit_sorted (st.get_constants ());
340 visit_sorted (st.get_methods ());
342 current_scope = current_scope.parent_scope;
344 write_end_block ();
345 write_newline ();
348 public override void visit_interface (Interface iface) {
349 if (iface.external_package) {
350 return;
353 if (!check_accessibility (iface)) {
354 return;
357 write_indent ();
359 bool first = true;
360 string cheaders = "";
361 foreach (string cheader in iface.get_cheader_filenames ()) {
362 if (first) {
363 cheaders = cheader;
364 first = false;
365 } else {
366 cheaders = "%s,%s".printf (cheaders, cheader);
369 write_string ("[CCode (cheader_filename = \"%s\"".printf (cheaders));
370 if (iface.get_lower_case_csuffix () != iface.get_default_lower_case_csuffix ())
371 write_string (", lower_case_csuffix = \"%s\"".printf (iface.get_lower_case_csuffix ()));
373 write_string (")]");
374 write_newline ();
376 write_indent ();
377 write_accessibility (iface);
378 write_string ("interface ");
379 write_identifier (iface.name);
381 var type_params = iface.get_type_parameters ();
382 if (type_params.size > 0) {
383 write_string ("<");
384 first = true;
385 foreach (TypeParameter type_param in type_params) {
386 if (first) {
387 first = false;
388 } else {
389 write_string (",");
391 write_identifier (type_param.name);
393 write_string (">");
396 var prerequisites = iface.get_prerequisites ();
397 if (prerequisites.size > 0) {
398 write_string (" : ");
400 first = true;
401 foreach (DataType prerequisite in prerequisites) {
402 if (!first) {
403 write_string (", ");
404 } else {
405 first = false;
407 write_type (prerequisite);
410 write_begin_block ();
412 current_scope = iface.scope;
414 visit_sorted (iface.get_classes ());
415 visit_sorted (iface.get_structs ());
416 visit_sorted (iface.get_enums ());
417 visit_sorted (iface.get_delegates ());
418 visit_sorted (iface.get_fields ());
419 visit_sorted (iface.get_methods ());
420 visit_sorted (iface.get_properties ());
421 visit_sorted (iface.get_signals ());
423 current_scope = current_scope.parent_scope;
425 write_end_block ();
426 write_newline ();
429 public override void visit_enum (Enum en) {
430 if (en.external_package) {
431 return;
434 if (!check_accessibility (en)) {
435 return;
438 write_indent ();
440 bool first = true;
441 string cheaders = "";
442 foreach (string cheader in en.get_cheader_filenames ()) {
443 if (first) {
444 cheaders = cheader;
445 first = false;
446 } else {
447 cheaders = "%s,%s".printf (cheaders, cheader);
451 write_string ("[CCode (cprefix = \"%s\", ".printf (en.get_cprefix ()));
453 if (!en.has_type_id) {
454 write_string ("has_type_id = \"%d\", ".printf (en.has_type_id ? 1 : 0));
457 write_string ("cheader_filename = \"%s\")]".printf (cheaders));
459 if (en.is_flags) {
460 write_indent ();
461 write_string ("[Flags]");
464 write_indent ();
465 write_accessibility (en);
466 write_string ("enum ");
467 write_identifier (en.name);
468 write_begin_block ();
470 first = true;
471 foreach (EnumValue ev in en.get_values ()) {
472 if (first) {
473 first = false;
474 } else {
475 write_string (",");
476 write_newline ();
479 if (ev.get_cname () != ev.get_default_cname ()) {
480 write_indent ();
481 write_string ("[CCode (cname = \"%s\")]".printf (ev.get_cname ()));
483 write_indent ();
484 write_identifier (ev.name);
487 if (!first) {
488 if (en.get_methods ().size > 0) {
489 write_string (";");
491 write_newline ();
494 current_scope = en.scope;
495 foreach (Method m in en.get_methods ()) {
496 m.accept (this);
498 current_scope = current_scope.parent_scope;
500 write_end_block ();
501 write_newline ();
504 public override void visit_error_domain (ErrorDomain edomain) {
505 if (edomain.external_package) {
506 return;
509 if (!check_accessibility (edomain)) {
510 return;
513 write_indent ();
515 var first = true;
516 string cheaders = "";
517 foreach (string cheader in edomain.get_cheader_filenames ()) {
518 if (first) {
519 cheaders = cheader;
520 first = false;
521 } else {
522 cheaders = "%s,%s".printf (cheaders, cheader);
525 write_string ("[CCode (cprefix = \"%s\", cheader_filename = \"%s\")]".printf (edomain.get_cprefix (), cheaders));
527 write_indent ();
528 write_accessibility (edomain);
529 write_string ("errordomain ");
530 write_identifier (edomain.name);
531 write_begin_block ();
533 edomain.accept_children (this);
535 write_end_block ();
536 write_newline ();
539 public override void visit_error_code (ErrorCode ecode) {
540 write_indent ();
541 write_identifier (ecode.name);
542 write_string (",");
543 write_newline ();
546 public override void visit_constant (Constant c) {
547 if (c.external_package) {
548 return;
551 if (!check_accessibility (c)) {
552 return;
555 bool custom_cname = (c.get_cname () != c.get_default_cname ());
556 bool custom_cheaders = (c.parent_symbol is Namespace);
557 if (custom_cname || custom_cheaders) {
558 write_indent ();
559 write_string ("[CCode (");
561 if (custom_cname) {
562 write_string ("cname = \"%s\"".printf (c.get_cname ()));
565 if (custom_cheaders) {
566 if (custom_cname) {
567 write_string (", ");
570 bool first = true;
571 string cheaders = "";
572 foreach (string cheader in c.get_cheader_filenames ()) {
573 if (first) {
574 cheaders = cheader;
575 first = false;
576 } else {
577 cheaders = "%s,%s".printf (cheaders, cheader);
580 write_string ("cheader_filename = \"%s\"".printf (cheaders));
583 write_string (")]");
586 write_indent ();
587 write_accessibility (c);
588 write_string ("const ");
590 write_type (c.type_reference);
592 write_string (" ");
593 write_identifier (c.name);
594 write_string (";");
595 write_newline ();
598 public override void visit_field (Field f) {
599 if (f.external_package) {
600 return;
603 if (!check_accessibility (f)) {
604 return;
607 bool custom_cname = (f.get_cname () != f.get_default_cname ());
608 bool custom_ctype = (f.get_ctype () != null);
609 bool custom_cheaders = (f.parent_symbol is Namespace);
610 if (custom_cname || custom_ctype || custom_cheaders || (f.no_array_length && f.field_type is ArrayType)) {
611 write_indent ();
612 write_string ("[CCode (");
614 if (custom_cname) {
615 write_string ("cname = \"%s\"".printf (f.get_cname ()));
618 if (custom_ctype) {
619 if (custom_cname) {
620 write_string (", ");
623 write_string ("type = \"%s\"".printf (f.get_ctype ()));
626 if (custom_cheaders) {
627 if (custom_cname || custom_ctype) {
628 write_string (", ");
631 bool first = true;
632 string cheaders = "";
633 foreach (string cheader in f.get_cheader_filenames ()) {
634 if (first) {
635 cheaders = cheader;
636 first = false;
637 } else {
638 cheaders = "%s,%s".printf (cheaders, cheader);
641 write_string ("cheader_filename = \"%s\"".printf (cheaders));
644 if (f.no_array_length && f.field_type is ArrayType) {
645 if (custom_cname || custom_ctype || custom_cheaders) {
646 write_string (", ");
649 write_string ("array_length = false");
652 write_string (")]");
655 write_indent ();
656 write_accessibility (f);
658 if (f.binding == MemberBinding.STATIC) {
659 write_string ("static ");
660 } else if (f.binding == MemberBinding.CLASS) {
661 write_string ("class ");
664 if (is_weak (f.field_type)) {
665 write_string ("weak ");
668 write_type (f.field_type);
670 write_string (" ");
671 write_identifier (f.name);
672 write_string (";");
673 write_newline ();
676 private void write_error_domains (Gee.List<DataType> error_domains) {
677 if (error_domains.size > 0) {
678 write_string (" throws ");
680 bool first = true;
681 foreach (DataType type in error_domains) {
682 if (!first) {
683 write_string (", ");
684 } else {
685 first = false;
688 write_type (type);
693 // equality comparison with 3 digit precision
694 private bool float_equal (double d1, double d2) {
695 return ((int) (d1 * 1000)) == ((int) (d2 * 1000));
698 private void write_params (Gee.List<FormalParameter> params) {
699 write_string ("(");
701 int i = 1;
702 foreach (FormalParameter param in params) {
703 if (i > 1) {
704 write_string (", ");
707 if (param.ellipsis) {
708 write_string ("...");
709 continue;
713 var ccode_params = new StringBuilder ();
714 var separator = "";
716 if (param.ctype != null) {
717 ccode_params.append_printf ("%stype = \"%s\"", separator, param.ctype);
718 separator = ", ";
720 if (param.no_array_length && param.parameter_type is ArrayType) {
721 ccode_params.append_printf ("%sarray_length = false", separator);
722 separator = ", ";
724 if (!float_equal (param.carray_length_parameter_position, i + 0.1)) {
725 ccode_params.append_printf ("%sarray_length_pos = %g", separator, param.carray_length_parameter_position);
726 separator = ", ";
728 if (!float_equal (param.cdelegate_target_parameter_position, i + 0.1)) {
729 ccode_params.append_printf ("%sdelegate_target_pos = %g", separator, param.cdelegate_target_parameter_position);
730 separator = ", ";
733 if (ccode_params.len > 0) {
734 write_string ("[CCode (%s)] ".printf (ccode_params.str));
737 if (param.params_array) {
738 write_string ("params ");
741 if (param.direction == ParameterDirection.IN) {
742 if (param.parameter_type.value_owned) {
743 write_string ("owned ");
745 } else {
746 if (param.direction == ParameterDirection.REF) {
747 write_string ("ref ");
748 } else if (param.direction == ParameterDirection.OUT) {
749 write_string ("out ");
751 if (is_weak (param.parameter_type)) {
752 write_string ("unowned ");
756 write_type (param.parameter_type);
758 write_string (" ");
759 write_identifier (param.name);
761 if (param.default_expression != null) {
762 write_string (" = ");
763 write_string (param.default_expression.to_string ());
766 i++;
769 write_string (")");
772 public override void visit_delegate (Delegate cb) {
773 if (cb.external_package) {
774 return;
777 if (!check_accessibility (cb)) {
778 return;
781 write_indent ();
783 var first = true;
784 string cheaders = "";
785 foreach (string cheader in cb.get_cheader_filenames ()) {
786 if (first) {
787 cheaders = cheader;
788 first = false;
789 } else {
790 cheaders = "%s,%s".printf (cheaders, cheader);
793 write_string ("[CCode (cheader_filename = \"%s\")]".printf (cheaders));
795 write_indent ();
797 write_accessibility (cb);
798 if (!cb.has_target) {
799 write_string ("static ");
801 write_string ("delegate ");
803 write_return_type (cb.return_type);
805 write_string (" ");
806 write_identifier (cb.name);
808 write_string (" ");
810 write_params (cb.get_parameters ());
812 write_string (";");
814 write_newline ();
817 public override void visit_method (Method m) {
818 if (m.external_package) {
819 return;
822 // don't write interface implementation unless it's an abstract or virtual method
823 if (!check_accessibility (m) || m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
824 if (!dump_tree) {
825 return;
829 if (m.get_attribute ("NoWrapper") != null) {
830 write_indent ();
831 write_string ("[NoWrapper]");
833 if (m.returns_modified_pointer) {
834 write_indent ();
835 write_string ("[ReturnsModifiedPointer]");
838 var ccode_params = new StringBuilder ();
839 var separator = "";
841 if (m.get_cname () != m.get_default_cname ()) {
842 ccode_params.append_printf ("%scname = \"%s\"", separator, m.get_cname ());
843 separator = ", ";
845 if (m.parent_symbol is Namespace) {
846 bool first = true;
847 string cheaders = "";
848 foreach (string cheader in m.get_cheader_filenames ()) {
849 if (first) {
850 cheaders = cheader;
851 first = false;
852 } else {
853 cheaders = "%s,%s".printf (cheaders, cheader);
856 ccode_params.append_printf ("%scheader_filename = \"%s\"", separator, cheaders);
857 separator = ", ";
859 if (!float_equal (m.cinstance_parameter_position, 0)) {
860 ccode_params.append_printf ("%sinstance_pos = %g", separator, m.cinstance_parameter_position);
861 separator = ", ";
863 if (m.no_array_length && m.return_type is ArrayType) {
864 ccode_params.append_printf ("%sarray_length = false", separator);
865 separator = ", ";
867 if (!float_equal (m.carray_length_parameter_position, -3)) {
868 ccode_params.append_printf ("%sarray_length_pos = %g", separator, m.carray_length_parameter_position);
869 separator = ", ";
871 if (m.array_null_terminated && m.return_type is ArrayType) {
872 ccode_params.append_printf ("%sarray_null_terminated = true", separator);
873 separator = ", ";
875 if (!float_equal (m.cdelegate_target_parameter_position, -3)) {
876 ccode_params.append_printf ("%sdelegate_target_pos = %g", separator, m.cdelegate_target_parameter_position);
877 separator = ", ";
879 if (m.sentinel != m.DEFAULT_SENTINEL) {
880 ccode_params.append_printf ("%ssentinel = \"%s\"", separator, m.sentinel);
881 separator = ", ";
883 if (m is CreationMethod && ((CreationMethod)m).custom_return_type_cname != null) {
884 ccode_params.append_printf ("%stype = \"%s\"", separator, ((CreationMethod)m).custom_return_type_cname);
885 separator = ", ";
887 if (m is CreationMethod && !m.has_construct_function) {
888 ccode_params.append_printf ("%shas_construct_function = false", separator);
889 separator = ", ";
892 if (ccode_params.len > 0) {
893 write_indent ();
894 write_string ("[CCode (%s)]".printf (ccode_params.str));
897 write_indent ();
898 write_accessibility (m);
900 if (m is CreationMethod) {
901 var datatype = (TypeSymbol) m.parent_symbol;
902 write_identifier (datatype.name);
903 if (m.name != "new") {
904 write_string (".");
905 write_identifier (m.name);
907 write_string (" ");
908 } else if (m.binding == MemberBinding.STATIC) {
909 write_string ("static ");
910 } else if (m.binding == MemberBinding.CLASS) {
911 write_string ("class ");
912 } else if (m.is_abstract) {
913 write_string ("abstract ");
914 } else if (m.is_virtual) {
915 write_string ("virtual ");
918 if (!(m is CreationMethod)) {
919 write_return_type (m.return_type);
920 write_string (" ");
922 write_identifier (m.name);
923 write_string (" ");
926 write_params (m.get_parameters ());
927 write_error_domains (m.get_error_types ());
929 write_code_block (m.body);
931 write_newline ();
934 public override void visit_creation_method (CreationMethod m) {
935 visit_method (m);
938 public override void visit_property (Property prop) {
939 if (!check_accessibility (prop) || prop.overrides || (prop.base_interface_property != null && !prop.is_abstract && !prop.is_virtual)) {
940 return;
943 if (prop.no_accessor_method) {
944 write_indent ();
945 write_string ("[NoAccessorMethod]");
948 write_indent ();
949 write_accessibility (prop);
951 if (prop.binding == MemberBinding.STATIC) {
952 write_string ("static ");
953 } else if (prop.is_abstract) {
954 write_string ("abstract ");
955 } else if (prop.is_virtual) {
956 write_string ("virtual ");
959 write_type (prop.property_type);
961 write_string (" ");
962 write_identifier (prop.name);
963 write_string (" {");
964 if (prop.get_accessor != null) {
965 if (prop.get_accessor.value_type.is_disposable ()) {
966 write_string (" owned");
969 write_string (" get");
970 write_code_block (prop.get_accessor.body);
972 if (prop.set_accessor != null) {
973 if (prop.set_accessor.value_type.value_owned) {
974 write_string ("owned ");
977 if (prop.set_accessor.writable) {
978 write_string (" set");
980 if (prop.set_accessor.construction) {
981 write_string (" construct");
983 write_code_block (prop.set_accessor.body);
985 write_string (" }");
986 write_newline ();
989 public override void visit_signal (Signal sig) {
990 if (!check_accessibility (sig)) {
991 return;
994 if (sig.has_emitter) {
995 write_indent ();
996 write_string ("[HasEmitter]");
999 write_indent ();
1000 write_accessibility (sig);
1002 if (sig.is_virtual) {
1003 write_string ("virtual ");
1006 write_string ("signal ");
1008 write_return_type (sig.return_type);
1010 write_string (" ");
1011 write_identifier (sig.name);
1013 write_string (" ");
1015 write_params (sig.get_parameters ());
1017 write_string (";");
1019 write_newline ();
1022 public override void visit_block (Block b) {
1023 write_begin_block ();
1025 foreach (Statement stmt in b.get_statements ()) {
1026 stmt.accept (this);
1029 write_end_block ();
1032 public override void visit_empty_statement (EmptyStatement stmt) {
1035 public override void visit_declaration_statement (DeclarationStatement stmt) {
1036 write_indent ();
1037 stmt.declaration.accept (this);
1038 write_string (";");
1039 write_newline ();
1042 public override void visit_local_variable (LocalVariable local) {
1043 write_type (local.variable_type);
1044 write_string (" ");
1045 write_identifier (local.name);
1046 if (local.initializer != null) {
1047 write_string (" = ");
1048 local.initializer.accept (this);
1052 public override void visit_initializer_list (InitializerList list) {
1053 write_string ("{");
1055 bool first = true;
1056 foreach (Expression initializer in list.get_initializers ()) {
1057 if (!first) {
1058 write_string (", ");
1059 } else {
1060 write_string (" ");
1062 first = false;
1063 initializer.accept (this);
1065 write_string (" }");
1068 public override void visit_expression_statement (ExpressionStatement stmt) {
1069 write_indent ();
1070 stmt.expression.accept (this);
1071 write_string (";");
1072 write_newline ();
1075 public override void visit_if_statement (IfStatement stmt) {
1076 write_indent ();
1077 write_string ("if (");
1078 stmt.condition.accept (this);
1079 write_string (")");
1080 stmt.true_statement.accept (this);
1081 if (stmt.false_statement != null) {
1082 write_string (" else");
1083 stmt.false_statement.accept (this);
1085 write_newline ();
1088 public override void visit_switch_statement (SwitchStatement stmt) {
1089 write_indent ();
1090 write_string ("switch (");
1091 stmt.expression.accept (this);
1092 write_string (") {");
1093 write_newline ();
1095 foreach (SwitchSection section in stmt.get_sections ()) {
1096 section.accept (this);
1099 write_indent ();
1100 write_string ("}");
1101 write_newline ();
1104 public override void visit_switch_section (SwitchSection section) {
1105 foreach (SwitchLabel label in section.get_labels ()) {
1106 label.accept (this);
1109 visit_block (section);
1112 public override void visit_switch_label (SwitchLabel label) {
1113 if (label.expression != null) {
1114 write_indent ();
1115 write_string ("case ");
1116 label.expression.accept (this);
1117 write_string (":");
1118 write_newline ();
1119 } else {
1120 write_indent ();
1121 write_string ("default:");
1122 write_newline ();
1126 public override void visit_while_statement (WhileStatement stmt) {
1127 write_indent ();
1128 write_string ("while (");
1129 stmt.condition.accept (this);
1130 write_string (")");
1131 stmt.body.accept (this);
1132 write_newline ();
1135 public override void visit_do_statement (DoStatement stmt) {
1136 write_indent ();
1137 write_string ("do");
1138 stmt.body.accept (this);
1139 write_string ("while (");
1140 stmt.condition.accept (this);
1141 write_string (");");
1142 write_newline ();
1145 public override void visit_for_statement (ForStatement stmt) {
1146 write_indent ();
1147 write_string ("for (");
1149 bool first = true;
1150 foreach (Expression initializer in stmt.get_initializer ()) {
1151 if (!first) {
1152 write_string (", ");
1154 first = false;
1155 initializer.accept (this);
1157 write_string ("; ");
1159 stmt.condition.accept (this);
1160 write_string ("; ");
1162 first = true;
1163 foreach (Expression iterator in stmt.get_iterator ()) {
1164 if (!first) {
1165 write_string (", ");
1167 first = false;
1168 iterator.accept (this);
1171 write_string (")");
1172 stmt.body.accept (this);
1173 write_newline ();
1176 public override void visit_foreach_statement (ForeachStatement stmt) {
1179 public override void visit_break_statement (BreakStatement stmt) {
1180 write_indent ();
1181 write_string ("break;");
1182 write_newline ();
1185 public override void visit_continue_statement (ContinueStatement stmt) {
1186 write_indent ();
1187 write_string ("continue;");
1188 write_newline ();
1191 public override void visit_return_statement (ReturnStatement stmt) {
1192 write_indent ();
1193 write_string ("return");
1194 if (stmt.return_expression != null) {
1195 write_string (" ");
1196 stmt.return_expression.accept (this);
1198 write_string (";");
1199 write_newline ();
1202 public override void visit_yield_statement (YieldStatement y) {
1203 write_indent ();
1204 write_string ("yield");
1205 if (y.yield_expression != null) {
1206 write_string (" ");
1207 y.yield_expression.accept (this);
1209 write_string (";");
1210 write_newline ();
1213 public override void visit_throw_statement (ThrowStatement stmt) {
1214 write_indent ();
1215 write_string ("throw");
1216 if (stmt.error_expression != null) {
1217 write_string (" ");
1218 stmt.error_expression.accept (this);
1220 write_string (";");
1221 write_newline ();
1224 public override void visit_try_statement (TryStatement stmt) {
1225 write_indent ();
1226 write_string ("try");
1227 stmt.body.accept (this);
1228 write_newline ();
1231 public override void visit_catch_clause (CatchClause clause) {
1234 public override void visit_lock_statement (LockStatement stmt) {
1237 public override void visit_delete_statement (DeleteStatement stmt) {
1240 public override void visit_array_creation_expression (ArrayCreationExpression expr) {
1241 write_string ("new ");
1242 write_type (expr.element_type);
1243 write_string ("[");
1245 bool first = true;
1246 foreach (Expression size in expr.get_sizes ()) {
1247 if (!first) {
1248 write_string (", ");
1250 first = false;
1252 size.accept (this);
1255 write_string ("]");
1257 if (expr.initializer_list != null) {
1258 write_string (" ");
1259 expr.initializer_list.accept (this);
1263 public override void visit_boolean_literal (BooleanLiteral lit) {
1264 write_string (lit.value.to_string ());
1267 public override void visit_character_literal (CharacterLiteral lit) {
1268 write_string (lit.value);
1271 public override void visit_integer_literal (IntegerLiteral lit) {
1272 write_string (lit.value);
1275 public override void visit_real_literal (RealLiteral lit) {
1276 write_string (lit.value);
1279 public override void visit_string_literal (StringLiteral lit) {
1280 write_string (lit.value);
1283 public override void visit_null_literal (NullLiteral lit) {
1284 write_string ("null");
1287 public override void visit_parenthesized_expression (ParenthesizedExpression expr) {
1288 write_string ("(");
1289 expr.inner.accept (this);
1290 write_string (")");
1293 public override void visit_member_access (MemberAccess expr) {
1294 if (expr.inner != null) {
1295 expr.inner.accept (this);
1296 write_string (".");
1298 write_identifier (expr.member_name);
1301 public override void visit_method_call (MethodCall expr) {
1302 expr.call.accept (this);
1303 write_string (" (");
1305 bool first = true;
1306 foreach (Expression arg in expr.get_argument_list ()) {
1307 if (!first) {
1308 write_string (", ");
1310 first = false;
1312 arg.accept (this);
1315 write_string (")");
1318 public override void visit_element_access (ElementAccess expr) {
1319 expr.container.accept (this);
1320 write_string ("[");
1322 bool first = true;
1323 foreach (Expression index in expr.get_indices ()) {
1324 if (!first) {
1325 write_string (", ");
1327 first = false;
1329 index.accept (this);
1332 write_string ("]");
1335 public override void visit_base_access (BaseAccess expr) {
1336 write_string ("base");
1339 public override void visit_postfix_expression (PostfixExpression expr) {
1340 expr.inner.accept (this);
1341 if (expr.increment) {
1342 write_string ("++");
1343 } else {
1344 write_string ("--");
1348 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
1349 write_string ("new ");
1350 write_type (expr.type_reference);
1351 write_string (" (");
1353 bool first = true;
1354 foreach (Expression arg in expr.get_argument_list ()) {
1355 if (!first) {
1356 write_string (", ");
1358 first = false;
1360 arg.accept (this);
1363 write_string (")");
1366 public override void visit_sizeof_expression (SizeofExpression expr) {
1367 write_string ("sizeof (");
1368 write_type (expr.type_reference);
1369 write_string (")");
1372 public override void visit_typeof_expression (TypeofExpression expr) {
1373 write_string ("typeof (");
1374 write_type (expr.type_reference);
1375 write_string (")");
1378 public override void visit_unary_expression (UnaryExpression expr) {
1379 switch (expr.operator) {
1380 case UnaryOperator.PLUS:
1381 write_string ("+");
1382 break;
1383 case UnaryOperator.MINUS:
1384 write_string ("-");
1385 break;
1386 case UnaryOperator.LOGICAL_NEGATION:
1387 write_string ("!");
1388 break;
1389 case UnaryOperator.BITWISE_COMPLEMENT:
1390 write_string ("~");
1391 break;
1392 case UnaryOperator.INCREMENT:
1393 write_string ("++");
1394 break;
1395 case UnaryOperator.DECREMENT:
1396 write_string ("--");
1397 break;
1398 case UnaryOperator.REF:
1399 write_string ("ref ");
1400 break;
1401 case UnaryOperator.OUT:
1402 write_string ("out ");
1403 break;
1404 default:
1405 assert_not_reached ();
1407 expr.inner.accept (this);
1410 public override void visit_cast_expression (CastExpression expr) {
1411 if (!expr.is_silent_cast) {
1412 write_string ("(");
1413 write_type (expr.type_reference);
1414 write_string (") ");
1417 expr.inner.accept (this);
1419 if (expr.is_silent_cast) {
1420 write_string (" as ");
1421 write_type (expr.type_reference);
1425 public override void visit_pointer_indirection (PointerIndirection expr) {
1426 write_string ("*");
1427 expr.inner.accept (this);
1430 public override void visit_addressof_expression (AddressofExpression expr) {
1431 write_string ("&");
1432 expr.inner.accept (this);
1435 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
1436 write_string ("(owned) ");
1437 expr.inner.accept (this);
1440 public override void visit_binary_expression (BinaryExpression expr) {
1441 expr.left.accept (this);
1443 switch (expr.operator) {
1444 case BinaryOperator.PLUS:
1445 write_string (" + ");
1446 break;
1447 case BinaryOperator.MINUS:
1448 write_string (" - ");
1449 break;
1450 case BinaryOperator.MUL:
1451 write_string (" * ");
1452 break;
1453 case BinaryOperator.DIV:
1454 write_string (" / ");
1455 break;
1456 case BinaryOperator.MOD:
1457 write_string (" % ");
1458 break;
1459 case BinaryOperator.SHIFT_LEFT:
1460 write_string (" << ");
1461 break;
1462 case BinaryOperator.SHIFT_RIGHT:
1463 write_string (" >> ");
1464 break;
1465 case BinaryOperator.LESS_THAN:
1466 write_string (" < ");
1467 break;
1468 case BinaryOperator.GREATER_THAN:
1469 write_string (" > ");
1470 break;
1471 case BinaryOperator.LESS_THAN_OR_EQUAL:
1472 write_string (" <= ");
1473 break;
1474 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1475 write_string (" >= ");
1476 break;
1477 case BinaryOperator.EQUALITY:
1478 write_string (" == ");
1479 break;
1480 case BinaryOperator.INEQUALITY:
1481 write_string (" != ");
1482 break;
1483 case BinaryOperator.BITWISE_AND:
1484 write_string (" & ");
1485 break;
1486 case BinaryOperator.BITWISE_OR:
1487 write_string (" | ");
1488 break;
1489 case BinaryOperator.BITWISE_XOR:
1490 write_string (" ^ ");
1491 break;
1492 case BinaryOperator.AND:
1493 write_string (" && ");
1494 break;
1495 case BinaryOperator.OR:
1496 write_string (" || ");
1497 break;
1498 case BinaryOperator.IN:
1499 write_string (" in ");
1500 break;
1501 default:
1502 assert_not_reached ();
1505 expr.right.accept (this);
1508 public override void visit_type_check (TypeCheck expr) {
1509 expr.expression.accept (this);
1510 write_string (" is ");
1511 write_type (expr.type_reference);
1514 public override void visit_conditional_expression (ConditionalExpression expr) {
1515 expr.condition.accept (this);
1516 write_string ("?");
1517 expr.true_expression.accept (this);
1518 write_string (":");
1519 expr.false_expression.accept (this);
1522 public override void visit_lambda_expression (LambdaExpression expr) {
1525 public override void visit_assignment (Assignment a) {
1526 a.left.accept (this);
1527 write_string (" = ");
1528 a.right.accept (this);
1531 private void write_indent () {
1532 int i;
1534 if (!bol) {
1535 stream.putc ('\n');
1538 for (i = 0; i < indent; i++) {
1539 stream.putc ('\t');
1542 bol = false;
1545 private void write_identifier (string s) {
1546 if (s == "base" || s == "break" || s == "class" ||
1547 s == "construct" || s == "delegate" || s == "delete" ||
1548 s == "do" || s == "foreach" || s == "in" ||
1549 s == "interface" || s == "lock" || s == "namespace" ||
1550 s == "new" || s == "out" || s == "ref" ||
1551 s == "signal") {
1552 stream.putc ('@');
1554 write_string (s);
1557 private void write_return_type (DataType type) {
1558 if (is_weak (type)) {
1559 write_string ("unowned ");
1562 write_type (type);
1565 private bool is_weak (DataType type) {
1566 if (type.value_owned) {
1567 return false;
1568 } else if (type is VoidType || type is PointerType) {
1569 return false;
1570 } else if (type is ValueType) {
1571 if (type.nullable) {
1572 // nullable structs are heap allocated
1573 return true;
1576 // TODO return true for structs with destroy
1577 return false;
1580 return true;
1583 private void write_type (DataType type) {
1584 write_string (type.to_qualified_string (current_scope));
1587 private void write_string (string s) {
1588 stream.printf ("%s", s);
1589 bol = false;
1592 private void write_newline () {
1593 stream.putc ('\n');
1594 bol = true;
1597 void write_code_block (Block? block) {
1598 if (block == null || !dump_tree) {
1599 write_string (";");
1600 return;
1603 block.accept (this);
1606 private void write_begin_block () {
1607 if (!bol) {
1608 stream.putc (' ');
1609 } else {
1610 write_indent ();
1612 stream.putc ('{');
1613 write_newline ();
1614 indent++;
1617 private void write_end_block () {
1618 indent--;
1619 write_indent ();
1620 stream.printf ("}");
1623 private bool check_accessibility (Symbol sym) {
1624 if (dump_tree ||
1625 sym.access == SymbolAccessibility.PUBLIC ||
1626 sym.access == SymbolAccessibility.PROTECTED) {
1627 return true;
1630 return false;
1633 private void write_accessibility (Symbol sym) {
1634 if (sym.access == SymbolAccessibility.PUBLIC) {
1635 write_string ("public ");
1636 } else if (sym.access == SymbolAccessibility.PROTECTED) {
1637 write_string ("protected ");
1638 } else if (sym.access == SymbolAccessibility.INTERNAL) {
1639 write_string ("internal ");
1640 } else if (sym.access == SymbolAccessibility.PRIVATE) {
1641 write_string ("private ");