3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
27 * Code visitor generating Vala API file for the public interface.
29 public class Vala
.CodeWriter
: CodeVisitor
{
30 private CodeContext context
;
35 /* at begin of line */
42 string? override_header
= null;
43 string? header_to_override
= null;
45 public CodeWriter (CodeWriterType type
= CodeWriterType
.EXTERNAL
) {
50 * Allows overriding of a specific cheader in the output
51 * @param original orignal cheader to override
52 * @param replacement cheader to replace original with
54 public void set_cheader_override (string original
, string replacement
)
56 header_to_override
= original
;
57 override_header
= replacement
;
61 * Writes the public interface of the specified code context into the
64 * @param context a code context
65 * @param filename a relative or absolute filename
67 public void write_file (CodeContext context
, string filename
) {
68 var file_exists
= FileUtils
.test (filename
, FileTest
.EXISTS
);
69 var temp_filename
= filename
+ ".valatmp";
70 this
.context
= context
;
73 stream
= FileStream
.open (temp_filename
, "w");
75 stream
= FileStream
.open (filename
, "w");
79 Report
.error (null, "unable to open `%s' for writing".printf (filename
));
83 var header
= context
.version_header ?
84 "/* %s generated by %s %s, do not modify. */".printf (Path
.get_basename (filename
), Environment
.get_prgname (), Config
.BUILD_VERSION
) :
85 "/* %s generated by %s, do not modify. */".printf (Path
.get_basename (filename
), Environment
.get_prgname ());
86 write_string (header
);
90 current_scope
= context
.root
.scope
;
92 context
.accept (this
);
102 var old_file
= new
MappedFile (filename
, false);
103 var new_file
= new
MappedFile (temp_filename
, false);
104 var len
= old_file
.get_length ();
105 if (len
== new_file
.get_length ()) {
106 if (Memory
.cmp (old_file
.get_contents (), new_file
.get_contents (), len
) == 0) {
112 } catch (FileError e
) {
113 // assume changed if mmap comparison doesn't work
117 FileUtils
.rename (temp_filename
, filename
);
119 FileUtils
.unlink (temp_filename
);
125 public override void visit_using_directive (UsingDirective ns
) {
126 if (type
== CodeWriterType
.FAST
) {
127 write_string ("using %s;\n".printf (ns
.namespace_symbol
.name
));
131 public override void visit_namespace (Namespace ns
) {
132 if (ns
.external_package
) {
136 if (ns
.name
== null) {
137 ns
.accept_children (this
);
142 write_string ("[CCode (cprefix = \"%s\", lower_case_cprefix = \"%s\"".printf (ns
.get_cprefix (), ns
.get_lower_case_cprefix ()));
144 if (ns
.source_reference
!= null) {
145 if (ns
.source_reference
.file
.gir_namespace
!= null) {
147 write_string ("gir_namespace = \"%s\"".printf (ns
.source_reference
.file
.gir_namespace
));
149 if (ns
.source_reference
.file
.gir_version
!= null) {
151 write_string ("gir_version = \"%s\"".printf (ns
.source_reference
.file
.gir_version
));
158 write_attributes (ns
);
161 write_string ("namespace ");
162 write_identifier (ns
.name
);
163 write_begin_block ();
165 current_scope
= ns
.scope
;
167 visit_sorted (ns
.get_namespaces ());
168 visit_sorted (ns
.get_classes ());
169 visit_sorted (ns
.get_interfaces ());
170 visit_sorted (ns
.get_structs ());
171 visit_sorted (ns
.get_enums ());
172 visit_sorted (ns
.get_error_domains ());
173 visit_sorted (ns
.get_delegates ());
174 visit_sorted (ns
.get_fields ());
175 visit_sorted (ns
.get_constants ());
176 visit_sorted (ns
.get_methods ());
178 current_scope
= current_scope
.parent_scope
;
184 private string get_cheaders (Symbol cl
) {
186 string cheaders
= "";
187 if (type
!= CodeWriterType
.FAST
) {
188 foreach (string cheader
in cl
.get_cheader_filenames ()) {
189 if (header_to_override
!= null &&
190 cheader
== header_to_override
) {
191 cheader
= override_header
;
197 cheaders
= "%s,%s".printf (cheaders
, cheader
);
204 private void emit_deprecated_attribute (Symbol symbol
) {
205 if (symbol
.deprecated
) {
207 write_string ("[Deprecated");
208 var since
= symbol
.deprecated_since
;
209 var replacement
= symbol
.replacement
;
211 if (since
!= null || replacement
!= null) {
214 write_string ("since = \"%s\"".printf (since
));
216 if (since
!= null && replacement
!= null) {
219 if (replacement
!= null) {
220 write_string ("replacement = \"%s\"".printf (replacement
));
228 public override void visit_class (Class cl
) {
229 if (cl
.external_package
) {
233 if (!check_accessibility (cl
)) {
239 write_string ("[Compact]");
243 if (cl
.is_immutable
) {
245 write_string ("[Immutable]");
249 emit_deprecated_attribute (cl
);
253 write_string ("[CCode (");
255 if (cl
.is_reference_counting () && type
!= CodeWriterType
.FAST
) {
256 if (cl
.base_class
== null || cl
.base_class
.get_ref_function () == null || cl
.base_class
.get_ref_function () != cl
.get_ref_function ()) {
257 write_string ("ref_function = \"%s\", ".printf (cl
.get_ref_function ()));
258 if (cl
.ref_function_void
) {
259 write_string ("ref_function_void = true, ");
262 if (cl
.base_class
== null || cl
.base_class
.get_unref_function () == null || cl
.base_class
.get_unref_function () != cl
.get_unref_function ()) {
263 write_string ("unref_function = \"%s\", ".printf (cl
.get_unref_function ()));
266 if (cl
.get_dup_function () != null) {
267 write_string ("copy_function = \"%s\", ".printf (cl
.get_dup_function ()));
269 if (cl
.get_free_function () != cl
.get_default_free_function ()) {
270 write_string ("free_function = \"%s\", ".printf (cl
.get_free_function ()));
274 if (cl
.get_cname () != cl
.get_default_cname ()) {
275 write_string ("cname = \"%s\", ".printf (cl
.get_cname ()));
277 if (cl
.const_cname
!= null) {
278 write_string ("const_cname = \"%s\", ".printf (cl
.const_cname
));
281 if (cl
.type_check_function
!= null) {
282 write_string ("type_check_function = \"%s\", ".printf (cl
.type_check_function
));
285 if (cl
.get_type_id () != cl
.get_default_type_id ()) {
286 write_string ("type_id = \"%s\", ".printf (cl
.get_type_id ()));
289 if (cl
.get_param_spec_function () != cl
.get_default_param_spec_function ()) {
290 write_string ("param_spec_function = \"%s\", ".printf (cl
.get_param_spec_function ()));
293 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(cl
)));
296 write_attributes (cl
);
299 write_accessibility (cl
);
300 if (cl
.is_abstract
) {
301 write_string ("abstract ");
303 write_string ("class ");
304 write_identifier (cl
.name
);
306 var type_params
= cl
.get_type_parameters ();
307 if (type_params
.size
> 0) {
310 foreach (TypeParameter type_param
in type_params
) {
316 write_identifier (type_param
.name
);
321 var base_types
= cl
.get_base_types ();
322 if (base_types
.size
> 0) {
323 write_string (" : ");
326 foreach (DataType base_type
in base_types
) {
332 write_type (base_type
);
335 write_begin_block ();
337 current_scope
= cl
.scope
;
339 visit_sorted (cl
.get_classes ());
340 visit_sorted (cl
.get_structs ());
341 visit_sorted (cl
.get_enums ());
342 visit_sorted (cl
.get_delegates ());
343 visit_sorted (cl
.get_fields ());
344 visit_sorted (cl
.get_constants ());
345 visit_sorted (cl
.get_methods ());
346 visit_sorted (cl
.get_properties ());
347 visit_sorted (cl
.get_signals ());
349 if (cl
.constructor
!= null) {
350 cl
.constructor
.accept (this
);
353 current_scope
= current_scope
.parent_scope
;
359 void visit_sorted (List
<Symbol
> symbols
) {
360 if (type
!= CodeWriterType
.EXTERNAL
) {
361 // order of virtual methods matters for fast vapis
362 foreach (Symbol sym
in symbols
) {
368 var sorted_symbols
= new ArrayList
<Symbol
> ();
369 foreach (Symbol sym
in symbols
) {
371 int right
= sorted_symbols
.size
- 1;
372 if (left
> right
|| sym
.name
< sorted_symbols
[left
].name
) {
373 sorted_symbols
.insert (0, sym
);
374 } else if (sym
.name
> sorted_symbols
[right
].name
) {
375 sorted_symbols
.add (sym
);
377 while (right
- left
> 1) {
378 int i
= (right
+ left
) / 2;
379 if (sym
.name
> sorted_symbols
[i
].name
) {
385 sorted_symbols
.insert (left
+ 1, sym
);
388 foreach (Symbol sym
in sorted_symbols
) {
393 public override void visit_struct (Struct st
) {
394 if (st
.external_package
) {
398 if (!check_accessibility (st
)) {
402 if (st
.is_immutable
) {
404 write_string ("[Immutable]");
408 emit_deprecated_attribute (st
);
412 write_string ("[CCode (");
414 if (st
.get_cname () != st
.get_default_cname ()) {
415 write_string ("cname = \"%s\", ".printf (st
.get_cname ()));
418 if (!st
.has_type_id
) {
419 write_string ("has_type_id = false, ");
420 } else if (!st
.is_simple_type () && st
.get_type_id () != "G_TYPE_POINTER") {
421 write_string ("type_id = \"%s\", ".printf (st
.get_type_id ()));
424 if (!st
.has_copy_function
) {
425 write_string ("has_copy_function = false, ");
428 if (!st
.has_destroy_function
) {
429 write_string ("has_destroy_function = false, ");
432 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(st
)));
435 if (st
.is_simple_type ()) {
437 write_string ("[SimpleType]");
441 if (st
.is_integer_type ()) {
443 write_string ("[IntegerType (rank = %d)]".printf (st
.get_rank ()));
447 if (st
.is_floating_type ()) {
449 write_string ("[FloatingType (rank = %d)]".printf (st
.get_rank ()));
453 write_attributes (st
);
456 write_accessibility (st
);
457 write_string ("struct ");
458 write_identifier (st
.name
);
460 if (st
.base_type
!= null) {
461 write_string (" : ");
462 write_type (st
.base_type
);
465 write_begin_block ();
467 current_scope
= st
.scope
;
469 foreach (Field field
in st
.get_fields ()) {
472 visit_sorted (st
.get_constants ());
473 visit_sorted (st
.get_methods ());
474 visit_sorted (st
.get_properties ());
476 current_scope
= current_scope
.parent_scope
;
482 public override void visit_interface (Interface iface
) {
483 if (iface
.external_package
) {
487 if (!check_accessibility (iface
)) {
491 emit_deprecated_attribute (iface
);
495 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(iface
)));
496 if (iface
.get_lower_case_csuffix () != iface
.get_default_lower_case_csuffix ())
497 write_string (", lower_case_csuffix = \"%s\"".printf (iface
.get_lower_case_csuffix ()));
502 write_attributes (iface
);
505 write_accessibility (iface
);
506 write_string ("interface ");
507 write_identifier (iface
.name
);
509 var type_params
= iface
.get_type_parameters ();
510 if (type_params
.size
> 0) {
513 foreach (TypeParameter type_param
in type_params
) {
519 write_identifier (type_param
.name
);
524 var prerequisites
= iface
.get_prerequisites ();
525 if (prerequisites
.size
> 0) {
526 write_string (" : ");
529 foreach (DataType prerequisite
in prerequisites
) {
535 write_type (prerequisite
);
538 write_begin_block ();
540 current_scope
= iface
.scope
;
542 visit_sorted (iface
.get_classes ());
543 visit_sorted (iface
.get_structs ());
544 visit_sorted (iface
.get_enums ());
545 visit_sorted (iface
.get_delegates ());
546 visit_sorted (iface
.get_fields ());
547 visit_sorted (iface
.get_constants ());
548 visit_sorted (iface
.get_methods ());
549 visit_sorted (iface
.get_properties ());
550 visit_sorted (iface
.get_signals ());
552 current_scope
= current_scope
.parent_scope
;
558 public override void visit_enum (Enum en
) {
559 if (en
.external_package
) {
563 if (!check_accessibility (en
)) {
567 emit_deprecated_attribute (en
);
571 write_string ("[CCode (cprefix = \"%s\", ".printf (en
.get_cprefix ()));
573 if (!en
.has_type_id
) {
574 write_string ("has_type_id = false, ");
577 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(en
)));
581 write_string ("[Flags]");
584 write_attributes (en
);
587 write_accessibility (en
);
588 write_string ("enum ");
589 write_identifier (en
.name
);
590 write_begin_block ();
593 foreach (EnumValue ev
in en
.get_values ()) {
601 if (ev
.get_cname () != ev
.get_default_cname ()) {
603 write_string ("[CCode (cname = \"%s\")]".printf (ev
.get_cname ()));
606 write_identifier (ev
.name
);
608 if (type
== CodeWriterType
.FAST
&& ev
.value
!= null) {
610 ev
.value
.accept (this
);
615 if (en
.get_methods ().size
> 0 || en
.get_constants ().size
> 0) {
621 current_scope
= en
.scope
;
622 foreach (Method m
in en
.get_methods ()) {
625 foreach (Constant c
in en
.get_constants ()) {
628 current_scope
= current_scope
.parent_scope
;
634 public override void visit_error_domain (ErrorDomain edomain
) {
635 if (edomain
.external_package
) {
639 if (!check_accessibility (edomain
)) {
643 emit_deprecated_attribute (edomain
);
647 write_string ("[CCode (cprefix = \"%s\", cheader_filename = \"%s\")]".printf (edomain
.get_cprefix (), get_cheaders(edomain
)));
649 write_attributes (edomain
);
652 write_accessibility (edomain
);
653 write_string ("errordomain ");
654 write_identifier (edomain
.name
);
655 write_begin_block ();
657 edomain
.accept_children (this
);
663 public override void visit_error_code (ErrorCode ecode
) {
665 write_identifier (ecode
.name
);
670 public override void visit_constant (Constant c
) {
671 if (c
.external_package
) {
675 if (!check_accessibility (c
)) {
679 emit_deprecated_attribute (c
);
681 bool custom_cname
= (c
.get_cname () != c
.get_default_cname ());
682 bool custom_cheaders
= (c
.parent_symbol is Namespace
);
683 if (custom_cname
|| custom_cheaders
) {
685 write_string ("[CCode (");
688 write_string ("cname = \"%s\"".printf (c
.get_cname ()));
691 if (custom_cheaders
) {
696 write_string ("cheader_filename = \"%s\"".printf (get_cheaders(c
)));
703 write_accessibility (c
);
704 write_string ("const ");
706 write_type (c
.type_reference
);
709 write_identifier (c
.name
);
710 if (type
== CodeWriterType
.FAST
&& c
.value
!= null) {
712 c
.value
.accept (this
);
718 public override void visit_field (Field f
) {
719 if (f
.external_package
) {
723 if (!check_accessibility (f
)) {
727 emit_deprecated_attribute (f
);
729 bool custom_cname
= (f
.get_cname () != f
.get_default_cname ());
730 bool custom_ctype
= (f
.get_ctype () != null);
731 bool custom_cheaders
= (f
.parent_symbol is Namespace
);
732 bool custom_array_length_cname
= (f
.get_array_length_cname () != null);
733 bool custom_array_length_type
= (f
.array_length_type
!= null);
734 if (custom_cname
|| custom_ctype
|| custom_cheaders
|| custom_array_length_cname
|| custom_array_length_type
|| (f
.no_array_length
&& f
.variable_type is ArrayType
)) {
736 write_string ("[CCode (");
739 write_string ("cname = \"%s\"".printf (f
.get_cname ()));
747 write_string ("type = \"%s\"".printf (f
.get_ctype ()));
750 if (custom_cheaders
) {
751 if (custom_cname
|| custom_ctype
) {
755 write_string ("cheader_filename = \"%s\"".printf (get_cheaders(f
)));
758 if (f
.variable_type is ArrayType
) {
759 if (f
.no_array_length
) {
760 if (custom_cname
|| custom_ctype
|| custom_cheaders
) {
764 write_string ("array_length = false");
766 if (f
.array_null_terminated
) {
767 write_string (", array_null_terminated = true");
770 if (custom_array_length_cname
) {
771 if (custom_cname
|| custom_ctype
|| custom_cheaders
) {
775 write_string ("array_length_cname = \"%s\"".printf (f
.get_array_length_cname ()));
778 if (custom_array_length_type
) {
779 if (custom_cname
|| custom_ctype
|| custom_cheaders
|| custom_array_length_cname
) {
783 write_string ("array_length_type = \"%s\"".printf (f
.array_length_type
));
792 write_accessibility (f
);
794 if (f
.binding
== MemberBinding
.STATIC
) {
795 write_string ("static ");
796 } else if (f
.binding
== MemberBinding
.CLASS
) {
797 write_string ("class ");
800 if (f
.variable_type
.is_weak ()) {
801 write_string ("weak ");
804 write_type (f
.variable_type
);
807 write_identifier (f
.name
);
812 private void write_error_domains (List
<DataType
> error_domains
) {
813 if (error_domains
.size
> 0) {
814 write_string (" throws ");
817 foreach (DataType type
in error_domains
) {
829 // equality comparison with 3 digit precision
830 private bool float_equal (double d1
, double d2
) {
831 return ((int) (d1
* 1000)) == ((int) (d2
* 1000));
834 private void write_params (List
<FormalParameter
> params
) {
838 foreach (FormalParameter param
in params
) {
843 if (param
.ellipsis
) {
844 write_string ("...");
849 var ccode_params
= new
StringBuilder ();
852 if (!float_equal (param
.cparameter_position
, i
)) {
853 ccode_params
.append_printf ("%spos = %g", separator
, param
.cparameter_position
);
856 if (param
.ctype
!= null) {
857 ccode_params
.append_printf ("%stype = \"%s\"", separator
, param
.ctype
);
860 if (param
.no_array_length
&& param
.variable_type is ArrayType
) {
861 ccode_params
.append_printf ("%sarray_length = false", separator
);
864 if (param
.array_length_type
!= null && param
.variable_type is ArrayType
) {
865 ccode_params
.append_printf ("%sarray_length_type = \"%s\"", separator
, param
.array_length_type
);
868 if (param
.get_array_length_cname () != null && param
.variable_type is ArrayType
) {
869 ccode_params
.append_printf ("%sarray_length_cname = \"%s\"", separator
, param
.get_array_length_cname ());
872 if (!float_equal (param
.carray_length_parameter_position
, i
+ 0.1)) {
873 ccode_params
.append_printf ("%sarray_length_pos = %g", separator
, param
.carray_length_parameter_position
);
876 if (!float_equal (param
.cdelegate_target_parameter_position
, i
+ 0.1)) {
877 ccode_params
.append_printf ("%sdelegate_target_pos = %g", separator
, param
.cdelegate_target_parameter_position
);
881 if (ccode_params
.len
> 0) {
882 write_string ("[CCode (%s)] ".printf (ccode_params
.str
));
885 if (param
.params_array
) {
886 write_string ("params ");
889 if (param
.direction
== ParameterDirection
.IN
) {
890 if (param
.variable_type
.value_owned
) {
891 write_string ("owned ");
894 if (param
.direction
== ParameterDirection
.REF
) {
895 write_string ("ref ");
896 } else if (param
.direction
== ParameterDirection
.OUT
) {
897 write_string ("out ");
899 if (param
.variable_type
.is_weak ()) {
900 write_string ("unowned ");
904 write_type (param
.variable_type
);
907 write_identifier (param
.name
);
909 if (param
.initializer
!= null) {
910 write_string (" = ");
911 param
.initializer
.accept (this
);
920 public override void visit_delegate (Delegate cb
) {
921 if (cb
.external_package
) {
925 if (!check_accessibility (cb
)) {
929 emit_deprecated_attribute (cb
);
933 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(cb
)));
935 if (!cb
.has_target
) {
936 write_string (", has_target = false");
937 } else if (!float_equal (cb
.cinstance_parameter_position
, -2)) {
938 write_string (", instance_pos = %g".printf (cb
.cinstance_parameter_position
));
945 write_accessibility (cb
);
946 write_string ("delegate ");
948 write_return_type (cb
.return_type
);
951 write_identifier (cb
.name
);
953 var type_params
= cb
.get_type_parameters ();
954 if (type_params
.size
> 0) {
957 foreach (TypeParameter type_param
in type_params
) {
963 write_identifier (type_param
.name
);
970 write_params (cb
.get_parameters ());
972 write_error_domains (cb
.get_error_types ());
979 public override void visit_constructor (Constructor c
) {
980 if (type
!= CodeWriterType
.DUMP
) {
985 write_string ("construct");
986 write_code_block (c
.body
);
990 public override void visit_method (Method m
) {
991 if (m
.external_package
) {
995 // don't write interface implementation unless it's an abstract or virtual method
996 if (!check_accessibility (m
) || (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
997 if (type
!= CodeWriterType
.DUMP
) {
1002 if (m
.get_attribute ("NoWrapper") != null) {
1004 write_string ("[NoWrapper]");
1006 if (m
.get_attribute ("NoThrow") != null) {
1008 write_string ("[NoThrow]");
1010 if (m
.returns_modified_pointer
) {
1012 write_string ("[ReturnsModifiedPointer]");
1014 if (m
.printf_format
) {
1016 write_string ("[PrintfFormat]");
1018 if (m
.scanf_format
) {
1020 write_string ("[ScanfFormat]");
1022 if (m
.get_attribute ("Print") != null) {
1024 write_string ("[Print]");
1026 if (m
.get_attribute ("NoReturn") != null) {
1028 write_string ("[NoReturn]");
1031 emit_deprecated_attribute (m
);
1033 var ccode_params
= new
StringBuilder ();
1036 if (m
.get_cname () != m
.get_default_cname ()) {
1037 ccode_params
.append_printf ("%scname = \"%s\"", separator
, m
.get_cname ());
1040 if (m
.parent_symbol is Namespace
) {
1041 ccode_params
.append_printf ("%scheader_filename = \"%s\"", separator
, get_cheaders(m
));
1044 if (!float_equal (m
.cinstance_parameter_position
, 0)) {
1045 ccode_params
.append_printf ("%sinstance_pos = %g", separator
, m
.cinstance_parameter_position
);
1048 if (m
.no_array_length
&& m
.return_type is ArrayType
) {
1049 ccode_params
.append_printf ("%sarray_length = false", separator
);
1052 if (!float_equal (m
.carray_length_parameter_position
, -3)) {
1053 ccode_params
.append_printf ("%sarray_length_pos = %g", separator
, m
.carray_length_parameter_position
);
1056 if (m
.array_null_terminated
&& m
.return_type is ArrayType
) {
1057 ccode_params
.append_printf ("%sarray_null_terminated = true", separator
);
1060 if (m
.array_length_type
!= null && m
.return_type is ArrayType
) {
1061 ccode_params
.append_printf ("%sarray_length_type = \"%s\"", separator
, m
.array_length_type
);
1064 if (!float_equal (m
.cdelegate_target_parameter_position
, -3)) {
1065 ccode_params
.append_printf ("%sdelegate_target_pos = %g", separator
, m
.cdelegate_target_parameter_position
);
1068 if (m
.vfunc_name
!= m
.name
) {
1069 ccode_params
.append_printf ("%svfunc_name = \"%s\"", separator
, m
.vfunc_name
);
1072 if (m
.coroutine
&& m
.get_finish_cname () != m
.get_default_finish_cname ()) {
1073 ccode_params
.append_printf ("%sfinish_name = \"%s\"", separator
, m
.get_finish_cname ());
1076 if (m
.sentinel
!= m
.DEFAULT_SENTINEL
) {
1077 ccode_params
.append_printf ("%ssentinel = \"%s\"", separator
, m
.sentinel
);
1080 var cm
= m as CreationMethod
;
1082 if (cm
.custom_return_type_cname
!= null) {
1083 ccode_params
.append_printf ("%stype = \"%s\"", separator
, cm
.custom_return_type_cname
);
1086 if (!m
.has_new_function
) {
1087 ccode_params
.append_printf ("%shas_new_function = false", separator
);
1090 if (!m
.has_construct_function
) {
1091 ccode_params
.append_printf ("%shas_construct_function = false", separator
);
1093 } else if (m
.name
== ".new" && m
.get_real_cname () != cm
.get_default_construct_function ()) {
1094 ccode_params
.append_printf ("%sconstruct_function = \"%s\"", separator
, m
.get_real_cname ());
1099 if (ccode_params
.len
> 0) {
1101 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1105 write_accessibility (m
);
1107 if (m is CreationMethod
) {
1109 write_string ("async ");
1112 var datatype
= (TypeSymbol
) m
.parent_symbol
;
1113 write_identifier (datatype
.name
);
1114 if (m
.name
!= ".new") {
1116 write_identifier (m
.name
);
1120 if (m
.binding
== MemberBinding
.STATIC
) {
1121 write_string ("static ");
1122 } else if (m
.binding
== MemberBinding
.CLASS
) {
1123 write_string ("class ");
1124 } else if (m
.is_abstract
) {
1125 write_string ("abstract ");
1126 } else if (m
.is_virtual
) {
1127 write_string ("virtual ");
1128 } else if (m
.overrides
) {
1129 write_string ("override ");
1133 write_string ("new ");
1137 write_string ("async ");
1140 write_return_type (m
.return_type
);
1143 write_identifier (m
.name
);
1145 var type_params
= m
.get_type_parameters ();
1146 if (type_params
.size
> 0) {
1149 foreach (TypeParameter type_param
in type_params
) {
1155 write_identifier (type_param
.name
);
1163 write_params (m
.get_parameters ());
1165 if (context
.profile
!= Profile
.DOVA
) {
1166 write_error_domains (m
.get_error_types ());
1169 write_code_block (m
.body
);
1174 public override void visit_creation_method (CreationMethod m
) {
1178 public override void visit_property (Property prop
) {
1179 if (!check_accessibility (prop
) || (prop
.base_interface_property
!= null && !prop
.is_abstract
&& !prop
.is_virtual
)) {
1183 emit_deprecated_attribute (prop
);
1185 if (prop
.no_accessor_method
) {
1187 write_string ("[NoAccessorMethod]");
1189 if (prop
.property_type is ArrayType
&& prop
.no_array_length
) {
1191 write_string ("[CCode (array_length = false");
1193 if (prop
.array_null_terminated
) {
1194 write_string (", array_null_terminated = true");
1197 write_string (")]");
1201 write_accessibility (prop
);
1203 if (prop
.binding
== MemberBinding
.STATIC
) {
1204 write_string ("static ");
1205 } else if (prop
.is_abstract
) {
1206 write_string ("abstract ");
1207 } else if (prop
.is_virtual
) {
1208 write_string ("virtual ");
1209 } else if (prop
.overrides
) {
1210 write_string ("override ");
1213 write_type (prop
.property_type
);
1216 write_identifier (prop
.name
);
1217 write_string (" {");
1218 if (prop
.get_accessor
!= null) {
1219 var ccode_params
= new
StringBuilder ();
1222 if (prop
.get_accessor
.get_cname () != prop
.get_accessor
.get_default_cname ()) {
1223 ccode_params
.append_printf ("%scname = \"%s\"", separator
, prop
.get_accessor
.get_cname ());
1226 if (ccode_params
.len
> 0) {
1228 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1231 write_property_accessor_accessibility (prop
.get_accessor
);
1233 if (context
.profile
!= Profile
.DOVA
&& prop
.get_accessor
.value_type
.is_disposable ()) {
1234 write_string (" owned");
1237 write_string (" get");
1238 write_code_block (prop
.get_accessor
.body
);
1240 if (prop
.set_accessor
!= null) {
1241 var ccode_params
= new
StringBuilder ();
1244 if (prop
.set_accessor
.get_cname () != prop
.set_accessor
.get_default_cname ()) {
1245 ccode_params
.append_printf ("%scname = \"%s\"", separator
, prop
.set_accessor
.get_cname ());
1248 if (ccode_params
.len
> 0) {
1250 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1253 write_property_accessor_accessibility (prop
.set_accessor
);
1255 if (context
.profile
!= Profile
.DOVA
&& prop
.set_accessor
.value_type
.value_owned
) {
1256 write_string (" owned");
1259 if (prop
.set_accessor
.writable
) {
1260 write_string (" set");
1262 if (prop
.set_accessor
.construction
) {
1263 write_string (" construct");
1265 write_code_block (prop
.set_accessor
.body
);
1267 write_string (" }");
1271 public override void visit_signal (Signal sig
) {
1272 if (!check_accessibility (sig
)) {
1276 if (sig
.has_emitter
) {
1278 write_string ("[HasEmitter]");
1281 emit_deprecated_attribute (sig
);
1284 write_accessibility (sig
);
1286 if (sig
.is_virtual
) {
1287 write_string ("virtual ");
1290 write_string ("signal ");
1292 write_return_type (sig
.return_type
);
1295 write_identifier (sig
.name
);
1299 write_params (sig
.get_parameters ());
1306 public override void visit_block (Block b
) {
1307 write_begin_block ();
1309 foreach (Statement stmt
in b
.get_statements ()) {
1316 public override void visit_empty_statement (EmptyStatement stmt
) {
1319 public override void visit_declaration_statement (DeclarationStatement stmt
) {
1321 stmt
.declaration
.accept (this
);
1326 public override void visit_local_variable (LocalVariable local
) {
1327 write_type (local
.variable_type
);
1329 write_identifier (local
.name
);
1330 if (local
.initializer
!= null) {
1331 write_string (" = ");
1332 local
.initializer
.accept (this
);
1336 public override void visit_initializer_list (InitializerList list
) {
1340 foreach (Expression initializer
in list
.get_initializers ()) {
1342 write_string (", ");
1347 initializer
.accept (this
);
1349 write_string (" }");
1352 public override void visit_expression_statement (ExpressionStatement stmt
) {
1354 stmt
.expression
.accept (this
);
1359 public override void visit_if_statement (IfStatement stmt
) {
1361 write_string ("if (");
1362 stmt
.condition
.accept (this
);
1364 stmt
.true_statement
.accept (this
);
1365 if (stmt
.false_statement
!= null) {
1366 write_string (" else");
1367 stmt
.false_statement
.accept (this
);
1372 public override void visit_switch_statement (SwitchStatement stmt
) {
1374 write_string ("switch (");
1375 stmt
.expression
.accept (this
);
1376 write_string (") {");
1379 foreach (SwitchSection section
in stmt
.get_sections ()) {
1380 section
.accept (this
);
1388 public override void visit_switch_section (SwitchSection section
) {
1389 foreach (SwitchLabel label
in section
.get_labels ()) {
1390 label
.accept (this
);
1393 visit_block (section
);
1396 public override void visit_switch_label (SwitchLabel label
) {
1397 if (label
.expression
!= null) {
1399 write_string ("case ");
1400 label
.expression
.accept (this
);
1405 write_string ("default:");
1410 public override void visit_loop (Loop stmt
) {
1412 write_string ("loop");
1413 stmt
.body
.accept (this
);
1417 public override void visit_while_statement (WhileStatement stmt
) {
1419 write_string ("while (");
1420 stmt
.condition
.accept (this
);
1422 stmt
.body
.accept (this
);
1426 public override void visit_do_statement (DoStatement stmt
) {
1428 write_string ("do");
1429 stmt
.body
.accept (this
);
1430 write_string ("while (");
1431 stmt
.condition
.accept (this
);
1432 write_string (");");
1436 public override void visit_for_statement (ForStatement stmt
) {
1438 write_string ("for (");
1441 foreach (Expression initializer
in stmt
.get_initializer ()) {
1443 write_string (", ");
1446 initializer
.accept (this
);
1448 write_string ("; ");
1450 stmt
.condition
.accept (this
);
1451 write_string ("; ");
1454 foreach (Expression iterator
in stmt
.get_iterator ()) {
1456 write_string (", ");
1459 iterator
.accept (this
);
1463 stmt
.body
.accept (this
);
1467 public override void visit_foreach_statement (ForeachStatement stmt
) {
1470 public override void visit_break_statement (BreakStatement stmt
) {
1472 write_string ("break;");
1476 public override void visit_continue_statement (ContinueStatement stmt
) {
1478 write_string ("continue;");
1482 public override void visit_return_statement (ReturnStatement stmt
) {
1484 write_string ("return");
1485 if (stmt
.return_expression
!= null) {
1487 stmt
.return_expression
.accept (this
);
1493 public override void visit_yield_statement (YieldStatement y
) {
1495 write_string ("yield");
1496 if (y
.yield_expression
!= null) {
1498 y
.yield_expression
.accept (this
);
1504 public override void visit_throw_statement (ThrowStatement stmt
) {
1506 write_string ("throw");
1507 if (stmt
.error_expression
!= null) {
1509 stmt
.error_expression
.accept (this
);
1515 public override void visit_try_statement (TryStatement stmt
) {
1517 write_string ("try");
1518 stmt
.body
.accept (this
);
1519 foreach (var clause
in stmt
.get_catch_clauses ()) {
1520 clause
.accept (this
);
1522 if (stmt
.finally_body
!= null) {
1523 write_string (" finally");
1524 stmt
.finally_body
.accept (this
);
1529 public override void visit_catch_clause (CatchClause clause
) {
1530 var type_name
= clause
.error_type
== null ?
"GLib.Error" : clause
.error_type
.to_string ();
1531 var var_name
= clause
.variable_name
== null ?
"_" : clause
.variable_name
;
1532 write_string (" catch (%s %s)".printf (type_name
, var_name
));
1533 clause
.body
.accept (this
);
1536 public override void visit_lock_statement (LockStatement stmt
) {
1538 write_string ("lock (");
1539 stmt
.resource
.accept (this
);
1541 if (stmt
.body
== null) {
1544 stmt
.body
.accept (this
);
1549 public override void visit_delete_statement (DeleteStatement stmt
) {
1551 write_string ("delete ");
1552 stmt
.expression
.accept (this
);
1557 public override void visit_array_creation_expression (ArrayCreationExpression expr
) {
1558 write_string ("new ");
1559 write_type (expr
.element_type
);
1563 foreach (Expression size
in expr
.get_sizes ()) {
1565 write_string (", ");
1574 if (expr
.initializer_list
!= null) {
1576 expr
.initializer_list
.accept (this
);
1580 public override void visit_boolean_literal (BooleanLiteral lit
) {
1581 write_string (lit
.value
.to_string ());
1584 public override void visit_character_literal (CharacterLiteral lit
) {
1585 write_string (lit
.value
);
1588 public override void visit_integer_literal (IntegerLiteral lit
) {
1589 write_string (lit
.value
);
1592 public override void visit_real_literal (RealLiteral lit
) {
1593 write_string (lit
.value
);
1596 public override void visit_string_literal (StringLiteral lit
) {
1597 write_string (lit
.value
);
1600 public override void visit_null_literal (NullLiteral lit
) {
1601 write_string ("null");
1604 public override void visit_member_access (MemberAccess expr
) {
1605 if (expr
.inner
!= null) {
1606 expr
.inner
.accept (this
);
1609 write_identifier (expr
.member_name
);
1612 public override void visit_method_call (MethodCall expr
) {
1613 expr
.call
.accept (this
);
1614 write_string (" (");
1617 foreach (Expression arg
in expr
.get_argument_list ()) {
1619 write_string (", ");
1629 public override void visit_element_access (ElementAccess expr
) {
1630 expr
.container
.accept (this
);
1634 foreach (Expression index
in expr
.get_indices ()) {
1636 write_string (", ");
1640 index
.accept (this
);
1646 public override void visit_slice_expression (SliceExpression expr
) {
1647 expr
.container
.accept (this
);
1649 expr
.start
.accept (this
);
1651 expr
.stop
.accept (this
);
1655 public override void visit_base_access (BaseAccess expr
) {
1656 write_string ("base");
1659 public override void visit_postfix_expression (PostfixExpression expr
) {
1660 expr
.inner
.accept (this
);
1661 if (expr
.increment
) {
1662 write_string ("++");
1664 write_string ("--");
1668 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
1669 if (!expr
.struct_creation
) {
1670 write_string ("new ");
1673 write_type (expr
.type_reference
);
1675 if (expr
.symbol_reference
.name
!= ".new") {
1677 write_string (expr
.symbol_reference
.name
);
1680 write_string (" (");
1683 foreach (Expression arg
in expr
.get_argument_list ()) {
1685 write_string (", ");
1695 public override void visit_sizeof_expression (SizeofExpression expr
) {
1696 write_string ("sizeof (");
1697 write_type (expr
.type_reference
);
1701 public override void visit_typeof_expression (TypeofExpression expr
) {
1702 write_string ("typeof (");
1703 write_type (expr
.type_reference
);
1707 public override void visit_unary_expression (UnaryExpression expr
) {
1708 switch (expr
.operator
) {
1709 case UnaryOperator
.PLUS
:
1712 case UnaryOperator
.MINUS
:
1715 case UnaryOperator
.LOGICAL_NEGATION
:
1718 case UnaryOperator
.BITWISE_COMPLEMENT
:
1721 case UnaryOperator
.INCREMENT
:
1722 write_string ("++");
1724 case UnaryOperator
.DECREMENT
:
1725 write_string ("--");
1727 case UnaryOperator
.REF
:
1728 write_string ("ref ");
1730 case UnaryOperator
.OUT
:
1731 write_string ("out ");
1734 assert_not_reached ();
1736 expr
.inner
.accept (this
);
1739 public override void visit_cast_expression (CastExpression expr
) {
1740 if (expr
.is_non_null_cast
) {
1741 write_string ("(!) ");
1742 expr
.inner
.accept (this
);
1746 if (!expr
.is_silent_cast
) {
1748 write_type (expr
.type_reference
);
1749 write_string (") ");
1752 expr
.inner
.accept (this
);
1754 if (expr
.is_silent_cast
) {
1755 write_string (" as ");
1756 write_type (expr
.type_reference
);
1760 public override void visit_pointer_indirection (PointerIndirection expr
) {
1762 expr
.inner
.accept (this
);
1765 public override void visit_addressof_expression (AddressofExpression expr
) {
1767 expr
.inner
.accept (this
);
1770 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
1771 write_string ("(owned) ");
1772 expr
.inner
.accept (this
);
1775 public override void visit_binary_expression (BinaryExpression expr
) {
1776 expr
.left
.accept (this
);
1778 switch (expr
.operator
) {
1779 case BinaryOperator
.PLUS
:
1780 write_string (" + ");
1782 case BinaryOperator
.MINUS
:
1783 write_string (" - ");
1785 case BinaryOperator
.MUL
:
1786 write_string (" * ");
1788 case BinaryOperator
.DIV
:
1789 write_string (" / ");
1791 case BinaryOperator
.MOD
:
1792 write_string (" % ");
1794 case BinaryOperator
.SHIFT_LEFT
:
1795 write_string (" << ");
1797 case BinaryOperator
.SHIFT_RIGHT
:
1798 write_string (" >> ");
1800 case BinaryOperator
.LESS_THAN
:
1801 write_string (" < ");
1803 case BinaryOperator
.GREATER_THAN
:
1804 write_string (" > ");
1806 case BinaryOperator
.LESS_THAN_OR_EQUAL
:
1807 write_string (" <= ");
1809 case BinaryOperator
.GREATER_THAN_OR_EQUAL
:
1810 write_string (" >= ");
1812 case BinaryOperator
.EQUALITY
:
1813 write_string (" == ");
1815 case BinaryOperator
.INEQUALITY
:
1816 write_string (" != ");
1818 case BinaryOperator
.BITWISE_AND
:
1819 write_string (" & ");
1821 case BinaryOperator
.BITWISE_OR
:
1822 write_string (" | ");
1824 case BinaryOperator
.BITWISE_XOR
:
1825 write_string (" ^ ");
1827 case BinaryOperator
.AND
:
1828 write_string (" && ");
1830 case BinaryOperator
.OR
:
1831 write_string (" || ");
1833 case BinaryOperator
.IN
:
1834 write_string (" in ");
1836 case BinaryOperator
.COALESCE
:
1837 write_string (" ?? ");
1840 assert_not_reached ();
1843 expr
.right
.accept (this
);
1846 public override void visit_type_check (TypeCheck expr
) {
1847 expr
.expression
.accept (this
);
1848 write_string (" is ");
1849 write_type (expr
.type_reference
);
1852 public override void visit_conditional_expression (ConditionalExpression expr
) {
1853 expr
.condition
.accept (this
);
1855 expr
.true_expression
.accept (this
);
1857 expr
.false_expression
.accept (this
);
1860 public override void visit_lambda_expression (LambdaExpression expr
) {
1862 var params
= expr
.get_parameters ();
1863 if (params
.size
!= 0) {
1864 for (var i
= 0; i
< params
.size
- 1; ++ i
) {
1865 write_string (params
[i
]);
1866 write_string (", ");
1868 write_string (params
[params
.size
- 1]);
1870 write_string (") =>");
1871 if (expr
.statement_body
!= null) {
1872 expr
.statement_body
.accept (this
);
1873 } else if (expr
.expression_body
!= null) {
1874 expr
.expression_body
.accept (this
);
1878 public override void visit_assignment (Assignment a
) {
1879 a
.left
.accept (this
);
1880 write_string (" = ");
1881 a
.right
.accept (this
);
1884 private void write_indent () {
1891 for (i
= 0; i
< indent
; i
++) {
1898 private void write_identifier (string s
) {
1899 char* id
= (char*)s
;
1900 int id_length
= (int)s
.length
;
1901 if (context
.profile
!= Profile
.DOVA
&&
1902 (Vala
.Scanner
.get_identifier_or_keyword (id
, id_length
) != Vala
.TokenType
.IDENTIFIER
||
1903 s
.get_char ().isdigit ())) {
1909 private void write_return_type (DataType type
) {
1910 if (type
.is_weak ()) {
1911 write_string ("unowned ");
1917 private void write_type (DataType type
) {
1918 write_string (type
.to_qualified_string (current_scope
));
1921 private void write_string (string s
) {
1922 stream
.printf ("%s", s
);
1926 private void write_newline () {
1931 void write_code_block (Block? block
) {
1932 if (block
== null || type
!= CodeWriterType
.DUMP
) {
1937 block
.accept (this
);
1940 private void write_begin_block () {
1951 private void write_end_block () {
1954 stream
.printf ("}");
1957 private bool check_accessibility (Symbol sym
) {
1959 case CodeWriterType
.EXTERNAL
:
1960 return sym
.access
== SymbolAccessibility
.PUBLIC
||
1961 sym
.access
== SymbolAccessibility
.PROTECTED
;
1963 case CodeWriterType
.INTERNAL
:
1964 case CodeWriterType
.FAST
:
1965 return sym
.access
== SymbolAccessibility
.INTERNAL
||
1966 sym
.access
== SymbolAccessibility
.PUBLIC
||
1967 sym
.access
== SymbolAccessibility
.PROTECTED
;
1969 case CodeWriterType
.DUMP
:
1973 assert_not_reached ();
1977 private void write_attributes (CodeNode node
) {
1978 foreach (Attribute attr
in node
.attributes
) {
1979 if (!filter_attribute (attr
)) {
1981 stream
.printf ("[%s", attr
.name
);
1983 var keys
= attr
.args
.get_keys ();
1984 if (keys
.size
!= 0) {
1985 stream
.printf (" (");
1987 string separator
= "";
1988 foreach (string arg_name
in keys
) {
1989 stream
.printf ("%s%s = %s", separator
, arg_name
, attr
.args
.get (arg_name
));
1993 stream
.printf (")");
1995 stream
.printf ("]");
2001 private bool filter_attribute (Attribute attr
) {
2002 if (attr
.name
== "CCode"
2003 || attr
.name
== "Compact" || attr
.name
== "Immutable"
2004 || attr
.name
== "SimpleType" || attr
.name
== "IntegerType" || attr
.name
== "FloatingType"
2005 || attr
.name
== "Flags") {
2011 private void write_accessibility (Symbol sym
) {
2012 if (sym
.access
== SymbolAccessibility
.PUBLIC
) {
2013 write_string ("public ");
2014 } else if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
2015 write_string ("protected ");
2016 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
2017 write_string ("internal ");
2018 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
2019 write_string ("private ");
2022 if (type
!= CodeWriterType
.EXTERNAL
&& sym
.external
&& !sym
.external_package
) {
2023 write_string ("extern ");
2027 void write_property_accessor_accessibility (Symbol sym
) {
2028 if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
2029 write_string (" protected");
2030 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
2031 write_string (" internal");
2032 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
2033 write_string (" private");
2038 public enum Vala
.CodeWriterType
{