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 public override void visit_class (Class cl
) {
230 if (cl
.external_package
) {
234 if (!check_accessibility (cl
)) {
240 write_string ("[Compact]");
244 if (cl
.is_immutable
) {
246 write_string ("[Immutable]");
250 emit_deprecated_attribute (cl
);
254 write_string ("[CCode (");
256 if (cl
.is_reference_counting () && type
!= CodeWriterType
.FAST
) {
257 if (cl
.base_class
== null || cl
.base_class
.get_ref_function () == null || cl
.base_class
.get_ref_function () != cl
.get_ref_function ()) {
258 write_string ("ref_function = \"%s\", ".printf (cl
.get_ref_function ()));
259 if (cl
.ref_function_void
) {
260 write_string ("ref_function_void = true, ");
263 if (cl
.base_class
== null || cl
.base_class
.get_unref_function () == null || cl
.base_class
.get_unref_function () != cl
.get_unref_function ()) {
264 write_string ("unref_function = \"%s\", ".printf (cl
.get_unref_function ()));
267 if (cl
.get_dup_function () != null) {
268 write_string ("copy_function = \"%s\", ".printf (cl
.get_dup_function ()));
270 if (cl
.get_free_function () != cl
.get_default_free_function ()) {
271 write_string ("free_function = \"%s\", ".printf (cl
.get_free_function ()));
275 if (cl
.get_cname () != cl
.get_default_cname ()) {
276 write_string ("cname = \"%s\", ".printf (cl
.get_cname ()));
278 if (cl
.const_cname
!= null) {
279 write_string ("const_cname = \"%s\", ".printf (cl
.const_cname
));
282 if (cl
.type_check_function
!= null) {
283 write_string ("type_check_function = \"%s\", ".printf (cl
.type_check_function
));
286 if (cl
.get_type_id () != cl
.get_default_type_id ()) {
287 write_string ("type_id = \"%s\", ".printf (cl
.get_type_id ()));
290 if (cl
.get_param_spec_function () != cl
.get_default_param_spec_function ()) {
291 write_string ("param_spec_function = \"%s\", ".printf (cl
.get_param_spec_function ()));
294 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(cl
)));
297 write_attributes (cl
);
300 write_accessibility (cl
);
301 if (cl
.is_abstract
) {
302 write_string ("abstract ");
304 write_string ("class ");
305 write_identifier (cl
.name
);
307 var type_params
= cl
.get_type_parameters ();
308 if (type_params
.size
> 0) {
311 foreach (TypeParameter type_param
in type_params
) {
317 write_identifier (type_param
.name
);
322 var base_types
= cl
.get_base_types ();
323 if (base_types
.size
> 0) {
324 write_string (" : ");
327 foreach (DataType base_type
in base_types
) {
333 write_type (base_type
);
336 write_begin_block ();
338 current_scope
= cl
.scope
;
340 visit_sorted (cl
.get_classes ());
341 visit_sorted (cl
.get_structs ());
342 visit_sorted (cl
.get_enums ());
343 visit_sorted (cl
.get_delegates ());
344 visit_sorted (cl
.get_fields ());
345 visit_sorted (cl
.get_constants ());
346 visit_sorted (cl
.get_methods ());
347 visit_sorted (cl
.get_properties ());
348 visit_sorted (cl
.get_signals ());
350 if (cl
.constructor
!= null) {
351 cl
.constructor
.accept (this
);
354 current_scope
= current_scope
.parent_scope
;
360 void visit_sorted (List
<Symbol
> symbols
) {
361 if (type
!= CodeWriterType
.EXTERNAL
) {
362 // order of virtual methods matters for fast vapis
363 foreach (Symbol sym
in symbols
) {
369 var sorted_symbols
= new ArrayList
<Symbol
> ();
370 foreach (Symbol sym
in symbols
) {
372 int right
= sorted_symbols
.size
- 1;
373 if (left
> right
|| sym
.name
< sorted_symbols
[left
].name
) {
374 sorted_symbols
.insert (0, sym
);
375 } else if (sym
.name
> sorted_symbols
[right
].name
) {
376 sorted_symbols
.add (sym
);
378 while (right
- left
> 1) {
379 int i
= (right
+ left
) / 2;
380 if (sym
.name
> sorted_symbols
[i
].name
) {
386 sorted_symbols
.insert (left
+ 1, sym
);
389 foreach (Symbol sym
in sorted_symbols
) {
394 public override void visit_struct (Struct st
) {
395 if (st
.external_package
) {
399 if (!check_accessibility (st
)) {
403 if (st
.is_immutable
) {
405 write_string ("[Immutable]");
409 emit_deprecated_attribute (st
);
413 write_string ("[CCode (");
415 if (st
.get_cname () != st
.get_default_cname ()) {
416 write_string ("cname = \"%s\", ".printf (st
.get_cname ()));
419 if (!st
.has_type_id
) {
420 write_string ("has_type_id = false, ");
421 } else if (!st
.is_simple_type () && st
.get_type_id () != "G_TYPE_POINTER") {
422 write_string ("type_id = \"%s\", ".printf (st
.get_type_id ()));
425 if (!st
.has_copy_function
) {
426 write_string ("has_copy_function = false, ");
429 if (!st
.has_destroy_function
) {
430 write_string ("has_destroy_function = false, ");
433 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(st
)));
436 if (st
.is_simple_type ()) {
438 write_string ("[SimpleType]");
442 if (st
.is_integer_type ()) {
444 write_string ("[IntegerType (rank = %d)]".printf (st
.get_rank ()));
448 if (st
.is_floating_type ()) {
450 write_string ("[FloatingType (rank = %d)]".printf (st
.get_rank ()));
454 write_attributes (st
);
457 write_accessibility (st
);
458 write_string ("struct ");
459 write_identifier (st
.name
);
461 if (st
.base_type
!= null) {
462 write_string (" : ");
463 write_type (st
.base_type
);
466 write_begin_block ();
468 current_scope
= st
.scope
;
470 foreach (Field field
in st
.get_fields ()) {
473 visit_sorted (st
.get_constants ());
474 visit_sorted (st
.get_methods ());
475 visit_sorted (st
.get_properties ());
477 current_scope
= current_scope
.parent_scope
;
483 public override void visit_interface (Interface iface
) {
484 if (iface
.external_package
) {
488 if (!check_accessibility (iface
)) {
492 emit_deprecated_attribute (iface
);
496 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(iface
)));
497 if (iface
.get_lower_case_csuffix () != iface
.get_default_lower_case_csuffix ())
498 write_string (", lower_case_csuffix = \"%s\"".printf (iface
.get_lower_case_csuffix ()));
499 if (iface
.get_type_cname () != iface
.get_default_type_cname ())
500 write_string (", type_cname = \"%s\"".printf (iface
.get_type_cname ()));
505 write_attributes (iface
);
508 write_accessibility (iface
);
509 write_string ("interface ");
510 write_identifier (iface
.name
);
512 var type_params
= iface
.get_type_parameters ();
513 if (type_params
.size
> 0) {
516 foreach (TypeParameter type_param
in type_params
) {
522 write_identifier (type_param
.name
);
527 var prerequisites
= iface
.get_prerequisites ();
528 if (prerequisites
.size
> 0) {
529 write_string (" : ");
532 foreach (DataType prerequisite
in prerequisites
) {
538 write_type (prerequisite
);
541 write_begin_block ();
543 current_scope
= iface
.scope
;
545 visit_sorted (iface
.get_classes ());
546 visit_sorted (iface
.get_structs ());
547 visit_sorted (iface
.get_enums ());
548 visit_sorted (iface
.get_delegates ());
549 visit_sorted (iface
.get_fields ());
550 visit_sorted (iface
.get_constants ());
551 visit_sorted (iface
.get_methods ());
552 visit_sorted (iface
.get_properties ());
553 visit_sorted (iface
.get_signals ());
555 current_scope
= current_scope
.parent_scope
;
561 public override void visit_enum (Enum en
) {
562 if (en
.external_package
) {
566 if (!check_accessibility (en
)) {
570 emit_deprecated_attribute (en
);
574 write_string ("[CCode (cprefix = \"%s\", ".printf (en
.get_cprefix ()));
576 if (!en
.has_type_id
) {
577 write_string ("has_type_id = false, ");
580 write_string ("cheader_filename = \"%s\")]".printf (get_cheaders(en
)));
584 write_string ("[Flags]");
587 write_attributes (en
);
590 write_accessibility (en
);
591 write_string ("enum ");
592 write_identifier (en
.name
);
593 write_begin_block ();
596 foreach (EnumValue ev
in en
.get_values ()) {
604 if (ev
.get_cname () != ev
.get_default_cname ()) {
606 write_string ("[CCode (cname = \"%s\")]".printf (ev
.get_cname ()));
609 write_identifier (ev
.name
);
611 if (type
== CodeWriterType
.FAST
&& ev
.value
!= null) {
613 ev
.value
.accept (this
);
618 if (en
.get_methods ().size
> 0 || en
.get_constants ().size
> 0) {
624 current_scope
= en
.scope
;
625 foreach (Method m
in en
.get_methods ()) {
628 foreach (Constant c
in en
.get_constants ()) {
631 current_scope
= current_scope
.parent_scope
;
637 public override void visit_error_domain (ErrorDomain edomain
) {
638 if (edomain
.external_package
) {
642 if (!check_accessibility (edomain
)) {
646 emit_deprecated_attribute (edomain
);
650 write_string ("[CCode (cprefix = \"%s\", cheader_filename = \"%s\")]".printf (edomain
.get_cprefix (), get_cheaders(edomain
)));
652 write_attributes (edomain
);
655 write_accessibility (edomain
);
656 write_string ("errordomain ");
657 write_identifier (edomain
.name
);
658 write_begin_block ();
660 edomain
.accept_children (this
);
666 public override void visit_error_code (ErrorCode ecode
) {
668 write_identifier (ecode
.name
);
673 public override void visit_constant (Constant c
) {
674 if (c
.external_package
) {
678 if (!check_accessibility (c
)) {
682 emit_deprecated_attribute (c
);
684 bool custom_cname
= (c
.get_cname () != c
.get_default_cname ());
685 bool custom_cheaders
= (c
.parent_symbol is Namespace
);
686 if (custom_cname
|| custom_cheaders
) {
688 write_string ("[CCode (");
691 write_string ("cname = \"%s\"".printf (c
.get_cname ()));
694 if (custom_cheaders
) {
699 write_string ("cheader_filename = \"%s\"".printf (get_cheaders(c
)));
706 write_accessibility (c
);
707 write_string ("const ");
709 write_type (c
.type_reference
);
712 write_identifier (c
.name
);
713 if (type
== CodeWriterType
.FAST
&& c
.value
!= null) {
715 c
.value
.accept (this
);
721 public override void visit_field (Field f
) {
722 if (f
.external_package
) {
726 if (!check_accessibility (f
)) {
730 emit_deprecated_attribute (f
);
732 bool custom_cname
= (f
.get_cname () != f
.get_default_cname ());
733 bool custom_ctype
= (f
.get_ctype () != null);
734 bool custom_cheaders
= (f
.parent_symbol is Namespace
);
735 bool custom_array_length_cname
= (f
.get_array_length_cname () != null);
736 bool custom_array_length_type
= (f
.array_length_type
!= null);
737 if (custom_cname
|| custom_ctype
|| custom_cheaders
|| custom_array_length_cname
|| custom_array_length_type
|| (f
.no_array_length
&& f
.variable_type is ArrayType
)) {
739 write_string ("[CCode (");
742 write_string ("cname = \"%s\"".printf (f
.get_cname ()));
750 write_string ("type = \"%s\"".printf (f
.get_ctype ()));
753 if (custom_cheaders
) {
754 if (custom_cname
|| custom_ctype
) {
758 write_string ("cheader_filename = \"%s\"".printf (get_cheaders(f
)));
761 if (f
.variable_type is ArrayType
) {
762 if (f
.no_array_length
) {
763 if (custom_cname
|| custom_ctype
|| custom_cheaders
) {
767 write_string ("array_length = false");
769 if (f
.array_null_terminated
) {
770 write_string (", array_null_terminated = true");
773 if (custom_array_length_cname
) {
774 if (custom_cname
|| custom_ctype
|| custom_cheaders
) {
778 write_string ("array_length_cname = \"%s\"".printf (f
.get_array_length_cname ()));
781 if (custom_array_length_type
) {
782 if (custom_cname
|| custom_ctype
|| custom_cheaders
|| custom_array_length_cname
) {
786 write_string ("array_length_type = \"%s\"".printf (f
.array_length_type
));
795 write_accessibility (f
);
797 if (f
.binding
== MemberBinding
.STATIC
) {
798 write_string ("static ");
799 } else if (f
.binding
== MemberBinding
.CLASS
) {
800 write_string ("class ");
803 if (f
.variable_type
.is_weak ()) {
804 write_string ("weak ");
807 write_type (f
.variable_type
);
810 write_identifier (f
.name
);
815 private void write_error_domains (List
<DataType
> error_domains
) {
816 if (error_domains
.size
> 0) {
817 write_string (" throws ");
820 foreach (DataType type
in error_domains
) {
832 // equality comparison with 3 digit precision
833 private bool float_equal (double d1
, double d2
) {
834 return ((int) (d1
* 1000)) == ((int) (d2
* 1000));
837 private void write_params (List
<Parameter
> params
) {
841 foreach (Parameter param
in params
) {
846 if (param
.ellipsis
) {
847 write_string ("...");
852 var ccode_params
= new
StringBuilder ();
855 if (!float_equal (param
.cparameter_position
, i
)) {
856 ccode_params
.append_printf ("%spos = %g", separator
, param
.cparameter_position
);
859 if (param
.ctype
!= null) {
860 ccode_params
.append_printf ("%stype = \"%s\"", separator
, param
.ctype
);
863 if (param
.no_array_length
&& param
.variable_type is ArrayType
) {
864 ccode_params
.append_printf ("%sarray_length = false", separator
);
867 if (param
.array_null_terminated
&& param
.variable_type is ArrayType
) {
868 ccode_params
.append_printf ("%sarray_null_terminated = true", separator
);
871 if (param
.array_length_type
!= null && param
.variable_type is ArrayType
) {
872 ccode_params
.append_printf ("%sarray_length_type = \"%s\"", separator
, param
.array_length_type
);
875 if (param
.get_array_length_cname () != null && param
.variable_type is ArrayType
) {
876 ccode_params
.append_printf ("%sarray_length_cname = \"%s\"", separator
, param
.get_array_length_cname ());
879 if (!float_equal (param
.carray_length_parameter_position
, i
+ 0.1)) {
880 ccode_params
.append_printf ("%sarray_length_pos = %g", separator
, param
.carray_length_parameter_position
);
883 if (!float_equal (param
.cdelegate_target_parameter_position
, i
+ 0.1)) {
884 ccode_params
.append_printf ("%sdelegate_target_pos = %g", separator
, param
.cdelegate_target_parameter_position
);
888 if (ccode_params
.len
> 0) {
889 write_string ("[CCode (%s)] ".printf (ccode_params
.str
));
892 if (param
.params_array
) {
893 write_string ("params ");
896 if (param
.direction
== ParameterDirection
.IN
) {
897 if (param
.variable_type
.value_owned
) {
898 write_string ("owned ");
901 if (param
.direction
== ParameterDirection
.REF
) {
902 write_string ("ref ");
903 } else if (param
.direction
== ParameterDirection
.OUT
) {
904 write_string ("out ");
906 if (param
.variable_type
.is_weak ()) {
907 write_string ("unowned ");
911 write_type (param
.variable_type
);
914 write_identifier (param
.name
);
916 if (param
.initializer
!= null) {
917 write_string (" = ");
918 param
.initializer
.accept (this
);
927 public override void visit_delegate (Delegate cb
) {
928 if (cb
.external_package
) {
932 if (!check_accessibility (cb
)) {
936 emit_deprecated_attribute (cb
);
940 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(cb
)));
942 if (!cb
.has_target
) {
943 write_string (", has_target = false");
944 } else if (!float_equal (cb
.cinstance_parameter_position
, -2)) {
945 write_string (", instance_pos = %g".printf (cb
.cinstance_parameter_position
));
952 write_accessibility (cb
);
953 write_string ("delegate ");
955 write_return_type (cb
.return_type
);
958 write_identifier (cb
.name
);
960 var type_params
= cb
.get_type_parameters ();
961 if (type_params
.size
> 0) {
964 foreach (TypeParameter type_param
in type_params
) {
970 write_identifier (type_param
.name
);
977 write_params (cb
.get_parameters ());
979 write_error_domains (cb
.get_error_types ());
986 public override void visit_constructor (Constructor c
) {
987 if (type
!= CodeWriterType
.DUMP
) {
992 write_string ("construct");
993 write_code_block (c
.body
);
997 public override void visit_method (Method m
) {
998 if (m
.external_package
) {
1002 // don't write interface implementation unless it's an abstract or virtual method
1003 if (!check_accessibility (m
) || (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
1004 if (type
!= CodeWriterType
.DUMP
) {
1009 if (m
.get_attribute ("NoWrapper") != null) {
1011 write_string ("[NoWrapper]");
1013 if (m
.get_attribute ("NoThrow") != null) {
1015 write_string ("[NoThrow]");
1017 if (m
.returns_modified_pointer
) {
1019 write_string ("[ReturnsModifiedPointer]");
1021 if (m
.printf_format
) {
1023 write_string ("[PrintfFormat]");
1025 if (m
.scanf_format
) {
1027 write_string ("[ScanfFormat]");
1029 if (m
.get_attribute ("Print") != null) {
1031 write_string ("[Print]");
1033 if (m
.get_attribute ("NoReturn") != null) {
1035 write_string ("[NoReturn]");
1038 emit_deprecated_attribute (m
);
1040 var ccode_params
= new
StringBuilder ();
1043 if (m
.get_cname () != m
.get_default_cname ()) {
1044 ccode_params
.append_printf ("%scname = \"%s\"", separator
, m
.get_cname ());
1047 if (m
.parent_symbol is Namespace
) {
1048 ccode_params
.append_printf ("%scheader_filename = \"%s\"", separator
, get_cheaders(m
));
1051 if (!float_equal (m
.cinstance_parameter_position
, 0)) {
1052 ccode_params
.append_printf ("%sinstance_pos = %g", separator
, m
.cinstance_parameter_position
);
1055 if (m
.no_array_length
&& m
.return_type is ArrayType
) {
1056 ccode_params
.append_printf ("%sarray_length = false", separator
);
1059 if (!float_equal (m
.carray_length_parameter_position
, -3)) {
1060 ccode_params
.append_printf ("%sarray_length_pos = %g", separator
, m
.carray_length_parameter_position
);
1063 if (m
.array_null_terminated
&& m
.return_type is ArrayType
) {
1064 ccode_params
.append_printf ("%sarray_null_terminated = true", separator
);
1067 if (m
.array_length_type
!= null && m
.return_type is ArrayType
) {
1068 ccode_params
.append_printf ("%sarray_length_type = \"%s\"", separator
, m
.array_length_type
);
1071 if (!float_equal (m
.cdelegate_target_parameter_position
, -3)) {
1072 ccode_params
.append_printf ("%sdelegate_target_pos = %g", separator
, m
.cdelegate_target_parameter_position
);
1075 if (m
.vfunc_name
!= m
.name
) {
1076 ccode_params
.append_printf ("%svfunc_name = \"%s\"", separator
, m
.vfunc_name
);
1079 if (m
.coroutine
&& m
.get_finish_cname () != m
.get_default_finish_cname ()) {
1080 ccode_params
.append_printf ("%sfinish_name = \"%s\"", separator
, m
.get_finish_cname ());
1083 if (m
.sentinel
!= m
.DEFAULT_SENTINEL
) {
1084 ccode_params
.append_printf ("%ssentinel = \"%s\"", separator
, m
.sentinel
);
1087 var cm
= m as CreationMethod
;
1089 if (cm
.custom_return_type_cname
!= null) {
1090 ccode_params
.append_printf ("%stype = \"%s\"", separator
, cm
.custom_return_type_cname
);
1093 if (!m
.has_new_function
) {
1094 ccode_params
.append_printf ("%shas_new_function = false", separator
);
1097 if (!m
.has_construct_function
) {
1098 ccode_params
.append_printf ("%shas_construct_function = false", separator
);
1100 } else if (m
.name
== ".new" && m
.get_real_cname () != cm
.get_default_construct_function ()) {
1101 ccode_params
.append_printf ("%sconstruct_function = \"%s\"", separator
, m
.get_real_cname ());
1106 if (ccode_params
.len
> 0) {
1108 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1112 write_accessibility (m
);
1114 if (m is CreationMethod
) {
1116 write_string ("async ");
1119 var datatype
= (TypeSymbol
) m
.parent_symbol
;
1120 write_identifier (datatype
.name
);
1121 if (m
.name
!= ".new") {
1123 write_identifier (m
.name
);
1127 if (m
.binding
== MemberBinding
.STATIC
) {
1128 write_string ("static ");
1129 } else if (m
.binding
== MemberBinding
.CLASS
) {
1130 write_string ("class ");
1131 } else if (m
.is_abstract
) {
1132 write_string ("abstract ");
1133 } else if (m
.is_virtual
) {
1134 write_string ("virtual ");
1135 } else if (m
.overrides
) {
1136 write_string ("override ");
1140 write_string ("new ");
1144 write_string ("async ");
1147 write_return_type (m
.return_type
);
1150 write_identifier (m
.name
);
1152 var type_params
= m
.get_type_parameters ();
1153 if (type_params
.size
> 0) {
1156 foreach (TypeParameter type_param
in type_params
) {
1162 write_identifier (type_param
.name
);
1170 write_params (m
.get_parameters ());
1172 if (context
.profile
!= Profile
.DOVA
) {
1173 write_error_domains (m
.get_error_types ());
1176 write_code_block (m
.body
);
1181 public override void visit_creation_method (CreationMethod m
) {
1185 public override void visit_property (Property prop
) {
1186 if (!check_accessibility (prop
) || (prop
.base_interface_property
!= null && !prop
.is_abstract
&& !prop
.is_virtual
)) {
1190 emit_deprecated_attribute (prop
);
1192 if (prop
.no_accessor_method
) {
1194 write_string ("[NoAccessorMethod]");
1196 if (prop
.property_type is ArrayType
&& prop
.no_array_length
) {
1198 write_string ("[CCode (array_length = false");
1200 if (prop
.array_null_terminated
) {
1201 write_string (", array_null_terminated = true");
1204 write_string (")]");
1208 write_accessibility (prop
);
1210 if (prop
.binding
== MemberBinding
.STATIC
) {
1211 write_string ("static ");
1212 } else if (prop
.is_abstract
) {
1213 write_string ("abstract ");
1214 } else if (prop
.is_virtual
) {
1215 write_string ("virtual ");
1216 } else if (prop
.overrides
) {
1217 write_string ("override ");
1220 write_type (prop
.property_type
);
1223 write_identifier (prop
.name
);
1224 write_string (" {");
1225 if (prop
.get_accessor
!= null) {
1226 var ccode_params
= new
StringBuilder ();
1229 if (prop
.get_accessor
.get_cname () != prop
.get_accessor
.get_default_cname ()) {
1230 ccode_params
.append_printf ("%scname = \"%s\"", separator
, prop
.get_accessor
.get_cname ());
1233 if (ccode_params
.len
> 0) {
1235 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1238 write_property_accessor_accessibility (prop
.get_accessor
);
1240 if (context
.profile
!= Profile
.DOVA
&& prop
.get_accessor
.value_type
.is_disposable ()) {
1241 write_string (" owned");
1244 write_string (" get");
1245 write_code_block (prop
.get_accessor
.body
);
1247 if (prop
.set_accessor
!= null) {
1248 var ccode_params
= new
StringBuilder ();
1251 if (prop
.set_accessor
.get_cname () != prop
.set_accessor
.get_default_cname ()) {
1252 ccode_params
.append_printf ("%scname = \"%s\"", separator
, prop
.set_accessor
.get_cname ());
1255 if (ccode_params
.len
> 0) {
1257 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1260 write_property_accessor_accessibility (prop
.set_accessor
);
1262 if (context
.profile
!= Profile
.DOVA
&& prop
.set_accessor
.value_type
.value_owned
) {
1263 write_string (" owned");
1266 if (prop
.set_accessor
.writable
) {
1267 write_string (" set");
1269 if (prop
.set_accessor
.construction
) {
1270 write_string (" construct");
1272 write_code_block (prop
.set_accessor
.body
);
1274 write_string (" }");
1278 public override void visit_signal (Signal sig
) {
1279 if (!check_accessibility (sig
)) {
1283 if (sig
.has_emitter
) {
1285 write_string ("[HasEmitter]");
1288 emit_deprecated_attribute (sig
);
1291 write_accessibility (sig
);
1293 if (sig
.is_virtual
) {
1294 write_string ("virtual ");
1297 write_string ("signal ");
1299 write_return_type (sig
.return_type
);
1302 write_identifier (sig
.name
);
1306 write_params (sig
.get_parameters ());
1313 public override void visit_block (Block b
) {
1314 write_begin_block ();
1316 foreach (Statement stmt
in b
.get_statements ()) {
1323 public override void visit_empty_statement (EmptyStatement stmt
) {
1326 public override void visit_declaration_statement (DeclarationStatement stmt
) {
1328 stmt
.declaration
.accept (this
);
1333 public override void visit_local_variable (LocalVariable local
) {
1334 write_type (local
.variable_type
);
1336 write_identifier (local
.name
);
1337 if (local
.initializer
!= null) {
1338 write_string (" = ");
1339 local
.initializer
.accept (this
);
1343 public override void visit_initializer_list (InitializerList list
) {
1347 foreach (Expression initializer
in list
.get_initializers ()) {
1349 write_string (", ");
1354 initializer
.accept (this
);
1356 write_string (" }");
1359 public override void visit_expression_statement (ExpressionStatement stmt
) {
1361 stmt
.expression
.accept (this
);
1366 public override void visit_if_statement (IfStatement stmt
) {
1368 write_string ("if (");
1369 stmt
.condition
.accept (this
);
1371 stmt
.true_statement
.accept (this
);
1372 if (stmt
.false_statement
!= null) {
1373 write_string (" else");
1374 stmt
.false_statement
.accept (this
);
1379 public override void visit_switch_statement (SwitchStatement stmt
) {
1381 write_string ("switch (");
1382 stmt
.expression
.accept (this
);
1383 write_string (") {");
1386 foreach (SwitchSection section
in stmt
.get_sections ()) {
1387 section
.accept (this
);
1395 public override void visit_switch_section (SwitchSection section
) {
1396 foreach (SwitchLabel label
in section
.get_labels ()) {
1397 label
.accept (this
);
1400 visit_block (section
);
1403 public override void visit_switch_label (SwitchLabel label
) {
1404 if (label
.expression
!= null) {
1406 write_string ("case ");
1407 label
.expression
.accept (this
);
1412 write_string ("default:");
1417 public override void visit_loop (Loop stmt
) {
1419 write_string ("loop");
1420 stmt
.body
.accept (this
);
1424 public override void visit_while_statement (WhileStatement stmt
) {
1426 write_string ("while (");
1427 stmt
.condition
.accept (this
);
1429 stmt
.body
.accept (this
);
1433 public override void visit_do_statement (DoStatement stmt
) {
1435 write_string ("do");
1436 stmt
.body
.accept (this
);
1437 write_string ("while (");
1438 stmt
.condition
.accept (this
);
1439 write_string (");");
1443 public override void visit_for_statement (ForStatement stmt
) {
1445 write_string ("for (");
1448 foreach (Expression initializer
in stmt
.get_initializer ()) {
1450 write_string (", ");
1453 initializer
.accept (this
);
1455 write_string ("; ");
1457 stmt
.condition
.accept (this
);
1458 write_string ("; ");
1461 foreach (Expression iterator
in stmt
.get_iterator ()) {
1463 write_string (", ");
1466 iterator
.accept (this
);
1470 stmt
.body
.accept (this
);
1474 public override void visit_foreach_statement (ForeachStatement stmt
) {
1477 public override void visit_break_statement (BreakStatement stmt
) {
1479 write_string ("break;");
1483 public override void visit_continue_statement (ContinueStatement stmt
) {
1485 write_string ("continue;");
1489 public override void visit_return_statement (ReturnStatement stmt
) {
1491 write_string ("return");
1492 if (stmt
.return_expression
!= null) {
1494 stmt
.return_expression
.accept (this
);
1500 public override void visit_yield_statement (YieldStatement y
) {
1502 write_string ("yield");
1503 if (y
.yield_expression
!= null) {
1505 y
.yield_expression
.accept (this
);
1511 public override void visit_throw_statement (ThrowStatement stmt
) {
1513 write_string ("throw");
1514 if (stmt
.error_expression
!= null) {
1516 stmt
.error_expression
.accept (this
);
1522 public override void visit_try_statement (TryStatement stmt
) {
1524 write_string ("try");
1525 stmt
.body
.accept (this
);
1526 foreach (var clause
in stmt
.get_catch_clauses ()) {
1527 clause
.accept (this
);
1529 if (stmt
.finally_body
!= null) {
1530 write_string (" finally");
1531 stmt
.finally_body
.accept (this
);
1536 public override void visit_catch_clause (CatchClause clause
) {
1537 var type_name
= clause
.error_type
== null ?
"GLib.Error" : clause
.error_type
.to_string ();
1538 var var_name
= clause
.variable_name
== null ?
"_" : clause
.variable_name
;
1539 write_string (" catch (%s %s)".printf (type_name
, var_name
));
1540 clause
.body
.accept (this
);
1543 public override void visit_lock_statement (LockStatement stmt
) {
1545 write_string ("lock (");
1546 stmt
.resource
.accept (this
);
1548 if (stmt
.body
== null) {
1551 stmt
.body
.accept (this
);
1556 public override void visit_delete_statement (DeleteStatement stmt
) {
1558 write_string ("delete ");
1559 stmt
.expression
.accept (this
);
1564 public override void visit_array_creation_expression (ArrayCreationExpression expr
) {
1565 write_string ("new ");
1566 write_type (expr
.element_type
);
1570 foreach (Expression size
in expr
.get_sizes ()) {
1572 write_string (", ");
1581 if (expr
.initializer_list
!= null) {
1583 expr
.initializer_list
.accept (this
);
1587 public override void visit_boolean_literal (BooleanLiteral lit
) {
1588 write_string (lit
.value
.to_string ());
1591 public override void visit_character_literal (CharacterLiteral lit
) {
1592 write_string (lit
.value
);
1595 public override void visit_integer_literal (IntegerLiteral lit
) {
1596 write_string (lit
.value
);
1599 public override void visit_real_literal (RealLiteral lit
) {
1600 write_string (lit
.value
);
1603 public override void visit_string_literal (StringLiteral lit
) {
1604 write_string (lit
.value
);
1607 public override void visit_null_literal (NullLiteral lit
) {
1608 write_string ("null");
1611 public override void visit_member_access (MemberAccess expr
) {
1612 if (expr
.inner
!= null) {
1613 expr
.inner
.accept (this
);
1616 write_identifier (expr
.member_name
);
1619 public override void visit_method_call (MethodCall expr
) {
1620 expr
.call
.accept (this
);
1621 write_string (" (");
1624 foreach (Expression arg
in expr
.get_argument_list ()) {
1626 write_string (", ");
1636 public override void visit_element_access (ElementAccess expr
) {
1637 expr
.container
.accept (this
);
1641 foreach (Expression index
in expr
.get_indices ()) {
1643 write_string (", ");
1647 index
.accept (this
);
1653 public override void visit_slice_expression (SliceExpression expr
) {
1654 expr
.container
.accept (this
);
1656 expr
.start
.accept (this
);
1658 expr
.stop
.accept (this
);
1662 public override void visit_base_access (BaseAccess expr
) {
1663 write_string ("base");
1666 public override void visit_postfix_expression (PostfixExpression expr
) {
1667 expr
.inner
.accept (this
);
1668 if (expr
.increment
) {
1669 write_string ("++");
1671 write_string ("--");
1675 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
1676 if (!expr
.struct_creation
) {
1677 write_string ("new ");
1680 write_type (expr
.type_reference
);
1682 if (expr
.symbol_reference
.name
!= ".new") {
1684 write_string (expr
.symbol_reference
.name
);
1687 write_string (" (");
1690 foreach (Expression arg
in expr
.get_argument_list ()) {
1692 write_string (", ");
1702 public override void visit_sizeof_expression (SizeofExpression expr
) {
1703 write_string ("sizeof (");
1704 write_type (expr
.type_reference
);
1708 public override void visit_typeof_expression (TypeofExpression expr
) {
1709 write_string ("typeof (");
1710 write_type (expr
.type_reference
);
1714 public override void visit_unary_expression (UnaryExpression expr
) {
1715 switch (expr
.operator
) {
1716 case UnaryOperator
.PLUS
:
1719 case UnaryOperator
.MINUS
:
1722 case UnaryOperator
.LOGICAL_NEGATION
:
1725 case UnaryOperator
.BITWISE_COMPLEMENT
:
1728 case UnaryOperator
.INCREMENT
:
1729 write_string ("++");
1731 case UnaryOperator
.DECREMENT
:
1732 write_string ("--");
1734 case UnaryOperator
.REF
:
1735 write_string ("ref ");
1737 case UnaryOperator
.OUT
:
1738 write_string ("out ");
1741 assert_not_reached ();
1743 expr
.inner
.accept (this
);
1746 public override void visit_cast_expression (CastExpression expr
) {
1747 if (expr
.is_non_null_cast
) {
1748 write_string ("(!) ");
1749 expr
.inner
.accept (this
);
1753 if (!expr
.is_silent_cast
) {
1755 write_type (expr
.type_reference
);
1756 write_string (") ");
1759 expr
.inner
.accept (this
);
1761 if (expr
.is_silent_cast
) {
1762 write_string (" as ");
1763 write_type (expr
.type_reference
);
1767 public override void visit_pointer_indirection (PointerIndirection expr
) {
1769 expr
.inner
.accept (this
);
1772 public override void visit_addressof_expression (AddressofExpression expr
) {
1774 expr
.inner
.accept (this
);
1777 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
1778 write_string ("(owned) ");
1779 expr
.inner
.accept (this
);
1782 public override void visit_binary_expression (BinaryExpression expr
) {
1783 expr
.left
.accept (this
);
1785 switch (expr
.operator
) {
1786 case BinaryOperator
.PLUS
:
1787 write_string (" + ");
1789 case BinaryOperator
.MINUS
:
1790 write_string (" - ");
1792 case BinaryOperator
.MUL
:
1793 write_string (" * ");
1795 case BinaryOperator
.DIV
:
1796 write_string (" / ");
1798 case BinaryOperator
.MOD
:
1799 write_string (" % ");
1801 case BinaryOperator
.SHIFT_LEFT
:
1802 write_string (" << ");
1804 case BinaryOperator
.SHIFT_RIGHT
:
1805 write_string (" >> ");
1807 case BinaryOperator
.LESS_THAN
:
1808 write_string (" < ");
1810 case BinaryOperator
.GREATER_THAN
:
1811 write_string (" > ");
1813 case BinaryOperator
.LESS_THAN_OR_EQUAL
:
1814 write_string (" <= ");
1816 case BinaryOperator
.GREATER_THAN_OR_EQUAL
:
1817 write_string (" >= ");
1819 case BinaryOperator
.EQUALITY
:
1820 write_string (" == ");
1822 case BinaryOperator
.INEQUALITY
:
1823 write_string (" != ");
1825 case BinaryOperator
.BITWISE_AND
:
1826 write_string (" & ");
1828 case BinaryOperator
.BITWISE_OR
:
1829 write_string (" | ");
1831 case BinaryOperator
.BITWISE_XOR
:
1832 write_string (" ^ ");
1834 case BinaryOperator
.AND
:
1835 write_string (" && ");
1837 case BinaryOperator
.OR
:
1838 write_string (" || ");
1840 case BinaryOperator
.IN
:
1841 write_string (" in ");
1843 case BinaryOperator
.COALESCE
:
1844 write_string (" ?? ");
1847 assert_not_reached ();
1850 expr
.right
.accept (this
);
1853 public override void visit_type_check (TypeCheck expr
) {
1854 expr
.expression
.accept (this
);
1855 write_string (" is ");
1856 write_type (expr
.type_reference
);
1859 public override void visit_conditional_expression (ConditionalExpression expr
) {
1860 expr
.condition
.accept (this
);
1862 expr
.true_expression
.accept (this
);
1864 expr
.false_expression
.accept (this
);
1867 public override void visit_lambda_expression (LambdaExpression expr
) {
1869 var params
= expr
.get_parameters ();
1870 if (params
.size
!= 0) {
1871 for (var i
= 0; i
< params
.size
- 1; ++ i
) {
1872 write_string (params
[i
]);
1873 write_string (", ");
1875 write_string (params
[params
.size
- 1]);
1877 write_string (") =>");
1878 if (expr
.statement_body
!= null) {
1879 expr
.statement_body
.accept (this
);
1880 } else if (expr
.expression_body
!= null) {
1881 expr
.expression_body
.accept (this
);
1885 public override void visit_assignment (Assignment a
) {
1886 a
.left
.accept (this
);
1887 write_string (" = ");
1888 a
.right
.accept (this
);
1891 private void write_indent () {
1898 for (i
= 0; i
< indent
; i
++) {
1905 private void write_identifier (string s
) {
1906 char* id
= (char*)s
;
1907 int id_length
= (int)s
.length
;
1908 if (context
.profile
!= Profile
.DOVA
&&
1909 (Vala
.Scanner
.get_identifier_or_keyword (id
, id_length
) != Vala
.TokenType
.IDENTIFIER
||
1910 s
.get_char ().isdigit ())) {
1916 private void write_return_type (DataType type
) {
1917 if (type
.is_weak ()) {
1918 write_string ("unowned ");
1924 private void write_type (DataType type
) {
1925 write_string (type
.to_qualified_string (current_scope
));
1928 private void write_string (string s
) {
1929 stream
.printf ("%s", s
);
1933 private void write_newline () {
1938 void write_code_block (Block? block
) {
1939 if (block
== null || type
!= CodeWriterType
.DUMP
) {
1944 block
.accept (this
);
1947 private void write_begin_block () {
1958 private void write_end_block () {
1961 stream
.printf ("}");
1964 private bool check_accessibility (Symbol sym
) {
1966 case CodeWriterType
.EXTERNAL
:
1967 return sym
.access
== SymbolAccessibility
.PUBLIC
||
1968 sym
.access
== SymbolAccessibility
.PROTECTED
;
1970 case CodeWriterType
.INTERNAL
:
1971 case CodeWriterType
.FAST
:
1972 return sym
.access
== SymbolAccessibility
.INTERNAL
||
1973 sym
.access
== SymbolAccessibility
.PUBLIC
||
1974 sym
.access
== SymbolAccessibility
.PROTECTED
;
1976 case CodeWriterType
.DUMP
:
1980 assert_not_reached ();
1984 private void write_attributes (CodeNode node
) {
1985 foreach (Attribute attr
in node
.attributes
) {
1986 if (!filter_attribute (attr
)) {
1988 stream
.printf ("[%s", attr
.name
);
1990 var keys
= attr
.args
.get_keys ();
1991 if (keys
.size
!= 0) {
1992 stream
.printf (" (");
1994 string separator
= "";
1995 foreach (string arg_name
in keys
) {
1996 stream
.printf ("%s%s = %s", separator
, arg_name
, attr
.args
.get (arg_name
));
2000 stream
.printf (")");
2002 stream
.printf ("]");
2008 private bool filter_attribute (Attribute attr
) {
2009 if (attr
.name
== "CCode"
2010 || attr
.name
== "Compact" || attr
.name
== "Immutable"
2011 || attr
.name
== "SimpleType" || attr
.name
== "IntegerType" || attr
.name
== "FloatingType"
2012 || attr
.name
== "Flags") {
2018 private void write_accessibility (Symbol sym
) {
2019 if (sym
.access
== SymbolAccessibility
.PUBLIC
) {
2020 write_string ("public ");
2021 } else if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
2022 write_string ("protected ");
2023 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
2024 write_string ("internal ");
2025 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
2026 write_string ("private ");
2029 if (type
!= CodeWriterType
.EXTERNAL
&& sym
.external
&& !sym
.external_package
) {
2030 write_string ("extern ");
2034 void write_property_accessor_accessibility (Symbol sym
) {
2035 if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
2036 write_string (" protected");
2037 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
2038 write_string (" internal");
2039 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
2040 write_string (" private");
2045 public enum Vala
.CodeWriterType
{