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 && ns
.parent_symbol
== context
.root
) {
145 // Set GIR information only for the main namespace of the file.
146 if (ns
.source_reference
.file
.gir_namespace
!= null) {
148 write_string ("gir_namespace = \"%s\"".printf (ns
.source_reference
.file
.gir_namespace
));
150 if (ns
.source_reference
.file
.gir_version
!= null) {
152 write_string ("gir_version = \"%s\"".printf (ns
.source_reference
.file
.gir_version
));
159 write_attributes (ns
);
162 write_string ("namespace ");
163 write_identifier (ns
.name
);
164 write_begin_block ();
166 current_scope
= ns
.scope
;
168 visit_sorted (ns
.get_namespaces ());
169 visit_sorted (ns
.get_classes ());
170 visit_sorted (ns
.get_interfaces ());
171 visit_sorted (ns
.get_structs ());
172 visit_sorted (ns
.get_enums ());
173 visit_sorted (ns
.get_error_domains ());
174 visit_sorted (ns
.get_delegates ());
175 visit_sorted (ns
.get_fields ());
176 visit_sorted (ns
.get_constants ());
177 visit_sorted (ns
.get_methods ());
179 current_scope
= current_scope
.parent_scope
;
185 private string get_cheaders (Symbol cl
) {
187 string cheaders
= "";
188 if (type
!= CodeWriterType
.FAST
) {
189 foreach (string cheader
in cl
.get_cheader_filenames ()) {
190 if (header_to_override
!= null &&
191 cheader
== header_to_override
) {
192 cheader
= override_header
;
198 cheaders
= "%s,%s".printf (cheaders
, cheader
);
205 private void emit_deprecated_attribute (Symbol symbol
) {
206 if (symbol
.deprecated
) {
208 write_string ("[Deprecated");
209 var since
= symbol
.deprecated_since
;
210 var replacement
= symbol
.replacement
;
212 if (since
!= null || replacement
!= null) {
215 write_string ("since = \"%s\"".printf (since
));
217 if (since
!= null && replacement
!= null) {
220 if (replacement
!= null) {
221 write_string ("replacement = \"%s\"".printf (replacement
));
229 private void emit_experimental_attribute (Symbol symbol
) {
230 if (symbol
.experimental
) {
232 write_string ("[Experimental]");
237 public override void visit_class (Class cl
) {
238 if (cl
.external_package
) {
242 if (!check_accessibility (cl
)) {
248 write_string ("[Compact]");
252 if (cl
.is_immutable
) {
254 write_string ("[Immutable]");
258 emit_deprecated_attribute (cl
);
259 emit_experimental_attribute (cl
);
263 write_string ("[CCode (");
265 if (cl
.is_reference_counting () && type
!= CodeWriterType
.FAST
) {
266 if (cl
.base_class
== null || cl
.base_class
.get_ref_function () == null || cl
.base_class
.get_ref_function () != cl
.get_ref_function ()) {
267 write_string ("ref_function = \"%s\", ".printf (cl
.get_ref_function ()));
268 if (cl
.ref_function_void
) {
269 write_string ("ref_function_void = true, ");
272 if (cl
.base_class
== null || cl
.base_class
.get_unref_function () == null || cl
.base_class
.get_unref_function () != cl
.get_unref_function ()) {
273 write_string ("unref_function = \"%s\", ".printf (cl
.get_unref_function ()));
276 if (cl
.get_dup_function () != null) {
277 write_string ("copy_function = \"%s\", ".printf (cl
.get_dup_function ()));
279 if (cl
.get_free_function () != cl
.get_default_free_function ()) {
280 write_string ("free_function = \"%s\", ".printf (cl
.get_free_function ()));
284 if (cl
.get_cname () != cl
.get_default_cname ()) {
285 write_string ("cname = \"%s\", ".printf (cl
.get_cname ()));
287 if (cl
.const_cname
!= null) {
288 write_string ("const_cname = \"%s\", ".printf (cl
.const_cname
));
291 if (cl
.type_check_function
!= null) {
292 write_string ("type_check_function = \"%s\", ".printf (cl
.type_check_function
));
295 if (cl
.get_type_id () != cl
.get_default_type_id ()) {
296 write_string ("type_id = \"%s\", ".printf (cl
.get_type_id ()));
299 if (cl
.get_param_spec_function () != cl
.get_default_param_spec_function ()) {
300 write_string ("param_spec_function = \"%s\", ".printf (cl
.get_param_spec_function ()));
303 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(cl
)));
306 write_attributes (cl
);
309 write_accessibility (cl
);
310 if (cl
.is_abstract
) {
311 write_string ("abstract ");
313 write_string ("class ");
314 write_identifier (cl
.name
);
316 var type_params
= cl
.get_type_parameters ();
317 if (type_params
.size
> 0) {
320 foreach (TypeParameter type_param
in type_params
) {
326 write_identifier (type_param
.name
);
331 var base_types
= cl
.get_base_types ();
332 if (base_types
.size
> 0) {
333 write_string (" : ");
336 foreach (DataType base_type
in base_types
) {
342 write_type (base_type
);
345 write_begin_block ();
347 current_scope
= cl
.scope
;
349 visit_sorted (cl
.get_classes ());
350 visit_sorted (cl
.get_structs ());
351 visit_sorted (cl
.get_enums ());
352 visit_sorted (cl
.get_delegates ());
353 visit_sorted (cl
.get_fields ());
354 visit_sorted (cl
.get_constants ());
355 visit_sorted (cl
.get_methods ());
356 visit_sorted (cl
.get_properties ());
357 visit_sorted (cl
.get_signals ());
359 if (cl
.constructor
!= null) {
360 cl
.constructor
.accept (this
);
363 current_scope
= current_scope
.parent_scope
;
369 void visit_sorted (List
<Symbol
> symbols
) {
370 if (type
!= CodeWriterType
.EXTERNAL
) {
371 // order of virtual methods matters for fast vapis
372 foreach (Symbol sym
in symbols
) {
378 var sorted_symbols
= new ArrayList
<Symbol
> ();
379 foreach (Symbol sym
in symbols
) {
381 int right
= sorted_symbols
.size
- 1;
382 if (left
> right
|| sym
.name
< sorted_symbols
[left
].name
) {
383 sorted_symbols
.insert (0, sym
);
384 } else if (sym
.name
> sorted_symbols
[right
].name
) {
385 sorted_symbols
.add (sym
);
387 while (right
- left
> 1) {
388 int i
= (right
+ left
) / 2;
389 if (sym
.name
> sorted_symbols
[i
].name
) {
395 sorted_symbols
.insert (left
+ 1, sym
);
398 foreach (Symbol sym
in sorted_symbols
) {
403 public override void visit_struct (Struct st
) {
404 if (st
.external_package
) {
408 if (!check_accessibility (st
)) {
412 if (st
.is_immutable
) {
414 write_string ("[Immutable]");
418 emit_deprecated_attribute (st
);
419 emit_experimental_attribute (st
);
423 write_string ("[CCode (");
425 if (st
.get_cname () != st
.get_default_cname ()) {
426 write_string ("cname = \"%s\", ".printf (st
.get_cname ()));
429 if (!st
.has_type_id
) {
430 write_string ("has_type_id = false, ");
431 } else if (!st
.is_simple_type () && st
.get_type_id () != "G_TYPE_POINTER") {
432 write_string ("type_id = \"%s\", ".printf (st
.get_type_id ()));
435 if (!st
.has_copy_function
) {
436 write_string ("has_copy_function = false, ");
439 if (!st
.has_destroy_function
) {
440 write_string ("has_destroy_function = false, ");
443 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(st
)));
446 if (st
.is_simple_type ()) {
448 write_string ("[SimpleType]");
452 if (st
.is_integer_type ()) {
454 write_string ("[IntegerType (rank = %d)]".printf (st
.get_rank ()));
458 if (st
.is_floating_type ()) {
460 write_string ("[FloatingType (rank = %d)]".printf (st
.get_rank ()));
464 write_attributes (st
);
467 write_accessibility (st
);
468 write_string ("struct ");
469 write_identifier (st
.name
);
471 if (st
.base_type
!= null) {
472 write_string (" : ");
473 write_type (st
.base_type
);
476 write_begin_block ();
478 current_scope
= st
.scope
;
480 foreach (Field field
in st
.get_fields ()) {
483 visit_sorted (st
.get_constants ());
484 visit_sorted (st
.get_methods ());
485 visit_sorted (st
.get_properties ());
487 current_scope
= current_scope
.parent_scope
;
493 public override void visit_interface (Interface iface
) {
494 if (iface
.external_package
) {
498 if (!check_accessibility (iface
)) {
502 emit_deprecated_attribute (iface
);
503 emit_experimental_attribute (iface
);
507 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(iface
)));
508 if (iface
.get_lower_case_csuffix () != iface
.get_default_lower_case_csuffix ())
509 write_string (", lower_case_csuffix = \"%s\"".printf (iface
.get_lower_case_csuffix ()));
510 if (iface
.get_type_cname () != iface
.get_default_type_cname ())
511 write_string (", type_cname = \"%s\"".printf (iface
.get_type_cname ()));
516 write_attributes (iface
);
519 write_accessibility (iface
);
520 write_string ("interface ");
521 write_identifier (iface
.name
);
523 var type_params
= iface
.get_type_parameters ();
524 if (type_params
.size
> 0) {
527 foreach (TypeParameter type_param
in type_params
) {
533 write_identifier (type_param
.name
);
538 var prerequisites
= iface
.get_prerequisites ();
539 if (prerequisites
.size
> 0) {
540 write_string (" : ");
543 foreach (DataType prerequisite
in prerequisites
) {
549 write_type (prerequisite
);
552 write_begin_block ();
554 current_scope
= iface
.scope
;
556 visit_sorted (iface
.get_classes ());
557 visit_sorted (iface
.get_structs ());
558 visit_sorted (iface
.get_enums ());
559 visit_sorted (iface
.get_delegates ());
560 visit_sorted (iface
.get_fields ());
561 visit_sorted (iface
.get_constants ());
562 visit_sorted (iface
.get_methods ());
563 visit_sorted (iface
.get_properties ());
564 visit_sorted (iface
.get_signals ());
566 current_scope
= current_scope
.parent_scope
;
572 public override void visit_enum (Enum en
) {
573 if (en
.external_package
) {
577 if (!check_accessibility (en
)) {
581 emit_deprecated_attribute (en
);
582 emit_experimental_attribute (en
);
586 write_string ("[CCode (cprefix = \"%s\", ".printf (en
.get_cprefix ()));
588 if (!en
.has_type_id
) {
589 write_string ("has_type_id = false, ");
592 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(en
)));
596 write_string ("[Flags]");
599 write_attributes (en
);
602 write_accessibility (en
);
603 write_string ("enum ");
604 write_identifier (en
.name
);
605 write_begin_block ();
608 foreach (EnumValue ev
in en
.get_values ()) {
616 if (ev
.get_cname () != ev
.get_default_cname ()) {
618 write_string ("[CCode (cname = \"%s\")]".printf (ev
.get_cname ()));
621 write_identifier (ev
.name
);
623 if (type
== CodeWriterType
.FAST
&& ev
.value
!= null) {
625 ev
.value
.accept (this
);
630 if (en
.get_methods ().size
> 0 || en
.get_constants ().size
> 0) {
636 current_scope
= en
.scope
;
637 foreach (Method m
in en
.get_methods ()) {
640 foreach (Constant c
in en
.get_constants ()) {
643 current_scope
= current_scope
.parent_scope
;
649 public override void visit_error_domain (ErrorDomain edomain
) {
650 if (edomain
.external_package
) {
654 if (!check_accessibility (edomain
)) {
658 emit_deprecated_attribute (edomain
);
659 emit_experimental_attribute (edomain
);
663 write_string ("[CCode (cprefix = \"%s\", cheader_filename = \"%s\")]".printf (edomain
.get_cprefix (), get_cheaders(edomain
)));
665 write_attributes (edomain
);
668 write_accessibility (edomain
);
669 write_string ("errordomain ");
670 write_identifier (edomain
.name
);
671 write_begin_block ();
673 edomain
.accept_children (this
);
679 public override void visit_error_code (ErrorCode ecode
) {
681 write_identifier (ecode
.name
);
686 public override void visit_constant (Constant c
) {
687 if (c
.external_package
) {
691 if (!check_accessibility (c
)) {
695 emit_deprecated_attribute (c
);
696 emit_experimental_attribute (c
);
698 bool custom_cname
= (c
.get_cname () != c
.get_default_cname ());
699 bool custom_cheaders
= (c
.parent_symbol is Namespace
);
700 if (custom_cname
|| custom_cheaders
) {
702 write_string ("[CCode (");
705 write_string ("cname = \"%s\"".printf (c
.get_cname ()));
708 if (custom_cheaders
) {
713 write_string ("cheader_filename = \"%s\"".printf (get_cheaders(c
)));
720 write_accessibility (c
);
721 write_string ("const ");
723 write_type (c
.type_reference
);
726 write_identifier (c
.name
);
727 if (type
== CodeWriterType
.FAST
&& c
.value
!= null) {
729 c
.value
.accept (this
);
735 public override void visit_field (Field f
) {
736 if (f
.external_package
) {
740 if (!check_accessibility (f
)) {
744 emit_deprecated_attribute (f
);
745 emit_experimental_attribute (f
);
747 bool custom_cname
= (f
.get_cname () != f
.get_default_cname ());
748 bool custom_ctype
= (f
.get_ctype () != null);
749 bool custom_cheaders
= (f
.parent_symbol is Namespace
);
750 bool custom_array_length_cname
= (f
.get_array_length_cname () != null);
751 bool custom_array_length_type
= (f
.array_length_type
!= null);
752 if (custom_cname
|| custom_ctype
|| custom_cheaders
|| custom_array_length_cname
|| custom_array_length_type
|| (f
.no_array_length
&& f
.variable_type is ArrayType
)) {
754 write_string ("[CCode (");
757 write_string ("cname = \"%s\"".printf (f
.get_cname ()));
765 write_string ("type = \"%s\"".printf (f
.get_ctype ()));
768 if (custom_cheaders
) {
769 if (custom_cname
|| custom_ctype
) {
773 write_string ("cheader_filename = \"%s\"".printf (get_cheaders(f
)));
776 if (f
.variable_type is ArrayType
) {
777 if (f
.no_array_length
) {
778 if (custom_cname
|| custom_ctype
|| custom_cheaders
) {
782 write_string ("array_length = false");
784 if (f
.array_null_terminated
) {
785 write_string (", array_null_terminated = true");
788 if (custom_array_length_cname
) {
789 if (custom_cname
|| custom_ctype
|| custom_cheaders
) {
793 write_string ("array_length_cname = \"%s\"".printf (f
.get_array_length_cname ()));
796 if (custom_array_length_type
) {
797 if (custom_cname
|| custom_ctype
|| custom_cheaders
|| custom_array_length_cname
) {
801 write_string ("array_length_type = \"%s\"".printf (f
.array_length_type
));
810 write_accessibility (f
);
812 if (f
.binding
== MemberBinding
.STATIC
) {
813 write_string ("static ");
814 } else if (f
.binding
== MemberBinding
.CLASS
) {
815 write_string ("class ");
818 if (f
.variable_type
.is_weak ()) {
819 write_string ("weak ");
822 write_type (f
.variable_type
);
825 write_identifier (f
.name
);
830 private void write_error_domains (List
<DataType
> error_domains
) {
831 if (error_domains
.size
> 0) {
832 write_string (" throws ");
835 foreach (DataType type
in error_domains
) {
847 // equality comparison with 3 digit precision
848 private bool float_equal (double d1
, double d2
) {
849 return ((int) (d1
* 1000)) == ((int) (d2
* 1000));
852 private void write_params (List
<Parameter
> params
) {
856 foreach (Parameter param
in params
) {
861 if (param
.ellipsis
) {
862 write_string ("...");
867 var ccode_params
= new
StringBuilder ();
870 if (!float_equal (param
.cparameter_position
, i
)) {
871 ccode_params
.append_printf ("%spos = %g", separator
, param
.cparameter_position
);
874 if (param
.ctype
!= null) {
875 ccode_params
.append_printf ("%stype = \"%s\"", separator
, param
.ctype
);
878 if (param
.no_array_length
&& param
.variable_type is ArrayType
) {
879 ccode_params
.append_printf ("%sarray_length = false", separator
);
882 if (param
.array_null_terminated
&& param
.variable_type is ArrayType
) {
883 ccode_params
.append_printf ("%sarray_null_terminated = true", separator
);
886 if (param
.array_length_type
!= null && param
.variable_type is ArrayType
) {
887 ccode_params
.append_printf ("%sarray_length_type = \"%s\"", separator
, param
.array_length_type
);
890 if (param
.get_array_length_cname () != null && param
.variable_type is ArrayType
) {
891 ccode_params
.append_printf ("%sarray_length_cname = \"%s\"", separator
, param
.get_array_length_cname ());
894 if (!float_equal (param
.carray_length_parameter_position
, i
+ 0.1)) {
895 ccode_params
.append_printf ("%sarray_length_pos = %g", separator
, param
.carray_length_parameter_position
);
898 if (!float_equal (param
.cdelegate_target_parameter_position
, i
+ 0.1)) {
899 ccode_params
.append_printf ("%sdelegate_target_pos = %g", separator
, param
.cdelegate_target_parameter_position
);
903 if (ccode_params
.len
> 0) {
904 write_string ("[CCode (%s)] ".printf (ccode_params
.str
));
907 if (param
.params_array
) {
908 write_string ("params ");
911 if (param
.direction
== ParameterDirection
.IN
) {
912 if (param
.variable_type
.value_owned
) {
913 write_string ("owned ");
916 if (param
.direction
== ParameterDirection
.REF
) {
917 write_string ("ref ");
918 } else if (param
.direction
== ParameterDirection
.OUT
) {
919 write_string ("out ");
921 if (param
.variable_type
.is_weak ()) {
922 write_string ("unowned ");
926 write_type (param
.variable_type
);
929 write_identifier (param
.name
);
931 if (param
.initializer
!= null) {
932 write_string (" = ");
933 param
.initializer
.accept (this
);
942 public override void visit_delegate (Delegate cb
) {
943 if (cb
.external_package
) {
947 if (!check_accessibility (cb
)) {
951 emit_deprecated_attribute (cb
);
952 emit_experimental_attribute (cb
);
956 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(cb
)));
958 if (!cb
.has_target
) {
959 write_string (", has_target = false");
960 } else if (!float_equal (cb
.cinstance_parameter_position
, -2)) {
961 write_string (", instance_pos = %g".printf (cb
.cinstance_parameter_position
));
968 write_accessibility (cb
);
969 write_string ("delegate ");
971 write_return_type (cb
.return_type
);
974 write_identifier (cb
.name
);
976 var type_params
= cb
.get_type_parameters ();
977 if (type_params
.size
> 0) {
980 foreach (TypeParameter type_param
in type_params
) {
986 write_identifier (type_param
.name
);
993 write_params (cb
.get_parameters ());
995 write_error_domains (cb
.get_error_types ());
1002 public override void visit_constructor (Constructor c
) {
1003 if (type
!= CodeWriterType
.DUMP
) {
1008 write_string ("construct");
1009 write_code_block (c
.body
);
1013 public override void visit_method (Method m
) {
1014 if (m
.external_package
) {
1018 // don't write interface implementation unless it's an abstract or virtual method
1019 if (!check_accessibility (m
) || (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
1020 if (type
!= CodeWriterType
.DUMP
) {
1025 if (m
.get_attribute ("NoWrapper") != null) {
1027 write_string ("[NoWrapper]");
1029 if (m
.get_attribute ("NoThrow") != null) {
1031 write_string ("[NoThrow]");
1033 if (m
.returns_modified_pointer
) {
1035 write_string ("[ReturnsModifiedPointer]");
1037 if (m
.printf_format
) {
1039 write_string ("[PrintfFormat]");
1041 if (m
.scanf_format
) {
1043 write_string ("[ScanfFormat]");
1045 if (m
.get_attribute ("Print") != null) {
1047 write_string ("[Print]");
1049 if (m
.get_attribute ("NoReturn") != null) {
1051 write_string ("[NoReturn]");
1053 if (m
.get_attribute ("Diagnostics") != null) {
1055 write_string ("[Diagnostics]");
1058 emit_deprecated_attribute (m
);
1059 emit_experimental_attribute (m
);
1061 var ccode_params
= new
StringBuilder ();
1064 if (m
.get_cname () != m
.get_default_cname ()) {
1065 ccode_params
.append_printf ("%scname = \"%s\"", separator
, m
.get_cname ());
1068 if (m
.parent_symbol is Namespace
) {
1069 ccode_params
.append_printf ("%scheader_filename = \"%s\"", separator
, get_cheaders(m
));
1072 if (!float_equal (m
.cinstance_parameter_position
, 0)) {
1073 ccode_params
.append_printf ("%sinstance_pos = %g", separator
, m
.cinstance_parameter_position
);
1076 if (m
.no_array_length
&& m
.return_type is ArrayType
) {
1077 ccode_params
.append_printf ("%sarray_length = false", separator
);
1080 if (!float_equal (m
.carray_length_parameter_position
, -3)) {
1081 ccode_params
.append_printf ("%sarray_length_pos = %g", separator
, m
.carray_length_parameter_position
);
1084 if (m
.array_null_terminated
&& m
.return_type is ArrayType
) {
1085 ccode_params
.append_printf ("%sarray_null_terminated = true", separator
);
1088 if (m
.array_length_type
!= null && m
.return_type is ArrayType
) {
1089 ccode_params
.append_printf ("%sarray_length_type = \"%s\"", separator
, m
.array_length_type
);
1092 if (!float_equal (m
.cdelegate_target_parameter_position
, -3)) {
1093 ccode_params
.append_printf ("%sdelegate_target_pos = %g", separator
, m
.cdelegate_target_parameter_position
);
1096 if (m
.vfunc_name
!= m
.name
) {
1097 ccode_params
.append_printf ("%svfunc_name = \"%s\"", separator
, m
.vfunc_name
);
1100 if (m
.coroutine
&& m
.get_finish_cname () != m
.get_default_finish_cname ()) {
1101 ccode_params
.append_printf ("%sfinish_name = \"%s\"", separator
, m
.get_finish_cname ());
1104 if (m
.sentinel
!= m
.DEFAULT_SENTINEL
) {
1105 ccode_params
.append_printf ("%ssentinel = \"%s\"", separator
, m
.sentinel
);
1108 var cm
= m as CreationMethod
;
1110 if (cm
.custom_return_type_cname
!= null) {
1111 ccode_params
.append_printf ("%stype = \"%s\"", separator
, cm
.custom_return_type_cname
);
1114 if (!m
.has_new_function
) {
1115 ccode_params
.append_printf ("%shas_new_function = false", separator
);
1118 if (!m
.has_construct_function
) {
1119 ccode_params
.append_printf ("%shas_construct_function = false", separator
);
1121 } else if (m
.name
== ".new" && m
.get_real_cname () != cm
.get_default_construct_function ()) {
1122 ccode_params
.append_printf ("%sconstruct_function = \"%s\"", separator
, m
.get_real_cname ());
1127 if (ccode_params
.len
> 0) {
1129 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1133 write_accessibility (m
);
1135 if (m is CreationMethod
) {
1137 write_string ("async ");
1140 var datatype
= (TypeSymbol
) m
.parent_symbol
;
1141 write_identifier (datatype
.name
);
1142 if (m
.name
!= ".new") {
1144 write_identifier (m
.name
);
1148 if (m
.binding
== MemberBinding
.STATIC
) {
1149 write_string ("static ");
1150 } else if (m
.binding
== MemberBinding
.CLASS
) {
1151 write_string ("class ");
1152 } else if (m
.is_abstract
) {
1153 write_string ("abstract ");
1154 } else if (m
.is_virtual
) {
1155 write_string ("virtual ");
1156 } else if (m
.overrides
) {
1157 write_string ("override ");
1161 write_string ("new ");
1165 write_string ("async ");
1168 write_return_type (m
.return_type
);
1171 write_identifier (m
.name
);
1173 var type_params
= m
.get_type_parameters ();
1174 if (type_params
.size
> 0) {
1177 foreach (TypeParameter type_param
in type_params
) {
1183 write_identifier (type_param
.name
);
1191 write_params (m
.get_parameters ());
1193 if (context
.profile
!= Profile
.DOVA
) {
1194 write_error_domains (m
.get_error_types ());
1197 write_code_block (m
.body
);
1202 public override void visit_creation_method (CreationMethod m
) {
1206 public override void visit_property (Property prop
) {
1207 if (!check_accessibility (prop
) || (prop
.base_interface_property
!= null && !prop
.is_abstract
&& !prop
.is_virtual
)) {
1211 emit_deprecated_attribute (prop
);
1212 emit_experimental_attribute (prop
);
1214 if (prop
.no_accessor_method
) {
1216 write_string ("[NoAccessorMethod]");
1218 if (prop
.property_type is ArrayType
&& prop
.no_array_length
) {
1220 write_string ("[CCode (array_length = false");
1222 if (prop
.array_null_terminated
) {
1223 write_string (", array_null_terminated = true");
1226 write_string (")]");
1230 write_accessibility (prop
);
1232 if (prop
.binding
== MemberBinding
.STATIC
) {
1233 write_string ("static ");
1234 } else if (prop
.is_abstract
) {
1235 write_string ("abstract ");
1236 } else if (prop
.is_virtual
) {
1237 write_string ("virtual ");
1238 } else if (prop
.overrides
) {
1239 write_string ("override ");
1242 write_type (prop
.property_type
);
1245 write_identifier (prop
.name
);
1246 write_string (" {");
1247 if (prop
.get_accessor
!= null) {
1248 var ccode_params
= new
StringBuilder ();
1251 if (prop
.get_accessor
.get_cname () != prop
.get_accessor
.get_default_cname ()) {
1252 ccode_params
.append_printf ("%scname = \"%s\"", separator
, prop
.get_accessor
.get_cname ());
1255 if (ccode_params
.len
> 0) {
1257 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1260 write_property_accessor_accessibility (prop
.get_accessor
);
1262 if (context
.profile
!= Profile
.DOVA
&& prop
.get_accessor
.value_type
.is_disposable ()) {
1263 write_string (" owned");
1266 write_string (" get");
1267 write_code_block (prop
.get_accessor
.body
);
1269 if (prop
.set_accessor
!= null) {
1270 var ccode_params
= new
StringBuilder ();
1273 if (prop
.set_accessor
.get_cname () != prop
.set_accessor
.get_default_cname ()) {
1274 ccode_params
.append_printf ("%scname = \"%s\"", separator
, prop
.set_accessor
.get_cname ());
1277 if (ccode_params
.len
> 0) {
1279 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1282 write_property_accessor_accessibility (prop
.set_accessor
);
1284 if (context
.profile
!= Profile
.DOVA
&& prop
.set_accessor
.value_type
.value_owned
) {
1285 write_string (" owned");
1288 if (prop
.set_accessor
.writable
) {
1289 write_string (" set");
1291 if (prop
.set_accessor
.construction
) {
1292 write_string (" construct");
1294 write_code_block (prop
.set_accessor
.body
);
1296 write_string (" }");
1300 public override void visit_signal (Signal sig
) {
1301 if (!check_accessibility (sig
)) {
1305 if (sig
.has_emitter
) {
1307 write_string ("[HasEmitter]");
1310 emit_deprecated_attribute (sig
);
1311 emit_experimental_attribute (sig
);
1314 write_accessibility (sig
);
1316 if (sig
.is_virtual
) {
1317 write_string ("virtual ");
1320 write_string ("signal ");
1322 write_return_type (sig
.return_type
);
1325 write_identifier (sig
.name
);
1329 write_params (sig
.get_parameters ());
1336 public override void visit_block (Block b
) {
1337 write_begin_block ();
1339 foreach (Statement stmt
in b
.get_statements ()) {
1346 public override void visit_empty_statement (EmptyStatement stmt
) {
1349 public override void visit_declaration_statement (DeclarationStatement stmt
) {
1351 stmt
.declaration
.accept (this
);
1356 public override void visit_local_variable (LocalVariable local
) {
1357 write_type (local
.variable_type
);
1359 write_identifier (local
.name
);
1360 if (local
.initializer
!= null) {
1361 write_string (" = ");
1362 local
.initializer
.accept (this
);
1366 public override void visit_initializer_list (InitializerList list
) {
1370 foreach (Expression initializer
in list
.get_initializers ()) {
1372 write_string (", ");
1377 initializer
.accept (this
);
1379 write_string (" }");
1382 public override void visit_expression_statement (ExpressionStatement stmt
) {
1384 stmt
.expression
.accept (this
);
1389 public override void visit_if_statement (IfStatement stmt
) {
1391 write_string ("if (");
1392 stmt
.condition
.accept (this
);
1394 stmt
.true_statement
.accept (this
);
1395 if (stmt
.false_statement
!= null) {
1396 write_string (" else");
1397 stmt
.false_statement
.accept (this
);
1402 public override void visit_switch_statement (SwitchStatement stmt
) {
1404 write_string ("switch (");
1405 stmt
.expression
.accept (this
);
1406 write_string (") {");
1409 foreach (SwitchSection section
in stmt
.get_sections ()) {
1410 section
.accept (this
);
1418 public override void visit_switch_section (SwitchSection section
) {
1419 foreach (SwitchLabel label
in section
.get_labels ()) {
1420 label
.accept (this
);
1423 visit_block (section
);
1426 public override void visit_switch_label (SwitchLabel label
) {
1427 if (label
.expression
!= null) {
1429 write_string ("case ");
1430 label
.expression
.accept (this
);
1435 write_string ("default:");
1440 public override void visit_loop (Loop stmt
) {
1442 write_string ("loop");
1443 stmt
.body
.accept (this
);
1447 public override void visit_while_statement (WhileStatement stmt
) {
1449 write_string ("while (");
1450 stmt
.condition
.accept (this
);
1452 stmt
.body
.accept (this
);
1456 public override void visit_do_statement (DoStatement stmt
) {
1458 write_string ("do");
1459 stmt
.body
.accept (this
);
1460 write_string ("while (");
1461 stmt
.condition
.accept (this
);
1462 write_string (");");
1466 public override void visit_for_statement (ForStatement stmt
) {
1468 write_string ("for (");
1471 foreach (Expression initializer
in stmt
.get_initializer ()) {
1473 write_string (", ");
1476 initializer
.accept (this
);
1478 write_string ("; ");
1480 stmt
.condition
.accept (this
);
1481 write_string ("; ");
1484 foreach (Expression iterator
in stmt
.get_iterator ()) {
1486 write_string (", ");
1489 iterator
.accept (this
);
1493 stmt
.body
.accept (this
);
1497 public override void visit_foreach_statement (ForeachStatement stmt
) {
1500 public override void visit_break_statement (BreakStatement stmt
) {
1502 write_string ("break;");
1506 public override void visit_continue_statement (ContinueStatement stmt
) {
1508 write_string ("continue;");
1512 public override void visit_return_statement (ReturnStatement stmt
) {
1514 write_string ("return");
1515 if (stmt
.return_expression
!= null) {
1517 stmt
.return_expression
.accept (this
);
1523 public override void visit_yield_statement (YieldStatement y
) {
1525 write_string ("yield");
1526 if (y
.yield_expression
!= null) {
1528 y
.yield_expression
.accept (this
);
1534 public override void visit_throw_statement (ThrowStatement stmt
) {
1536 write_string ("throw");
1537 if (stmt
.error_expression
!= null) {
1539 stmt
.error_expression
.accept (this
);
1545 public override void visit_try_statement (TryStatement stmt
) {
1547 write_string ("try");
1548 stmt
.body
.accept (this
);
1549 foreach (var clause
in stmt
.get_catch_clauses ()) {
1550 clause
.accept (this
);
1552 if (stmt
.finally_body
!= null) {
1553 write_string (" finally");
1554 stmt
.finally_body
.accept (this
);
1559 public override void visit_catch_clause (CatchClause clause
) {
1560 var type_name
= clause
.error_type
== null ?
"GLib.Error" : clause
.error_type
.to_string ();
1561 var var_name
= clause
.variable_name
== null ?
"_" : clause
.variable_name
;
1562 write_string (" catch (%s %s)".printf (type_name
, var_name
));
1563 clause
.body
.accept (this
);
1566 public override void visit_lock_statement (LockStatement stmt
) {
1568 write_string ("lock (");
1569 stmt
.resource
.accept (this
);
1571 if (stmt
.body
== null) {
1574 stmt
.body
.accept (this
);
1579 public override void visit_delete_statement (DeleteStatement stmt
) {
1581 write_string ("delete ");
1582 stmt
.expression
.accept (this
);
1587 public override void visit_array_creation_expression (ArrayCreationExpression expr
) {
1588 write_string ("new ");
1589 write_type (expr
.element_type
);
1593 foreach (Expression size
in expr
.get_sizes ()) {
1595 write_string (", ");
1604 if (expr
.initializer_list
!= null) {
1606 expr
.initializer_list
.accept (this
);
1610 public override void visit_boolean_literal (BooleanLiteral lit
) {
1611 write_string (lit
.value
.to_string ());
1614 public override void visit_character_literal (CharacterLiteral lit
) {
1615 write_string (lit
.value
);
1618 public override void visit_integer_literal (IntegerLiteral lit
) {
1619 write_string (lit
.value
);
1622 public override void visit_real_literal (RealLiteral lit
) {
1623 write_string (lit
.value
);
1626 public override void visit_string_literal (StringLiteral lit
) {
1627 write_string (lit
.value
);
1630 public override void visit_null_literal (NullLiteral lit
) {
1631 write_string ("null");
1634 public override void visit_member_access (MemberAccess expr
) {
1635 if (expr
.inner
!= null) {
1636 expr
.inner
.accept (this
);
1639 write_identifier (expr
.member_name
);
1642 public override void visit_method_call (MethodCall expr
) {
1643 expr
.call
.accept (this
);
1644 write_string (" (");
1647 foreach (Expression arg
in expr
.get_argument_list ()) {
1649 write_string (", ");
1659 public override void visit_element_access (ElementAccess expr
) {
1660 expr
.container
.accept (this
);
1664 foreach (Expression index
in expr
.get_indices ()) {
1666 write_string (", ");
1670 index
.accept (this
);
1676 public override void visit_slice_expression (SliceExpression expr
) {
1677 expr
.container
.accept (this
);
1679 expr
.start
.accept (this
);
1681 expr
.stop
.accept (this
);
1685 public override void visit_base_access (BaseAccess expr
) {
1686 write_string ("base");
1689 public override void visit_postfix_expression (PostfixExpression expr
) {
1690 expr
.inner
.accept (this
);
1691 if (expr
.increment
) {
1692 write_string ("++");
1694 write_string ("--");
1698 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
1699 if (!expr
.struct_creation
) {
1700 write_string ("new ");
1703 write_type (expr
.type_reference
);
1705 if (expr
.symbol_reference
.name
!= ".new") {
1707 write_string (expr
.symbol_reference
.name
);
1710 write_string (" (");
1713 foreach (Expression arg
in expr
.get_argument_list ()) {
1715 write_string (", ");
1725 public override void visit_sizeof_expression (SizeofExpression expr
) {
1726 write_string ("sizeof (");
1727 write_type (expr
.type_reference
);
1731 public override void visit_typeof_expression (TypeofExpression expr
) {
1732 write_string ("typeof (");
1733 write_type (expr
.type_reference
);
1737 public override void visit_unary_expression (UnaryExpression expr
) {
1738 switch (expr
.operator
) {
1739 case UnaryOperator
.PLUS
:
1742 case UnaryOperator
.MINUS
:
1745 case UnaryOperator
.LOGICAL_NEGATION
:
1748 case UnaryOperator
.BITWISE_COMPLEMENT
:
1751 case UnaryOperator
.INCREMENT
:
1752 write_string ("++");
1754 case UnaryOperator
.DECREMENT
:
1755 write_string ("--");
1757 case UnaryOperator
.REF
:
1758 write_string ("ref ");
1760 case UnaryOperator
.OUT
:
1761 write_string ("out ");
1764 assert_not_reached ();
1766 expr
.inner
.accept (this
);
1769 public override void visit_cast_expression (CastExpression expr
) {
1770 if (expr
.is_non_null_cast
) {
1771 write_string ("(!) ");
1772 expr
.inner
.accept (this
);
1776 if (!expr
.is_silent_cast
) {
1778 write_type (expr
.type_reference
);
1779 write_string (") ");
1782 expr
.inner
.accept (this
);
1784 if (expr
.is_silent_cast
) {
1785 write_string (" as ");
1786 write_type (expr
.type_reference
);
1790 public override void visit_pointer_indirection (PointerIndirection expr
) {
1792 expr
.inner
.accept (this
);
1795 public override void visit_addressof_expression (AddressofExpression expr
) {
1797 expr
.inner
.accept (this
);
1800 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
1801 write_string ("(owned) ");
1802 expr
.inner
.accept (this
);
1805 public override void visit_binary_expression (BinaryExpression expr
) {
1806 expr
.left
.accept (this
);
1808 switch (expr
.operator
) {
1809 case BinaryOperator
.PLUS
:
1810 write_string (" + ");
1812 case BinaryOperator
.MINUS
:
1813 write_string (" - ");
1815 case BinaryOperator
.MUL
:
1816 write_string (" * ");
1818 case BinaryOperator
.DIV
:
1819 write_string (" / ");
1821 case BinaryOperator
.MOD
:
1822 write_string (" % ");
1824 case BinaryOperator
.SHIFT_LEFT
:
1825 write_string (" << ");
1827 case BinaryOperator
.SHIFT_RIGHT
:
1828 write_string (" >> ");
1830 case BinaryOperator
.LESS_THAN
:
1831 write_string (" < ");
1833 case BinaryOperator
.GREATER_THAN
:
1834 write_string (" > ");
1836 case BinaryOperator
.LESS_THAN_OR_EQUAL
:
1837 write_string (" <= ");
1839 case BinaryOperator
.GREATER_THAN_OR_EQUAL
:
1840 write_string (" >= ");
1842 case BinaryOperator
.EQUALITY
:
1843 write_string (" == ");
1845 case BinaryOperator
.INEQUALITY
:
1846 write_string (" != ");
1848 case BinaryOperator
.BITWISE_AND
:
1849 write_string (" & ");
1851 case BinaryOperator
.BITWISE_OR
:
1852 write_string (" | ");
1854 case BinaryOperator
.BITWISE_XOR
:
1855 write_string (" ^ ");
1857 case BinaryOperator
.AND
:
1858 write_string (" && ");
1860 case BinaryOperator
.OR
:
1861 write_string (" || ");
1863 case BinaryOperator
.IN
:
1864 write_string (" in ");
1866 case BinaryOperator
.COALESCE
:
1867 write_string (" ?? ");
1870 assert_not_reached ();
1873 expr
.right
.accept (this
);
1876 public override void visit_type_check (TypeCheck expr
) {
1877 expr
.expression
.accept (this
);
1878 write_string (" is ");
1879 write_type (expr
.type_reference
);
1882 public override void visit_conditional_expression (ConditionalExpression expr
) {
1883 expr
.condition
.accept (this
);
1885 expr
.true_expression
.accept (this
);
1887 expr
.false_expression
.accept (this
);
1890 public override void visit_lambda_expression (LambdaExpression expr
) {
1892 var params
= expr
.get_parameters ();
1893 if (params
.size
!= 0) {
1894 for (var i
= 0; i
< params
.size
- 1; ++ i
) {
1895 write_string (params
[i
]);
1896 write_string (", ");
1898 write_string (params
[params
.size
- 1]);
1900 write_string (") =>");
1901 if (expr
.statement_body
!= null) {
1902 expr
.statement_body
.accept (this
);
1903 } else if (expr
.expression_body
!= null) {
1904 expr
.expression_body
.accept (this
);
1908 public override void visit_assignment (Assignment a
) {
1909 a
.left
.accept (this
);
1910 write_string (" = ");
1911 a
.right
.accept (this
);
1914 private void write_indent () {
1921 for (i
= 0; i
< indent
; i
++) {
1928 private void write_identifier (string s
) {
1929 char* id
= (char*)s
;
1930 int id_length
= (int)s
.length
;
1931 if (context
.profile
!= Profile
.DOVA
&&
1932 (Vala
.Scanner
.get_identifier_or_keyword (id
, id_length
) != Vala
.TokenType
.IDENTIFIER
||
1933 s
.get_char ().isdigit ())) {
1939 private void write_return_type (DataType type
) {
1940 if (type
.is_weak ()) {
1941 write_string ("unowned ");
1947 private void write_type (DataType type
) {
1948 write_string (type
.to_qualified_string (current_scope
));
1951 private void write_string (string s
) {
1952 stream
.printf ("%s", s
);
1956 private void write_newline () {
1961 void write_code_block (Block? block
) {
1962 if (block
== null || type
!= CodeWriterType
.DUMP
) {
1967 block
.accept (this
);
1970 private void write_begin_block () {
1981 private void write_end_block () {
1984 stream
.printf ("}");
1987 private bool check_accessibility (Symbol sym
) {
1989 case CodeWriterType
.EXTERNAL
:
1990 return sym
.access
== SymbolAccessibility
.PUBLIC
||
1991 sym
.access
== SymbolAccessibility
.PROTECTED
;
1993 case CodeWriterType
.INTERNAL
:
1994 case CodeWriterType
.FAST
:
1995 return sym
.access
== SymbolAccessibility
.INTERNAL
||
1996 sym
.access
== SymbolAccessibility
.PUBLIC
||
1997 sym
.access
== SymbolAccessibility
.PROTECTED
;
1999 case CodeWriterType
.DUMP
:
2003 assert_not_reached ();
2007 private void write_attributes (CodeNode node
) {
2008 foreach (Attribute attr
in node
.attributes
) {
2009 if (!filter_attribute (attr
)) {
2011 stream
.printf ("[%s", attr
.name
);
2013 var keys
= attr
.args
.get_keys ();
2014 if (keys
.size
!= 0) {
2015 stream
.printf (" (");
2017 string separator
= "";
2018 foreach (string arg_name
in keys
) {
2019 stream
.printf ("%s%s = %s", separator
, arg_name
, attr
.args
.get (arg_name
));
2023 stream
.printf (")");
2025 stream
.printf ("]");
2031 private bool filter_attribute (Attribute attr
) {
2032 if (attr
.name
== "CCode"
2033 || attr
.name
== "Compact" || attr
.name
== "Immutable"
2034 || attr
.name
== "SimpleType" || attr
.name
== "IntegerType" || attr
.name
== "FloatingType"
2035 || attr
.name
== "Flags") {
2041 private void write_accessibility (Symbol sym
) {
2042 if (sym
.access
== SymbolAccessibility
.PUBLIC
) {
2043 write_string ("public ");
2044 } else if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
2045 write_string ("protected ");
2046 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
2047 write_string ("internal ");
2048 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
2049 write_string ("private ");
2052 if (type
!= CodeWriterType
.EXTERNAL
&& sym
.external
&& !sym
.external_package
) {
2053 write_string ("extern ");
2057 void write_property_accessor_accessibility (Symbol sym
) {
2058 if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
2059 write_string (" protected");
2060 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
2061 write_string (" internal");
2062 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
2063 write_string (" private");
2068 public enum Vala
.CodeWriterType
{