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_length_type
!= null && param
.variable_type is ArrayType
) {
868 ccode_params
.append_printf ("%sarray_length_type = \"%s\"", separator
, param
.array_length_type
);
871 if (param
.get_array_length_cname () != null && param
.variable_type is ArrayType
) {
872 ccode_params
.append_printf ("%sarray_length_cname = \"%s\"", separator
, param
.get_array_length_cname ());
875 if (!float_equal (param
.carray_length_parameter_position
, i
+ 0.1)) {
876 ccode_params
.append_printf ("%sarray_length_pos = %g", separator
, param
.carray_length_parameter_position
);
879 if (!float_equal (param
.cdelegate_target_parameter_position
, i
+ 0.1)) {
880 ccode_params
.append_printf ("%sdelegate_target_pos = %g", separator
, param
.cdelegate_target_parameter_position
);
884 if (ccode_params
.len
> 0) {
885 write_string ("[CCode (%s)] ".printf (ccode_params
.str
));
888 if (param
.params_array
) {
889 write_string ("params ");
892 if (param
.direction
== ParameterDirection
.IN
) {
893 if (param
.variable_type
.value_owned
) {
894 write_string ("owned ");
897 if (param
.direction
== ParameterDirection
.REF
) {
898 write_string ("ref ");
899 } else if (param
.direction
== ParameterDirection
.OUT
) {
900 write_string ("out ");
902 if (param
.variable_type
.is_weak ()) {
903 write_string ("unowned ");
907 write_type (param
.variable_type
);
910 write_identifier (param
.name
);
912 if (param
.initializer
!= null) {
913 write_string (" = ");
914 param
.initializer
.accept (this
);
923 public override void visit_delegate (Delegate cb
) {
924 if (cb
.external_package
) {
928 if (!check_accessibility (cb
)) {
932 emit_deprecated_attribute (cb
);
936 write_string ("[CCode (cheader_filename = \"%s\"".printf (get_cheaders(cb
)));
938 if (!cb
.has_target
) {
939 write_string (", has_target = false");
940 } else if (!float_equal (cb
.cinstance_parameter_position
, -2)) {
941 write_string (", instance_pos = %g".printf (cb
.cinstance_parameter_position
));
948 write_accessibility (cb
);
949 write_string ("delegate ");
951 write_return_type (cb
.return_type
);
954 write_identifier (cb
.name
);
956 var type_params
= cb
.get_type_parameters ();
957 if (type_params
.size
> 0) {
960 foreach (TypeParameter type_param
in type_params
) {
966 write_identifier (type_param
.name
);
973 write_params (cb
.get_parameters ());
975 write_error_domains (cb
.get_error_types ());
982 public override void visit_constructor (Constructor c
) {
983 if (type
!= CodeWriterType
.DUMP
) {
988 write_string ("construct");
989 write_code_block (c
.body
);
993 public override void visit_method (Method m
) {
994 if (m
.external_package
) {
998 // don't write interface implementation unless it's an abstract or virtual method
999 if (!check_accessibility (m
) || (m
.base_interface_method
!= null && !m
.is_abstract
&& !m
.is_virtual
)) {
1000 if (type
!= CodeWriterType
.DUMP
) {
1005 if (m
.get_attribute ("NoWrapper") != null) {
1007 write_string ("[NoWrapper]");
1009 if (m
.get_attribute ("NoThrow") != null) {
1011 write_string ("[NoThrow]");
1013 if (m
.returns_modified_pointer
) {
1015 write_string ("[ReturnsModifiedPointer]");
1017 if (m
.printf_format
) {
1019 write_string ("[PrintfFormat]");
1021 if (m
.scanf_format
) {
1023 write_string ("[ScanfFormat]");
1025 if (m
.get_attribute ("Print") != null) {
1027 write_string ("[Print]");
1029 if (m
.get_attribute ("NoReturn") != null) {
1031 write_string ("[NoReturn]");
1034 emit_deprecated_attribute (m
);
1036 var ccode_params
= new
StringBuilder ();
1039 if (m
.get_cname () != m
.get_default_cname ()) {
1040 ccode_params
.append_printf ("%scname = \"%s\"", separator
, m
.get_cname ());
1043 if (m
.parent_symbol is Namespace
) {
1044 ccode_params
.append_printf ("%scheader_filename = \"%s\"", separator
, get_cheaders(m
));
1047 if (!float_equal (m
.cinstance_parameter_position
, 0)) {
1048 ccode_params
.append_printf ("%sinstance_pos = %g", separator
, m
.cinstance_parameter_position
);
1051 if (m
.no_array_length
&& m
.return_type is ArrayType
) {
1052 ccode_params
.append_printf ("%sarray_length = false", separator
);
1055 if (!float_equal (m
.carray_length_parameter_position
, -3)) {
1056 ccode_params
.append_printf ("%sarray_length_pos = %g", separator
, m
.carray_length_parameter_position
);
1059 if (m
.array_null_terminated
&& m
.return_type is ArrayType
) {
1060 ccode_params
.append_printf ("%sarray_null_terminated = true", separator
);
1063 if (m
.array_length_type
!= null && m
.return_type is ArrayType
) {
1064 ccode_params
.append_printf ("%sarray_length_type = \"%s\"", separator
, m
.array_length_type
);
1067 if (!float_equal (m
.cdelegate_target_parameter_position
, -3)) {
1068 ccode_params
.append_printf ("%sdelegate_target_pos = %g", separator
, m
.cdelegate_target_parameter_position
);
1071 if (m
.vfunc_name
!= m
.name
) {
1072 ccode_params
.append_printf ("%svfunc_name = \"%s\"", separator
, m
.vfunc_name
);
1075 if (m
.coroutine
&& m
.get_finish_cname () != m
.get_default_finish_cname ()) {
1076 ccode_params
.append_printf ("%sfinish_name = \"%s\"", separator
, m
.get_finish_cname ());
1079 if (m
.sentinel
!= m
.DEFAULT_SENTINEL
) {
1080 ccode_params
.append_printf ("%ssentinel = \"%s\"", separator
, m
.sentinel
);
1083 var cm
= m as CreationMethod
;
1085 if (cm
.custom_return_type_cname
!= null) {
1086 ccode_params
.append_printf ("%stype = \"%s\"", separator
, cm
.custom_return_type_cname
);
1089 if (!m
.has_new_function
) {
1090 ccode_params
.append_printf ("%shas_new_function = false", separator
);
1093 if (!m
.has_construct_function
) {
1094 ccode_params
.append_printf ("%shas_construct_function = false", separator
);
1096 } else if (m
.name
== ".new" && m
.get_real_cname () != cm
.get_default_construct_function ()) {
1097 ccode_params
.append_printf ("%sconstruct_function = \"%s\"", separator
, m
.get_real_cname ());
1102 if (ccode_params
.len
> 0) {
1104 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1108 write_accessibility (m
);
1110 if (m is CreationMethod
) {
1112 write_string ("async ");
1115 var datatype
= (TypeSymbol
) m
.parent_symbol
;
1116 write_identifier (datatype
.name
);
1117 if (m
.name
!= ".new") {
1119 write_identifier (m
.name
);
1123 if (m
.binding
== MemberBinding
.STATIC
) {
1124 write_string ("static ");
1125 } else if (m
.binding
== MemberBinding
.CLASS
) {
1126 write_string ("class ");
1127 } else if (m
.is_abstract
) {
1128 write_string ("abstract ");
1129 } else if (m
.is_virtual
) {
1130 write_string ("virtual ");
1131 } else if (m
.overrides
) {
1132 write_string ("override ");
1136 write_string ("new ");
1140 write_string ("async ");
1143 write_return_type (m
.return_type
);
1146 write_identifier (m
.name
);
1148 var type_params
= m
.get_type_parameters ();
1149 if (type_params
.size
> 0) {
1152 foreach (TypeParameter type_param
in type_params
) {
1158 write_identifier (type_param
.name
);
1166 write_params (m
.get_parameters ());
1168 if (context
.profile
!= Profile
.DOVA
) {
1169 write_error_domains (m
.get_error_types ());
1172 write_code_block (m
.body
);
1177 public override void visit_creation_method (CreationMethod m
) {
1181 public override void visit_property (Property prop
) {
1182 if (!check_accessibility (prop
) || (prop
.base_interface_property
!= null && !prop
.is_abstract
&& !prop
.is_virtual
)) {
1186 emit_deprecated_attribute (prop
);
1188 if (prop
.no_accessor_method
) {
1190 write_string ("[NoAccessorMethod]");
1192 if (prop
.property_type is ArrayType
&& prop
.no_array_length
) {
1194 write_string ("[CCode (array_length = false");
1196 if (prop
.array_null_terminated
) {
1197 write_string (", array_null_terminated = true");
1200 write_string (")]");
1204 write_accessibility (prop
);
1206 if (prop
.binding
== MemberBinding
.STATIC
) {
1207 write_string ("static ");
1208 } else if (prop
.is_abstract
) {
1209 write_string ("abstract ");
1210 } else if (prop
.is_virtual
) {
1211 write_string ("virtual ");
1212 } else if (prop
.overrides
) {
1213 write_string ("override ");
1216 write_type (prop
.property_type
);
1219 write_identifier (prop
.name
);
1220 write_string (" {");
1221 if (prop
.get_accessor
!= null) {
1222 var ccode_params
= new
StringBuilder ();
1225 if (prop
.get_accessor
.get_cname () != prop
.get_accessor
.get_default_cname ()) {
1226 ccode_params
.append_printf ("%scname = \"%s\"", separator
, prop
.get_accessor
.get_cname ());
1229 if (ccode_params
.len
> 0) {
1231 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1234 write_property_accessor_accessibility (prop
.get_accessor
);
1236 if (context
.profile
!= Profile
.DOVA
&& prop
.get_accessor
.value_type
.is_disposable ()) {
1237 write_string (" owned");
1240 write_string (" get");
1241 write_code_block (prop
.get_accessor
.body
);
1243 if (prop
.set_accessor
!= null) {
1244 var ccode_params
= new
StringBuilder ();
1247 if (prop
.set_accessor
.get_cname () != prop
.set_accessor
.get_default_cname ()) {
1248 ccode_params
.append_printf ("%scname = \"%s\"", separator
, prop
.set_accessor
.get_cname ());
1251 if (ccode_params
.len
> 0) {
1253 write_string ("[CCode (%s)]".printf (ccode_params
.str
));
1256 write_property_accessor_accessibility (prop
.set_accessor
);
1258 if (context
.profile
!= Profile
.DOVA
&& prop
.set_accessor
.value_type
.value_owned
) {
1259 write_string (" owned");
1262 if (prop
.set_accessor
.writable
) {
1263 write_string (" set");
1265 if (prop
.set_accessor
.construction
) {
1266 write_string (" construct");
1268 write_code_block (prop
.set_accessor
.body
);
1270 write_string (" }");
1274 public override void visit_signal (Signal sig
) {
1275 if (!check_accessibility (sig
)) {
1279 if (sig
.has_emitter
) {
1281 write_string ("[HasEmitter]");
1284 emit_deprecated_attribute (sig
);
1287 write_accessibility (sig
);
1289 if (sig
.is_virtual
) {
1290 write_string ("virtual ");
1293 write_string ("signal ");
1295 write_return_type (sig
.return_type
);
1298 write_identifier (sig
.name
);
1302 write_params (sig
.get_parameters ());
1309 public override void visit_block (Block b
) {
1310 write_begin_block ();
1312 foreach (Statement stmt
in b
.get_statements ()) {
1319 public override void visit_empty_statement (EmptyStatement stmt
) {
1322 public override void visit_declaration_statement (DeclarationStatement stmt
) {
1324 stmt
.declaration
.accept (this
);
1329 public override void visit_local_variable (LocalVariable local
) {
1330 write_type (local
.variable_type
);
1332 write_identifier (local
.name
);
1333 if (local
.initializer
!= null) {
1334 write_string (" = ");
1335 local
.initializer
.accept (this
);
1339 public override void visit_initializer_list (InitializerList list
) {
1343 foreach (Expression initializer
in list
.get_initializers ()) {
1345 write_string (", ");
1350 initializer
.accept (this
);
1352 write_string (" }");
1355 public override void visit_expression_statement (ExpressionStatement stmt
) {
1357 stmt
.expression
.accept (this
);
1362 public override void visit_if_statement (IfStatement stmt
) {
1364 write_string ("if (");
1365 stmt
.condition
.accept (this
);
1367 stmt
.true_statement
.accept (this
);
1368 if (stmt
.false_statement
!= null) {
1369 write_string (" else");
1370 stmt
.false_statement
.accept (this
);
1375 public override void visit_switch_statement (SwitchStatement stmt
) {
1377 write_string ("switch (");
1378 stmt
.expression
.accept (this
);
1379 write_string (") {");
1382 foreach (SwitchSection section
in stmt
.get_sections ()) {
1383 section
.accept (this
);
1391 public override void visit_switch_section (SwitchSection section
) {
1392 foreach (SwitchLabel label
in section
.get_labels ()) {
1393 label
.accept (this
);
1396 visit_block (section
);
1399 public override void visit_switch_label (SwitchLabel label
) {
1400 if (label
.expression
!= null) {
1402 write_string ("case ");
1403 label
.expression
.accept (this
);
1408 write_string ("default:");
1413 public override void visit_loop (Loop stmt
) {
1415 write_string ("loop");
1416 stmt
.body
.accept (this
);
1420 public override void visit_while_statement (WhileStatement stmt
) {
1422 write_string ("while (");
1423 stmt
.condition
.accept (this
);
1425 stmt
.body
.accept (this
);
1429 public override void visit_do_statement (DoStatement stmt
) {
1431 write_string ("do");
1432 stmt
.body
.accept (this
);
1433 write_string ("while (");
1434 stmt
.condition
.accept (this
);
1435 write_string (");");
1439 public override void visit_for_statement (ForStatement stmt
) {
1441 write_string ("for (");
1444 foreach (Expression initializer
in stmt
.get_initializer ()) {
1446 write_string (", ");
1449 initializer
.accept (this
);
1451 write_string ("; ");
1453 stmt
.condition
.accept (this
);
1454 write_string ("; ");
1457 foreach (Expression iterator
in stmt
.get_iterator ()) {
1459 write_string (", ");
1462 iterator
.accept (this
);
1466 stmt
.body
.accept (this
);
1470 public override void visit_foreach_statement (ForeachStatement stmt
) {
1473 public override void visit_break_statement (BreakStatement stmt
) {
1475 write_string ("break;");
1479 public override void visit_continue_statement (ContinueStatement stmt
) {
1481 write_string ("continue;");
1485 public override void visit_return_statement (ReturnStatement stmt
) {
1487 write_string ("return");
1488 if (stmt
.return_expression
!= null) {
1490 stmt
.return_expression
.accept (this
);
1496 public override void visit_yield_statement (YieldStatement y
) {
1498 write_string ("yield");
1499 if (y
.yield_expression
!= null) {
1501 y
.yield_expression
.accept (this
);
1507 public override void visit_throw_statement (ThrowStatement stmt
) {
1509 write_string ("throw");
1510 if (stmt
.error_expression
!= null) {
1512 stmt
.error_expression
.accept (this
);
1518 public override void visit_try_statement (TryStatement stmt
) {
1520 write_string ("try");
1521 stmt
.body
.accept (this
);
1522 foreach (var clause
in stmt
.get_catch_clauses ()) {
1523 clause
.accept (this
);
1525 if (stmt
.finally_body
!= null) {
1526 write_string (" finally");
1527 stmt
.finally_body
.accept (this
);
1532 public override void visit_catch_clause (CatchClause clause
) {
1533 var type_name
= clause
.error_type
== null ?
"GLib.Error" : clause
.error_type
.to_string ();
1534 var var_name
= clause
.variable_name
== null ?
"_" : clause
.variable_name
;
1535 write_string (" catch (%s %s)".printf (type_name
, var_name
));
1536 clause
.body
.accept (this
);
1539 public override void visit_lock_statement (LockStatement stmt
) {
1541 write_string ("lock (");
1542 stmt
.resource
.accept (this
);
1544 if (stmt
.body
== null) {
1547 stmt
.body
.accept (this
);
1552 public override void visit_delete_statement (DeleteStatement stmt
) {
1554 write_string ("delete ");
1555 stmt
.expression
.accept (this
);
1560 public override void visit_array_creation_expression (ArrayCreationExpression expr
) {
1561 write_string ("new ");
1562 write_type (expr
.element_type
);
1566 foreach (Expression size
in expr
.get_sizes ()) {
1568 write_string (", ");
1577 if (expr
.initializer_list
!= null) {
1579 expr
.initializer_list
.accept (this
);
1583 public override void visit_boolean_literal (BooleanLiteral lit
) {
1584 write_string (lit
.value
.to_string ());
1587 public override void visit_character_literal (CharacterLiteral lit
) {
1588 write_string (lit
.value
);
1591 public override void visit_integer_literal (IntegerLiteral lit
) {
1592 write_string (lit
.value
);
1595 public override void visit_real_literal (RealLiteral lit
) {
1596 write_string (lit
.value
);
1599 public override void visit_string_literal (StringLiteral lit
) {
1600 write_string (lit
.value
);
1603 public override void visit_null_literal (NullLiteral lit
) {
1604 write_string ("null");
1607 public override void visit_member_access (MemberAccess expr
) {
1608 if (expr
.inner
!= null) {
1609 expr
.inner
.accept (this
);
1612 write_identifier (expr
.member_name
);
1615 public override void visit_method_call (MethodCall expr
) {
1616 expr
.call
.accept (this
);
1617 write_string (" (");
1620 foreach (Expression arg
in expr
.get_argument_list ()) {
1622 write_string (", ");
1632 public override void visit_element_access (ElementAccess expr
) {
1633 expr
.container
.accept (this
);
1637 foreach (Expression index
in expr
.get_indices ()) {
1639 write_string (", ");
1643 index
.accept (this
);
1649 public override void visit_slice_expression (SliceExpression expr
) {
1650 expr
.container
.accept (this
);
1652 expr
.start
.accept (this
);
1654 expr
.stop
.accept (this
);
1658 public override void visit_base_access (BaseAccess expr
) {
1659 write_string ("base");
1662 public override void visit_postfix_expression (PostfixExpression expr
) {
1663 expr
.inner
.accept (this
);
1664 if (expr
.increment
) {
1665 write_string ("++");
1667 write_string ("--");
1671 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
1672 if (!expr
.struct_creation
) {
1673 write_string ("new ");
1676 write_type (expr
.type_reference
);
1678 if (expr
.symbol_reference
.name
!= ".new") {
1680 write_string (expr
.symbol_reference
.name
);
1683 write_string (" (");
1686 foreach (Expression arg
in expr
.get_argument_list ()) {
1688 write_string (", ");
1698 public override void visit_sizeof_expression (SizeofExpression expr
) {
1699 write_string ("sizeof (");
1700 write_type (expr
.type_reference
);
1704 public override void visit_typeof_expression (TypeofExpression expr
) {
1705 write_string ("typeof (");
1706 write_type (expr
.type_reference
);
1710 public override void visit_unary_expression (UnaryExpression expr
) {
1711 switch (expr
.operator
) {
1712 case UnaryOperator
.PLUS
:
1715 case UnaryOperator
.MINUS
:
1718 case UnaryOperator
.LOGICAL_NEGATION
:
1721 case UnaryOperator
.BITWISE_COMPLEMENT
:
1724 case UnaryOperator
.INCREMENT
:
1725 write_string ("++");
1727 case UnaryOperator
.DECREMENT
:
1728 write_string ("--");
1730 case UnaryOperator
.REF
:
1731 write_string ("ref ");
1733 case UnaryOperator
.OUT
:
1734 write_string ("out ");
1737 assert_not_reached ();
1739 expr
.inner
.accept (this
);
1742 public override void visit_cast_expression (CastExpression expr
) {
1743 if (expr
.is_non_null_cast
) {
1744 write_string ("(!) ");
1745 expr
.inner
.accept (this
);
1749 if (!expr
.is_silent_cast
) {
1751 write_type (expr
.type_reference
);
1752 write_string (") ");
1755 expr
.inner
.accept (this
);
1757 if (expr
.is_silent_cast
) {
1758 write_string (" as ");
1759 write_type (expr
.type_reference
);
1763 public override void visit_pointer_indirection (PointerIndirection expr
) {
1765 expr
.inner
.accept (this
);
1768 public override void visit_addressof_expression (AddressofExpression expr
) {
1770 expr
.inner
.accept (this
);
1773 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
1774 write_string ("(owned) ");
1775 expr
.inner
.accept (this
);
1778 public override void visit_binary_expression (BinaryExpression expr
) {
1779 expr
.left
.accept (this
);
1781 switch (expr
.operator
) {
1782 case BinaryOperator
.PLUS
:
1783 write_string (" + ");
1785 case BinaryOperator
.MINUS
:
1786 write_string (" - ");
1788 case BinaryOperator
.MUL
:
1789 write_string (" * ");
1791 case BinaryOperator
.DIV
:
1792 write_string (" / ");
1794 case BinaryOperator
.MOD
:
1795 write_string (" % ");
1797 case BinaryOperator
.SHIFT_LEFT
:
1798 write_string (" << ");
1800 case BinaryOperator
.SHIFT_RIGHT
:
1801 write_string (" >> ");
1803 case BinaryOperator
.LESS_THAN
:
1804 write_string (" < ");
1806 case BinaryOperator
.GREATER_THAN
:
1807 write_string (" > ");
1809 case BinaryOperator
.LESS_THAN_OR_EQUAL
:
1810 write_string (" <= ");
1812 case BinaryOperator
.GREATER_THAN_OR_EQUAL
:
1813 write_string (" >= ");
1815 case BinaryOperator
.EQUALITY
:
1816 write_string (" == ");
1818 case BinaryOperator
.INEQUALITY
:
1819 write_string (" != ");
1821 case BinaryOperator
.BITWISE_AND
:
1822 write_string (" & ");
1824 case BinaryOperator
.BITWISE_OR
:
1825 write_string (" | ");
1827 case BinaryOperator
.BITWISE_XOR
:
1828 write_string (" ^ ");
1830 case BinaryOperator
.AND
:
1831 write_string (" && ");
1833 case BinaryOperator
.OR
:
1834 write_string (" || ");
1836 case BinaryOperator
.IN
:
1837 write_string (" in ");
1839 case BinaryOperator
.COALESCE
:
1840 write_string (" ?? ");
1843 assert_not_reached ();
1846 expr
.right
.accept (this
);
1849 public override void visit_type_check (TypeCheck expr
) {
1850 expr
.expression
.accept (this
);
1851 write_string (" is ");
1852 write_type (expr
.type_reference
);
1855 public override void visit_conditional_expression (ConditionalExpression expr
) {
1856 expr
.condition
.accept (this
);
1858 expr
.true_expression
.accept (this
);
1860 expr
.false_expression
.accept (this
);
1863 public override void visit_lambda_expression (LambdaExpression expr
) {
1865 var params
= expr
.get_parameters ();
1866 if (params
.size
!= 0) {
1867 for (var i
= 0; i
< params
.size
- 1; ++ i
) {
1868 write_string (params
[i
]);
1869 write_string (", ");
1871 write_string (params
[params
.size
- 1]);
1873 write_string (") =>");
1874 if (expr
.statement_body
!= null) {
1875 expr
.statement_body
.accept (this
);
1876 } else if (expr
.expression_body
!= null) {
1877 expr
.expression_body
.accept (this
);
1881 public override void visit_assignment (Assignment a
) {
1882 a
.left
.accept (this
);
1883 write_string (" = ");
1884 a
.right
.accept (this
);
1887 private void write_indent () {
1894 for (i
= 0; i
< indent
; i
++) {
1901 private void write_identifier (string s
) {
1902 char* id
= (char*)s
;
1903 int id_length
= (int)s
.length
;
1904 if (context
.profile
!= Profile
.DOVA
&&
1905 (Vala
.Scanner
.get_identifier_or_keyword (id
, id_length
) != Vala
.TokenType
.IDENTIFIER
||
1906 s
.get_char ().isdigit ())) {
1912 private void write_return_type (DataType type
) {
1913 if (type
.is_weak ()) {
1914 write_string ("unowned ");
1920 private void write_type (DataType type
) {
1921 write_string (type
.to_qualified_string (current_scope
));
1924 private void write_string (string s
) {
1925 stream
.printf ("%s", s
);
1929 private void write_newline () {
1934 void write_code_block (Block? block
) {
1935 if (block
== null || type
!= CodeWriterType
.DUMP
) {
1940 block
.accept (this
);
1943 private void write_begin_block () {
1954 private void write_end_block () {
1957 stream
.printf ("}");
1960 private bool check_accessibility (Symbol sym
) {
1962 case CodeWriterType
.EXTERNAL
:
1963 return sym
.access
== SymbolAccessibility
.PUBLIC
||
1964 sym
.access
== SymbolAccessibility
.PROTECTED
;
1966 case CodeWriterType
.INTERNAL
:
1967 case CodeWriterType
.FAST
:
1968 return sym
.access
== SymbolAccessibility
.INTERNAL
||
1969 sym
.access
== SymbolAccessibility
.PUBLIC
||
1970 sym
.access
== SymbolAccessibility
.PROTECTED
;
1972 case CodeWriterType
.DUMP
:
1976 assert_not_reached ();
1980 private void write_attributes (CodeNode node
) {
1981 foreach (Attribute attr
in node
.attributes
) {
1982 if (!filter_attribute (attr
)) {
1984 stream
.printf ("[%s", attr
.name
);
1986 var keys
= attr
.args
.get_keys ();
1987 if (keys
.size
!= 0) {
1988 stream
.printf (" (");
1990 string separator
= "";
1991 foreach (string arg_name
in keys
) {
1992 stream
.printf ("%s%s = %s", separator
, arg_name
, attr
.args
.get (arg_name
));
1996 stream
.printf (")");
1998 stream
.printf ("]");
2004 private bool filter_attribute (Attribute attr
) {
2005 if (attr
.name
== "CCode"
2006 || attr
.name
== "Compact" || attr
.name
== "Immutable"
2007 || attr
.name
== "SimpleType" || attr
.name
== "IntegerType" || attr
.name
== "FloatingType"
2008 || attr
.name
== "Flags") {
2014 private void write_accessibility (Symbol sym
) {
2015 if (sym
.access
== SymbolAccessibility
.PUBLIC
) {
2016 write_string ("public ");
2017 } else if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
2018 write_string ("protected ");
2019 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
2020 write_string ("internal ");
2021 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
2022 write_string ("private ");
2025 if (type
!= CodeWriterType
.EXTERNAL
&& sym
.external
&& !sym
.external_package
) {
2026 write_string ("extern ");
2030 void write_property_accessor_accessibility (Symbol sym
) {
2031 if (sym
.access
== SymbolAccessibility
.PROTECTED
) {
2032 write_string (" protected");
2033 } else if (sym
.access
== SymbolAccessibility
.INTERNAL
) {
2034 write_string (" internal");
2035 } else if (sym
.access
== SymbolAccessibility
.PRIVATE
) {
2036 write_string (" private");
2041 public enum Vala
.CodeWriterType
{