3 * Copyright (C) 2011 Florian Brosch
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Florian Brosch <flo.brosch@gmail.com>
27 * Creates an simpler, minimized, more abstract AST for valacs AST.
29 public class Valadoc
.Drivers
.TreeBuilder
: Vala
.CodeVisitor
{
30 private Vala
.ArrayList
<PackageMetaData
> packages
= new Vala
.ArrayList
<PackageMetaData
> ();
31 private PackageMetaData source_package
;
33 private Vala
.HashMap
<Vala
.SourceFile
, SourceFile
> files
= new Vala
.HashMap
<Vala
.SourceFile
, SourceFile
> ();
34 private Vala
.HashMap
<Vala
.Symbol
, Symbol
> symbol_map
= new Vala
.HashMap
<Vala
.Symbol
, Symbol
> ();
36 private ErrorReporter reporter
;
37 private Settings settings
;
39 private Api
.Node current_node
;
40 private Api
.Tree tree
;
42 private Valadoc
.Api
.Class glib_error
= null;
49 public Api
.Class
get_glib_error () {
53 public Vala
.HashMap
<Vala
.Symbol
, Symbol
> get_symbol_map () {
62 private class PackageMetaData
{
63 public Package package
;
64 public Vala
.HashMap
<Vala
.Namespace
, Namespace
> namespaces
= new Vala
.HashMap
<Vala
.Namespace
, Namespace
> ();
65 public Vala
.ArrayList
<Vala
.SourceFile
> files
= new Vala
.ArrayList
<Vala
.SourceFile
> ();
67 public PackageMetaData (Package package
) {
68 this
.package
= package
;
71 public Namespace
get_namespace (Vala
.Namespace vns
, SourceFile file
) {
72 Namespace? ns
= namespaces
.get (vns
);
77 // find documentation comment if existing:
78 SourceComment? comment
= null;
79 if (vns
.source_reference
!= null) {
80 foreach (Vala
.Comment c
in vns
.get_comments()) {
81 if (c
.source_reference
.file
== file
.data
||
82 (c
.source_reference
.file
.file_type
== Vala
.SourceFileType
.SOURCE
83 && ((Vala
.SourceFile
) file
.data
).file_type
== Vala
.SourceFileType
.SOURCE
)
85 Vala
.SourceReference pos
= c
.source_reference
;
86 if (c is Vala
.GirComment
) {
87 comment
= new
GirSourceComment (c
.content
,
94 comment
= new
SourceComment (c
.content
,
106 // find parent if existing
107 var parent_vns
= vns
.parent_symbol
;
109 if (parent_vns
== null) {
110 ns
= new
Namespace (package
, file
, vns
.name
, comment
, vns
);
111 package
.add_child (ns
);
113 Namespace parent_ns
= get_namespace ((Vala
.Namespace
) parent_vns
, file
);
114 ns
= new
Namespace (parent_ns
, file
, vns
.name
, comment
, vns
);
115 parent_ns
.add_child (ns
);
118 namespaces
.set (vns
, ns
);
122 public void register_source_file (Vala
.SourceFile file
) {
126 public bool is_package_for_file (Vala
.SourceFile source_file
) {
127 if (source_file
.file_type
== Vala
.SourceFileType
.SOURCE
&& !package
.is_package
) {
131 return files
.contains (source_file
);
137 // Type constructor translation helpers:
140 private Pointer
create_pointer (Vala
.PointerType vtyperef
, Item parent
, Api
.Node caller
) {
141 Pointer ptr
= new
Pointer (parent
, vtyperef
);
143 Vala
.DataType vntype
= vtyperef
.base_type
;
144 if (vntype is Vala
.PointerType
) {
145 ptr
.data_type
= create_pointer ((Vala
.PointerType
) vntype
, ptr
, caller
);
146 } else if (vntype is Vala
.ArrayType
) {
147 ptr
.data_type
= create_array ((Vala
.ArrayType
) vntype
, ptr
, caller
);
149 ptr
.data_type
= create_type_reference (vntype
, ptr
, caller
);
155 private Api
.Array
create_array (Vala
.ArrayType vtyperef
, Item parent
, Api
.Node caller
) {
156 Api
.Array arr
= new Api
.Array (parent
, vtyperef
);
158 Vala
.DataType vntype
= vtyperef
.element_type
;
159 if (vntype is Vala
.ArrayType
) {
160 arr
.data_type
= create_array ((Vala
.ArrayType
) vntype
, arr
, caller
);
162 arr
.data_type
= create_type_reference (vntype
, arr
, caller
);
168 private TypeReference
create_type_reference (Vala
.DataType? vtyperef
, Item parent
, Api
.Node caller
) {
169 bool is_nullable
= vtyperef
!= null
171 && !(vtyperef is Vala
.GenericType
)
172 && !(vtyperef is Vala
.PointerType
);
173 string? signature
= (vtyperef
!= null
174 && vtyperef
.data_type
!= null)? Vala
.GVariantModule
.get_dbus_signature (vtyperef
.data_type
) : null;
175 bool pass_ownership
= type_reference_pass_ownership (vtyperef
);
176 Ownership ownership
= get_type_reference_ownership (vtyperef
);
177 bool is_dynamic
= vtyperef
!= null && vtyperef
.is_dynamic
;
179 TypeReference type_ref
= new
TypeReference (parent
,
187 if (vtyperef is Vala
.PointerType
) {
188 type_ref
.data_type
= create_pointer ((Vala
.PointerType
) vtyperef
, type_ref
, caller
);
189 } else if (vtyperef is Vala
.ArrayType
) {
190 type_ref
.data_type
= create_array ((Vala
.ArrayType
) vtyperef
, type_ref
, caller
);
191 //} else if (vtyperef is Vala.GenericType) {
192 // type_ref.data_type = new TypeParameter (caller,
193 // caller.get_source_file (),
194 // ((Vala.GenericType) vtyperef).type_parameter.name,
199 if (vtyperef
!= null) {
200 foreach (Vala
.DataType vdtype
in vtyperef
.get_type_arguments ()) {
201 var type_param
= create_type_reference (vdtype
, type_ref
, caller
);
202 type_ref
.add_type_argument (type_param
);
212 // Translation helpers:
215 private void process_attributes (Api
.Symbol parent
, GLib
.List
<Vala
.Attribute
> lst
) {
216 // attributes without arguments:
217 string[] attributes
= {
218 "ReturnsModifiedPointer",
244 foreach (Vala
.Attribute att
in lst
) {
245 if (att
.name
== "CCode" && (tmp
= att
.args
.get ("has_target")) != null && tmp
== "false") {
246 Attribute new_attribute
= new
Attribute (parent
, parent
.get_source_file (), att
.name
, att
);
247 new_attribute
.add_boolean ("has_target", false, att
);
248 parent
.add_attribute (new_attribute
);
249 } else if (att
.name
== "Version") {
250 Attribute new_attribute
= new
Attribute (parent
, parent
.get_source_file (), att
.name
, att
);
251 if ((tmp
= att
.args
.get ("deprecated")) != null) {
252 new_attribute
.add_boolean ("deprecated", bool.parse (tmp
), att
);
254 if ((tmp
= att
.args
.get ("since")) != null) {
255 new_attribute
.add_string ("since", tmp
, att
);
257 if ((tmp
= att
.args
.get ("deprecated_since")) != null) {
258 new_attribute
.add_string ("deprecated_since", tmp
, att
);
259 if (att
.args
.get ("deprecated") == null) {
260 new_attribute
.add_boolean ("deprecated", true, att
);
263 if ((tmp
= att
.args
.get ("replacement")) != null) {
264 new_attribute
.add_string ("replacement", tmp
, att
);
266 parent
.add_attribute (new_attribute
);
267 } else if (att
.name
== "Deprecated") {
268 Attribute new_attribute
= new
Attribute (parent
, parent
.get_source_file (), att
.name
, att
);
269 if ((tmp
= att
.args
.get ("since")) != null) {
270 new_attribute
.add_string ("since", tmp
, att
);
272 if ((tmp
= att
.args
.get ("replacement")) != null) {
273 new_attribute
.add_string ("replacement", tmp
, att
);
275 parent
.add_attribute (new_attribute
);
276 } else if (att
.name
in attributes
) {
277 Attribute new_attribute
= new
Attribute (parent
, parent
.get_source_file (), att
.name
, att
);
278 parent
.add_attribute (new_attribute
);
283 private string?
get_ccode_type_id (Vala
.CodeNode node
) {
284 return Vala
.get_ccode_type_id (node
);
287 private bool is_reference_counting (Vala
.TypeSymbol sym
) {
288 return Vala
.is_reference_counting (sym
);
291 private string?
get_ref_function (Vala
.Class sym
) {
292 return Vala
.get_ccode_ref_function (sym
);
295 private string?
get_unref_function (Vala
.Class sym
) {
296 return Vala
.get_ccode_unref_function (sym
);
299 private string?
get_finalize_function_name (Vala
.Class element
) {
300 if (!element
.is_fundamental ()) {
304 return "%s_finalize".printf (Vala
.get_ccode_lower_case_name (element
, null));
307 private string?
get_free_function_name (Vala
.Class element
) {
308 if (!element
.is_compact
) {
312 return Vala
.get_ccode_free_function (element
);
315 private string?
get_finish_name (Vala
.Method m
) {
316 return Vala
.get_ccode_finish_name (m
);
319 private string?
get_take_value_function (Vala
.Class sym
) {
320 return Vala
.get_ccode_take_value_function (sym
);
323 private string?
get_get_value_function (Vala
.Class sym
) {
324 return Vala
.get_ccode_get_value_function (sym
);
327 private string?
get_set_value_function (Vala
.Class sym
) {
328 return Vala
.get_ccode_set_value_function (sym
);
332 private string?
get_param_spec_function (Vala
.CodeNode sym
) {
333 return Vala
.get_ccode_param_spec_function (sym
);
336 private string?
get_dup_function (Vala
.TypeSymbol sym
) {
337 return Vala
.get_ccode_dup_function (sym
);
340 private string?
get_copy_function (Vala
.TypeSymbol sym
) {
341 return Vala
.get_ccode_copy_function (sym
);
344 private string?
get_destroy_function (Vala
.TypeSymbol sym
) {
345 return Vala
.get_ccode_destroy_function (sym
);
348 private string?
get_free_function (Vala
.TypeSymbol sym
) {
349 return Vala
.get_ccode_free_function (sym
);
352 private string?
get_cname (Vala
.Symbol symbol
) {
353 return Vala
.get_ccode_name (symbol
);
356 private SourceComment?
create_comment (Vala
.Comment? comment
) {
357 if (comment
!= null) {
358 Vala
.SourceReference pos
= comment
.source_reference
;
359 SourceFile file
= files
.get (pos
.file
);
360 if (comment is Vala
.GirComment
) {
361 var tmp
= new
GirSourceComment (comment
.content
,
367 if (((Vala
.GirComment
) comment
).return_content
!= null) {
368 Vala
.SourceReference return_pos
= ((Vala
.GirComment
) comment
).return_content
.source_reference
;
369 tmp
.return_comment
= new
SourceComment (((Vala
.GirComment
) comment
).return_content
.content
,
371 return_pos
.begin
.line
,
372 return_pos
.begin
.column
,
374 return_pos
.end
.column
);
377 Vala
.MapIterator
<string, Vala
.Comment
> it
= ((Vala
.GirComment
) comment
).parameter_iterator ();
379 Vala
.Comment vala_param
= it
.get_value ();
380 Vala
.SourceReference param_pos
= vala_param
.source_reference
;
381 var param_comment
= new
SourceComment (vala_param
.content
,
383 param_pos
.begin
.line
,
384 param_pos
.begin
.column
,
386 param_pos
.end
.column
);
387 tmp
.add_parameter_content (it
.get_key (), param_comment
);
391 return new
SourceComment (comment
.content
,
403 private string get_method_name (Vala
.Method element
) {
404 if (element is Vala
.CreationMethod
) {
405 if (element
.name
== ".new") {
406 return element
.parent_symbol
.name
;
408 return element
.parent_symbol
.name
+ "." + element
.name
;
415 private string?
get_quark_macro_name (Vala
.ErrorDomain element
) {
416 return Vala
.get_ccode_upper_case_name (element
, null);
419 private string?
get_private_cname (Vala
.Class element
) {
420 if (element
.is_compact
) {
424 string? cname
= get_cname (element
);
425 return (cname
!= null)? cname
+ "Private" : null;
428 private string?
get_class_macro_name (Vala
.Class element
) {
429 if (element
.is_compact
) {
433 return "%s_GET_CLASS".printf (Vala
.get_ccode_upper_case_name (element
, null));
436 private string?
get_class_type_macro_name (Vala
.Class element
) {
437 if (element
.is_compact
) {
441 return "%s_CLASS".printf (Vala
.get_ccode_upper_case_name (element
, null));
444 private string?
get_is_type_macro_name (Vala
.TypeSymbol element
) {
445 string? name
= Vala
.get_ccode_type_check_function (element
);
446 return (name
!= null && name
!= "")? name
: null;
449 private string?
get_is_class_type_macro_name (Vala
.TypeSymbol element
) {
450 string? name
= get_is_type_macro_name (element
);
451 return (name
!= null)? name
+ "_CLASS" : null;
454 private string?
get_type_function_name (Vala
.TypeSymbol element
) {
455 if ((element is Vala
.Class
456 && ((Vala
.Class
) element
).is_compact
)
457 || element is Vala
.ErrorDomain
458 || element is Vala
.Delegate
)
463 return "%s_get_type".printf (Vala
.get_ccode_lower_case_name (element
, null));
466 private string?
get_type_macro_name (Vala
.TypeSymbol element
) {
467 if ((element is Vala
.Class
468 && ((Vala
.Class
) element
).is_compact
)
469 || element is Vala
.ErrorDomain
470 || element is Vala
.Delegate
)
475 return Vala
.get_ccode_type_id (element
);
478 private string?
get_type_cast_macro_name (Vala
.TypeSymbol element
) {
479 if ((element is Vala
.Class
480 && !((Vala
.Class
) element
).is_compact
)
481 || element is Vala
.Interface
)
483 return Vala
.get_ccode_upper_case_name (element
, null);
489 private string?
get_interface_macro_name (Vala
.Interface element
) {
490 return "%s_GET_INTERFACE".printf (Vala
.get_ccode_upper_case_name (element
, null));
493 private string get_quark_function_name (Vala
.ErrorDomain element
) {
494 return Vala
.get_ccode_lower_case_prefix (element
) + "quark";
497 private PackageMetaData?
get_package_meta_data (Package pkg
) {
498 foreach (PackageMetaData data
in packages
) {
499 if (data
.package
== pkg
) {
507 private PackageMetaData
register_package (Package package
) {
508 PackageMetaData meta_data
= new
PackageMetaData (package
);
509 tree
.add_package (package
);
510 packages
.add (meta_data
);
514 private SourceFile
register_source_file (PackageMetaData meta_data
, Vala
.SourceFile source_file
) {
515 SourceFile file
= new
SourceFile (meta_data
.package
,
516 source_file
.get_relative_filename (),
517 source_file
.get_csource_filename (),
519 files
.set (source_file
, file
);
521 meta_data
.register_source_file (source_file
);
525 private SourceFile?
get_source_file (Vala
.Symbol symbol
) {
526 Vala
.SourceReference source_ref
= symbol
.source_reference
;
527 if (source_ref
== null) {
531 SourceFile? file
= files
.get (source_ref
.file
);
532 assert (file
!= null);
536 private Package?
find_package_for_file (Vala
.SourceFile source_file
) {
537 foreach (PackageMetaData pkg
in this
.packages
) {
538 if (pkg
.is_package_for_file (source_file
)) {
547 private Namespace
get_namespace (Package pkg
, Vala
.Symbol symbol
, SourceFile? file
) {
548 // Find the closest namespace in our vala-tree
549 Vala
.Symbol namespace_symbol
= symbol
;
550 while (!(namespace_symbol is Vala
.Namespace
)) {
551 namespace_symbol
= namespace_symbol
.parent_symbol
;
554 PackageMetaData? meta_data
= get_package_meta_data (pkg
);
555 assert (meta_data
!= null);
557 return meta_data
.get_namespace ((Vala
.Namespace
) namespace_symbol
, file
);
560 private MethodBindingType
get_method_binding_type (Vala
.Method element
) {
561 if (element
.is_inline
) {
562 return MethodBindingType
.INLINE
;
563 } else if (element
.is_abstract
) {
564 return MethodBindingType
.ABSTRACT
;
565 } else if (element
.is_virtual
) {
566 return MethodBindingType
.VIRTUAL
;
567 } else if (element
.overrides
) {
568 return MethodBindingType
.OVERRIDE
;
569 } else if (element
.is_inline
) {
570 return MethodBindingType
.INLINE
;
571 } else if (element
.binding
!= Vala
.MemberBinding
.INSTANCE
) {
572 return MethodBindingType
.STATIC
;
574 return MethodBindingType
.UNMODIFIED
;
578 private SymbolAccessibility
get_access_modifier(Vala
.Symbol symbol
) {
579 switch (symbol
.access
) {
580 case Vala
.SymbolAccessibility
.PROTECTED
:
581 return SymbolAccessibility
.PROTECTED
;
583 case Vala
.SymbolAccessibility
.INTERNAL
:
584 return SymbolAccessibility
.INTERNAL
;
586 case Vala
.SymbolAccessibility
.PRIVATE
:
587 return SymbolAccessibility
.PRIVATE
;
589 case Vala
.SymbolAccessibility
.PUBLIC
:
590 return SymbolAccessibility
.PUBLIC
;
593 error ("Unknown symbol accessibility modifier found");
597 private PropertyAccessorType
get_property_accessor_type (Vala
.PropertyAccessor element
) {
598 if (element
.construction
) {
599 if (element
.writable
) {
600 return (PropertyAccessorType
.CONSTRUCT
| PropertyAccessorType
.SET
);
602 return PropertyAccessorType
.CONSTRUCT
;
603 } else if (element
.writable
) {
604 return PropertyAccessorType
.SET
;
605 } else if (element
.readable
) {
606 return PropertyAccessorType
.GET
;
609 error ("Unknown symbol accessibility type");
612 private bool type_reference_pass_ownership (Vala
.DataType? element
) {
613 if (element
== null) {
617 weak Vala
.CodeNode? node
= element
.parent_node
;
621 if (node is Vala
.Parameter
) {
622 return (((Vala
.Parameter
)node
).direction
== Vala
.ParameterDirection
.IN
&&
623 ((Vala
.Parameter
)node
).variable_type
.value_owned
);
625 if (node is Vala
.Property
) {
626 return ((Vala
.Property
)node
).property_type
.value_owned
;
632 private bool is_type_reference_unowned (Vala
.DataType? element
) {
633 if (element
== null) {
637 // non ref counted types are weak, not unowned
638 if (element
.data_type is Vala
.TypeSymbol
639 && is_reference_counting ((Vala
.TypeSymbol
) element
.data_type
) == true)
644 // FormalParameters are weak by default
645 return (element
.parent_node is Vala
.Parameter
== false)
650 private bool is_type_reference_owned (Vala
.DataType? element
) {
651 if (element
== null) {
655 weak Vala
.CodeNode parent
= element
.parent_node
;
658 if (parent is Vala
.Parameter
) {
659 if (((Vala
.Parameter
)parent
).direction
!= Vala
.ParameterDirection
.IN
) {
662 return ((Vala
.Parameter
)parent
).variable_type
.value_owned
;
668 private bool is_type_reference_weak (Vala
.DataType? element
) {
669 if (element
== null) {
673 // non ref counted types are unowned, not weak
674 if (element
.data_type is Vala
.TypeSymbol
675 && is_reference_counting ((Vala
.TypeSymbol
) element
.data_type
) == false)
680 // arrays are unowned, not weak
681 if (element is Vala
.ArrayType
) {
685 // FormalParameters are weak by default
686 return (element
.parent_node is Vala
.Parameter
== false)? element
.is_weak () : false;
689 private Ownership
get_type_reference_ownership (Vala
.DataType? element
) {
690 if (is_type_reference_owned (element
)) {
691 return Ownership
.OWNED
;
692 } else if (is_type_reference_weak (element
)) {
693 return Ownership
.WEAK
;
694 } else if (is_type_reference_unowned (element
)) {
695 return Ownership
.UNOWNED
;
698 return Ownership
.DEFAULT
;
701 private Ownership
get_property_ownership (Vala
.PropertyAccessor element
) {
702 if (element
.value_type
.value_owned
) {
703 return Ownership
.OWNED
;
706 // the exact type (weak, unowned) does not matter
707 return Ownership
.UNOWNED
;
710 private PropertyBindingType
get_property_binding_type (Vala
.Property element
) {
711 if (element
.is_abstract
) {
712 return PropertyBindingType
.ABSTRACT
;
713 } else if (element
.is_virtual
) {
714 return PropertyBindingType
.VIRTUAL
;
715 } else if (element
.overrides
) {
716 return PropertyBindingType
.OVERRIDE
;
719 return PropertyBindingType
.UNMODIFIED
;
722 private FormalParameterType
get_formal_parameter_type (Vala
.Parameter element
) {
723 if (element
.direction
== Vala
.ParameterDirection
.OUT
) {
724 return FormalParameterType
.OUT
;
725 } else if (element
.direction
== Vala
.ParameterDirection
.REF
) {
726 return FormalParameterType
.REF
;
727 } else if (element
.direction
== Vala
.ParameterDirection
.IN
) {
728 return FormalParameterType
.IN
;
731 error ("Unknown formal parameter type");
736 // Vala tree creation:
739 private string get_package_name (string path
) {
740 string file_name
= Path
.get_basename (path
);
741 return file_name
.substring (0, file_name
.last_index_of_char ('.'));
744 private bool add_package (Vala
.CodeContext context
, string pkg
) {
745 // ignore multiple occurences of the same package
746 if (context
.has_package (pkg
)) {
750 string vapi_name
= pkg
+ ".vapi";
751 string gir_name
= pkg
+ ".gir";
752 foreach (string source_file
in settings
.source_files
) {
753 string basename
= Path
.get_basename (source_file
);
754 if (basename
== vapi_name
|| basename
== gir_name
) {
760 var package_path
= context
.get_vapi_path (pkg
) ?? context
.get_gir_path (pkg
);
761 if (package_path
== null) {
762 Vala
.Report
.error (null, "Package `%s' not found in specified Vala API directories or GObject-Introspection GIR directories".printf (pkg
));
766 context
.add_package (pkg
);
768 var vfile
= new Vala
.SourceFile (context
, Vala
.SourceFileType
.PACKAGE
, package_path
);
769 context
.add_source_file (vfile
);
770 Package vdpkg
= new
Package (pkg
, true, null);
771 register_source_file (register_package (vdpkg
), vfile
);
773 add_deps (context
, Path
.build_filename (Path
.get_dirname (package_path
), "%s.deps".printf (pkg
)), pkg
);
777 private void add_deps (Vala
.CodeContext context
, string file_path
, string pkg_name
) {
778 if (FileUtils
.test (file_path
, FileTest
.EXISTS
)) {
782 FileUtils
.get_contents (file_path
, out deps_content
, out deps_len
);
783 foreach (string dep
in deps_content
.split ("\n")) {
786 if (!add_package (context
, dep
)) {
787 Vala
.Report
.error (null, "%s, dependency of %s, not found in specified Vala API directories".printf (dep
, pkg_name
));
791 } catch (FileError e
) {
792 Vala
.Report
.error (null, "Unable to read dependency file: %s".printf (e
.message
));
798 * Adds the specified packages to the list of used packages.
800 * @param context The code context
801 * @param packages a list of package names
803 private void add_depencies (Vala
.CodeContext context
, string[] packages
) {
804 foreach (string package
in packages
) {
805 if (!add_package (context
, package
)) {
806 Vala
.Report
.error (null, "Package `%s' not found in specified Vala API directories or GObject-Introspection GIR directories".printf (package
));
812 * Add the specified source file to the context. Only .vala, .vapi, .gs,
813 * and .c files are supported.
815 private void add_documented_files (Vala
.CodeContext context
, string[] sources
) {
816 if (sources
== null) {
820 foreach (string source
in sources
) {
821 if (FileUtils
.test (source
, FileTest
.EXISTS
)) {
822 var rpath
= Vala
.CodeContext
.realpath (source
);
823 if (source
.has_suffix (".vala") || source
.has_suffix (".gs")) {
824 var source_file
= new Vala
.SourceFile (context
, Vala
.SourceFileType
.SOURCE
, rpath
);
826 if (source_package
== null) {
827 source_package
= register_package (new
Package (settings
.pkg_name
, false, null));
830 register_source_file (source_package
, source_file
);
832 if (context
.profile
== Vala
.Profile
.GOBJECT
) {
833 // import the GLib namespace by default (namespace of backend-specific standard library)
834 var ns_ref
= new Vala
.UsingDirective (new Vala
.UnresolvedSymbol (null, "GLib", null));
835 source_file
.add_using_directive (ns_ref
);
836 context
.root
.add_using_directive (ns_ref
);
839 context
.add_source_file (source_file
);
840 } else if (source
.has_suffix (".vapi") || source
.has_suffix (".gir")) {
841 string file_name
= get_package_name (source
);
843 var vfile
= new Vala
.SourceFile (context
, Vala
.SourceFileType
.PACKAGE
, rpath
);
844 context
.add_source_file (vfile
);
846 if (source_package
== null) {
847 source_package
= register_package (new
Package (settings
.pkg_name
, false, null));
850 register_source_file (source_package
, vfile
);
852 add_deps (context
, Path
.build_filename (Path
.get_dirname (source
), "%s.deps".printf (file_name
)), file_name
);
853 } else if (source
.has_suffix (".c")) {
854 context
.add_c_source_file (rpath
);
855 tree
.add_external_c_files (rpath
);
857 Vala
.Report
.error (null, "%s is not a supported source file type. Only .vala, .vapi, .gs, and .c files are supported.".printf (source
));
860 Vala
.Report
.error (null, "%s not found".printf (source
));
865 private void create_valac_tree (Vala
.CodeContext context
, Settings settings
) {
867 context
.experimental
= settings
.experimental
;
868 context
.experimental_non_null
= settings
.experimental
|| settings
.experimental_non_null
;
869 context
.vapi_directories
= settings
.vapi_directories
;
870 context
.report
.enable_warnings
= settings
.verbose
;
871 context
.metadata_directories
= settings
.metadata_directories
;
872 context
.gir_directories
= settings
.gir_directories
;
874 if (settings
.basedir
== null) {
875 context
.basedir
= Vala
.CodeContext
.realpath (".");
877 context
.basedir
= Vala
.CodeContext
.realpath (settings
.basedir
);
880 if (settings
.directory
!= null) {
881 context
.directory
= Vala
.CodeContext
.realpath (settings
.directory
);
883 context
.directory
= context
.basedir
;
887 // add default packages:
888 if (settings
.profile
== "gobject-2.0" || settings
.profile
== "gobject" || settings
.profile
== null) {
889 context
.profile
= Vala
.Profile
.GOBJECT
;
890 context
.add_define ("GOBJECT");
894 if (settings
.defines
!= null) {
895 foreach (string define
in settings
.defines
) {
896 context
.add_define (define
);
900 for (int i
= 2; i
<= 42; i
+= 2) {
901 context
.add_define ("VALA_0_%d".printf (i
));
904 if (context
.profile
== Vala
.Profile
.GOBJECT
) {
908 context
.target_glib_major
= glib_major
;
909 context
.target_glib_minor
= glib_minor
;
910 if (context
.target_glib_major
!= 2) {
911 Vala
.Report
.error (null, "This version of valac only supports GLib 2");
914 if (settings
.target_glib
!= null && settings
.target_glib
.scanf ("%d.%d", out glib_major
, out glib_minor
) != 2) {
915 Vala
.Report
.error (null, "Invalid format for --target-glib");
918 context
.target_glib_major
= glib_major
;
919 context
.target_glib_minor
= glib_minor
;
920 if (context
.target_glib_major
!= 2) {
921 Vala
.Report
.error (null, "This version of valac only supports GLib 2");
924 for (int i
= 16; i
<= glib_minor
; i
+= 2) {
925 context
.add_define ("GLIB_2_%d".printf (i
));
929 if (!this
.add_package (context
, "glib-2.0")) { //
930 Vala
.Report
.error (null, "glib-2.0 not found in specified Vala API directories");
933 if (!this
.add_package (context
, "gobject-2.0")) { //
934 Vala
.Report
.error (null, "gobject-2.0 not found in specified Vala API directories");
938 // add user defined files:
939 add_depencies (context
, settings
.packages
);
940 if (reporter
.errors
> 0) {
944 add_documented_files (context
, settings
.source_files
);
945 if (reporter
.errors
> 0) {
950 Vala
.Parser parser
= new Vala
.Parser ();
952 parser
.parse (context
);
953 if (context
.report
.get_errors () > 0) {
958 Vala
.GirParser gir_parser
= new Vala
.GirParser ();
960 gir_parser
.parse (context
);
961 if (context
.report
.get_errors () > 0) {
967 if (context
.report
.get_errors () > 0) {
975 // Valadoc tree creation:
978 private void process_children (Api
.Node node
, Vala
.CodeNode element
) {
979 Api
.Node old_node
= current_node
;
981 element
.accept_children (this
);
982 current_node
= old_node
;
985 private Api
.Node
get_parent_node_for (Vala
.Symbol element
) {
986 if (current_node
!= null) {
990 Vala
.SourceFile vala_source_file
= element
.source_reference
.file
;
991 Package package
= find_package_for_file (vala_source_file
);
992 SourceFile? source_file
= get_source_file (element
);
994 return get_namespace (package
, element
, source_file
);
1000 public override void visit_namespace (Vala
.Namespace element
) {
1001 element
.accept_children (this
);
1007 public override void visit_class (Vala
.Class element
) {
1008 Api
.Node parent
= get_parent_node_for (element
);
1009 SourceFile? file
= get_source_file (element
);
1010 SourceComment? comment
= create_comment (element
.comment
);
1012 bool is_basic_type
= element
.base_class
== null && element
.name
== "string";
1014 Class node
= new
Class (parent
,
1017 get_access_modifier (element
),
1019 get_cname (element
),
1020 get_private_cname (element
),
1021 get_class_macro_name (element
),
1022 get_type_macro_name (element
),
1023 get_is_type_macro_name (element
),
1024 get_type_cast_macro_name (element
),
1025 get_type_function_name (element
),
1026 get_class_type_macro_name (element
),
1027 get_is_class_type_macro_name (element
),
1028 Vala
.GDBusModule
.get_dbus_name (element
),
1029 get_ccode_type_id (element
),
1030 get_param_spec_function (element
),
1031 get_ref_function (element
),
1032 get_unref_function (element
),
1033 get_free_function_name (element
),
1034 get_finalize_function_name (element
),
1035 get_take_value_function (element
),
1036 get_get_value_function (element
),
1037 get_set_value_function (element
),
1038 element
.is_fundamental (),
1039 element
.is_abstract
,
1042 symbol_map
.set (element
, node
);
1043 parent
.add_child (node
);
1046 foreach (Vala
.DataType vala_type_ref
in element
.get_base_types ()) {
1047 var type_ref
= create_type_reference (vala_type_ref
, node
, node
);
1049 if (vala_type_ref
.data_type is Vala
.Interface
) {
1050 node
.add_interface (type_ref
);
1051 } else if (vala_type_ref
.data_type is Vala
.Class
) {
1052 node
.base_type
= type_ref
;
1056 process_attributes (node
, element
.attributes
);
1057 process_children (node
, element
);
1060 if (glib_error
== null && node
.get_full_name () == "GLib.Error") {
1068 public override void visit_interface (Vala
.Interface element
) {
1069 Api
.Node parent
= get_parent_node_for (element
);
1070 SourceFile? file
= get_source_file (element
);
1071 SourceComment? comment
= create_comment (element
.comment
);
1073 Interface node
= new
Interface (parent
,
1076 get_access_modifier (element
),
1078 get_cname (element
),
1079 get_type_macro_name (element
),
1080 get_is_type_macro_name (element
),
1081 get_type_cast_macro_name (element
),
1082 get_type_function_name (element
),
1083 get_interface_macro_name (element
),
1084 Vala
.GDBusModule
.get_dbus_name (element
),
1086 symbol_map
.set (element
, node
);
1087 parent
.add_child (node
);
1090 foreach (Vala
.DataType vala_type_ref
in element
.get_prerequisites ()) {
1091 TypeReference type_ref
= create_type_reference (vala_type_ref
, node
, node
);
1092 if (vala_type_ref
.data_type is Vala
.Interface
) {
1093 node
.add_interface (type_ref
);
1095 node
.base_type
= type_ref
;
1099 process_attributes (node
, element
.attributes
);
1100 process_children (node
, element
);
1106 public override void visit_struct (Vala
.Struct element
) {
1107 Api
.Node parent
= get_parent_node_for (element
);
1108 SourceFile? file
= get_source_file (element
);
1109 SourceComment? comment
= create_comment (element
.comment
);
1111 bool is_basic_type
= element
.base_type
== null
1112 && (element
.is_boolean_type ()
1113 || element
.is_floating_type ()
1114 || element
.is_integer_type ());
1116 Struct node
= new
Struct (parent
,
1119 get_access_modifier (element
),
1121 get_cname (element
),
1122 get_type_macro_name (element
),
1123 get_type_function_name (element
),
1124 get_ccode_type_id (element
),
1125 get_dup_function (element
),
1126 get_copy_function (element
),
1127 get_destroy_function (element
),
1128 get_free_function (element
),
1131 symbol_map
.set (element
, node
);
1132 parent
.add_child (node
);
1135 Vala
.ValueType? basetype
= element
.base_type as Vala
.ValueType
;
1136 if (basetype
!= null) {
1137 node
.base_type
= create_type_reference (basetype
, node
, node
);
1140 process_attributes (node
, element
.attributes
);
1141 process_children (node
, element
);
1147 public override void visit_field (Vala
.Field element
) {
1148 Api
.Node parent
= get_parent_node_for (element
);
1149 SourceFile? file
= get_source_file (element
);
1150 SourceComment? comment
= create_comment (element
.comment
);
1152 Field node
= new
Field (parent
,
1155 get_access_modifier (element
),
1157 get_cname (element
),
1158 element
.binding
== Vala
.MemberBinding
.STATIC
,
1159 element
.is_volatile
,
1161 node
.field_type
= create_type_reference (element
.variable_type
, node
, node
);
1162 symbol_map
.set (element
, node
);
1163 parent
.add_child (node
);
1165 process_attributes (node
, element
.attributes
);
1166 process_children (node
, element
);
1172 public override void visit_property (Vala
.Property element
) {
1173 Api
.Node parent
= get_parent_node_for (element
);
1174 SourceFile? file
= get_source_file (element
);
1175 SourceComment? comment
= create_comment (element
.comment
);
1177 Property node
= new
Property (parent
,
1180 get_access_modifier (element
),
1183 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1184 Vala
.GDBusModule
.is_dbus_visible (element
),
1185 get_property_binding_type (element
),
1187 node
.property_type
= create_type_reference (element
.property_type
, node
, node
);
1188 symbol_map
.set (element
, node
);
1189 parent
.add_child (node
);
1191 // Process property type
1192 if (element
.get_accessor
!= null) {
1193 var accessor
= element
.get_accessor
;
1194 node
.getter
= new
PropertyAccessor (node
,
1197 get_access_modifier (accessor
),
1198 get_cname (accessor
),
1199 get_property_accessor_type (accessor
),
1200 get_property_ownership (accessor
),
1204 if (element
.set_accessor
!= null) {
1205 var accessor
= element
.set_accessor
;
1206 node
.setter
= new
PropertyAccessor (node
,
1209 get_access_modifier (accessor
),
1210 get_cname (accessor
),
1211 get_property_accessor_type (accessor
),
1212 get_property_ownership (accessor
),
1216 process_attributes (node
, element
.attributes
);
1217 process_children (node
, element
);
1223 public override void visit_creation_method (Vala
.CreationMethod element
) {
1224 Api
.Node parent
= get_parent_node_for (element
);
1225 SourceFile? file
= get_source_file (element
);
1226 SourceComment? comment
= create_comment (element
.comment
);
1228 Method node
= new
Method (parent
,
1230 get_method_name (element
),
1231 get_access_modifier (element
),
1233 get_cname (element
),
1234 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1235 Vala
.GDBusModule
.dbus_result_name (element
),
1236 (element
.coroutine
)?
get_finish_name (element
) : null,
1237 get_method_binding_type (element
),
1239 Vala
.GDBusModule
.is_dbus_visible (element
),
1240 element is Vala
.CreationMethod
,
1242 node
.return_type
= create_type_reference (element
.return_type
, node
, node
);
1243 symbol_map
.set (element
, node
);
1244 parent
.add_child (node
);
1246 process_attributes (node
, element
.attributes
);
1247 process_children (node
, element
);
1253 public override void visit_method (Vala
.Method element
) {
1254 Api
.Node parent
= get_parent_node_for (element
);
1255 SourceFile? file
= get_source_file (element
);
1256 SourceComment? comment
= create_comment (element
.comment
);
1258 Method node
= new
Method (parent
,
1260 get_method_name (element
),
1261 get_access_modifier (element
),
1263 get_cname (element
),
1264 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1265 Vala
.GDBusModule
.dbus_result_name (element
),
1266 (element
.coroutine
)?
get_finish_name (element
) : null,
1267 get_method_binding_type (element
),
1269 Vala
.GDBusModule
.is_dbus_visible (element
),
1270 element is Vala
.CreationMethod
,
1272 node
.return_type
= create_type_reference (element
.return_type
, node
, node
);
1273 symbol_map
.set (element
, node
);
1274 parent
.add_child (node
);
1276 process_attributes (node
, element
.attributes
);
1277 process_children (node
, element
);
1283 public override void visit_signal (Vala
.Signal element
) {
1284 Api
.Node parent
= get_parent_node_for (element
);
1285 SourceFile? file
= get_source_file (element
);
1286 SourceComment? comment
= create_comment (element
.comment
);
1288 Api
.Signal node
= new Api
.Signal (parent
,
1291 get_access_modifier (element
),
1293 get_cname (element
),
1294 (element
.default_handler
!= null)?
get_cname (element
.default_handler
) : null,
1295 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1296 Vala
.GDBusModule
.is_dbus_visible (element
),
1299 node
.return_type
= create_type_reference (element
.return_type
, node
, node
);
1300 symbol_map
.set (element
, node
);
1301 parent
.add_child (node
);
1303 process_attributes (node
, element
.attributes
);
1304 process_children (node
, element
);
1310 public override void visit_delegate (Vala
.Delegate element
) {
1311 Api
.Node parent
= get_parent_node_for (element
);
1312 SourceFile? file
= get_source_file (element
);
1313 SourceComment? comment
= create_comment (element
.comment
);
1315 Delegate node
= new
Delegate (parent
,
1318 get_access_modifier (element
),
1320 get_cname (element
),
1321 !element
.has_target
,
1323 node
.return_type
= create_type_reference (element
.return_type
, node
, node
);
1324 symbol_map
.set (element
, node
);
1325 parent
.add_child (node
);
1327 process_attributes (node
, element
.attributes
);
1328 process_children (node
, element
);
1334 public override void visit_enum (Vala
.Enum element
) {
1335 Api
.Node parent
= get_parent_node_for (element
);
1336 SourceFile? file
= get_source_file (element
);
1337 SourceComment? comment
= create_comment (element
.comment
);
1339 Symbol node
= new
Enum (parent
,
1342 get_access_modifier (element
),
1344 get_cname (element
),
1345 get_type_macro_name (element
),
1346 get_type_function_name (element
),
1348 symbol_map
.set (element
, node
);
1349 parent
.add_child (node
);
1351 process_attributes (node
, element
.attributes
);
1352 process_children (node
, element
);
1358 public override void visit_enum_value (Vala
.EnumValue element
) {
1359 Api
.Enum parent
= (Enum
) get_parent_node_for (element
);
1360 SourceFile? file
= get_source_file (element
);
1361 SourceComment? comment
= create_comment (element
.comment
);
1363 Symbol node
= new Api
.EnumValue (parent
,
1367 get_cname (element
),
1369 symbol_map
.set (element
, node
);
1370 parent
.add_child (node
);
1372 process_attributes (node
, element
.attributes
);
1373 process_children (node
, element
);
1379 public override void visit_constant (Vala
.Constant element
) {
1380 Api
.Node parent
= get_parent_node_for (element
);
1381 SourceFile? file
= get_source_file (element
);
1382 SourceComment? comment
= create_comment (element
.comment
);
1384 Constant node
= new
Constant (parent
,
1387 get_access_modifier (element
),
1389 get_cname (element
),
1391 node
.constant_type
= create_type_reference (element
.type_reference
, node
, node
);
1392 symbol_map
.set (element
, node
);
1393 parent
.add_child (node
);
1395 process_attributes (node
, element
.attributes
);
1396 process_children (node
, element
);
1402 public override void visit_error_domain (Vala
.ErrorDomain element
) {
1403 Api
.Node parent
= get_parent_node_for (element
);
1404 SourceFile? file
= get_source_file (element
);
1405 SourceComment? comment
= create_comment (element
.comment
);
1407 Symbol node
= new
ErrorDomain (parent
,
1410 get_access_modifier (element
),
1412 get_cname (element
),
1413 get_quark_macro_name (element
),
1414 get_quark_function_name (element
),
1415 Vala
.GDBusModule
.get_dbus_name (element
),
1417 symbol_map
.set (element
, node
);
1418 parent
.add_child (node
);
1420 process_attributes (node
, element
.attributes
);
1421 process_children (node
, element
);
1427 public override void visit_error_code (Vala
.ErrorCode element
) {
1428 Api
.ErrorDomain parent
= (ErrorDomain
) get_parent_node_for (element
);
1429 SourceFile? file
= get_source_file (element
);
1431 file
= parent
.get_source_file ();
1434 SourceComment? comment
= create_comment (element
.comment
);
1436 Symbol node
= new Api
.ErrorCode (parent
,
1440 get_cname (element
),
1441 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1443 symbol_map
.set (element
, node
);
1444 parent
.add_child (node
);
1446 process_attributes (node
, element
.attributes
);
1447 process_children (node
, element
);
1453 public override void visit_type_parameter (Vala
.TypeParameter element
) {
1454 Api
.Node parent
= get_parent_node_for (element
);
1455 SourceFile? file
= get_source_file (element
);
1457 Symbol node
= new
TypeParameter (parent
,
1461 symbol_map
.set (element
, node
);
1462 parent
.add_child (node
);
1464 process_children (node
, element
);
1470 public override void visit_formal_parameter (Vala
.Parameter element
) {
1471 Api
.Node parent
= get_parent_node_for (element
);
1472 SourceFile? file
= get_source_file (element
);
1474 FormalParameter node
= new
FormalParameter (parent
,
1477 get_access_modifier(element
),
1478 get_formal_parameter_type (element
),
1481 node
.parameter_type
= create_type_reference (element
.variable_type
, node
, node
);
1482 parent
.add_child (node
);
1484 process_children (node
, element
);
1492 public Api
.Tree?
build (Settings settings
, ErrorReporter reporter
) {
1493 this
.settings
= settings
;
1494 this
.reporter
= reporter
;
1496 var context
= new Vala
.CodeContext ();
1497 Vala
.CodeContext
.push (context
);
1499 this
.tree
= new Api
.Tree (reporter
, settings
, context
);
1500 create_valac_tree (context
, settings
);
1502 reporter
.warnings_offset
= context
.report
.get_warnings ();
1503 reporter
.errors_offset
= context
.report
.get_errors ();
1505 // TODO: Register all packages here
1506 // register packages included by gir-files
1507 foreach (Vala
.SourceFile vfile
in context
.get_source_files ()) {
1508 if (vfile
.file_type
== Vala
.SourceFileType
.PACKAGE
1509 && vfile
.get_nodes ().size
> 0
1510 && files
.contains (vfile
) == false)
1512 Package vdpkg
= new
Package (get_package_name (vfile
.filename
), true, null);
1513 register_source_file (register_package (vdpkg
), vfile
);
1517 context
.accept(this
);
1519 return (reporter
.errors
== 0)? tree
: null;