vapi: Update GIR-based bindings
[vala-gnome.git] / valadoc / treebuilder.vala
blob4c4cd02cffa0268a019daf38c3edcd3c832e301d
1 /* treebuilder.vala
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
19 * Author:
20 * Florian Brosch <flo.brosch@gmail.com>
24 using Valadoc.Api;
26 /**
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;
46 // Accessors
49 public Api.Class get_glib_error () {
50 return glib_error;
53 public Vala.HashMap<Vala.Symbol, Symbol> get_symbol_map () {
54 return 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);
73 if (ns != null) {
74 return ns;
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)
84 ) {
85 Vala.SourceReference pos = c.source_reference;
86 if (c is Vala.GirComment) {
87 comment = new GirSourceComment (c.content,
88 file,
89 pos.begin.line,
90 pos.begin.column,
91 pos.end.line,
92 pos.end.column);
93 } else {
94 comment = new SourceComment (c.content,
95 file,
96 pos.begin.line,
97 pos.begin.column,
98 pos.end.line,
99 pos.end.column);
101 break;
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);
112 } else {
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);
119 return ns;
122 public void register_source_file (Vala.SourceFile file) {
123 files.add (file);
126 public bool is_package_for_file (Vala.SourceFile source_file) {
127 if (source_file.file_type == Vala.SourceFileType.SOURCE && !package.is_package) {
128 return true;
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);
148 } else {
149 ptr.data_type = create_type_reference (vntype, ptr, caller);
152 return ptr;
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);
161 } else {
162 arr.data_type = create_type_reference (vntype, arr, caller);
165 return arr;
168 private TypeReference create_type_reference (Vala.DataType? vtyperef, Item parent, Api.Node caller) {
169 bool is_nullable = vtyperef != null
170 && vtyperef.nullable
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,
180 ownership,
181 pass_ownership,
182 is_dynamic,
183 is_nullable,
184 signature,
185 vtyperef);
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,
195 // vtyperef);
198 // type parameters:
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);
206 return type_ref;
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",
219 "DestroysInstance",
220 "GenericAccessors",
221 "NoAccessorMethod",
222 "NoArrayLength",
223 "Experimental",
224 "Diagnostics",
225 "PrintfFormat",
226 "PointerType",
227 "ScanfFormat",
228 "ThreadLocal",
229 "SimpleType",
230 "HasEmitter",
231 "ModuleInit",
232 "NoWrapper",
233 "Immutable",
234 "ErrorBase",
235 "NoReturn",
236 "NoThrow",
237 "Compact",
238 "Assert",
239 "Flags"
242 string? tmp = "";
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 ()) {
301 return null;
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) {
309 return null;
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,
362 file,
363 pos.begin.line,
364 pos.begin.column,
365 pos.end.line,
366 pos.end.column);
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,
370 file,
371 return_pos.begin.line,
372 return_pos.begin.column,
373 return_pos.end.line,
374 return_pos.end.column);
377 Vala.MapIterator<string, Vala.Comment> it = ((Vala.GirComment) comment).parameter_iterator ();
378 while (it.next ()) {
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,
382 file,
383 param_pos.begin.line,
384 param_pos.begin.column,
385 param_pos.end.line,
386 param_pos.end.column);
387 tmp.add_parameter_content (it.get_key (), param_comment);
389 return tmp;
390 } else {
391 return new SourceComment (comment.content,
392 file,
393 pos.begin.line,
394 pos.begin.column,
395 pos.end.line,
396 pos.end.column);
400 return null;
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;
407 } else {
408 return element.parent_symbol.name + "." + element.name;
412 return 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) {
421 return null;
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) {
430 return null;
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) {
438 return null;
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)
460 return null;
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)
472 return null;
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);
484 } else {
485 return 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) {
500 return data;
504 return null;
507 private PackageMetaData register_package (Package package) {
508 PackageMetaData meta_data = new PackageMetaData (package);
509 tree.add_package (package);
510 packages.add (meta_data);
511 return 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 (),
518 source_file);
519 files.set (source_file, file);
521 meta_data.register_source_file (source_file);
522 return file;
525 private SourceFile? get_source_file (Vala.Symbol symbol) {
526 Vala.SourceReference source_ref = symbol.source_reference;
527 if (source_ref == null) {
528 return null;
531 SourceFile? file = files.get (source_ref.file);
532 assert (file != null);
533 return file;
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)) {
539 return pkg.package;
543 return null;
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;
592 default:
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) {
614 return false;
617 weak Vala.CodeNode? node = element.parent_node;
618 if (node == null) {
619 return false;
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;
629 return false;
632 private bool is_type_reference_unowned (Vala.DataType? element) {
633 if (element == null) {
634 return false;
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)
641 return false;
644 // FormalParameters are weak by default
645 return (element.parent_node is Vala.Parameter == false)
646 ? element.is_weak ()
647 : false;
650 private bool is_type_reference_owned (Vala.DataType? element) {
651 if (element == null) {
652 return false;
655 weak Vala.CodeNode parent = element.parent_node;
657 // parameter:
658 if (parent is Vala.Parameter) {
659 if (((Vala.Parameter)parent).direction != Vala.ParameterDirection.IN) {
660 return false;
662 return ((Vala.Parameter)parent).variable_type.value_owned;
665 return false;
668 private bool is_type_reference_weak (Vala.DataType? element) {
669 if (element == null) {
670 return false;
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)
677 return false;
680 // arrays are unowned, not weak
681 if (element is Vala.ArrayType) {
682 return false;
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)) {
747 return true;
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) {
755 return true;
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));
763 return false;
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);
774 return true;
777 private void add_deps (Vala.CodeContext context, string file_path, string pkg_name) {
778 if (FileUtils.test (file_path, FileTest.EXISTS)) {
779 try {
780 string deps_content;
781 ulong deps_len;
782 FileUtils.get_contents (file_path, out deps_content, out deps_len);
783 foreach (string dep in deps_content.split ("\n")) {
784 dep = dep.strip ();
785 if (dep != "") {
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) {
817 return;
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);
856 } else {
857 Vala.Report.error (null, "%s is not a supported source file type. Only .vala, .vapi, .gs, and .c files are supported.".printf (source));
859 } else {
860 Vala.Report.error (null, "%s not found".printf (source));
865 private Vala.CodeContext create_valac_tree (Settings settings) {
866 // init context:
867 var context = new Vala.CodeContext ();
868 Vala.CodeContext.push (context);
871 // settings:
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 (".");
881 } else {
882 context.basedir = Vala.CodeContext.realpath (settings.basedir);
885 if (settings.directory != null) {
886 context.directory = Vala.CodeContext.realpath (settings.directory);
887 } else {
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) {
910 int glib_major = 2;
911 int glib_minor = 40;
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));
933 // default packages
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) {
946 return context;
949 add_documented_files (context, settings.source_files);
950 if (reporter.errors > 0) {
951 return context;
955 // parse vala-code:
956 Vala.Parser parser = new Vala.Parser ();
958 parser.parse (context);
959 if (context.report.get_errors () > 0) {
960 return context;
963 // parse gir:
964 Vala.GirParser gir_parser = new Vala.GirParser ();
966 gir_parser.parse (context);
967 if (context.report.get_errors () > 0) {
968 return context;
973 // check context:
974 context.check ();
975 if (context.report.get_errors () > 0) {
976 return context;
979 return context;
985 // Valadoc tree creation:
988 private void process_children (Api.Node node, Vala.CodeNode element) {
989 Api.Node old_node = current_node;
990 current_node = 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) {
997 return current_node;
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);
1008 * {@inheritDoc}
1010 public override void visit_namespace (Vala.Namespace element) {
1011 element.accept_children (this);
1015 * {@inheritDoc}
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,
1025 file,
1026 element.name,
1027 get_access_modifier (element),
1028 comment,
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,
1050 is_basic_type,
1051 element);
1052 symbol_map.set (element, node);
1053 parent.add_child (node);
1055 // relations
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);
1069 // save GLib.Error
1070 if (glib_error == null && node.get_full_name () == "GLib.Error") {
1071 glib_error = node;
1076 * {@inheritDoc}
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,
1084 file,
1085 element.name,
1086 get_access_modifier (element),
1087 comment,
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),
1095 element);
1096 symbol_map.set (element, node);
1097 parent.add_child (node);
1099 // prerequisites:
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);
1104 } else {
1105 node.base_type = type_ref;
1109 process_attributes (node, element.attributes);
1110 process_children (node, element);
1114 * {@inheritDoc}
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,
1127 file,
1128 element.name,
1129 get_access_modifier (element),
1130 comment,
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),
1139 is_basic_type,
1140 element);
1141 symbol_map.set (element, node);
1142 parent.add_child (node);
1144 // parent type:
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);
1155 * {@inheritDoc}
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,
1163 file,
1164 element.name,
1165 get_access_modifier (element),
1166 comment,
1167 get_cname (element),
1168 element.binding == Vala.MemberBinding.STATIC,
1169 element.is_volatile,
1170 element);
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);
1180 * {@inheritDoc}
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,
1188 file,
1189 element.name,
1190 get_access_modifier (element),
1191 comment,
1192 element.nick,
1193 Vala.GDBusModule.get_dbus_name_for_member (element),
1194 Vala.GDBusModule.is_dbus_visible (element),
1195 get_property_binding_type (element),
1196 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,
1205 file,
1206 element.name,
1207 get_access_modifier (accessor),
1208 get_cname (accessor),
1209 get_property_accessor_type (accessor),
1210 get_property_ownership (accessor),
1211 accessor);
1214 if (element.set_accessor != null) {
1215 var accessor = element.set_accessor;
1216 node.setter = new PropertyAccessor (node,
1217 file,
1218 element.name,
1219 get_access_modifier (accessor),
1220 get_cname (accessor),
1221 get_property_accessor_type (accessor),
1222 get_property_ownership (accessor),
1223 accessor);
1226 process_attributes (node, element.attributes);
1227 process_children (node, element);
1231 * {@inheritDoc}
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,
1239 file,
1240 get_method_name (element),
1241 get_access_modifier (element),
1242 comment,
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),
1248 element.coroutine,
1249 Vala.GDBusModule.is_dbus_visible (element),
1250 element is Vala.CreationMethod,
1251 element);
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);
1261 * {@inheritDoc}
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,
1269 file,
1270 get_method_name (element),
1271 get_access_modifier (element),
1272 comment,
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),
1278 element.coroutine,
1279 Vala.GDBusModule.is_dbus_visible (element),
1280 element is Vala.CreationMethod,
1281 element);
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);
1291 * {@inheritDoc}
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,
1299 file,
1300 element.name,
1301 get_access_modifier (element),
1302 comment,
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),
1307 element.is_virtual,
1308 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);
1318 * {@inheritDoc}
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,
1326 file,
1327 element.name,
1328 get_access_modifier (element),
1329 comment,
1330 get_cname (element),
1331 !element.has_target,
1332 element);
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);
1342 * {@inheritDoc}
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,
1350 file,
1351 element.name,
1352 get_access_modifier (element),
1353 comment,
1354 get_cname (element),
1355 get_type_macro_name (element),
1356 get_type_function_name (element),
1357 element);
1358 symbol_map.set (element, node);
1359 parent.add_child (node);
1361 process_attributes (node, element.attributes);
1362 process_children (node, element);
1366 * {@inheritDoc}
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,
1374 file,
1375 element.name,
1376 comment,
1377 get_cname (element),
1378 element);
1379 symbol_map.set (element, node);
1380 parent.add_child (node);
1382 process_attributes (node, element.attributes);
1383 process_children (node, element);
1387 * {@inheritDoc}
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,
1395 file,
1396 element.name,
1397 get_access_modifier (element),
1398 comment,
1399 get_cname (element),
1400 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);
1410 * {@inheritDoc}
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,
1418 file,
1419 element.name,
1420 get_access_modifier (element),
1421 comment,
1422 get_cname (element),
1423 get_quark_macro_name (element),
1424 get_quark_function_name (element),
1425 Vala.GDBusModule.get_dbus_name (element),
1426 element);
1427 symbol_map.set (element, node);
1428 parent.add_child (node);
1430 process_attributes (node, element.attributes);
1431 process_children (node, element);
1435 * {@inheritDoc}
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);
1440 if (file == null) {
1441 file = parent.get_source_file ();
1444 SourceComment? comment = create_comment (element.comment);
1446 Symbol node = new Api.ErrorCode (parent,
1447 file,
1448 element.name,
1449 comment,
1450 get_cname (element),
1451 Vala.GDBusModule.get_dbus_name_for_member (element),
1452 element);
1453 symbol_map.set (element, node);
1454 parent.add_child (node);
1456 process_attributes (node, element.attributes);
1457 process_children (node, element);
1461 * {@inheritDoc}
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,
1468 file,
1469 element.name,
1470 element);
1471 symbol_map.set (element, node);
1472 parent.add_child (node);
1474 process_children (node, element);
1478 * {@inheritDoc}
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,
1485 file,
1486 element.name,
1487 get_access_modifier(element),
1488 get_formal_parameter_type (element),
1489 element.ellipsis,
1490 element);
1491 node.parameter_type = create_type_reference (element.variable_type, node, node);
1492 parent.add_child (node);
1494 process_children (node, element);
1499 // startpoint:
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) {
1514 return 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;