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
) {
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
);
565 write_string ("const ");
567 write_type (c
.type_reference
);
570 write_identifier (c
.name
);
571 write_type_suffix (c
.type_reference
);
572 if (type
== CodeWriterType
.FAST
&& c
.value
!= null) {
574 c
.value
.accept (this
);
580 public override void visit_field (Field f
) {
581 if (f
.external_package
) {
585 if (!check_accessibility (f
)) {
589 if (context
.vapi_comments
&& f
.comment
!= null) {
590 write_comment (f
.comment
);
593 write_attributes (f
);
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
);
611 write_identifier (f
.name
);
612 write_type_suffix (f
.variable_type
);
617 private void write_error_domains (List
<DataType
> error_domains
) {
618 if (error_domains
.size
> 0) {
619 write_string (" throws ");
622 foreach (DataType type
in error_domains
) {
634 private void write_params (List
<Parameter
> params
) {
638 foreach (Parameter param
in params
) {
643 if (param
.ellipsis
) {
644 write_string ("...");
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 ");
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
);
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
);
686 public override void visit_delegate (Delegate cb
) {
687 if (cb
.external_package
) {
691 if (!check_accessibility (cb
)) {
695 if (context
.vapi_comments
&& cb
.comment
!= null) {
696 write_comment (cb
.comment
);
699 write_attributes (cb
);
703 write_accessibility (cb
);
704 write_string ("delegate ");
706 write_return_type (cb
.return_type
);
709 write_identifier (cb
.name
);
711 write_type_parameters (cb
.get_type_parameters ());
715 write_params (cb
.get_parameters ());
717 write_error_domains (cb
.get_error_types ());
724 public override void visit_constructor (Constructor c
) {
725 if (type
!= CodeWriterType
.DUMP
) {
729 if (context
.vapi_comments
&& c
.comment
!= null) {
730 write_comment (c
.comment
);
734 write_string ("construct");
735 write_code_block (c
.body
);
739 public override void visit_method (Method m
) {
740 if (m
.external_package
) {
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
) {
751 if (context
.vapi_comments
&& m
.comment
!= null) {
752 write_comment (m
.comment
);
755 write_attributes (m
);
758 write_accessibility (m
);
760 if (m is CreationMethod
) {
762 write_string ("async ");
765 var datatype
= (TypeSymbol
) m
.parent_symbol
;
766 write_identifier (datatype
.name
);
767 if (m
.name
!= ".new") {
769 write_identifier (m
.name
);
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 ");
786 write_string ("new ");
790 write_string ("async ");
793 write_return_type (m
.return_type
);
796 write_identifier (m
.name
);
798 write_type_parameters (m
.get_type_parameters ());
803 write_params (m
.get_parameters ());
805 write_error_domains (m
.get_error_types ());
807 write_code_block (m
.body
);
812 public override void visit_creation_method (CreationMethod 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
)) {
821 if (context
.vapi_comments
&& prop
.comment
!= null) {
822 write_comment (prop
.comment
);
825 write_attributes (prop
);
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
);
843 write_identifier (prop
.name
);
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
);
878 public override void visit_signal (Signal sig
) {
879 if (!check_accessibility (sig
)) {
883 if (context
.vapi_comments
&& sig
.comment
!= null) {
884 write_comment (sig
.comment
);
887 write_attributes (sig
);
890 write_accessibility (sig
);
892 if (sig
.is_virtual
) {
893 write_string ("virtual ");
896 write_string ("signal ");
898 write_return_type (sig
.return_type
);
901 write_identifier (sig
.name
);
905 write_params (sig
.get_parameters ());
912 public override void visit_block (Block b
) {
913 write_begin_block ();
915 foreach (Statement stmt
in b
.get_statements ()) {
922 public override void visit_empty_statement (EmptyStatement stmt
) {
925 public override void visit_declaration_statement (DeclarationStatement stmt
) {
927 stmt
.declaration
.accept (this
);
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
);
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
) {
950 foreach (Expression initializer
in list
.get_initializers ()) {
957 initializer
.accept (this
);
962 public override void visit_expression_statement (ExpressionStatement stmt
) {
964 stmt
.expression
.accept (this
);
969 public override void visit_if_statement (IfStatement stmt
) {
971 write_string ("if (");
972 stmt
.condition
.accept (this
);
974 stmt
.true_statement
.accept (this
);
975 if (stmt
.false_statement
!= null) {
976 write_string (" else");
977 stmt
.false_statement
.accept (this
);
982 public override void visit_switch_statement (SwitchStatement stmt
) {
984 write_string ("switch (");
985 stmt
.expression
.accept (this
);
986 write_string (") {");
989 foreach (SwitchSection section
in stmt
.get_sections ()) {
990 section
.accept (this
);
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) {
1009 write_string ("case ");
1010 label
.expression
.accept (this
);
1015 write_string ("default:");
1020 public override void visit_loop (Loop stmt
) {
1022 write_string ("loop");
1023 stmt
.body
.accept (this
);
1027 public override void visit_while_statement (WhileStatement stmt
) {
1029 write_string ("while (");
1030 stmt
.condition
.accept (this
);
1032 stmt
.body
.accept (this
);
1036 public override void visit_do_statement (DoStatement stmt
) {
1038 write_string ("do");
1039 stmt
.body
.accept (this
);
1040 write_string ("while (");
1041 stmt
.condition
.accept (this
);
1042 write_string (");");
1046 public override void visit_for_statement (ForStatement stmt
) {
1048 write_string ("for (");
1051 foreach (Expression initializer
in stmt
.get_initializer ()) {
1053 write_string (", ");
1056 initializer
.accept (this
);
1058 write_string ("; ");
1060 stmt
.condition
.accept (this
);
1061 write_string ("; ");
1064 foreach (Expression iterator
in stmt
.get_iterator ()) {
1066 write_string (", ");
1069 iterator
.accept (this
);
1073 stmt
.body
.accept (this
);
1077 public override void visit_foreach_statement (ForeachStatement stmt
) {
1080 public override void visit_break_statement (BreakStatement stmt
) {
1082 write_string ("break;");
1086 public override void visit_continue_statement (ContinueStatement stmt
) {
1088 write_string ("continue;");
1092 public override void visit_return_statement (ReturnStatement stmt
) {
1094 write_string ("return");
1095 if (stmt
.return_expression
!= null) {
1097 stmt
.return_expression
.accept (this
);
1103 public override void visit_yield_statement (YieldStatement y
) {
1105 write_string ("yield");
1106 if (y
.yield_expression
!= null) {
1108 y
.yield_expression
.accept (this
);
1114 public override void visit_throw_statement (ThrowStatement stmt
) {
1116 write_string ("throw");
1117 if (stmt
.error_expression
!= null) {
1119 stmt
.error_expression
.accept (this
);
1125 public override void visit_try_statement (TryStatement stmt
) {
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
);
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
) {
1148 write_string ("lock (");
1149 stmt
.resource
.accept (this
);
1151 if (stmt
.body
== null) {
1154 stmt
.body
.accept (this
);
1159 public override void visit_delete_statement (DeleteStatement stmt
) {
1161 write_string ("delete ");
1162 stmt
.expression
.accept (this
);
1167 public override void visit_array_creation_expression (ArrayCreationExpression expr
) {
1168 write_string ("new ");
1169 write_type (expr
.element_type
);
1173 foreach (Expression size
in expr
.get_sizes ()) {
1175 write_string (", ");
1184 if (expr
.initializer_list
!= null) {
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
);
1219 write_identifier (expr
.member_name
);
1222 public override void visit_method_call (MethodCall expr
) {
1223 expr
.call
.accept (this
);
1224 write_string (" (");
1227 foreach (Expression arg
in expr
.get_argument_list ()) {
1229 write_string (", ");
1239 public override void visit_element_access (ElementAccess expr
) {
1240 expr
.container
.accept (this
);
1244 foreach (Expression index
in expr
.get_indices ()) {
1246 write_string (", ");
1250 index
.accept (this
);
1256 public override void visit_slice_expression (SliceExpression expr
) {
1257 expr
.container
.accept (this
);
1259 expr
.start
.accept (this
);
1261 expr
.stop
.accept (this
);
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 ("++");
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") {
1287 write_string (expr
.symbol_reference
.name
);
1290 write_string (" (");
1293 foreach (Expression arg
in expr
.get_argument_list ()) {
1295 write_string (", ");
1305 public override void visit_sizeof_expression (SizeofExpression expr
) {
1306 write_string ("sizeof (");
1307 write_type (expr
.type_reference
);
1311 public override void visit_typeof_expression (TypeofExpression expr
) {
1312 write_string ("typeof (");
1313 write_type (expr
.type_reference
);
1317 public override void visit_unary_expression (UnaryExpression expr
) {
1318 switch (expr
.operator
) {
1319 case UnaryOperator
.PLUS
:
1322 case UnaryOperator
.MINUS
:
1325 case UnaryOperator
.LOGICAL_NEGATION
:
1328 case UnaryOperator
.BITWISE_COMPLEMENT
:
1331 case UnaryOperator
.INCREMENT
:
1332 write_string ("++");
1334 case UnaryOperator
.DECREMENT
:
1335 write_string ("--");
1337 case UnaryOperator
.REF
:
1338 write_string ("ref ");
1340 case UnaryOperator
.OUT
:
1341 write_string ("out ");
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
);
1356 if (!expr
.is_silent_cast
) {
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
) {
1372 expr
.inner
.accept (this
);
1375 public override void visit_addressof_expression (AddressofExpression expr
) {
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 (" + ");
1392 case BinaryOperator
.MINUS
:
1393 write_string (" - ");
1395 case BinaryOperator
.MUL
:
1396 write_string (" * ");
1398 case BinaryOperator
.DIV
:
1399 write_string (" / ");
1401 case BinaryOperator
.MOD
:
1402 write_string (" % ");
1404 case BinaryOperator
.SHIFT_LEFT
:
1405 write_string (" << ");
1407 case BinaryOperator
.SHIFT_RIGHT
:
1408 write_string (" >> ");
1410 case BinaryOperator
.LESS_THAN
:
1411 write_string (" < ");
1413 case BinaryOperator
.GREATER_THAN
:
1414 write_string (" > ");
1416 case BinaryOperator
.LESS_THAN_OR_EQUAL
:
1417 write_string (" <= ");
1419 case BinaryOperator
.GREATER_THAN_OR_EQUAL
:
1420 write_string (" >= ");
1422 case BinaryOperator
.EQUALITY
:
1423 write_string (" == ");
1425 case BinaryOperator
.INEQUALITY
:
1426 write_string (" != ");
1428 case BinaryOperator
.BITWISE_AND
:
1429 write_string (" & ");
1431 case BinaryOperator
.BITWISE_OR
:
1432 write_string (" | ");
1434 case BinaryOperator
.BITWISE_XOR
:
1435 write_string (" ^ ");
1437 case BinaryOperator
.AND
:
1438 write_string (" && ");
1440 case BinaryOperator
.OR
:
1441 write_string (" || ");
1443 case BinaryOperator
.IN
:
1444 write_string (" in ");
1446 case BinaryOperator
.COALESCE
:
1447 write_string (" ?? ");
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
);
1465 expr
.true_expression
.accept (this
);
1467 expr
.false_expression
.accept (this
);
1470 public override void visit_lambda_expression (LambdaExpression expr
) {
1472 var params
= expr
.get_parameters ();
1474 foreach (var param
in params
) {
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
);
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 () {
1508 stream
.puts (string.nfill (indent
, '\t'));
1512 private void write_comment (Comment comment
) {
1514 if (fix_indent_regex
== null)
1515 fix_indent_regex
= new
Regex ("\\n[\\t ]*");
1517 assert_not_reached ();
1520 string replacement
= "\n%s ".printf (string.nfill (indent
, '\t'));
1521 string fixed_content
;
1523 fixed_content
= fix_indent_regex
.replace (comment
.content
, comment
.content
.length
, 0, replacement
);
1525 assert_not_reached();
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 ()) {
1544 private void write_return_type (DataType type
) {
1545 if (type
.is_weak ()) {
1546 write_string ("unowned ");
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
) {
1560 array_type
.length
.accept (this
);
1565 private void write_string (string s
) {
1570 private void write_newline () {
1575 void write_code_block (Block? block
) {
1576 if (block
== null || type
!= CodeWriterType
.DUMP
) {
1581 block
.accept (this
);
1584 private void write_begin_block () {
1595 private void write_end_block () {
1601 private bool check_accessibility (Symbol sym
) {
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
:
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
) {
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
) {
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
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
)) {
1675 if (!(node is Parameter
) && !(node is PropertyAccessor
)) {
1679 stream
.printf ("[%s", attr
.name
);
1680 if (keys
.get_length () > 0) {
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
));
1691 stream
.printf ("%s%s = %s", separator
, arg_name
, attr
.args
.get (arg_name
));
1699 if (node is Parameter
|| node is PropertyAccessor
) {
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) {
1737 foreach (TypeParameter type_param
in type_params
) {
1743 write_identifier (type_param
.name
);
1750 public enum Vala
.CodeWriterType
{