gstreamer-1.0: Update to 1.13.1+
[vala-gnome.git] / vala / valacodewriter.vala
blob2fed2d8f59ca085993bf4bf83ba900a444c451ca
1 /* valacodewriter.vala
3 * Copyright (C) 2006-2014 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
5 * Copyright (C) 2014 Richard Wiedenhöft
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Author:
22 * Jürg Billeter <j@bitron.ch>
23 * Raffaele Sandrini <raffaele@sandrini.ch>
27 /**
28 * Code visitor generating Vala API file for the public interface.
30 public class Vala.CodeWriter : CodeVisitor {
31 static GLib.Regex fix_indent_regex;
33 private CodeContext context;
35 FileStream stream;
37 int indent;
38 /* at begin of line */
39 bool bol = true;
41 Scope current_scope;
43 CodeWriterType type;
45 string? override_header = null;
46 string? header_to_override = null;
48 public CodeWriter (CodeWriterType type = CodeWriterType.EXTERNAL) {
49 this.type = type;
52 /**
53 * Allows overriding of a specific cheader in the output
54 * @param original orignal cheader to override
55 * @param replacement cheader to replace original with
57 public void set_cheader_override (string original, string replacement)
59 header_to_override = original;
60 override_header = replacement;
63 /**
64 * Writes the public interface of the specified code context into the
65 * specified file.
67 * @param context a code context
68 * @param filename a relative or absolute filename
70 public void write_file (CodeContext context, string filename) {
71 var file_exists = FileUtils.test (filename, FileTest.EXISTS);
72 var temp_filename = "%s.valatmp".printf (filename);
73 this.context = context;
75 if (file_exists) {
76 stream = FileStream.open (temp_filename, "w");
77 } else {
78 stream = FileStream.open (filename, "w");
81 if (stream == null) {
82 Report.error (null, "unable to open `%s' for writing".printf (filename));
83 return;
86 var header = context.version_header ?
87 "/* %s generated by %s %s, do not modify. */".printf (Path.get_basename (filename), Environment.get_prgname (), Config.BUILD_VERSION) :
88 "/* %s generated by %s, do not modify. */".printf (Path.get_basename (filename), Environment.get_prgname ());
89 write_string (header);
90 write_newline ();
91 write_newline ();
93 current_scope = context.root.scope;
95 context.accept (this);
97 current_scope = null;
99 stream = null;
101 if (file_exists) {
102 var changed = true;
104 try {
105 var old_file = new MappedFile (filename, false);
106 var new_file = new MappedFile (temp_filename, false);
107 var len = old_file.get_length ();
108 if (len == new_file.get_length ()) {
109 if (Memory.cmp (old_file.get_contents (), new_file.get_contents (), len) == 0) {
110 changed = false;
113 old_file = null;
114 new_file = null;
115 } catch (FileError e) {
116 // assume changed if mmap comparison doesn't work
119 if (changed) {
120 FileUtils.rename (temp_filename, filename);
121 } else {
122 FileUtils.unlink (temp_filename);
128 public override void visit_using_directive (UsingDirective ns) {
129 if (type == CodeWriterType.FAST) {
130 write_string ("using ");
132 var symbols = new GLib.List<UnresolvedSymbol> ();
133 var sym = (UnresolvedSymbol) ns.namespace_symbol;
134 symbols.prepend (sym);
136 while ((sym = sym.inner) != null) {
137 symbols.prepend (sym);
140 write_string (symbols.nth_data (0).name);
142 for (int i = 1; i < symbols.length (); i++) {
143 write_string (".");
144 write_string (symbols.nth_data (i).name);
147 write_string (";\n");
151 public override void visit_namespace (Namespace ns) {
152 if (ns.external_package) {
153 return;
156 if (ns.name == null) {
157 ns.accept_children (this);
158 return;
161 var comments = ns.get_comments ();
162 if (context.vapi_comments && comments.size > 0) {
163 bool first = true;
164 SourceReference? first_reference = null;
165 foreach (Comment comment in comments) {
166 if (comment.source_reference.file.file_type == SourceFileType.SOURCE) {
167 if (first) {
168 write_comment (comment);
169 first = false;
170 first_reference = comment.source_reference;
171 } else {
172 Report.warning (comment.source_reference, "Comment describes namespace, that was already described by another comment.");
173 Report.notice (first_reference, "Previous comment was here.");
179 write_attributes (ns);
181 write_indent ();
182 write_string ("namespace ");
183 write_identifier (ns.name);
184 write_begin_block ();
186 current_scope = ns.scope;
188 visit_sorted (ns.get_namespaces ());
189 visit_sorted (ns.get_classes ());
190 visit_sorted (ns.get_interfaces ());
191 visit_sorted (ns.get_structs ());
192 visit_sorted (ns.get_enums ());
193 visit_sorted (ns.get_error_domains ());
194 visit_sorted (ns.get_delegates ());
195 visit_sorted (ns.get_fields ());
196 visit_sorted (ns.get_constants ());
197 visit_sorted (ns.get_methods ());
199 current_scope = current_scope.parent_scope;
201 write_end_block ();
202 write_newline ();
205 private string get_cheaders (Symbol sym) {
206 string cheaders = "";
207 if (type != CodeWriterType.FAST && !sym.external_package) {
208 cheaders = sym.get_attribute_string ("CCode", "cheader_filename") ?? "";
209 if (cheaders == "" && sym.parent_symbol != null && sym.parent_symbol != context.root) {
210 cheaders = get_cheaders (sym.parent_symbol);
212 if (cheaders == "" && sym.source_reference != null && !sym.external_package) {
213 cheaders = sym.source_reference.file.get_cinclude_filename ();
216 if (header_to_override != null) {
217 var cheaders_array = cheaders.split (",");
218 for (int i = 0; i < cheaders_array.length; i++) {
219 if (cheaders_array[i] == header_to_override) {
220 cheaders_array[i] = override_header;
223 cheaders = string.joinv (",", cheaders_array);
226 return cheaders;
229 public override void visit_class (Class cl) {
230 if (cl.external_package) {
231 return;
234 if (!check_accessibility (cl)) {
235 return;
238 if (context.vapi_comments && cl.comment != null) {
239 write_comment (cl.comment);
242 write_attributes (cl);
244 write_indent ();
245 write_accessibility (cl);
246 if (cl.is_abstract) {
247 write_string ("abstract ");
249 write_string ("class ");
250 write_identifier (cl.name);
252 write_type_parameters (cl.get_type_parameters ());
254 var base_types = cl.get_base_types ();
255 if (base_types.size > 0) {
256 write_string (" : ");
258 bool first = true;
259 foreach (DataType base_type in base_types) {
260 if (!first) {
261 write_string (", ");
262 } else {
263 first = false;
265 write_type (base_type);
268 write_begin_block ();
270 current_scope = cl.scope;
272 visit_sorted (cl.get_classes ());
273 visit_sorted (cl.get_structs ());
274 visit_sorted (cl.get_enums ());
275 visit_sorted (cl.get_delegates ());
276 visit_sorted (cl.get_fields ());
277 visit_sorted (cl.get_constants ());
278 visit_sorted (cl.get_methods ());
279 visit_sorted (cl.get_properties ());
280 visit_sorted (cl.get_signals ());
282 if (cl.constructor != null) {
283 cl.constructor.accept (this);
286 current_scope = current_scope.parent_scope;
288 write_end_block ();
289 write_newline ();
292 void visit_sorted (List<Symbol> symbols) {
293 if (type != CodeWriterType.EXTERNAL) {
294 // order of virtual methods matters for fast vapis
295 foreach (Symbol sym in symbols) {
296 sym.accept (this);
298 return;
301 var sorted_symbols = new ArrayList<Symbol> ();
302 foreach (Symbol sym in symbols) {
303 int left = 0;
304 int right = sorted_symbols.size - 1;
305 if (left > right || sym.name < sorted_symbols[left].name) {
306 sorted_symbols.insert (0, sym);
307 } else if (sym.name > sorted_symbols[right].name) {
308 sorted_symbols.add (sym);
309 } else {
310 while (right - left > 1) {
311 int i = (right + left) / 2;
312 if (sym.name > sorted_symbols[i].name) {
313 left = i;
314 } else {
315 right = i;
318 sorted_symbols.insert (left + 1, sym);
321 foreach (Symbol sym in sorted_symbols) {
322 sym.accept (this);
326 public override void visit_struct (Struct st) {
327 if (st.external_package) {
328 return;
331 if (!check_accessibility (st)) {
332 return;
335 if (context.vapi_comments && st.comment != null) {
336 write_comment (st.comment);
339 write_attributes (st);
341 write_indent ();
342 write_accessibility (st);
343 write_string ("struct ");
344 write_identifier (st.name);
346 write_type_parameters (st.get_type_parameters ());
348 if (st.base_type != null) {
349 write_string (" : ");
350 write_type (st.base_type);
353 write_begin_block ();
355 current_scope = st.scope;
357 foreach (Field field in st.get_fields ()) {
358 field.accept (this);
360 visit_sorted (st.get_constants ());
361 visit_sorted (st.get_methods ());
362 visit_sorted (st.get_properties ());
364 current_scope = current_scope.parent_scope;
366 write_end_block ();
367 write_newline ();
370 public override void visit_interface (Interface iface) {
371 if (iface.external_package) {
372 return;
375 if (!check_accessibility (iface)) {
376 return;
379 if (context.vapi_comments && iface.comment != null) {
380 write_comment (iface.comment);
383 write_attributes (iface);
385 write_indent ();
386 write_accessibility (iface);
387 write_string ("interface ");
388 write_identifier (iface.name);
390 write_type_parameters (iface.get_type_parameters ());
392 var prerequisites = iface.get_prerequisites ();
393 if (prerequisites.size > 0) {
394 write_string (" : ");
396 bool first = true;
397 foreach (DataType prerequisite in prerequisites) {
398 if (!first) {
399 write_string (", ");
400 } else {
401 first = false;
403 write_type (prerequisite);
406 write_begin_block ();
408 current_scope = iface.scope;
410 visit_sorted (iface.get_classes ());
411 visit_sorted (iface.get_structs ());
412 visit_sorted (iface.get_enums ());
413 visit_sorted (iface.get_delegates ());
414 visit_sorted (iface.get_fields ());
415 visit_sorted (iface.get_constants ());
416 visit_sorted (iface.get_methods ());
417 visit_sorted (iface.get_properties ());
418 visit_sorted (iface.get_signals ());
420 current_scope = current_scope.parent_scope;
422 write_end_block ();
423 write_newline ();
426 public override void visit_enum (Enum en) {
427 if (en.external_package) {
428 return;
431 if (!check_accessibility (en)) {
432 return;
435 if (context.vapi_comments && en.comment != null) {
436 write_comment (en.comment);
439 write_attributes (en);
441 write_indent ();
442 write_accessibility (en);
443 write_string ("enum ");
444 write_identifier (en.name);
445 write_begin_block ();
447 bool first = true;
448 foreach (EnumValue ev in en.get_values ()) {
449 if (first) {
450 first = false;
451 } else {
452 write_string (",");
453 write_newline ();
456 if (context.vapi_comments && ev.comment != null) {
457 write_comment (ev.comment);
460 write_attributes (ev);
462 write_indent ();
463 write_identifier (ev.name);
465 if (type == CodeWriterType.FAST && ev.value != null) {
466 write_string(" = ");
467 ev.value.accept (this);
471 if (!first) {
472 if (en.get_methods ().size > 0 || en.get_constants ().size > 0) {
473 write_string (";");
475 write_newline ();
478 current_scope = en.scope;
479 foreach (Method m in en.get_methods ()) {
480 m.accept (this);
482 foreach (Constant c in en.get_constants ()) {
483 c.accept (this);
485 current_scope = current_scope.parent_scope;
487 write_end_block ();
488 write_newline ();
491 public override void visit_error_domain (ErrorDomain edomain) {
492 if (edomain.external_package) {
493 return;
496 if (!check_accessibility (edomain)) {
497 return;
500 if (context.vapi_comments && edomain.comment != null) {
501 write_comment (edomain.comment);
504 write_attributes (edomain);
506 write_indent ();
507 write_accessibility (edomain);
508 write_string ("errordomain ");
509 write_identifier (edomain.name);
510 write_begin_block ();
512 bool first = true;
513 foreach (ErrorCode ecode in edomain.get_codes ()) {
514 if (first) {
515 first = false;
516 } else {
517 write_string (",");
518 write_newline ();
521 if (context.vapi_comments && ecode.comment != null) {
522 write_comment (ecode.comment);
525 write_attributes (ecode);
527 write_indent ();
528 write_identifier (ecode.name);
531 if (!first) {
532 if (edomain.get_methods ().size > 0) {
533 write_string (";");
535 write_newline ();
538 current_scope = edomain.scope;
539 foreach (Method m in edomain.get_methods ()) {
540 m.accept (this);
542 current_scope = current_scope.parent_scope;
544 write_end_block ();
545 write_newline ();
548 public override void visit_constant (Constant c) {
549 if (c.external_package) {
550 return;
553 if (!check_accessibility (c)) {
554 return;
557 if (context.vapi_comments && c.comment != null) {
558 write_comment (c.comment);
561 write_attributes (c);
563 write_indent ();
564 write_accessibility (c);
565 write_string ("const ");
567 write_type (c.type_reference);
569 write_string (" ");
570 write_identifier (c.name);
571 write_type_suffix (c.type_reference);
572 if (type == CodeWriterType.FAST && c.value != null) {
573 write_string(" = ");
574 c.value.accept (this);
576 write_string (";");
577 write_newline ();
580 public override void visit_field (Field f) {
581 if (f.external_package) {
582 return;
585 if (!check_accessibility (f)) {
586 return;
589 if (context.vapi_comments && f.comment != null) {
590 write_comment (f.comment);
593 write_attributes (f);
595 write_indent ();
596 write_accessibility (f);
598 if (f.binding == MemberBinding.STATIC) {
599 write_string ("static ");
600 } else if (f.binding == MemberBinding.CLASS) {
601 write_string ("class ");
604 if (f.variable_type.is_weak ()) {
605 write_string ("weak ");
608 write_type (f.variable_type);
610 write_string (" ");
611 write_identifier (f.name);
612 write_type_suffix (f.variable_type);
613 write_string (";");
614 write_newline ();
617 private void write_error_domains (List<DataType> error_domains) {
618 if (error_domains.size > 0) {
619 write_string (" throws ");
621 bool first = true;
622 foreach (DataType type in error_domains) {
623 if (!first) {
624 write_string (", ");
625 } else {
626 first = false;
629 write_type (type);
634 private void write_params (List<Parameter> params) {
635 write_string ("(");
637 int i = 1;
638 foreach (Parameter param in params) {
639 if (i > 1) {
640 write_string (", ");
643 if (param.ellipsis) {
644 write_string ("...");
645 continue;
648 write_attributes (param);
650 if (param.params_array) {
651 write_string ("params ");
654 if (param.direction == ParameterDirection.IN) {
655 if (param.variable_type.value_owned) {
656 write_string ("owned ");
658 } else {
659 if (param.direction == ParameterDirection.REF) {
660 write_string ("ref ");
661 } else if (param.direction == ParameterDirection.OUT) {
662 write_string ("out ");
664 if (param.variable_type.is_weak ()) {
665 write_string ("unowned ");
669 write_type (param.variable_type);
671 write_string (" ");
672 write_identifier (param.name);
673 write_type_suffix (param.variable_type);
675 if (param.initializer != null) {
676 write_string (" = ");
677 param.initializer.accept (this);
680 i++;
683 write_string (")");
686 public override void visit_delegate (Delegate cb) {
687 if (cb.external_package) {
688 return;
691 if (!check_accessibility (cb)) {
692 return;
695 if (context.vapi_comments && cb.comment != null) {
696 write_comment (cb.comment);
699 write_attributes (cb);
701 write_indent ();
703 write_accessibility (cb);
704 write_string ("delegate ");
706 write_return_type (cb.return_type);
708 write_string (" ");
709 write_identifier (cb.name);
711 write_type_parameters (cb.get_type_parameters ());
713 write_string (" ");
715 write_params (cb.get_parameters ());
717 write_error_domains (cb.get_error_types ());
719 write_string (";");
721 write_newline ();
724 public override void visit_constructor (Constructor c) {
725 if (type != CodeWriterType.DUMP) {
726 return;
729 if (context.vapi_comments && c.comment != null) {
730 write_comment (c.comment);
733 write_indent ();
734 write_string ("construct");
735 write_code_block (c.body);
736 write_newline ();
739 public override void visit_method (Method m) {
740 if (m.external_package) {
741 return;
744 // don't write interface implementation unless it's an abstract or virtual method
745 if (!check_accessibility (m) || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
746 if (type != CodeWriterType.DUMP) {
747 return;
751 if (context.vapi_comments && m.comment != null) {
752 write_comment (m.comment);
755 write_attributes (m);
757 write_indent ();
758 write_accessibility (m);
760 if (m is CreationMethod) {
761 if (m.coroutine) {
762 write_string ("async ");
765 var datatype = (TypeSymbol) m.parent_symbol;
766 write_identifier (datatype.name);
767 if (m.name != ".new") {
768 write_string (".");
769 write_identifier (m.name);
771 write_string (" ");
772 } else {
773 if (m.binding == MemberBinding.STATIC) {
774 write_string ("static ");
775 } else if (m.binding == MemberBinding.CLASS) {
776 write_string ("class ");
777 } else if (m.is_abstract) {
778 write_string ("abstract ");
779 } else if (m.is_virtual) {
780 write_string ("virtual ");
781 } else if (m.overrides) {
782 write_string ("override ");
785 if (m.hides) {
786 write_string ("new ");
789 if (m.coroutine) {
790 write_string ("async ");
793 write_return_type (m.return_type);
794 write_string (" ");
796 write_identifier (m.name);
798 write_type_parameters (m.get_type_parameters ());
800 write_string (" ");
803 write_params (m.get_parameters ());
805 write_error_domains (m.get_error_types ());
807 write_code_block (m.body);
809 write_newline ();
812 public override void visit_creation_method (CreationMethod m) {
813 visit_method (m);
816 public override void visit_property (Property prop) {
817 if (!check_accessibility (prop) || (prop.base_interface_property != null && !prop.is_abstract && !prop.is_virtual)) {
818 return;
821 if (context.vapi_comments && prop.comment != null) {
822 write_comment (prop.comment);
825 write_attributes (prop);
827 write_indent ();
828 write_accessibility (prop);
830 if (prop.binding == MemberBinding.STATIC) {
831 write_string ("static ");
832 } else if (prop.is_abstract) {
833 write_string ("abstract ");
834 } else if (prop.is_virtual) {
835 write_string ("virtual ");
836 } else if (prop.overrides) {
837 write_string ("override ");
840 write_type (prop.property_type);
842 write_string (" ");
843 write_identifier (prop.name);
844 write_string (" {");
845 if (prop.get_accessor != null) {
846 write_attributes (prop.get_accessor);
848 write_property_accessor_accessibility (prop.get_accessor);
850 if (prop.get_accessor.value_type.is_disposable ()) {
851 write_string (" owned");
854 write_string (" get");
855 write_code_block (prop.get_accessor.body);
857 if (prop.set_accessor != null) {
858 write_attributes (prop.set_accessor);
860 write_property_accessor_accessibility (prop.set_accessor);
862 if (prop.set_accessor.value_type.value_owned) {
863 write_string (" owned");
866 if (prop.set_accessor.writable) {
867 write_string (" set");
869 if (prop.set_accessor.construction) {
870 write_string (" construct");
872 write_code_block (prop.set_accessor.body);
874 write_string (" }");
875 write_newline ();
878 public override void visit_signal (Signal sig) {
879 if (!check_accessibility (sig)) {
880 return;
883 if (context.vapi_comments && sig.comment != null) {
884 write_comment (sig.comment);
887 write_attributes (sig);
889 write_indent ();
890 write_accessibility (sig);
892 if (sig.is_virtual) {
893 write_string ("virtual ");
896 write_string ("signal ");
898 write_return_type (sig.return_type);
900 write_string (" ");
901 write_identifier (sig.name);
903 write_string (" ");
905 write_params (sig.get_parameters ());
907 write_string (";");
909 write_newline ();
912 public override void visit_block (Block b) {
913 write_begin_block ();
915 foreach (Statement stmt in b.get_statements ()) {
916 stmt.accept (this);
919 write_end_block ();
922 public override void visit_empty_statement (EmptyStatement stmt) {
925 public override void visit_declaration_statement (DeclarationStatement stmt) {
926 write_indent ();
927 stmt.declaration.accept (this);
928 write_string (";");
929 write_newline ();
932 public override void visit_local_variable (LocalVariable local) {
933 if (local.variable_type.is_weak ()) {
934 write_string ("unowned ");
936 write_type (local.variable_type);
937 write_string (" ");
938 write_identifier (local.name);
939 write_type_suffix (local.variable_type);
940 if (local.initializer != null) {
941 write_string (" = ");
942 local.initializer.accept (this);
946 public override void visit_initializer_list (InitializerList list) {
947 write_string ("{");
949 bool first = true;
950 foreach (Expression initializer in list.get_initializers ()) {
951 if (!first) {
952 write_string (", ");
953 } else {
954 write_string (" ");
956 first = false;
957 initializer.accept (this);
959 write_string (" }");
962 public override void visit_expression_statement (ExpressionStatement stmt) {
963 write_indent ();
964 stmt.expression.accept (this);
965 write_string (";");
966 write_newline ();
969 public override void visit_if_statement (IfStatement stmt) {
970 write_indent ();
971 write_string ("if (");
972 stmt.condition.accept (this);
973 write_string (")");
974 stmt.true_statement.accept (this);
975 if (stmt.false_statement != null) {
976 write_string (" else");
977 stmt.false_statement.accept (this);
979 write_newline ();
982 public override void visit_switch_statement (SwitchStatement stmt) {
983 write_indent ();
984 write_string ("switch (");
985 stmt.expression.accept (this);
986 write_string (") {");
987 write_newline ();
989 foreach (SwitchSection section in stmt.get_sections ()) {
990 section.accept (this);
993 write_indent ();
994 write_string ("}");
995 write_newline ();
998 public override void visit_switch_section (SwitchSection section) {
999 foreach (SwitchLabel label in section.get_labels ()) {
1000 label.accept (this);
1003 visit_block (section);
1006 public override void visit_switch_label (SwitchLabel label) {
1007 if (label.expression != null) {
1008 write_indent ();
1009 write_string ("case ");
1010 label.expression.accept (this);
1011 write_string (":");
1012 write_newline ();
1013 } else {
1014 write_indent ();
1015 write_string ("default:");
1016 write_newline ();
1020 public override void visit_loop (Loop stmt) {
1021 write_indent ();
1022 write_string ("loop");
1023 stmt.body.accept (this);
1024 write_newline ();
1027 public override void visit_while_statement (WhileStatement stmt) {
1028 write_indent ();
1029 write_string ("while (");
1030 stmt.condition.accept (this);
1031 write_string (")");
1032 stmt.body.accept (this);
1033 write_newline ();
1036 public override void visit_do_statement (DoStatement stmt) {
1037 write_indent ();
1038 write_string ("do");
1039 stmt.body.accept (this);
1040 write_string ("while (");
1041 stmt.condition.accept (this);
1042 write_string (");");
1043 write_newline ();
1046 public override void visit_for_statement (ForStatement stmt) {
1047 write_indent ();
1048 write_string ("for (");
1050 bool first = true;
1051 foreach (Expression initializer in stmt.get_initializer ()) {
1052 if (!first) {
1053 write_string (", ");
1055 first = false;
1056 initializer.accept (this);
1058 write_string ("; ");
1060 stmt.condition.accept (this);
1061 write_string ("; ");
1063 first = true;
1064 foreach (Expression iterator in stmt.get_iterator ()) {
1065 if (!first) {
1066 write_string (", ");
1068 first = false;
1069 iterator.accept (this);
1072 write_string (")");
1073 stmt.body.accept (this);
1074 write_newline ();
1077 public override void visit_foreach_statement (ForeachStatement stmt) {
1080 public override void visit_break_statement (BreakStatement stmt) {
1081 write_indent ();
1082 write_string ("break;");
1083 write_newline ();
1086 public override void visit_continue_statement (ContinueStatement stmt) {
1087 write_indent ();
1088 write_string ("continue;");
1089 write_newline ();
1092 public override void visit_return_statement (ReturnStatement stmt) {
1093 write_indent ();
1094 write_string ("return");
1095 if (stmt.return_expression != null) {
1096 write_string (" ");
1097 stmt.return_expression.accept (this);
1099 write_string (";");
1100 write_newline ();
1103 public override void visit_yield_statement (YieldStatement y) {
1104 write_indent ();
1105 write_string ("yield");
1106 if (y.yield_expression != null) {
1107 write_string (" ");
1108 y.yield_expression.accept (this);
1110 write_string (";");
1111 write_newline ();
1114 public override void visit_throw_statement (ThrowStatement stmt) {
1115 write_indent ();
1116 write_string ("throw");
1117 if (stmt.error_expression != null) {
1118 write_string (" ");
1119 stmt.error_expression.accept (this);
1121 write_string (";");
1122 write_newline ();
1125 public override void visit_try_statement (TryStatement stmt) {
1126 write_indent ();
1127 write_string ("try");
1128 stmt.body.accept (this);
1129 foreach (var clause in stmt.get_catch_clauses ()) {
1130 clause.accept (this);
1132 if (stmt.finally_body != null) {
1133 write_string (" finally");
1134 stmt.finally_body.accept (this);
1136 write_newline ();
1139 public override void visit_catch_clause (CatchClause clause) {
1140 var type_name = clause.error_type == null ? "GLib.Error" : clause.error_type.to_string ();
1141 var var_name = clause.variable_name == null ? "_" : clause.variable_name;
1142 write_string (" catch (%s %s)".printf (type_name, var_name));
1143 clause.body.accept (this);
1146 public override void visit_lock_statement (LockStatement stmt) {
1147 write_indent ();
1148 write_string ("lock (");
1149 stmt.resource.accept (this);
1150 write_string (")");
1151 if (stmt.body == null) {
1152 write_string (";");
1153 } else {
1154 stmt.body.accept (this);
1156 write_newline ();
1159 public override void visit_delete_statement (DeleteStatement stmt) {
1160 write_indent ();
1161 write_string ("delete ");
1162 stmt.expression.accept (this);
1163 write_string (";");
1164 write_newline ();
1167 public override void visit_array_creation_expression (ArrayCreationExpression expr) {
1168 write_string ("new ");
1169 write_type (expr.element_type);
1170 write_string ("[");
1172 bool first = true;
1173 foreach (Expression size in expr.get_sizes ()) {
1174 if (!first) {
1175 write_string (", ");
1177 first = false;
1179 size.accept (this);
1182 write_string ("]");
1184 if (expr.initializer_list != null) {
1185 write_string (" ");
1186 expr.initializer_list.accept (this);
1190 public override void visit_boolean_literal (BooleanLiteral lit) {
1191 write_string (lit.value.to_string ());
1194 public override void visit_character_literal (CharacterLiteral lit) {
1195 write_string (lit.value);
1198 public override void visit_integer_literal (IntegerLiteral lit) {
1199 write_string (lit.value);
1202 public override void visit_real_literal (RealLiteral lit) {
1203 write_string (lit.value);
1206 public override void visit_string_literal (StringLiteral lit) {
1207 write_string (lit.value);
1210 public override void visit_null_literal (NullLiteral lit) {
1211 write_string ("null");
1214 public override void visit_member_access (MemberAccess expr) {
1215 if (expr.inner != null) {
1216 expr.inner.accept (this);
1217 write_string (".");
1219 write_identifier (expr.member_name);
1222 public override void visit_method_call (MethodCall expr) {
1223 expr.call.accept (this);
1224 write_string (" (");
1226 bool first = true;
1227 foreach (Expression arg in expr.get_argument_list ()) {
1228 if (!first) {
1229 write_string (", ");
1231 first = false;
1233 arg.accept (this);
1236 write_string (")");
1239 public override void visit_element_access (ElementAccess expr) {
1240 expr.container.accept (this);
1241 write_string ("[");
1243 bool first = true;
1244 foreach (Expression index in expr.get_indices ()) {
1245 if (!first) {
1246 write_string (", ");
1248 first = false;
1250 index.accept (this);
1253 write_string ("]");
1256 public override void visit_slice_expression (SliceExpression expr) {
1257 expr.container.accept (this);
1258 write_string ("[");
1259 expr.start.accept (this);
1260 write_string (":");
1261 expr.stop.accept (this);
1262 write_string ("]");
1265 public override void visit_base_access (BaseAccess expr) {
1266 write_string ("base");
1269 public override void visit_postfix_expression (PostfixExpression expr) {
1270 expr.inner.accept (this);
1271 if (expr.increment) {
1272 write_string ("++");
1273 } else {
1274 write_string ("--");
1278 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
1279 if (!expr.struct_creation) {
1280 write_string ("new ");
1283 write_type (expr.type_reference);
1285 if (expr.symbol_reference.name != ".new") {
1286 write_string (".");
1287 write_string (expr.symbol_reference.name);
1290 write_string (" (");
1292 bool first = true;
1293 foreach (Expression arg in expr.get_argument_list ()) {
1294 if (!first) {
1295 write_string (", ");
1297 first = false;
1299 arg.accept (this);
1302 write_string (")");
1305 public override void visit_sizeof_expression (SizeofExpression expr) {
1306 write_string ("sizeof (");
1307 write_type (expr.type_reference);
1308 write_string (")");
1311 public override void visit_typeof_expression (TypeofExpression expr) {
1312 write_string ("typeof (");
1313 write_type (expr.type_reference);
1314 write_string (")");
1317 public override void visit_unary_expression (UnaryExpression expr) {
1318 switch (expr.operator) {
1319 case UnaryOperator.PLUS:
1320 write_string ("+");
1321 break;
1322 case UnaryOperator.MINUS:
1323 write_string ("-");
1324 break;
1325 case UnaryOperator.LOGICAL_NEGATION:
1326 write_string ("!");
1327 break;
1328 case UnaryOperator.BITWISE_COMPLEMENT:
1329 write_string ("~");
1330 break;
1331 case UnaryOperator.INCREMENT:
1332 write_string ("++");
1333 break;
1334 case UnaryOperator.DECREMENT:
1335 write_string ("--");
1336 break;
1337 case UnaryOperator.REF:
1338 write_string ("ref ");
1339 break;
1340 case UnaryOperator.OUT:
1341 write_string ("out ");
1342 break;
1343 default:
1344 assert_not_reached ();
1346 expr.inner.accept (this);
1349 public override void visit_cast_expression (CastExpression expr) {
1350 if (expr.is_non_null_cast) {
1351 write_string ("(!) ");
1352 expr.inner.accept (this);
1353 return;
1356 if (!expr.is_silent_cast) {
1357 write_string ("(");
1358 write_type (expr.type_reference);
1359 write_string (") ");
1362 expr.inner.accept (this);
1364 if (expr.is_silent_cast) {
1365 write_string (" as ");
1366 write_type (expr.type_reference);
1370 public override void visit_pointer_indirection (PointerIndirection expr) {
1371 write_string ("*");
1372 expr.inner.accept (this);
1375 public override void visit_addressof_expression (AddressofExpression expr) {
1376 write_string ("&");
1377 expr.inner.accept (this);
1380 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
1381 write_string ("(owned) ");
1382 expr.inner.accept (this);
1385 public override void visit_binary_expression (BinaryExpression expr) {
1386 expr.left.accept (this);
1388 switch (expr.operator) {
1389 case BinaryOperator.PLUS:
1390 write_string (" + ");
1391 break;
1392 case BinaryOperator.MINUS:
1393 write_string (" - ");
1394 break;
1395 case BinaryOperator.MUL:
1396 write_string (" * ");
1397 break;
1398 case BinaryOperator.DIV:
1399 write_string (" / ");
1400 break;
1401 case BinaryOperator.MOD:
1402 write_string (" % ");
1403 break;
1404 case BinaryOperator.SHIFT_LEFT:
1405 write_string (" << ");
1406 break;
1407 case BinaryOperator.SHIFT_RIGHT:
1408 write_string (" >> ");
1409 break;
1410 case BinaryOperator.LESS_THAN:
1411 write_string (" < ");
1412 break;
1413 case BinaryOperator.GREATER_THAN:
1414 write_string (" > ");
1415 break;
1416 case BinaryOperator.LESS_THAN_OR_EQUAL:
1417 write_string (" <= ");
1418 break;
1419 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1420 write_string (" >= ");
1421 break;
1422 case BinaryOperator.EQUALITY:
1423 write_string (" == ");
1424 break;
1425 case BinaryOperator.INEQUALITY:
1426 write_string (" != ");
1427 break;
1428 case BinaryOperator.BITWISE_AND:
1429 write_string (" & ");
1430 break;
1431 case BinaryOperator.BITWISE_OR:
1432 write_string (" | ");
1433 break;
1434 case BinaryOperator.BITWISE_XOR:
1435 write_string (" ^ ");
1436 break;
1437 case BinaryOperator.AND:
1438 write_string (" && ");
1439 break;
1440 case BinaryOperator.OR:
1441 write_string (" || ");
1442 break;
1443 case BinaryOperator.IN:
1444 write_string (" in ");
1445 break;
1446 case BinaryOperator.COALESCE:
1447 write_string (" ?? ");
1448 break;
1449 default:
1450 assert_not_reached ();
1453 expr.right.accept (this);
1456 public override void visit_type_check (TypeCheck expr) {
1457 expr.expression.accept (this);
1458 write_string (" is ");
1459 write_type (expr.type_reference);
1462 public override void visit_conditional_expression (ConditionalExpression expr) {
1463 expr.condition.accept (this);
1464 write_string ("?");
1465 expr.true_expression.accept (this);
1466 write_string (":");
1467 expr.false_expression.accept (this);
1470 public override void visit_lambda_expression (LambdaExpression expr) {
1471 write_string ("(");
1472 var params = expr.get_parameters ();
1473 int i = 1;
1474 foreach (var param in params) {
1475 if (i > 1) {
1476 write_string (", ");
1479 if (param.direction == ParameterDirection.REF) {
1480 write_string ("ref ");
1481 } else if (param.direction == ParameterDirection.OUT) {
1482 write_string ("out ");
1485 write_identifier (param.name);
1487 i++;
1489 write_string (") =>");
1490 if (expr.statement_body != null) {
1491 expr.statement_body.accept (this);
1492 } else if (expr.expression_body != null) {
1493 expr.expression_body.accept (this);
1497 public override void visit_assignment (Assignment a) {
1498 a.left.accept (this);
1499 write_string (" = ");
1500 a.right.accept (this);
1503 private void write_indent () {
1504 if (!bol) {
1505 stream.putc ('\n');
1508 stream.puts (string.nfill (indent, '\t'));
1509 bol = false;
1512 private void write_comment (Comment comment) {
1513 try {
1514 if (fix_indent_regex == null)
1515 fix_indent_regex = new Regex ("\\n[\\t ]*");
1516 } catch (Error e) {
1517 assert_not_reached ();
1520 string replacement = "\n%s ".printf (string.nfill (indent, '\t'));
1521 string fixed_content;
1522 try {
1523 fixed_content = fix_indent_regex.replace (comment.content, comment.content.length, 0, replacement);
1524 } catch (Error e) {
1525 assert_not_reached();
1528 write_indent ();
1529 write_string ("/*");
1530 write_string (fixed_content);
1531 write_string ("*/");
1534 private void write_identifier (string s) {
1535 char* id = (char*)s;
1536 int id_length = (int)s.length;
1537 if (Vala.Scanner.get_identifier_or_keyword (id, id_length) != Vala.TokenType.IDENTIFIER ||
1538 s.get_char ().isdigit ()) {
1539 stream.putc ('@');
1541 write_string (s);
1544 private void write_return_type (DataType type) {
1545 if (type.is_weak ()) {
1546 write_string ("unowned ");
1549 write_type (type);
1552 private void write_type (DataType type) {
1553 write_string (type.to_qualified_string (current_scope));
1556 private void write_type_suffix (DataType type) {
1557 var array_type = type as ArrayType;
1558 if (array_type != null && array_type.fixed_length) {
1559 write_string ("[");
1560 array_type.length.accept (this);
1561 write_string ("]");
1565 private void write_string (string s) {
1566 stream.puts (s);
1567 bol = false;
1570 private void write_newline () {
1571 stream.putc ('\n');
1572 bol = true;
1575 void write_code_block (Block? block) {
1576 if (block == null || type != CodeWriterType.DUMP) {
1577 write_string (";");
1578 return;
1581 block.accept (this);
1584 private void write_begin_block () {
1585 if (!bol) {
1586 stream.putc (' ');
1587 } else {
1588 write_indent ();
1590 stream.putc ('{');
1591 write_newline ();
1592 indent++;
1595 private void write_end_block () {
1596 indent--;
1597 write_indent ();
1598 stream.putc ('}');
1601 private bool check_accessibility (Symbol sym) {
1602 switch (type) {
1603 case CodeWriterType.EXTERNAL:
1604 return sym.access == SymbolAccessibility.PUBLIC ||
1605 sym.access == SymbolAccessibility.PROTECTED;
1607 case CodeWriterType.INTERNAL:
1608 case CodeWriterType.FAST:
1609 return sym.access == SymbolAccessibility.INTERNAL ||
1610 sym.access == SymbolAccessibility.PUBLIC ||
1611 sym.access == SymbolAccessibility.PROTECTED;
1613 case CodeWriterType.DUMP:
1614 return true;
1616 default:
1617 assert_not_reached ();
1621 private bool skip_since_tag_check (Symbol sym, string since_val) {
1622 Symbol parent_symbol = sym;
1624 while (parent_symbol.parent_symbol != null) {
1625 parent_symbol = parent_symbol.parent_symbol;
1626 if (parent_symbol.version.since == since_val) {
1627 return true;
1631 return false;
1634 private void write_attributes (CodeNode node) {
1635 var sym = node as Symbol;
1637 var need_cheaders = type != CodeWriterType.FAST && sym != null && !(sym is Namespace) && sym.parent_symbol is Namespace;
1639 var attributes = new GLib.Sequence<Attribute> ();
1640 foreach (var attr in node.attributes) {
1641 attributes.insert_sorted (attr, (a, b) => strcmp (a.name, b.name));
1643 if (need_cheaders && node.get_attribute ("CCode") == null) {
1644 attributes.insert_sorted (new Attribute ("CCode"), (a, b) => strcmp (a.name, b.name));
1647 var iter = attributes.get_begin_iter ();
1648 while (!iter.is_end ()) {
1649 unowned Attribute attr = iter.get ();
1650 iter = iter.next ();
1652 var keys = new GLib.Sequence<string> ();
1653 foreach (var key in attr.args.get_keys ()) {
1654 if (key == "cheader_filename" && sym is Namespace) {
1655 continue;
1657 keys.insert_sorted (key, (CompareDataFunc<string>) strcmp);
1659 if (need_cheaders && attr.name == "CCode" && !attr.has_argument ("cheader_filename")) {
1660 keys.insert_sorted ("cheader_filename", (CompareDataFunc<string>) strcmp);
1663 if (attr.name == "CCode" && keys.get_length () == 0) {
1664 // only cheader_filename on namespace
1665 continue;
1668 if (sym != null && attr.args.size == 1 && attr.name == "Version") {
1669 string since_val = attr.get_string ("since");
1670 if (since_val != null && skip_since_tag_check (sym, since_val)) {
1671 continue;
1675 if (!(node is Parameter) && !(node is PropertyAccessor)) {
1676 write_indent ();
1679 stream.printf ("[%s", attr.name);
1680 if (keys.get_length () > 0) {
1681 stream.puts (" (");
1683 unowned string separator = "";
1684 var arg_iter = keys.get_begin_iter ();
1685 while (!arg_iter.is_end ()) {
1686 unowned string arg_name = arg_iter.get ();
1687 arg_iter = arg_iter.next ();
1688 if (arg_name == "cheader_filename") {
1689 stream.printf ("%scheader_filename = \"%s\"", separator, get_cheaders (sym));
1690 } else {
1691 stream.printf ("%s%s = %s", separator, arg_name, attr.args.get (arg_name));
1693 separator = ", ";
1696 stream.puts (")");
1698 stream.puts ("]");
1699 if (node is Parameter || node is PropertyAccessor) {
1700 write_string (" ");
1701 } else {
1702 write_newline ();
1707 private void write_accessibility (Symbol sym) {
1708 if (sym.access == SymbolAccessibility.PUBLIC) {
1709 write_string ("public ");
1710 } else if (sym.access == SymbolAccessibility.PROTECTED) {
1711 write_string ("protected ");
1712 } else if (sym.access == SymbolAccessibility.INTERNAL) {
1713 write_string ("internal ");
1714 } else if (sym.access == SymbolAccessibility.PRIVATE) {
1715 write_string ("private ");
1718 if (type != CodeWriterType.EXTERNAL && sym.external && !sym.external_package) {
1719 write_string ("extern ");
1723 void write_property_accessor_accessibility (Symbol sym) {
1724 if (sym.access == SymbolAccessibility.PROTECTED) {
1725 write_string (" protected");
1726 } else if (sym.access == SymbolAccessibility.INTERNAL) {
1727 write_string (" internal");
1728 } else if (sym.access == SymbolAccessibility.PRIVATE) {
1729 write_string (" private");
1733 void write_type_parameters (List<TypeParameter> type_params) {
1734 if (type_params.size > 0) {
1735 write_string ("<");
1736 bool first = true;
1737 foreach (TypeParameter type_param in type_params) {
1738 if (first) {
1739 first = false;
1740 } else {
1741 write_string (",");
1743 write_identifier (type_param.name);
1745 write_string (">");
1750 public enum Vala.CodeWriterType {
1751 EXTERNAL,
1752 INTERNAL,
1753 FAST,
1754 DUMP