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_type_reference (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 Vala
.CodeContext
create_valac_tree (Settings settings
) {
867 var context
= new Vala
.CodeContext ();
868 Vala
.CodeContext
.push (context
);
872 context
.experimental
= settings
.experimental
;
873 context
.experimental_non_null
= settings
.experimental
|| settings
.experimental_non_null
;
874 context
.vapi_directories
= settings
.vapi_directories
;
875 context
.report
.enable_warnings
= settings
.verbose
;
876 context
.metadata_directories
= settings
.metadata_directories
;
877 context
.gir_directories
= settings
.gir_directories
;
879 if (settings
.basedir
== null) {
880 context
.basedir
= Vala
.CodeContext
.realpath (".");
882 context
.basedir
= Vala
.CodeContext
.realpath (settings
.basedir
);
885 if (settings
.directory
!= null) {
886 context
.directory
= Vala
.CodeContext
.realpath (settings
.directory
);
888 context
.directory
= context
.basedir
;
892 // add default packages:
893 if (settings
.profile
== "gobject-2.0" || settings
.profile
== "gobject" || settings
.profile
== null) {
894 context
.profile
= Vala
.Profile
.GOBJECT
;
895 context
.add_define ("GOBJECT");
899 if (settings
.defines
!= null) {
900 foreach (string define
in settings
.defines
) {
901 context
.add_define (define
);
905 for (int i
= 2; i
<= 42; i
+= 2) {
906 context
.add_define ("VALA_0_%d".printf (i
));
909 if (context
.profile
== Vala
.Profile
.GOBJECT
) {
913 context
.target_glib_major
= glib_major
;
914 context
.target_glib_minor
= glib_minor
;
915 if (context
.target_glib_major
!= 2) {
916 Vala
.Report
.error (null, "This version of valac only supports GLib 2");
919 if (settings
.target_glib
!= null && settings
.target_glib
.scanf ("%d.%d", out glib_major
, out glib_minor
) != 2) {
920 Vala
.Report
.error (null, "Invalid format for --target-glib");
923 context
.target_glib_major
= glib_major
;
924 context
.target_glib_minor
= glib_minor
;
925 if (context
.target_glib_major
!= 2) {
926 Vala
.Report
.error (null, "This version of valac only supports GLib 2");
929 for (int i
= 16; i
<= glib_minor
; i
+= 2) {
930 context
.add_define ("GLIB_2_%d".printf (i
));
934 if (!this
.add_package (context
, "glib-2.0")) { //
935 Vala
.Report
.error (null, "glib-2.0 not found in specified Vala API directories");
938 if (!this
.add_package (context
, "gobject-2.0")) { //
939 Vala
.Report
.error (null, "gobject-2.0 not found in specified Vala API directories");
943 // add user defined files:
944 add_depencies (context
, settings
.packages
);
945 if (reporter
.errors
> 0) {
949 add_documented_files (context
, settings
.source_files
);
950 if (reporter
.errors
> 0) {
956 Vala
.Parser parser
= new Vala
.Parser ();
958 parser
.parse (context
);
959 if (context
.report
.get_errors () > 0) {
964 Vala
.GirParser gir_parser
= new Vala
.GirParser ();
966 gir_parser
.parse (context
);
967 if (context
.report
.get_errors () > 0) {
975 if (context
.report
.get_errors () > 0) {
985 // Valadoc tree creation:
988 private void process_children (Api
.Node node
, Vala
.CodeNode element
) {
989 Api
.Node old_node
= current_node
;
991 element
.accept_children (this
);
992 current_node
= old_node
;
995 private Api
.Node
get_parent_node_for (Vala
.Symbol element
) {
996 if (current_node
!= null) {
1000 Vala
.SourceFile vala_source_file
= element
.source_reference
.file
;
1001 Package package
= find_package_for_file (vala_source_file
);
1002 SourceFile? source_file
= get_source_file (element
);
1004 return get_namespace (package
, element
, source_file
);
1010 public override void visit_namespace (Vala
.Namespace element
) {
1011 element
.accept_children (this
);
1017 public override void visit_class (Vala
.Class element
) {
1018 Api
.Node parent
= get_parent_node_for (element
);
1019 SourceFile? file
= get_source_file (element
);
1020 SourceComment? comment
= create_comment (element
.comment
);
1022 bool is_basic_type
= element
.base_class
== null && element
.name
== "string";
1024 Class node
= new
Class (parent
,
1027 get_access_modifier (element
),
1029 get_cname (element
),
1030 get_private_cname (element
),
1031 get_class_macro_name (element
),
1032 get_type_macro_name (element
),
1033 get_is_type_macro_name (element
),
1034 get_type_cast_macro_name (element
),
1035 get_type_function_name (element
),
1036 get_class_type_macro_name (element
),
1037 get_is_class_type_macro_name (element
),
1038 Vala
.GDBusModule
.get_dbus_name (element
),
1039 get_ccode_type_id (element
),
1040 get_param_spec_function (element
),
1041 get_ref_function (element
),
1042 get_unref_function (element
),
1043 get_free_function_name (element
),
1044 get_finalize_function_name (element
),
1045 get_take_value_function (element
),
1046 get_get_value_function (element
),
1047 get_set_value_function (element
),
1048 element
.is_fundamental (),
1049 element
.is_abstract
,
1052 symbol_map
.set (element
, node
);
1053 parent
.add_child (node
);
1056 foreach (Vala
.DataType vala_type_ref
in element
.get_base_types ()) {
1057 var type_ref
= create_type_reference (vala_type_ref
, node
, node
);
1059 if (vala_type_ref
.data_type is Vala
.Interface
) {
1060 node
.add_interface (type_ref
);
1061 } else if (vala_type_ref
.data_type is Vala
.Class
) {
1062 node
.base_type
= type_ref
;
1066 process_attributes (node
, element
.attributes
);
1067 process_children (node
, element
);
1070 if (glib_error
== null && node
.get_full_name () == "GLib.Error") {
1078 public override void visit_interface (Vala
.Interface element
) {
1079 Api
.Node parent
= get_parent_node_for (element
);
1080 SourceFile? file
= get_source_file (element
);
1081 SourceComment? comment
= create_comment (element
.comment
);
1083 Interface node
= new
Interface (parent
,
1086 get_access_modifier (element
),
1088 get_cname (element
),
1089 get_type_macro_name (element
),
1090 get_is_type_macro_name (element
),
1091 get_type_cast_macro_name (element
),
1092 get_type_function_name (element
),
1093 get_interface_macro_name (element
),
1094 Vala
.GDBusModule
.get_dbus_name (element
),
1096 symbol_map
.set (element
, node
);
1097 parent
.add_child (node
);
1100 foreach (Vala
.DataType vala_type_ref
in element
.get_prerequisites ()) {
1101 TypeReference type_ref
= create_type_reference (vala_type_ref
, node
, node
);
1102 if (vala_type_ref
.data_type is Vala
.Interface
) {
1103 node
.add_interface (type_ref
);
1105 node
.base_type
= type_ref
;
1109 process_attributes (node
, element
.attributes
);
1110 process_children (node
, element
);
1116 public override void visit_struct (Vala
.Struct element
) {
1117 Api
.Node parent
= get_parent_node_for (element
);
1118 SourceFile? file
= get_source_file (element
);
1119 SourceComment? comment
= create_comment (element
.comment
);
1121 bool is_basic_type
= element
.base_type
== null
1122 && (element
.is_boolean_type ()
1123 || element
.is_floating_type ()
1124 || element
.is_integer_type ());
1126 Struct node
= new
Struct (parent
,
1129 get_access_modifier (element
),
1131 get_cname (element
),
1132 get_type_macro_name (element
),
1133 get_type_function_name (element
),
1134 get_ccode_type_id (element
),
1135 get_dup_function (element
),
1136 get_copy_function (element
),
1137 get_destroy_function (element
),
1138 get_free_function (element
),
1141 symbol_map
.set (element
, node
);
1142 parent
.add_child (node
);
1145 Vala
.ValueType? basetype
= element
.base_type as Vala
.ValueType
;
1146 if (basetype
!= null) {
1147 node
.base_type
= create_type_reference (basetype
, node
, node
);
1150 process_attributes (node
, element
.attributes
);
1151 process_children (node
, element
);
1157 public override void visit_field (Vala
.Field element
) {
1158 Api
.Node parent
= get_parent_node_for (element
);
1159 SourceFile? file
= get_source_file (element
);
1160 SourceComment? comment
= create_comment (element
.comment
);
1162 Field node
= new
Field (parent
,
1165 get_access_modifier (element
),
1167 get_cname (element
),
1168 element
.binding
== Vala
.MemberBinding
.STATIC
,
1169 element
.is_volatile
,
1171 node
.field_type
= create_type_reference (element
.variable_type
, node
, node
);
1172 symbol_map
.set (element
, node
);
1173 parent
.add_child (node
);
1175 process_attributes (node
, element
.attributes
);
1176 process_children (node
, element
);
1182 public override void visit_property (Vala
.Property element
) {
1183 Api
.Node parent
= get_parent_node_for (element
);
1184 SourceFile? file
= get_source_file (element
);
1185 SourceComment? comment
= create_comment (element
.comment
);
1187 Property node
= new
Property (parent
,
1190 get_access_modifier (element
),
1193 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1194 Vala
.GDBusModule
.is_dbus_visible (element
),
1195 get_property_binding_type (element
),
1197 node
.property_type
= create_type_reference (element
.property_type
, node
, node
);
1198 symbol_map
.set (element
, node
);
1199 parent
.add_child (node
);
1201 // Process property type
1202 if (element
.get_accessor
!= null) {
1203 var accessor
= element
.get_accessor
;
1204 node
.getter
= new
PropertyAccessor (node
,
1207 get_access_modifier (accessor
),
1208 get_cname (accessor
),
1209 get_property_accessor_type (accessor
),
1210 get_property_ownership (accessor
),
1214 if (element
.set_accessor
!= null) {
1215 var accessor
= element
.set_accessor
;
1216 node
.setter
= new
PropertyAccessor (node
,
1219 get_access_modifier (accessor
),
1220 get_cname (accessor
),
1221 get_property_accessor_type (accessor
),
1222 get_property_ownership (accessor
),
1226 process_attributes (node
, element
.attributes
);
1227 process_children (node
, element
);
1233 public override void visit_creation_method (Vala
.CreationMethod element
) {
1234 Api
.Node parent
= get_parent_node_for (element
);
1235 SourceFile? file
= get_source_file (element
);
1236 SourceComment? comment
= create_comment (element
.comment
);
1238 Method node
= new
Method (parent
,
1240 get_method_name (element
),
1241 get_access_modifier (element
),
1243 get_cname (element
),
1244 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1245 Vala
.GDBusModule
.dbus_result_name (element
),
1246 (element
.coroutine
)?
get_finish_name (element
) : null,
1247 get_method_binding_type (element
),
1249 Vala
.GDBusModule
.is_dbus_visible (element
),
1250 element is Vala
.CreationMethod
,
1252 node
.return_type
= create_type_reference (element
.return_type
, node
, node
);
1253 symbol_map
.set (element
, node
);
1254 parent
.add_child (node
);
1256 process_attributes (node
, element
.attributes
);
1257 process_children (node
, element
);
1263 public override void visit_method (Vala
.Method element
) {
1264 Api
.Node parent
= get_parent_node_for (element
);
1265 SourceFile? file
= get_source_file (element
);
1266 SourceComment? comment
= create_comment (element
.comment
);
1268 Method node
= new
Method (parent
,
1270 get_method_name (element
),
1271 get_access_modifier (element
),
1273 get_cname (element
),
1274 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1275 Vala
.GDBusModule
.dbus_result_name (element
),
1276 (element
.coroutine
)?
get_finish_name (element
) : null,
1277 get_method_binding_type (element
),
1279 Vala
.GDBusModule
.is_dbus_visible (element
),
1280 element is Vala
.CreationMethod
,
1282 node
.return_type
= create_type_reference (element
.return_type
, node
, node
);
1283 symbol_map
.set (element
, node
);
1284 parent
.add_child (node
);
1286 process_attributes (node
, element
.attributes
);
1287 process_children (node
, element
);
1293 public override void visit_signal (Vala
.Signal element
) {
1294 Api
.Node parent
= get_parent_node_for (element
);
1295 SourceFile? file
= get_source_file (element
);
1296 SourceComment? comment
= create_comment (element
.comment
);
1298 Api
.Signal node
= new Api
.Signal (parent
,
1301 get_access_modifier (element
),
1303 get_cname (element
),
1304 (element
.default_handler
!= null)?
get_cname (element
.default_handler
) : null,
1305 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1306 Vala
.GDBusModule
.is_dbus_visible (element
),
1309 node
.return_type
= create_type_reference (element
.return_type
, node
, node
);
1310 symbol_map
.set (element
, node
);
1311 parent
.add_child (node
);
1313 process_attributes (node
, element
.attributes
);
1314 process_children (node
, element
);
1320 public override void visit_delegate (Vala
.Delegate element
) {
1321 Api
.Node parent
= get_parent_node_for (element
);
1322 SourceFile? file
= get_source_file (element
);
1323 SourceComment? comment
= create_comment (element
.comment
);
1325 Delegate node
= new
Delegate (parent
,
1328 get_access_modifier (element
),
1330 get_cname (element
),
1331 !element
.has_target
,
1333 node
.return_type
= create_type_reference (element
.return_type
, node
, node
);
1334 symbol_map
.set (element
, node
);
1335 parent
.add_child (node
);
1337 process_attributes (node
, element
.attributes
);
1338 process_children (node
, element
);
1344 public override void visit_enum (Vala
.Enum element
) {
1345 Api
.Node parent
= get_parent_node_for (element
);
1346 SourceFile? file
= get_source_file (element
);
1347 SourceComment? comment
= create_comment (element
.comment
);
1349 Symbol node
= new
Enum (parent
,
1352 get_access_modifier (element
),
1354 get_cname (element
),
1355 get_type_macro_name (element
),
1356 get_type_function_name (element
),
1358 symbol_map
.set (element
, node
);
1359 parent
.add_child (node
);
1361 process_attributes (node
, element
.attributes
);
1362 process_children (node
, element
);
1368 public override void visit_enum_value (Vala
.EnumValue element
) {
1369 Api
.Enum parent
= (Enum
) get_parent_node_for (element
);
1370 SourceFile? file
= get_source_file (element
);
1371 SourceComment? comment
= create_comment (element
.comment
);
1373 Symbol node
= new Api
.EnumValue (parent
,
1377 get_cname (element
),
1379 symbol_map
.set (element
, node
);
1380 parent
.add_child (node
);
1382 process_attributes (node
, element
.attributes
);
1383 process_children (node
, element
);
1389 public override void visit_constant (Vala
.Constant element
) {
1390 Api
.Node parent
= get_parent_node_for (element
);
1391 SourceFile? file
= get_source_file (element
);
1392 SourceComment? comment
= create_comment (element
.comment
);
1394 Constant node
= new
Constant (parent
,
1397 get_access_modifier (element
),
1399 get_cname (element
),
1401 node
.constant_type
= create_type_reference (element
.type_reference
, node
, node
);
1402 symbol_map
.set (element
, node
);
1403 parent
.add_child (node
);
1405 process_attributes (node
, element
.attributes
);
1406 process_children (node
, element
);
1412 public override void visit_error_domain (Vala
.ErrorDomain element
) {
1413 Api
.Node parent
= get_parent_node_for (element
);
1414 SourceFile? file
= get_source_file (element
);
1415 SourceComment? comment
= create_comment (element
.comment
);
1417 Symbol node
= new
ErrorDomain (parent
,
1420 get_access_modifier (element
),
1422 get_cname (element
),
1423 get_quark_macro_name (element
),
1424 get_quark_function_name (element
),
1425 Vala
.GDBusModule
.get_dbus_name (element
),
1427 symbol_map
.set (element
, node
);
1428 parent
.add_child (node
);
1430 process_attributes (node
, element
.attributes
);
1431 process_children (node
, element
);
1437 public override void visit_error_code (Vala
.ErrorCode element
) {
1438 Api
.ErrorDomain parent
= (ErrorDomain
) get_parent_node_for (element
);
1439 SourceFile? file
= get_source_file (element
);
1441 file
= parent
.get_source_file ();
1444 SourceComment? comment
= create_comment (element
.comment
);
1446 Symbol node
= new Api
.ErrorCode (parent
,
1450 get_cname (element
),
1451 Vala
.GDBusModule
.get_dbus_name_for_member (element
),
1453 symbol_map
.set (element
, node
);
1454 parent
.add_child (node
);
1456 process_attributes (node
, element
.attributes
);
1457 process_children (node
, element
);
1463 public override void visit_type_parameter (Vala
.TypeParameter element
) {
1464 Api
.Node parent
= get_parent_node_for (element
);
1465 SourceFile? file
= get_source_file (element
);
1467 Symbol node
= new
TypeParameter (parent
,
1471 symbol_map
.set (element
, node
);
1472 parent
.add_child (node
);
1474 process_children (node
, element
);
1480 public override void visit_formal_parameter (Vala
.Parameter element
) {
1481 Api
.Node parent
= get_parent_node_for (element
);
1482 SourceFile? file
= get_source_file (element
);
1484 FormalParameter node
= new
FormalParameter (parent
,
1487 get_access_modifier(element
),
1488 get_formal_parameter_type (element
),
1491 node
.parameter_type
= create_type_reference (element
.variable_type
, node
, node
);
1492 parent
.add_child (node
);
1494 process_children (node
, element
);
1502 public Api
.Tree?
build (Settings settings
, ErrorReporter reporter
) {
1503 this
.settings
= settings
;
1504 this
.reporter
= reporter
;
1506 this
.tree
= new Api
.Tree (reporter
, settings
);
1507 var context
= create_valac_tree (settings
);
1508 this
.tree
.data
= context
;
1510 reporter
.warnings_offset
= context
.report
.get_warnings ();
1511 reporter
.errors_offset
= context
.report
.get_errors ();
1513 if (context
== null) {
1517 // TODO: Register all packages here
1518 // register packages included by gir-files
1519 foreach (Vala
.SourceFile vfile
in context
.get_source_files ()) {
1520 if (vfile
.file_type
== Vala
.SourceFileType
.PACKAGE
1521 && vfile
.get_nodes ().size
> 0
1522 && files
.contains (vfile
) == false)
1524 Package vdpkg
= new
Package (get_package_name (vfile
.filename
), true, null);
1525 register_source_file (register_package (vdpkg
), vfile
);
1529 context
.accept(this
);
1531 return (reporter
.errors
== 0)? tree
: null;