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
22 * Jürg Billeter <j@bitron.ch>
23 * Raffaele Sandrini <raffaele@sandrini.ch>
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
;
38 /* at begin of line */
45 string? override_header
= null;
46 string? header_to_override
= null;
48 public CodeWriter (CodeWriterType type
= CodeWriterType
.EXTERNAL
) {
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
;
64 * Writes the public interface of the specified code context into the
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
;
76 stream
= FileStream
.open (temp_filename
, "w");
78 stream
= FileStream
.open (filename
, "w");
82 Report
.error (null, "unable to open `%s' for writing".printf (filename
));
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
);
93 current_scope
= context
.root
.scope
;
95 context
.accept (this
);
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) {
115 } catch (FileError e
) {
116 // assume changed if mmap comparison doesn't work
120 FileUtils
.rename (temp_filename
, filename
);
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
++) {
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
) {
156 if (ns
.name
== null) {
157 ns
.accept_children (this
);
161 var comments
= ns
.get_comments ();
162 if (context
.vapi_comments
&& comments
.size
> 0) {
164 SourceReference? first_reference
= null;
165 foreach (Comment comment
in comments
) {
166 if (comment
.source_reference
.file
.file_type
== SourceFileType
.SOURCE
) {
168 write_comment (comment
);
170 first_reference
= comment
.source_reference
;
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
);
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
;
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
);
229 public override void visit_class (Class cl
) {
230 if (cl
.external_package
) {
234 if (!check_accessibility (cl
)) {
238 if (context
.vapi_comments
&& cl
.comment
!= null) {
239 write_comment (cl
.comment
);
242 write_attributes (cl
);
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 (" : ");
259 foreach (DataType base_type
in base_types
) {
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
;
292 void visit_sorted (List
<Symbol
> symbols
) {
293 if (type
!= CodeWriterType
.EXTERNAL
&& type
!= CodeWriterType
.VAPIGEN
) {
294 // order of virtual methods matters for fast vapis
295 foreach (Symbol sym
in symbols
) {
301 var sorted_symbols
= new ArrayList
<Symbol
> ();
302 foreach (Symbol sym
in symbols
) {
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
);
310 while (right
- left
> 1) {
311 int i
= (right
+ left
) / 2;
312 if (sym
.name
> sorted_symbols
[i
].name
) {
318 sorted_symbols
.insert (left
+ 1, sym
);
321 foreach (Symbol sym
in sorted_symbols
) {
326 public override void visit_struct (Struct st
) {
327 if (st
.external_package
) {
331 if (!check_accessibility (st
)) {
335 if (context
.vapi_comments
&& st
.comment
!= null) {
336 write_comment (st
.comment
);
339 write_attributes (st
);
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 ()) {
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
;
370 public override void visit_interface (Interface iface
) {
371 if (iface
.external_package
) {
375 if (!check_accessibility (iface
)) {
379 if (context
.vapi_comments
&& iface
.comment
!= null) {
380 write_comment (iface
.comment
);
383 write_attributes (iface
);
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 (" : ");
397 foreach (DataType prerequisite
in prerequisites
) {
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
;
426 public override void visit_enum (Enum en
) {
427 if (en
.external_package
) {
431 if (!check_accessibility (en
)) {
435 if (context
.vapi_comments
&& en
.comment
!= null) {
436 write_comment (en
.comment
);
439 write_attributes (en
);
442 write_accessibility (en
);
443 write_string ("enum ");
444 write_identifier (en
.name
);
445 write_begin_block ();
448 foreach (EnumValue ev
in en
.get_values ()) {
456 if (context
.vapi_comments
&& ev
.comment
!= null) {
457 write_comment (ev
.comment
);
460 write_attributes (ev
);
463 write_identifier (ev
.name
);
465 if (type
== CodeWriterType
.FAST
&& ev
.value
!= null) {
467 ev
.value
.accept (this
);
472 if (en
.get_methods ().size
> 0 || en
.get_constants ().size
> 0) {
478 current_scope
= en
.scope
;
479 foreach (Method m
in en
.get_methods ()) {
482 foreach (Constant c
in en
.get_constants ()) {
485 current_scope
= current_scope
.parent_scope
;
491 public override void visit_error_domain (ErrorDomain edomain
) {
492 if (edomain
.external_package
) {
496 if (!check_accessibility (edomain
)) {
500 if (context
.vapi_comments
&& edomain
.comment
!= null) {
501 write_comment (edomain
.comment
);
504 write_attributes (edomain
);
507 write_accessibility (edomain
);
508 write_string ("errordomain ");
509 write_identifier (edomain
.name
);
510 write_begin_block ();
513 foreach (ErrorCode ecode
in edomain
.get_codes ()) {
521 if (context
.vapi_comments
&& ecode
.comment
!= null) {
522 write_comment (ecode
.comment
);
525 write_attributes (ecode
);
528 write_identifier (ecode
.name
);
532 if (edomain
.get_methods ().size
> 0) {
538 current_scope
= edomain
.scope
;
539 foreach (Method m
in edomain
.get_methods ()) {
542 current_scope
= current_scope
.parent_scope
;
548 public override void visit_constant (Constant c
) {
549 if (c
.external_package
) {
553 if (!check_accessibility (c
)) {
557 if (context
.vapi_comments
&& c
.comment
!= null) {
558 write_comment (c
.comment
);
561 write_attributes (c
);
564 write_accessibility (c
);
567 write_string ("new ");
570 write_string ("const ");
572 write_type (c
.type_reference
);
575 write_identifier (c
.name
);
576 write_type_suffix (c
.type_reference
);
577 if (type
== CodeWriterType
.FAST
&& c
.value
!= null) {
579 c
.value
.accept (this
);
585 public override void visit_field (Field f
) {
586 if (f
.external_package
) {
590 if (!check_accessibility (f
)) {
594 if (context
.vapi_comments
&& f
.comment
!= null) {
595 write_comment (f
.comment
);
598 write_attributes (f
);
601 write_accessibility (f
);
604 write_string ("new ");
607 if (f
.binding
== MemberBinding
.STATIC
) {
608 write_string ("static ");
609 } else if (f
.binding
== MemberBinding
.CLASS
) {
610 write_string ("class ");
613 if (f
.variable_type
.is_weak ()) {
614 write_string ("weak ");
617 write_type (f
.variable_type
);
620 write_identifier (f
.name
);
621 write_type_suffix (f
.variable_type
);
626 private void write_error_domains (List
<DataType
> error_domains
) {
627 if (error_domains
.size
> 0) {
628 write_string (" throws ");
631 foreach (DataType type
in error_domains
) {
643 private void write_params (List
<Parameter
> params
) {
647 foreach (Parameter param
in params
) {
652 if (param
.ellipsis
) {
653 write_string ("...");
657 write_attributes (param
);
659 if (param
.params_array
) {
660 write_string ("params ");
663 if (param
.direction
== ParameterDirection
.IN
) {
664 if (param
.variable_type
.value_owned
) {
665 write_string ("owned ");
668 if (param
.direction
== ParameterDirection
.REF
) {
669 write_string ("ref ");
670 } else if (param
.direction
== ParameterDirection
.OUT
) {
671 write_string ("out ");
673 if (param
.variable_type
.is_weak ()) {
674 write_string ("unowned ");
678 write_type (param
.variable_type
);
681 write_identifier (param
.name
);
682 write_type_suffix (param
.variable_type
);
684 if (param
.initializer
!= null) {
685 write_string (" = ");
686 param
.initializer
.accept (this
);
695 public override void visit_delegate (Delegate cb
) {
696 if (cb
.external_package
) {
700 if (!check_accessibility (cb
)) {
704 if (context
.vapi_comments
&& cb
.comment
!= null) {
705 write_comment (cb
.comment
);
708 write_attributes (cb
);
712 write_accessibility (cb
);
713 write_string ("delegate ");
715 write_return_type (cb
.return_type
);
718 write_identifier (cb
.name
);
720 write_type_parameters (cb
.get_type_parameters ());
724 write_params (cb
.get_parameters ());
726 write_error_domains (cb
.get_error_types ());
733 public override void visit_constructor (Constructor c
) {
734 if (type
!= CodeWriterType
.DUMP
) {
738 if (context
.vapi_comments
&& c
.comment
!= null) {
739 write_comment (c
.comment
);
743 write_string ("construct");
744 write_code_block (c
.body
);
748 public override void visit_method (Method m
) {
749 if (m
.external_package
) {
753 // don't write interface implementation unless it's an abstract or virtual method
754 if (!check_accessibility (m
) || (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
755 if (type
!= CodeWriterType
.DUMP
) {
760 if (context
.vapi_comments
&& m
.comment
!= null) {
761 write_comment (m
.comment
);
764 write_attributes (m
);
767 write_accessibility (m
);
769 if (m is CreationMethod
) {
771 write_string ("async ");
774 var datatype
= (TypeSymbol
) m
.parent_symbol
;
775 write_identifier (datatype
.name
);
776 if (m
.name
!= ".new") {
778 write_identifier (m
.name
);
783 write_string ("new ");
786 if (m
.binding
== MemberBinding
.STATIC
) {
787 write_string ("static ");
788 } else if (m
.binding
== MemberBinding
.CLASS
) {
789 write_string ("class ");
790 } else if (m
.is_abstract
) {
791 write_string ("abstract ");
792 } else if (m
.is_virtual
) {
793 write_string ("virtual ");
794 } else if (m
.overrides
) {
795 write_string ("override ");
799 write_string ("async ");
802 write_return_type (m
.return_type
);
805 write_identifier (m
.name
);
807 write_type_parameters (m
.get_type_parameters ());
812 write_params (m
.get_parameters ());
814 write_error_domains (m
.get_error_types ());
816 write_code_block (m
.body
);
821 public override void visit_creation_method (CreationMethod m
) {
825 public override void visit_property (Property prop
) {
826 if (!check_accessibility (prop
) || (prop
.base_interface_property
!= null && !prop
.is_abstract
&& !prop
.is_virtual
)) {
830 if (context
.vapi_comments
&& prop
.comment
!= null) {
831 write_comment (prop
.comment
);
834 write_attributes (prop
);
837 write_accessibility (prop
);
840 write_string ("new ");
843 if (prop
.binding
== MemberBinding
.STATIC
) {
844 write_string ("static ");
845 } else if (prop
.is_abstract
) {
846 write_string ("abstract ");
847 } else if (prop
.is_virtual
) {
848 write_string ("virtual ");
849 } else if (prop
.overrides
) {
850 write_string ("override ");
853 write_type (prop
.property_type
);
856 write_identifier (prop
.name
);
858 if (prop
.get_accessor
!= null) {
859 write_attributes (prop
.get_accessor
);
861 write_property_accessor_accessibility (prop
.get_accessor
);
863 if (prop
.get_accessor
.value_type
.is_disposable ()) {
864 write_string (" owned");
867 write_string (" get");
868 write_code_block (prop
.get_accessor
.body
);
870 if (prop
.set_accessor
!= null) {
871 write_attributes (prop
.set_accessor
);
873 write_property_accessor_accessibility (prop
.set_accessor
);
875 if (prop
.set_accessor
.value_type
.value_owned
) {
876 write_string (" owned");
879 if (prop
.set_accessor
.writable
) {
880 write_string (" set");
882 if (prop
.set_accessor
.construction
) {
883 write_string (" construct");
885 write_code_block (prop
.set_accessor
.body
);
891 public override void visit_signal (Signal sig
) {
892 if (!check_accessibility (sig
)) {
896 if (context
.vapi_comments
&& sig
.comment
!= null) {
897 write_comment (sig
.comment
);
900 write_attributes (sig
);
903 write_accessibility (sig
);
906 write_string ("new ");
909 if (sig
.is_virtual
) {
910 write_string ("virtual ");
913 write_string ("signal ");
915 write_return_type (sig
.return_type
);
918 write_identifier (sig
.name
);
922 write_params (sig
.get_parameters ());
929 public override void visit_block (Block b
) {
930 write_begin_block ();
932 foreach (Statement stmt
in b
.get_statements ()) {
939 public override void visit_empty_statement (EmptyStatement stmt
) {
942 public override void visit_declaration_statement (DeclarationStatement stmt
) {
944 stmt
.declaration
.accept (this
);
949 public override void visit_local_variable (LocalVariable local
) {
950 if (local
.variable_type
.is_weak ()) {
951 write_string ("unowned ");
953 write_type (local
.variable_type
);
955 write_identifier (local
.name
);
956 write_type_suffix (local
.variable_type
);
957 if (local
.initializer
!= null) {
958 write_string (" = ");
959 local
.initializer
.accept (this
);
963 public override void visit_initializer_list (InitializerList list
) {
967 foreach (Expression initializer
in list
.get_initializers ()) {
974 initializer
.accept (this
);
979 public override void visit_expression_statement (ExpressionStatement stmt
) {
981 stmt
.expression
.accept (this
);
986 public override void visit_if_statement (IfStatement stmt
) {
988 write_string ("if (");
989 stmt
.condition
.accept (this
);
991 stmt
.true_statement
.accept (this
);
992 if (stmt
.false_statement
!= null) {
993 write_string (" else");
994 stmt
.false_statement
.accept (this
);
999 public override void visit_switch_statement (SwitchStatement stmt
) {
1001 write_string ("switch (");
1002 stmt
.expression
.accept (this
);
1003 write_string (") {");
1006 foreach (SwitchSection section
in stmt
.get_sections ()) {
1007 section
.accept (this
);
1015 public override void visit_switch_section (SwitchSection section
) {
1016 foreach (SwitchLabel label
in section
.get_labels ()) {
1017 label
.accept (this
);
1020 visit_block (section
);
1023 public override void visit_switch_label (SwitchLabel label
) {
1024 if (label
.expression
!= null) {
1026 write_string ("case ");
1027 label
.expression
.accept (this
);
1032 write_string ("default:");
1037 public override void visit_loop (Loop stmt
) {
1039 write_string ("loop");
1040 stmt
.body
.accept (this
);
1044 public override void visit_while_statement (WhileStatement stmt
) {
1046 write_string ("while (");
1047 stmt
.condition
.accept (this
);
1049 stmt
.body
.accept (this
);
1053 public override void visit_do_statement (DoStatement stmt
) {
1055 write_string ("do");
1056 stmt
.body
.accept (this
);
1057 write_string ("while (");
1058 stmt
.condition
.accept (this
);
1059 write_string (");");
1063 public override void visit_for_statement (ForStatement stmt
) {
1065 write_string ("for (");
1068 foreach (Expression initializer
in stmt
.get_initializer ()) {
1070 write_string (", ");
1073 initializer
.accept (this
);
1075 write_string ("; ");
1077 stmt
.condition
.accept (this
);
1078 write_string ("; ");
1081 foreach (Expression iterator
in stmt
.get_iterator ()) {
1083 write_string (", ");
1086 iterator
.accept (this
);
1090 stmt
.body
.accept (this
);
1094 public override void visit_foreach_statement (ForeachStatement stmt
) {
1097 public override void visit_break_statement (BreakStatement stmt
) {
1099 write_string ("break;");
1103 public override void visit_continue_statement (ContinueStatement stmt
) {
1105 write_string ("continue;");
1109 public override void visit_return_statement (ReturnStatement stmt
) {
1111 write_string ("return");
1112 if (stmt
.return_expression
!= null) {
1114 stmt
.return_expression
.accept (this
);
1120 public override void visit_yield_statement (YieldStatement y
) {
1122 write_string ("yield");
1123 if (y
.yield_expression
!= null) {
1125 y
.yield_expression
.accept (this
);
1131 public override void visit_throw_statement (ThrowStatement stmt
) {
1133 write_string ("throw");
1134 if (stmt
.error_expression
!= null) {
1136 stmt
.error_expression
.accept (this
);
1142 public override void visit_try_statement (TryStatement stmt
) {
1144 write_string ("try");
1145 stmt
.body
.accept (this
);
1146 foreach (var clause
in stmt
.get_catch_clauses ()) {
1147 clause
.accept (this
);
1149 if (stmt
.finally_body
!= null) {
1150 write_string (" finally");
1151 stmt
.finally_body
.accept (this
);
1156 public override void visit_catch_clause (CatchClause clause
) {
1157 var type_name
= clause
.error_type
== null ?
"GLib.Error" : clause
.error_type
.to_string ();
1158 var var_name
= clause
.variable_name
== null ?
"_" : clause
.variable_name
;
1159 write_string (" catch (%s %s)".printf (type_name
, var_name
));
1160 clause
.body
.accept (this
);
1163 public override void visit_lock_statement (LockStatement stmt
) {
1165 write_string ("lock (");
1166 stmt
.resource
.accept (this
);
1168 if (stmt
.body
== null) {
1171 stmt
.body
.accept (this
);
1176 public override void visit_delete_statement (DeleteStatement stmt
) {
1178 write_string ("delete ");
1179 stmt
.expression
.accept (this
);
1184 public override void visit_array_creation_expression (ArrayCreationExpression expr
) {
1185 write_string ("new ");
1186 write_type (expr
.element_type
);
1190 foreach (Expression size
in expr
.get_sizes ()) {
1192 write_string (", ");
1201 if (expr
.initializer_list
!= null) {
1203 expr
.initializer_list
.accept (this
);
1207 public override void visit_boolean_literal (BooleanLiteral lit
) {
1208 write_string (lit
.value
.to_string ());
1211 public override void visit_character_literal (CharacterLiteral lit
) {
1212 write_string (lit
.value
);
1215 public override void visit_integer_literal (IntegerLiteral lit
) {
1216 write_string (lit
.value
);
1219 public override void visit_real_literal (RealLiteral lit
) {
1220 write_string (lit
.value
);
1223 public override void visit_string_literal (StringLiteral lit
) {
1224 write_string (lit
.value
);
1227 public override void visit_null_literal (NullLiteral lit
) {
1228 write_string ("null");
1231 public override void visit_member_access (MemberAccess expr
) {
1232 if (expr
.inner
!= null) {
1233 expr
.inner
.accept (this
);
1236 write_identifier (expr
.member_name
);
1239 public override void visit_method_call (MethodCall expr
) {
1240 expr
.call
.accept (this
);
1241 write_string (" (");
1244 foreach (Expression arg
in expr
.get_argument_list ()) {
1246 write_string (", ");
1256 public override void visit_element_access (ElementAccess expr
) {
1257 expr
.container
.accept (this
);
1261 foreach (Expression index
in expr
.get_indices ()) {
1263 write_string (", ");
1267 index
.accept (this
);
1273 public override void visit_slice_expression (SliceExpression expr
) {
1274 expr
.container
.accept (this
);
1276 expr
.start
.accept (this
);
1278 expr
.stop
.accept (this
);
1282 public override void visit_base_access (BaseAccess expr
) {
1283 write_string ("base");
1286 public override void visit_postfix_expression (PostfixExpression expr
) {
1287 expr
.inner
.accept (this
);
1288 if (expr
.increment
) {
1289 write_string ("++");
1291 write_string ("--");
1295 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
1296 if (!expr
.struct_creation
) {
1297 write_string ("new ");
1300 write_type (expr
.type_reference
);
1302 if (expr
.symbol_reference
.name
!= ".new") {
1304 write_string (expr
.symbol_reference
.name
);
1307 write_string (" (");
1310 foreach (Expression arg
in expr
.get_argument_list ()) {
1312 write_string (", ");
1322 public override void visit_sizeof_expression (SizeofExpression expr
) {
1323 write_string ("sizeof (");
1324 write_type (expr
.type_reference
);
1328 public override void visit_typeof_expression (TypeofExpression expr
) {
1329 write_string ("typeof (");
1330 write_type (expr
.type_reference
);
1334 public override void visit_unary_expression (UnaryExpression expr
) {
1335 switch (expr
.operator
) {
1336 case UnaryOperator
.PLUS
:
1339 case UnaryOperator
.MINUS
:
1342 case UnaryOperator
.LOGICAL_NEGATION
:
1345 case UnaryOperator
.BITWISE_COMPLEMENT
:
1348 case UnaryOperator
.INCREMENT
:
1349 write_string ("++");
1351 case UnaryOperator
.DECREMENT
:
1352 write_string ("--");
1354 case UnaryOperator
.REF
:
1355 write_string ("ref ");
1357 case UnaryOperator
.OUT
:
1358 write_string ("out ");
1361 assert_not_reached ();
1363 expr
.inner
.accept (this
);
1366 public override void visit_cast_expression (CastExpression expr
) {
1367 if (expr
.is_non_null_cast
) {
1368 write_string ("(!) ");
1369 expr
.inner
.accept (this
);
1373 if (!expr
.is_silent_cast
) {
1375 write_type (expr
.type_reference
);
1376 write_string (") ");
1379 expr
.inner
.accept (this
);
1381 if (expr
.is_silent_cast
) {
1382 write_string (" as ");
1383 write_type (expr
.type_reference
);
1387 public override void visit_pointer_indirection (PointerIndirection expr
) {
1389 expr
.inner
.accept (this
);
1392 public override void visit_addressof_expression (AddressofExpression expr
) {
1394 expr
.inner
.accept (this
);
1397 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
1398 write_string ("(owned) ");
1399 expr
.inner
.accept (this
);
1402 public override void visit_binary_expression (BinaryExpression expr
) {
1403 expr
.left
.accept (this
);
1405 switch (expr
.operator
) {
1406 case BinaryOperator
.PLUS
:
1407 write_string (" + ");
1409 case BinaryOperator
.MINUS
:
1410 write_string (" - ");
1412 case BinaryOperator
.MUL
:
1413 write_string (" * ");
1415 case BinaryOperator
.DIV
:
1416 write_string (" / ");
1418 case BinaryOperator
.MOD
:
1419 write_string (" % ");
1421 case BinaryOperator
.SHIFT_LEFT
:
1422 write_string (" << ");
1424 case BinaryOperator
.SHIFT_RIGHT
:
1425 write_string (" >> ");
1427 case BinaryOperator
.LESS_THAN
:
1428 write_string (" < ");
1430 case BinaryOperator
.GREATER_THAN
:
1431 write_string (" > ");
1433 case BinaryOperator
.LESS_THAN_OR_EQUAL
:
1434 write_string (" <= ");
1436 case BinaryOperator
.GREATER_THAN_OR_EQUAL
:
1437 write_string (" >= ");
1439 case BinaryOperator
.EQUALITY
:
1440 write_string (" == ");
1442 case BinaryOperator
.INEQUALITY
:
1443 write_string (" != ");
1445 case BinaryOperator
.BITWISE_AND
:
1446 write_string (" & ");
1448 case BinaryOperator
.BITWISE_OR
:
1449 write_string (" | ");
1451 case BinaryOperator
.BITWISE_XOR
:
1452 write_string (" ^ ");
1454 case BinaryOperator
.AND
:
1455 write_string (" && ");
1457 case BinaryOperator
.OR
:
1458 write_string (" || ");
1460 case BinaryOperator
.IN
:
1461 write_string (" in ");
1463 case BinaryOperator
.COALESCE
:
1464 write_string (" ?? ");
1467 assert_not_reached ();
1470 expr
.right
.accept (this
);
1473 public override void visit_type_check (TypeCheck expr
) {
1474 expr
.expression
.accept (this
);
1475 write_string (" is ");
1476 write_type (expr
.type_reference
);
1479 public override void visit_conditional_expression (ConditionalExpression expr
) {
1480 expr
.condition
.accept (this
);
1482 expr
.true_expression
.accept (this
);
1484 expr
.false_expression
.accept (this
);
1487 public override void visit_lambda_expression (LambdaExpression expr
) {
1489 var params
= expr
.get_parameters ();
1491 foreach (var param
in params
) {
1493 write_string (", ");
1496 if (param
.direction
== ParameterDirection
.REF
) {
1497 write_string ("ref ");
1498 } else if (param
.direction
== ParameterDirection
.OUT
) {
1499 write_string ("out ");
1502 write_identifier (param
.name
);
1506 write_string (") =>");
1507 if (expr
.statement_body
!= null) {
1508 expr
.statement_body
.accept (this
);
1509 } else if (expr
.expression_body
!= null) {
1510 expr
.expression_body
.accept (this
);
1514 public override void visit_assignment (Assignment a
) {
1515 a
.left
.accept (this
);
1516 write_string (" = ");
1517 a
.right
.accept (this
);
1520 private void write_indent () {
1525 stream
.puts (string.nfill (indent
, '\t'));
1529 private void write_comment (Comment comment
) {
1531 if (fix_indent_regex
== null)
1532 fix_indent_regex
= new
Regex ("\\n[\\t ]*");
1534 assert_not_reached ();
1537 string replacement
= "\n%s ".printf (string.nfill (indent
, '\t'));
1538 string fixed_content
;
1540 fixed_content
= fix_indent_regex
.replace (comment
.content
, comment
.content
.length
, 0, replacement
);
1542 assert_not_reached();
1546 write_string ("/*");
1547 write_string (fixed_content
);
1548 write_string ("*/");
1551 private void write_identifier (string s
) {
1552 char* id
= (char*)s
;
1553 int id_length
= (int)s
.length
;
1554 if (Vala
.Scanner
.get_identifier_or_keyword (id
, id_length
) != Vala
.TokenType
.IDENTIFIER
||
1555 s
.get_char ().isdigit ()) {
1561 private void write_return_type (DataType type
) {
1562 if (type
.is_weak ()) {
1563 write_string ("unowned ");
1569 private void write_type (DataType type
) {
1570 write_string (type
.to_qualified_string (current_scope
));
1573 private void write_type_suffix (DataType type
) {
1574 var array_type
= type as ArrayType
;
1575 if (array_type
!= null && array_type
.fixed_length
) {
1577 array_type
.length
.accept (this
);
1582 private void write_string (string s
) {
1587 private void write_newline () {
1592 void write_code_block (Block? block
) {
1593 if (block
== null || (type
!= CodeWriterType
.DUMP
&& type
!= CodeWriterType
.VAPIGEN
)) {
1598 block
.accept (this
);
1601 private void write_begin_block () {
1612 private void write_end_block () {
1618 private bool check_accessibility (Symbol sym
) {
1620 case CodeWriterType
.EXTERNAL
:
1621 case CodeWriterType
.VAPIGEN
:
1622 return sym
.access
== SymbolAccessibility
.PUBLIC
||
1623 sym
.access
== SymbolAccessibility
.PROTECTED
;
1625 case CodeWriterType
.INTERNAL
:
1626 case CodeWriterType
.FAST
:
1627 return sym
.access
== SymbolAccessibility
.INTERNAL
||
1628 sym
.access
== SymbolAccessibility
.PUBLIC
||
1629 sym
.access
== SymbolAccessibility
.PROTECTED
;
1631 case CodeWriterType
.DUMP
:
1635 assert_not_reached ();
1639 private bool skip_since_tag_check (Symbol sym
, string since_val
) {
1640 Symbol parent_symbol
= sym
;
1642 while (parent_symbol
.parent_symbol
!= null) {
1643 parent_symbol
= parent_symbol
.parent_symbol
;
1644 if (parent_symbol
.version
.since
== since_val
) {
1652 private void write_attributes (CodeNode node
) {
1653 var sym
= node as Symbol
;
1655 var need_cheaders
= type
!= CodeWriterType
.FAST
&& sym
!= null && !(sym is Namespace
) && sym
.parent_symbol is Namespace
;
1657 var attributes
= new GLib
.Sequence
<Attribute
> ();
1658 foreach (var attr
in node
.attributes
) {
1659 attributes
.insert_sorted (attr
, (a
, b
) => strcmp (a
.name
, b
.name
));
1661 if (need_cheaders
&& node
.get_attribute ("CCode") == null) {
1662 attributes
.insert_sorted (new
Attribute ("CCode"), (a
, b
) => strcmp (a
.name
, b
.name
));
1665 var iter
= attributes
.get_begin_iter ();
1666 while (!iter
.is_end ()) {
1667 unowned Attribute attr
= iter
.get ();
1668 iter
= iter
.next ();
1670 var keys
= new GLib
.Sequence
<string> ();
1671 foreach (var key
in attr
.args
.get_keys ()) {
1672 if (key
== "cheader_filename" && sym is Namespace
) {
1675 keys
.insert_sorted (key
, (CompareDataFunc
<string>) strcmp
);
1677 if (need_cheaders
&& attr
.name
== "CCode" && !attr
.has_argument ("cheader_filename")) {
1678 keys
.insert_sorted ("cheader_filename", (CompareDataFunc
<string>) strcmp
);
1681 if (attr
.name
== "CCode" && keys
.get_length () == 0) {
1682 // only cheader_filename on namespace
1686 if (sym
!= null && attr
.args
.size
== 1 && attr
.name
== "Version") {
1687 string since_val
= attr
.get_string ("since");
1688 if (since_val
!= null && skip_since_tag_check (sym
, since_val
)) {
1693 if (!(node is Parameter
) && !(node is PropertyAccessor
)) {
1697 stream
.printf ("[%s", attr
.name
);
1698 if (keys
.get_length () > 0) {
1701 unowned
string separator
= "";
1702 var arg_iter
= keys
.get_begin_iter ();
1703 while (!arg_iter
.is_end ()) {
1704 unowned
string arg_name
= arg_iter
.get ();
1705 arg_iter
= arg_iter
.next ();
1706 if (arg_name
== "cheader_filename") {
1707 stream
.printf ("%scheader_filename = \"%s\"", separator
, get_cheaders (sym
));
1709 stream
.printf ("%s%s = %s", separator
, arg_name
, attr
.args
.get (arg_name
));
1717 if (node is Parameter
|| node is PropertyAccessor
) {
1725 private void write_accessibility (Symbol sym
) {
1726 if (sym
.access
== SymbolAccessibility
.PUBLIC
) {
1727 write_string ("public ");
1728 } else if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
1729 write_string ("protected ");
1730 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
1731 write_string ("internal ");
1732 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
1733 write_string ("private ");
1736 if (type
!= CodeWriterType
.EXTERNAL
&& type
!= CodeWriterType
.VAPIGEN
&& sym
.external
&& !sym
.external_package
) {
1737 write_string ("extern ");
1741 void write_property_accessor_accessibility (Symbol sym
) {
1742 if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
1743 write_string (" protected");
1744 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
1745 write_string (" internal");
1746 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
1747 write_string (" private");
1751 void write_type_parameters (List
<TypeParameter
> type_params
) {
1752 if (type_params
.size
> 0) {
1755 foreach (TypeParameter type_param
in type_params
) {
1761 write_identifier (type_param
.name
);
1768 public enum Vala
.CodeWriterType
{