src/Palete/VapiParser.vala
authorAlan Knowles <alan@roojs.com>
Tue, 5 May 2015 11:36:31 +0000 (19:36 +0800)
committerAlan Knowles <alan@roojs.com>
Tue, 5 May 2015 11:36:31 +0000 (19:36 +0800)
src/Palete/VapiParser.vala

index 8ed4880..9e8de68 100644 (file)
+/* valadoc.vala
+ *
+ * Copyright (C) 2008-2014 Florian Brosch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Florian Brosch <flo.brosch@gmail.com>
+ */
 
+using GLib.Path;
+using Valadoc.Importer;
+using Valadoc;
+using Config;
+using Gee;
 
-// valac VapiParser.vala --pkg libvala-0.24 --pkg posix -o /tmp/treebuilder
 
-namespace Palete {
-        
-       private class PackageMetaData {
-               public  Valadoc.Api.Package  package;
-               public Gee.HashMap<Vala.Namespace, Valadoc.Api.Namespace> namespaces = new HashMap<Vala.Namespace, Valadoc.Api.Namespace> ();
-               public Gee.ArrayList<Vala.SourceFile> files = new ArrayList<Vala.SourceFile> ();
 
-               public PackageMetaData ( Valadoc.Api.Package  package) {
-                       this.package = package;
+public class ValaDoc : Object {
+       private static string wikidirectory = null;
+       private static string pkg_version = null;
+       private static string docletpath = null;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] pluginargs;
+       private static string gir_directory = null;
+       private static string directory = null;
+       private static string pkg_name = null;
+       private static string gir_name = null;
+       private static string gir_namespace = null;
+       private static string gir_version = null;
+       private static string driverpath = null;
+
+       private static bool add_inherited = false;
+       private static bool _protected = true;
+       private static bool _internal = false;
+       private static bool with_deps = false;
+       private static bool _private = false;
+       private static bool version = false;
+
+       private static bool verbose = false;
+       private static bool force = false;
+
+       private static string basedir = null;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] defines;
+       private static bool experimental;
+       private static bool experimental_non_null = false;
+       private static string profile;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] import_packages;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] import_directories;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] vapi_directories;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] metadata_directories;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] gir_directories;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] tsources;
+       [CCode (array_length = false, array_null_terminated = true)]
+       private static string[] packages;
+       static string target_glib;
+
+       private const GLib.OptionEntry[] options = {
+               { "directory", 'o', 0, OptionArg.FILENAME, ref directory, "Output directory", "DIRECTORY" },
+
+               { "basedir", 'b', 0, OptionArg.FILENAME, ref basedir, "Base source directory", "DIRECTORY" },
+               { "define", 'D', 0, OptionArg.STRING_ARRAY, ref defines, "Define SYMBOL", "SYMBOL..." },
+               { "profile", 0, 0, OptionArg.STRING, ref profile, "Use the given profile instead of the default", "PROFILE" },
+
+               { "enable-experimental", 0, 0, OptionArg.NONE, ref experimental, "Enable experimental features", null },
+               { "enable-experimental-non-null", 0, 0, OptionArg.NONE, ref experimental_non_null, "Enable experimental enhancements for non-null types", null },
+
+               { "metadatadir", 0, 0, OptionArg.FILENAME_ARRAY, ref metadata_directories, "Look for GIR .metadata files in DIRECTORY", "DIRECTORY..." },
+               { "girdir", 0, 0, OptionArg.FILENAME_ARRAY, ref gir_directories, "Look for .gir files in DIRECTORY", "DIRECTORY..." },
+               { "vapidir", 0, 0, OptionArg.FILENAME_ARRAY, ref vapi_directories, "Look for package bindings in DIRECTORY", "DIRECTORY..." },
+               { "pkg", 0, 0, OptionArg.STRING_ARRAY, ref packages, "Include binding for PACKAGE", "PACKAGE..." },
+
+               { "driver", 0, 0, OptionArg.STRING, ref driverpath, "Name of an driver or path to a custom driver", null },
+
+               { "importdir", 0, 0, OptionArg.FILENAME_ARRAY, ref import_directories, "Look for external documentation in DIRECTORY", "DIRECTORY..." },
+               { "import", 0, 0, OptionArg.STRING_ARRAY, ref import_packages, "Include binding for PACKAGE", "PACKAGE..." },
+
+               { "wiki", 0, 0, OptionArg.FILENAME, ref wikidirectory, "Wiki directory", "DIRECTORY" },
+
+               { "deps", 0, 0, OptionArg.NONE, ref with_deps, "Adds packages to the documentation", null },
+
+               { "doclet", 0, 0, OptionArg.STRING, ref docletpath, "Name of an included doclet or path to custom doclet", "PLUGIN"},
+               { "doclet-arg", 'X', 0, OptionArg.STRING_ARRAY, ref pluginargs, "Pass arguments to the doclet", "ARG" },
+
+               { "no-protected", 0, OptionFlags.REVERSE, OptionArg.NONE, ref _protected, "Removes protected elements from documentation", null },
+               { "internal", 0, 0, OptionArg.NONE, ref _internal, "Adds internal elements to documentation", null },
+               { "private", 0, 0, OptionArg.NONE, ref _private, "Adds private elements to documentation", null },
+
+               { "package-name", 0, 0, OptionArg.STRING, ref pkg_name, "package name", "NAME" },
+               { "package-version", 0, 0, OptionArg.STRING, ref pkg_version, "package version", "VERSION" },
+               { "gir", 0, 0, OptionArg.STRING, ref gir_name, "GObject-Introspection repository file name", "NAME-VERSION.gir" },
+
+               { "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null },
+
+               { "force", 0, 0, OptionArg.NONE, ref force, "force", null },
+               { "verbose", 0, 0, OptionArg.NONE, ref verbose, "Show all warnings", null },
+               { "target-glib", 0, 0, OptionArg.STRING, ref target_glib, "Target version of glib for code generation", "MAJOR.MINOR" },
+               { "", 0, 0, OptionArg.FILENAME_ARRAY, ref tsources, null, "FILE..." },
+
+               { null }
+       };
+
+       private static int quit (ErrorReporter reporter) {
+               if (reporter.errors == 0) {
+                       stdout.printf ("Succeeded - %d warning(s)\n", reporter.warnings);
+                       return 0;
+               } else {
+                       stdout.printf ("Failed: %d error(s), %d warning(s)\n", reporter.errors, reporter.warnings);
+                       return 1;
                }
+       }
 
-               public Namespace get_namespace (Vala.Namespace vns, SourceFile file) {
-                       Namespace? ns = namespaces.get (vns);
-                       if (ns != null) {
-                               return ns;
-                       }
+       private static bool check_pkg_name () {
+               if (pkg_name == null) {
+                       return true;
+               }
 
-                       // find documentation comment if existing:
-                       /*
-                       SourceComment? comment = null;
-                       if (vns.source_reference != null) {
-                               foreach (Vala.Comment c in vns.get_comments()) {
-                                       if (c.source_reference.file == file.data ||
-                                               (c.source_reference.file.file_type == Vala.SourceFileType.SOURCE
-                                                && ((Vala.SourceFile) file.data).file_type == Vala.SourceFileType.SOURCE)
-                                       ) {
-                                               Vala.SourceReference pos = c.source_reference;
-                                               if (c is Vala.GirComment) {
-                                                       comment = new GirSourceComment (c.content,
-                                                                                                                       file,
-                                                                                                                       pos.begin.line,
-                                                                                                                       pos.begin.column,
-                                                                                                                       pos.end.line,
-                                                                                                                       pos.end.column);
-                                               } else {
-                                                       comment = new SourceComment (c.content,
-                                                                                                                file,
-                                                                                                                pos.begin.line,
-                                                                                                                pos.begin.column,
-                                                                                                                pos.end.line,
-                                                                                                                pos.end.column);
-                                               }
-                                               break;
-                                       }
-                               }
-                       }
-                       * */
+               if (pkg_name == "glib-2.0" || pkg_name == "gobject-2.0") {
+                       return false;
+               }
 
-                       // find parent if existing
-                       var parent_vns = vns.parent_symbol;
+               foreach (string package in tsources) {
+                       if (pkg_name == package) {
+                               return false;
+                       }
+               }
+               return true;
+       }
 
-                       if (parent_vns == null) {
-                               ns = new Namespace (package, file, vns.name, comment, vns);
-                               package.add_child (ns);
+       private string get_pkg_name () {
+               if (ValaDoc.pkg_name == null) {
+                       if (ValaDoc.directory.has_suffix ("/")) {
+                               ValaDoc.pkg_name = GLib.Path.get_dirname (ValaDoc.directory);
                        } else {
-                               Namespace parent_ns = get_namespace ((Vala.Namespace) parent_vns, file);
-                               ns = new Namespace (parent_ns, file, vns.name, comment, vns);
-                               parent_ns.add_child (ns);
+                               ValaDoc.pkg_name = GLib.Path.get_basename (ValaDoc.directory);
                        }
+               }
+
+               return ValaDoc.pkg_name;
+       }
+
+       private ModuleLoader? create_module_loader (ErrorReporter reporter, out Doclet? doclet, out Driver? driver) {
+               ModuleLoader modules = ModuleLoader.get_instance ();
+
+               doclet = null;
+               driver = null;
+               print("docletpath %s", docletpath);
+               // doclet:
+               string? pluginpath = ModuleLoader.get_doclet_path (docletpath, reporter);
+               if (pluginpath == null) {
+                       return null;
+               }
 
-                       namespaces.set (vns, ns);
-                       return ns;
+               doclet = modules.create_doclet (pluginpath);
+               if (doclet == null) {
+                       reporter.simple_error ("error: failed to load doclet");
+                       return null;
                }
 
-               public void register_source_file (Vala.SourceFile file) {
-                       files.add (file);
+
+               // driver:
+               pluginpath = ModuleLoader.get_driver_path (driverpath, reporter);
+               if (pluginpath == null) {
+                       return null;
                }
 
-               public bool is_package_for_file (Vala.SourceFile source_file) {
-                       if (source_file.file_type == Vala.SourceFileType.SOURCE && !package.is_package) {
-                               return true;
+               driver = modules.create_driver (pluginpath);
+               if (driver == null) {
+                       reporter.simple_error ("error: failed to load driver");
+                       return null;
+               }
+
+               assert (driver != null && doclet != null);
+
+               return modules;
+       }
+
+       private int run (ErrorReporter reporter) {
+               // settings:
+               var settings = new Valadoc.Settings ();
+               reporter.settings = settings;
+
+               settings.pkg_name = this.get_pkg_name ();
+               settings.gir_namespace = ValaDoc.gir_namespace;
+               settings.gir_version = ValaDoc.gir_version;
+               if (ValaDoc.gir_name != null) {
+                       settings.gir_name = GLib.Path.get_basename (ValaDoc.gir_name);
+                       settings.gir_directory = GLib.Path.get_dirname (ValaDoc.gir_name);
+                       if (settings.gir_directory == "") {
+                               settings.gir_directory = GLib.Path.get_dirname (ValaDoc.directory);
                        }
+               }
+               settings.pkg_version = ValaDoc.pkg_version;
+               settings.add_inherited = ValaDoc.add_inherited;
+               settings._protected = ValaDoc._protected;
+               settings._internal = ValaDoc._internal;
+               settings.with_deps = ValaDoc.with_deps;
+               settings._private = ValaDoc._private;
+               settings.path = realpath (ValaDoc.directory);
+               settings.verbose = ValaDoc.verbose;
+               settings.wiki_directory = ValaDoc.wikidirectory;
+               settings.pluginargs = ValaDoc.pluginargs;
+
+               settings.experimental = experimental;
+               settings.experimental_non_null = experimental_non_null;
+               settings.basedir = basedir;
+               settings.directory = directory;
+               settings.vapi_directories = vapi_directories;
+               settings.metadata_directories = metadata_directories;
+               settings.gir_directories = gir_directories;
+               settings.target_glib = target_glib;
+
+               settings.source_files = tsources;
+               settings.packages = packages;
+
+               settings.profile = profile;
+               settings.defines = defines;
+
+
+               // load plugins:
+               Doclet? doclet = null;
+               Driver? driver = null;
 
-                       return files.contains (source_file);
+               ModuleLoader? modules = create_module_loader (reporter, out doclet, out driver);
+               if (reporter.errors > 0 || modules == null) {
+                       return quit (reporter);
                }
+
+
+               // Create tree:
+               Valadoc.Api.Tree doctree = driver.build (settings, reporter);
+               if (reporter.errors > 0) {
+                       driver = null;
+                       doclet = null;
+                       return quit (reporter);
+               }
+
+               // register child symbols:
+               Valadoc.Api.ChildSymbolRegistrar registrar = new Valadoc.Api.ChildSymbolRegistrar ();
+               doctree.accept (registrar);
+
+               // process documentation
+               Valadoc.DocumentationParser docparser = new Valadoc.DocumentationParser (settings, reporter, doctree, modules);
+               if (!doctree.create_tree()) {
+                       return quit (reporter);
+               }
+
+               DocumentationImporter[] importers = {
+                       new ValadocDocumentationImporter (doctree, docparser, modules, settings, reporter),
+                       new GirDocumentationImporter (doctree, docparser, modules, settings, reporter)
+               };
+
+               doctree.parse_comments (docparser);
+               if (reporter.errors > 0) {
+                       return quit (reporter);
+               }
+
+               doctree.import_comments (importers, import_packages, import_directories);
+               if (reporter.errors > 0) {
+                       return quit (reporter);
+               }
+
+               doctree.check_comments (docparser);
+               if (reporter.errors > 0) {
+                       return quit (reporter);
+               }
+
+               if (ValaDoc.gir_name != null) {
+                       driver.write_gir (settings, reporter);
+                       if (reporter.errors > 0) {
+                               return quit (reporter);
+                       }
+               }
+
+               doclet.process (settings, doctree, reporter);
+               return quit (reporter);
        }
 
-        
-
-       public class VapiParser : Vala.CodeVisitor {
-               private ArrayList<PackageMetaData> packages = new ArrayList<PackageMetaData> ();
-               Vala.CodeContext context;
-               public VapiParser() {
-                       base();
-                       
-               }
-               private PackageMetaData register_package (Package package) {
-                       PackageMetaData meta_data = new PackageMetaData (package);
-                       tree.add_package (package);
-                       packages.add (meta_data);
-                       return meta_data;
-               }
-
-               
-               public void checkPackage(string name)
-               {
-                       // init context:
-                       context = new Vala.CodeContext ();
-                       Vala.CodeContext.push (context);
-               
-                       context.experimental = false;
-                       context.experimental_non_null = false;
-                       
-#if VALA_0_28
-                       var ver=28;
-#elif VALA_0_26        
-                       var ver=26;
-#elif VALA_0_24
-                       var ver=24;
-#elif VALA_0_22        
-                       var ver=22;
-#endif
-                       
-                       for (int i = 2; i <= ver; i += 2) {
-                               context.add_define ("VALA_0_%d".printf (i));
+       static int main (string[] args) {
+               ErrorReporter reporter = new ErrorReporter();
+
+               try {
+                       var opt_context = new OptionContext ("- Vala Documentation Tool");
+                       opt_context.set_help_enabled (true);
+                       opt_context.add_main_entries (options, null);
+                       opt_context.parse (ref args);
+               } catch (OptionError e) {
+                       reporter.simple_error ("error: %s", e.message);
+                       stdout.printf ("Run '%s --help' to see a full list of available command line options.\n", args[0]);
+                       return quit (reporter);
+               }
+
+               if (version) {
+                       stdout.printf ("Valadoc %s\n", Config.version);
+                       return 0;
+               }
+
+               if (directory == null) {
+                       reporter.simple_error ("error: No output directory specified.");
+                       return quit (reporter);
+               }
+
+               if (!check_pkg_name ()) {
+                       reporter.simple_error ("error: File already exists");
+                       return quit (reporter);
+               }
+
+               if (FileUtils.test (directory, FileTest.EXISTS)) {
+                       if (force == true) {
+                               bool tmp = remove_directory (directory);
+                               if (tmp == false) {
+                                       reporter.simple_error ("error: Can't remove directory.");
+                                       return quit (reporter);
+                               }
+                       } else {
+                               reporter.simple_error ("error: File already exists");
+                               return quit (reporter);
                        }
-                       
-                        
-                       //var vapidirs = ((Project.Gtk)this.file.project).vapidirs();
-                       // what's the current version of vala???
-                       
-                       
-                       //vapidirs +=  Path.get_dirname (context.get_vapi_path("glib-2.0")) ;
-                       
-                       //for(var i =0 ; i < vapidirs.length; i++) {
-                       //      valac += " --vapidir=" + vapidirs[i];
-                       //}
-                               
-                       
-                       // or context.get_vapi_path("glib-2.0"); // should return path..
-                       //context.vapi_directories = vapidirs;
-                       context.report.enable_warnings = true;
-                       context.metadata_directories = { };
-                       context.gir_directories = {};
-                       context.thread = true;
-                       
-                       
-                       //this.report = new ValaSourceReport(this.file);
-                       //context.report = this.report;
-                       
-                       
-                       context.basedir = "/tmp"; //Posix.realpath (".");
-               
-                       context.directory = context.basedir;
-               
-
-                       // add default packages:
-                       //if (settings.profile == "gobject-2.0" || settings.profile == "gobject" || settings.profile == null) {
-                       context.profile = Vala.Profile.GOBJECT;
-                        
-                       var ns_ref = new Vala.UsingDirective (new Vala.UnresolvedSymbol (null, "GLib", null));
-                       context.root.add_using_directive (ns_ref);
-                       // default.. packages..
-                       context.add_external_package ("glib-2.0"); 
-                       context.add_external_package ("gobject-2.0");
-                       // user defined ones..
-                       context.add_package ("Gtk");
-                 
-                       var vfile = new Vala.SourceFile (context, Vala.SourceFileType.PACKAGE, "/usr/share/vala-0.26/vapi/gtk+-3.0.vapi");
-                       context.add_source_file (vfile);
-                       Package vdpkg = new Package (pkg, true, null);
-                       register_source_file (register_package (vdpkg), vfile);
-                       
-                       //context.add_external_package ("libvala-0.24");
-                       
-                        
-               
-                       //add_documented_files (context, settings.source_files);
-               
-                       Vala.Parser parser = new Vala.Parser ();
-                       parser.parse (context);
-                       //gir_parser.parse (context);
-                       if (context.report.get_errors () > 0) {
-                               print("parse got errors");
-                                
-                               
-                               Vala.CodeContext.pop ();
-                               return ;
+               }
+
+               if (wikidirectory != null) {
+                       if (!FileUtils.test(wikidirectory, FileTest.IS_DIR)) {
+                               reporter.simple_error ("error: Wiki-directory does not exist.");
+                               return quit (reporter);
                        }
+               }
 
+               if (gir_name != null) {
+                       long gir_len = gir_name.length;
+                       int last_hyphen = gir_name.last_index_of_char ('-');
 
-                       
-                       // check context:
-                       context.check ();
-                       if (context.report.get_errors () > 0) {
-                               print("check got errors");
-                                
-                               Vala.CodeContext.pop ();
-                                
-                               return;
-                               
+                       if (last_hyphen == -1 || !gir_name.has_suffix (".gir")) {
+                               reporter.simple_error ("error: GIR file name `%s' is not well-formed, expected NAME-VERSION.gir", gir_name);
+                               return quit (reporter);
                        }
-                        
-                       Vala.CodeContext.pop ();
-                        
-                       print("%s\n", valac);
-                       print("ALL OK?\n");
-                
-               }
-       //
-               // startpoint:
-               //
-        
-       }
-}
-int main (string[] args) {
 
-       var a = new VapiParser(file);
-       a.create_valac_tree();
-       return 0;
-}
-*/
+                       gir_namespace = gir_name.substring (0, last_hyphen);
+                       gir_version = gir_name.substring (last_hyphen + 1, gir_len - last_hyphen - 5);
+                       gir_version.canon ("0123456789.", '?');
 
+                       if (gir_namespace == "" || gir_version == "" || !gir_version[0].isdigit () || gir_version.contains ("?")) {
+                               reporter.simple_error ("error: GIR file name `%s' is not well-formed, expected NAME-VERSION.gir", gir_name);
+                               return quit (reporter);
+                       }
+
+
+                       bool report_warning = true;
+                       foreach (string source in tsources) {
+                               if (source.has_suffix (".vala") || source.has_suffix (".gs")) {
+                                       report_warning = false;
+                                       break;
+                               }
+                       }
+
+                       if (report_warning == true) {
+                               reporter.simple_error ("error: No source file specified to be compiled to gir.");
+                               return quit (reporter);
+                       }
+               }
+
+               var valadoc = new ValaDoc( );
+               return valadoc.run (reporter);
+       }
+}