From: Florian Brosch Date: Mon, 28 Nov 2011 16:11:49 +0000 (+0100) Subject: gir: basic reading support X-Git-Tag: 0.37.1~3^2~271 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dc6edfc736bb630b805d0c3f7afc6ca4768e605c;p=thirdparty%2Fvala.git gir: basic reading support --- diff --git a/src/doclets/htm/doclet.vala b/src/doclets/htm/doclet.vala index 23dec682a..7613f17bb 100755 --- a/src/doclets/htm/doclet.vala +++ b/src/doclets/htm/doclet.vala @@ -74,9 +74,9 @@ public class Valadoc.HtmlDoclet : Valadoc.Html.BasicDoclet { string path = GLib.Path.build_filename ( this.settings.path, pkg_name ); var rt = DirUtils.create (path, 0777); - rt = DirUtils.create (GLib.Path.build_filename ( path, "img" ), 0777); + rt = DirUtils.create (GLib.Path.build_filename (path, "img"), 0777); - GLib.FileStream file = GLib.FileStream.open (GLib.Path.build_filename ( path, "index.htm" ), "w"); + GLib.FileStream file = GLib.FileStream.open (GLib.Path.build_filename (path, "index.htm"), "w"); writer = new Html.MarkupWriter (file); _renderer.set_writer (writer); write_file_header (this.css_path, this.js_path, pkg_name); diff --git a/src/driver/0.10.x/treebuilder.vala b/src/driver/0.10.x/treebuilder.vala index c3543a52e..6bc66b4aa 100644 --- a/src/driver/0.10.x/treebuilder.vala +++ b/src/driver/0.10.x/treebuilder.vala @@ -271,7 +271,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { } private SourceFile register_source_file (PackageMetaData meta_data, Vala.SourceFile source_file) { - SourceFile file = new SourceFile (source_file.get_relative_filename (), source_file.get_csource_filename ()); + SourceFile file = new SourceFile (meta_data.package, source_file.get_relative_filename (), source_file.get_csource_filename ()); files.set (source_file, file); meta_data.register_source_file (source_file); diff --git a/src/driver/0.11.0/treebuilder.vala b/src/driver/0.11.0/treebuilder.vala index 6ebc8713a..ba51196ea 100644 --- a/src/driver/0.11.0/treebuilder.vala +++ b/src/driver/0.11.0/treebuilder.vala @@ -273,7 +273,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { } private SourceFile register_source_file (PackageMetaData meta_data, Vala.SourceFile source_file) { - SourceFile file = new SourceFile (source_file.get_relative_filename (), source_file.get_csource_filename ()); + SourceFile file = new SourceFile (meta_data.package, source_file.get_relative_filename (), source_file.get_csource_filename ()); files.set (source_file, file); meta_data.register_source_file (source_file); diff --git a/src/driver/0.11.x/treebuilder.vala b/src/driver/0.11.x/treebuilder.vala index f297a1eda..130a3ca71 100644 --- a/src/driver/0.11.x/treebuilder.vala +++ b/src/driver/0.11.x/treebuilder.vala @@ -224,7 +224,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { } private SourceFile register_source_file (PackageMetaData meta_data, Vala.SourceFile source_file) { - SourceFile file = new SourceFile (source_file.get_relative_filename (), source_file.get_csource_filename ()); + SourceFile file = new SourceFile (meta_data.package, source_file.get_relative_filename (), source_file.get_csource_filename ()); files.set (source_file, file); meta_data.register_source_file (source_file); diff --git a/src/driver/0.12.x/treebuilder.vala b/src/driver/0.12.x/treebuilder.vala index 455a0e67e..ac91568ff 100644 --- a/src/driver/0.12.x/treebuilder.vala +++ b/src/driver/0.12.x/treebuilder.vala @@ -273,7 +273,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { } private SourceFile register_source_file (PackageMetaData meta_data, Vala.SourceFile source_file) { - SourceFile file = new SourceFile (source_file.get_relative_filename (), source_file.get_csource_filename ()); + SourceFile file = new SourceFile (meta_data.package, source_file.get_relative_filename (), source_file.get_csource_filename ()); files.set (source_file, file); meta_data.register_source_file (source_file); diff --git a/src/driver/0.13.x/treebuilder.vala b/src/driver/0.13.x/treebuilder.vala index 9739d927c..9cfac5258 100644 --- a/src/driver/0.13.x/treebuilder.vala +++ b/src/driver/0.13.x/treebuilder.vala @@ -392,7 +392,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { } private SourceFile register_source_file (PackageMetaData meta_data, Vala.SourceFile source_file) { - SourceFile file = new SourceFile (source_file.get_relative_filename (), source_file.get_csource_filename ()); + SourceFile file = new SourceFile (meta_data.package, source_file.get_relative_filename (), source_file.get_csource_filename ()); files.set (source_file, file); meta_data.register_source_file (source_file); diff --git a/src/driver/0.14.x/Makefile.am b/src/driver/0.14.x/Makefile.am index a2c24a1de..b8bb5960d 100755 --- a/src/driver/0.14.x/Makefile.am +++ b/src/driver/0.14.x/Makefile.am @@ -2,8 +2,6 @@ NULL = VERSIONED_VAPI_DIR=`pkg-config libvala-0.14 --variable vapidir` - - AM_CFLAGS = -g \ -DPACKAGE_ICONDIR=\"$(datadir)/valadoc/icons/\" \ -I ../../libvaladoc/ \ diff --git a/src/driver/0.14.x/treebuilder.vala b/src/driver/0.14.x/treebuilder.vala index 691faddd4..daff9b253 100644 --- a/src/driver/0.14.x/treebuilder.vala +++ b/src/driver/0.14.x/treebuilder.vala @@ -326,7 +326,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { } private SourceFile register_source_file (PackageMetaData meta_data, Vala.SourceFile source_file) { - SourceFile file = new SourceFile (source_file.get_relative_filename (), source_file.get_csource_filename ()); + SourceFile file = new SourceFile (meta_data.package, source_file.get_relative_filename (), source_file.get_csource_filename ()); files.set (source_file, file); meta_data.register_source_file (source_file); diff --git a/src/driver/0.16.x/treebuilder.vala b/src/driver/0.16.x/treebuilder.vala index 7d523953f..512d7b18f 100644 --- a/src/driver/0.16.x/treebuilder.vala +++ b/src/driver/0.16.x/treebuilder.vala @@ -82,7 +82,11 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { foreach (Vala.Comment c in vns.get_comments()) { if (c.source_reference.file == vns.source_reference.file) { Vala.SourceReference pos = c.source_reference; - comment = new SourceComment (c.content, file, pos.first_line, pos.first_column, pos.last_line, pos.last_column); + if (c is Vala.GirComment) { + comment = new GirSourceComment (c.content, file, pos.first_line, pos.first_column, pos.last_line, pos.last_column); + } else { + comment = new SourceComment (c.content, file, pos.first_line, pos.first_column, pos.last_line, pos.last_column); + } break; } } @@ -290,7 +294,24 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { if (comment != null) { Vala.SourceReference pos = comment.source_reference; SourceFile file = files.get (pos.file); - return new SourceComment (comment.content, file, pos.first_line, pos.first_column, pos.last_line, pos.last_column); + if (comment is Vala.GirComment) { + var tmp = new GirSourceComment (comment.content, file, pos.first_line, pos.first_column, pos.last_line, pos.last_column); + if (((Vala.GirComment) comment).return_content != null) { + Vala.SourceReference return_pos = ((Vala.GirComment) comment).return_content.source_reference; + tmp.return_comment = new SourceComment (((Vala.GirComment) comment).return_content.content, file, return_pos.first_line, return_pos.first_column, return_pos.last_line, return_pos.last_column); + } + + Vala.MapIterator it = ((Vala.GirComment) comment).parameter_iterator (); + while (it.next ()) { + Vala.Comment vala_param = it.get_value (); + Vala.SourceReference param_pos = vala_param.source_reference; + var param_comment = new SourceComment (vala_param.content, file, param_pos.first_line, param_pos.first_column, param_pos.last_line, param_pos.last_column); + tmp.add_parameter_content (it.get_key (), param_comment); + } + return tmp; + } else { + return new SourceComment (comment.content, file, pos.first_line, pos.first_column, pos.last_line, pos.last_column); + } } return null; @@ -326,7 +347,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { } private SourceFile register_source_file (PackageMetaData meta_data, Vala.SourceFile source_file) { - SourceFile file = new SourceFile (source_file.get_relative_filename (), source_file.get_csource_filename ()); + SourceFile file = new SourceFile (meta_data.package, source_file.get_relative_filename (), source_file.get_csource_filename ()); files.set (source_file, file); meta_data.register_source_file (source_file); @@ -340,7 +361,6 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { } SourceFile? file = files.get (source_ref.file); - assert (file != null); return file; } @@ -534,6 +554,11 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { // Vala tree creation: // + private string get_package_name (string path) { + string file_name = Path.get_basename (path); + return file_name.substring (0, file_name.last_index_of_char ('.')); + } + private bool add_package (Vala.CodeContext context, string pkg) { // ignore multiple occurences of the same package if (context.has_package (pkg)) { @@ -636,8 +661,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { context.add_source_file (source_file); } else if (source.has_suffix (".vapi") || source.has_suffix (".gir")) { - string file_name = Path.get_basename (source); - file_name = file_name.substring (0, file_name.last_index_of_char ('.')); + string file_name = get_package_name (source); var vfile = new Vala.SourceFile (context, Vala.SourceFileType.PACKAGE, rpath); context.add_source_file (vfile); @@ -1126,6 +1150,15 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor { return null; } + // TODO: Register all packages here + // register packages included by gir-files + foreach (Vala.SourceFile vfile in context.get_source_files ()) { + if (vfile.file_type == Vala.SourceFileType.PACKAGE && vfile.get_nodes ().size > 0 && files.contains (vfile) == false) { + Package vdpkg = new Package (get_package_name (vfile.filename), true, null); + register_source_file (register_package (vdpkg), vfile); + } + } + context.accept(this); return (reporter.errors == 0)? tree : null; diff --git a/src/libvaladoc/Makefile.am b/src/libvaladoc/Makefile.am index 9fba54824..14a8bfa90 100755 --- a/src/libvaladoc/Makefile.am +++ b/src/libvaladoc/Makefile.am @@ -36,11 +36,14 @@ libvaladoc_la_VALASOURCES = \ documentation/documentationparser.vala \ documentation/wiki.vala \ documentation/wikiscanner.vala \ + documentation/gtkdoccommentparser.vala \ + documentation/gtkdoccommentscanner.vala \ importer/documentationimporter.vala \ importer/valadocdocumentationimporter.vala \ importer/valadocdocumentationimporterscanner.vala \ api/symbolaccessibility.vala \ api/sourcecomment.vala \ + api/girsourcecomment.vala \ api/attributeargument.vala \ api/attribute.vala \ api/array.vala \ diff --git a/src/libvaladoc/api/girsourcecomment.vala b/src/libvaladoc/api/girsourcecomment.vala new file mode 100644 index 000000000..e55409238 --- /dev/null +++ b/src/libvaladoc/api/girsourcecomment.vala @@ -0,0 +1,55 @@ +/* sourcecomment.vala + * + * Copyright (C) 2011 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 + */ + + +using Gee; + + +/** + * A documentation comment used by valadoc + */ +public class Valadoc.Api.GirSourceComment : SourceComment { + private Map parameters = new HashMap (); + + public SourceComment return_comment { set; get; } + + public MapIterator parameter_iterator () { + return parameters.map_iterator (); + } + + public void add_parameter_content (string param_name, SourceComment comment) { + this.parameters.set (param_name, comment); + } + + public SourceComment? get_parameter_comment (string param_name) { + if (parameters == null) { + return null; + } + + return parameters.get (param_name); + } + + public GirSourceComment (string content, SourceFile file, int first_line, int first_column, int last_line, int last_column) { + base (content, file, first_line, first_column, last_line, last_column); + } +} + diff --git a/src/libvaladoc/api/sourcefile.vala b/src/libvaladoc/api/sourcefile.vala index 6ac672036..09b821fe8 100644 --- a/src/libvaladoc/api/sourcefile.vala +++ b/src/libvaladoc/api/sourcefile.vala @@ -24,6 +24,11 @@ * Represents a source file */ public class Valadoc.Api.SourceFile : Object { + public Package package { + private set; + get; + } + public string relative_path { private set; get; @@ -38,9 +43,10 @@ public class Valadoc.Api.SourceFile : Object { return Path.get_basename (relative_path); } - public SourceFile (string relative_path, string? relative_c_path) { + public SourceFile (Package package, string relative_path, string? relative_c_path) { this.relative_c_path = relative_c_path; this.relative_path = relative_path; + this.package = package; } } diff --git a/src/libvaladoc/api/tree.vala b/src/libvaladoc/api/tree.vala index bddb1bfb9..1298d0692 100755 --- a/src/libvaladoc/api/tree.vala +++ b/src/libvaladoc/api/tree.vala @@ -143,21 +143,25 @@ public class Valadoc.Api.Tree { // absolute foreach (Package package in packages) { // search in root namespace - node = search_relative_to (package.find_by_name (""), path); - if (node != null) { - return node; + + Node? global = package.find_by_name (""); + if (global != null) { + node = search_relative_to (global, path); + if (node != null) { + return node; + } } } return null; } - public Node? search_symbol_cstr (string cname) { + public Node? search_symbol_cstr (Node? element, string cname) { if (_cresolver == null) { _cresolver = new CTypeResolver (this); } - return _cresolver.resolve_symbol (cname); + return _cresolver.resolve_symbol (element, cname); } public Node? search_symbol_str (Node? element, string symname) { diff --git a/src/libvaladoc/ctyperesolver.vala b/src/libvaladoc/ctyperesolver.vala index 87fc6f344..a7adac8b2 100755 --- a/src/libvaladoc/ctyperesolver.vala +++ b/src/libvaladoc/ctyperesolver.vala @@ -34,40 +34,99 @@ public class Valadoc.CTypeResolver : Visitor { tree.accept (this); } + + private string convert_array_to_camelcase (string[] elements) { + StringBuilder builder = new StringBuilder (); + + foreach (string element in elements) { + builder.append_c (((char[])element)[0].toupper ()); + builder.append (element.next_char ().down ()); + } + + return (owned) builder.str; + } + + private bool is_capitalized_and_underscored (string name) { + unowned string pos; + + unichar c = name.get_char (); + + + if (c < 'A' || c > 'Z') { + return false; + } + + bool last_was_underscore = false; + for (c = (pos = name).get_char (); c != '\0' ; c = (pos = pos.next_char ()).get_char ()) { + if ((c != '_' && !(c >= 'A' && c <= 'Z')) || (last_was_underscore && c == '_')) { + return false; + } + + last_was_underscore = (c == '_'); + } + + return !last_was_underscore; + } + + private string? translate_cname (string name) { + if (is_capitalized_and_underscored (name)) { + string[] segments = name.split ("_"); + unowned string last_segment = segments[segments.length - 1]; + if (last_segment == "ERROR") { + } else if (last_segment == "TYPE") { + segments.resize (segments.length - 1); + } else { + return null; + } + + return convert_array_to_camelcase (segments); + } + + int length = name.length; + if (length > 5 && name.has_suffix ("Iface")) { + return name.substring (0, length - 5); + } else if (length > 5 && name.has_suffix ("Class")) { + return name.substring (0, length - 5); + } + + return null; + } + /** * Resolves symbols by C-names * * @param name a C-name * @return the resolved node or null */ - public Api.Node? resolve_symbol (string _name) { + public Api.Node? resolve_symbol (Api.Node? element, string _name) { string name = _name.replace ("-", "_"); + if (element != null && _name.has_prefix (":")) { + Item parent = element; + while (parent != null && !(parent is Class || parent is Interface)) { + parent = parent.parent; + } + + if (parent is Class && ((Class) parent).get_cname () != null) { + name = ((Class) parent).get_cname () + name; + } else if (parent is Interface && ((Interface) parent).get_cname () != null) { + name = ((Interface) parent).get_cname () + name; + } else { + return null; + } + + } + Api.Node? node = nodes.get (name); if (node != null) { return node; } - var name_length = name.length; - if (name_length > 5 && name.has_suffix ("Class")) { - return nodes.get (name.substring (0, name_length - 5)); + string? alternative = translate_cname (_name); + if (alternative != null) { + return nodes.get (alternative); } - /* - for (int i = 0; name[i] != '\0' ; i++) { - if (name[i] == ':' && name[i+1] == ':') { - string first_part = name.substring (0, i - 1); - string second_part = name.substring (i + 2, -1); - string nick = first_part + ":" + second_part; - return nodes.get (nick); - } else if (name[i] == ':') { - string first_part = name.substring (0, i); - string second_part = name.substring (i + 1, -1); - string nick = first_part + "::" + second_part; - return nodes.get (nick); - } - } */ - return null; } diff --git a/src/libvaladoc/documentation/documentationparser.vala b/src/libvaladoc/documentation/documentationparser.vala index 92aa69865..b2a96f025 100755 --- a/src/libvaladoc/documentation/documentationparser.vala +++ b/src/libvaladoc/documentation/documentationparser.vala @@ -43,9 +43,13 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator { _comment_parser = new Parser (_settings, _comment_scanner, _reporter); _comment_scanner.set_parser (_comment_parser); + gtkdoc_parser = new Gtkdoc.Parser (settings, reporter, tree, modules); + init_valadoc_rules (); } + private Gtkdoc.Parser gtkdoc_parser; + private Settings _settings; private ErrorReporter _reporter; private Api.Tree _tree; @@ -61,7 +65,12 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator { private Scanner _scanner; public Comment? parse (Api.Node element, Api.SourceComment comment) { - return parse_comment_str (element, comment.content, comment.file.get_name (), comment.first_line, comment.first_column); + if (comment is Api.GirSourceComment) { + Comment doc_comment = gtkdoc_parser.parse (element, (Api.GirSourceComment) comment); + return doc_comment; + } else { + return parse_comment_str (element, comment.content, comment.file.get_name (), comment.first_line, comment.first_column); + } } public Comment? parse_comment_str (Api.Node element, string content, string filename, int first_line, int first_column) { diff --git a/src/libvaladoc/documentation/gtkdoccommentparser.vala b/src/libvaladoc/documentation/gtkdoccommentparser.vala new file mode 100644 index 000000000..48e52276b --- /dev/null +++ b/src/libvaladoc/documentation/gtkdoccommentparser.vala @@ -0,0 +1,942 @@ +/* gtkcommentparser.vala + * + * Copyright (C) 2011 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 + */ + + +using Valadoc.Content; +using Valadoc.Gtkdoc; +using Gee; + + + +public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator { + private Scanner scanner = new Scanner (); + private Token current; + + private LinkedList stack = new LinkedList (); + + private ContentFactory factory; + private ErrorReporter reporter; + private Settings settings; + private Api.Tree tree; + + private bool show_warnings; + private Api.SourceComment comment; + + private string[]? comment_lines; + + private void reset (Api.SourceComment comment) { + this.scanner.reset (comment.content); + this.show_warnings = !comment.file.package.is_package || settings.verbose; + this.comment_lines = null; + this.comment = comment; + current = null; + stack.clear (); + } + + private void report_unexpected_token (Token got, string expected) { + if (this.show_warnings) { + return ; + } + + int startpos = (got.line == 0)? comment.first_column + got.first_column : got.first_column; + int endpos = (got.line == 0)? comment.first_column + got.last_column : got.last_column; + + if (this.comment_lines == null) { + this.comment_lines = this.comment.content.split ("\n"); + } + + this.reporter.warning (this.comment.file.get_name (), comment.first_line + got.line, startpos + 1, endpos + 1, this.comment_lines[got.line], "Unexpected Token: %s (Expected: %s)", got.to_string (), expected); + } + + public Parser (Settings settings, ErrorReporter reporter, Api.Tree tree, ModuleLoader modules) { + this.factory = new ContentFactory (settings, this, modules); + this.reporter = reporter; + this.settings = settings; + this.tree = tree; + } + + public Comment? parse (Api.Node element, Api.GirSourceComment gir_comment) { + Comment? comment = this.parse_main_content (gir_comment); + if (comment == null) { + return null; + } + + if (gir_comment.return_comment != null) { + Taglet? taglet = this.parse_block_taglet (gir_comment.return_comment, "return"); + if (taglet == null) { + return null; + } + + comment.taglets.add (taglet); + } + + MapIterator iter = gir_comment.parameter_iterator (); + for (bool has_next = iter.first (); has_next; has_next = iter.next ()) { + Taglets.Param? taglet = this.parse_block_taglet (iter.get_value (), "param") as Taglets.Param; + if (taglet == null) { + return null; + } + + taglet.parameter_name = iter.get_key (); + comment.taglets.add (taglet); + } + + comment.check (tree, element, reporter, settings); + return comment; + } + + private Taglet? parse_block_taglet (Api.SourceComment gir_comment, string taglet_name) { + this.reset (gir_comment); + current = null; + next (); + + parse_docbook_spaces (false); + var ic = parse_inline_content (); + parse_docbook_spaces (false); + + if (current.type != TokenType.EOF) { + this.report_unexpected_token (current, ""); + return null; + } + + InlineContent? taglet = factory.create_taglet (taglet_name) as InlineContent; + assert (taglet != null); + taglet.content.add (ic); + return taglet as Taglet; + } + + private Comment? parse_main_content (Api.GirSourceComment gir_comment) { + this.reset (gir_comment); + current = null; + + next (); + + Token tmp = null; + parse_docbook_spaces (false); + + Comment comment = factory.create_comment (); + while (current.type != TokenType.EOF && tmp != current) { + tmp = current; + var ic = parse_inline_content (); + if (ic != null && ic.content.size > 0) { + Paragraph p = factory.create_paragraph (); + p.content.add (ic); + comment.content.add (p); + } + + var bc = parse_block_content (); + if (bc != null && bc.size > 0) { + comment.content.add_all (bc); + } + } + + if (current.type != TokenType.EOF) { + this.report_unexpected_token (current, ""); + return null; + } + + return comment; + } + + + + // + // Common: + // + + private Token next () { + current = scanner.next (); + return current; + } + + private bool ignore_current_xml_close () { + if (current.type != TokenType.XML_CLOSE) { + return false; + } + + string name = current.content; + if ((name in stack) == false) { + return true; + } + + return false; + } + + private bool check_xml_open_tag (string tagname) { + if (current.type == TokenType.XML_OPEN && current.content != tagname) { + return false; + } + + stack.offer_head (tagname); + return true; + } + + private bool check_xml_close_tag (string tagname) { + if (current.type == TokenType.XML_CLOSE && current.content != tagname) { + return false; + } + + if (stack.poll_head () == tagname) { + stack.peek_head (); + } + + return true; + } + + + private void parse_docbook_spaces (bool accept_paragraphs = true) { + while (true) { + if (current.type == TokenType.SPACE) { + next (); + } else if (current.type == TokenType.NEWLINE) { + next (); + } else if (accept_paragraphs && current.type == TokenType.GTKDOC_PARAGRAPH) { + next (); + } else { + break; + } + } + } + + + + // + // Rules, Ground: + // + + private Inline? parse_docbook_link_tempalte (string tagname) { + if (!check_xml_open_tag (tagname)) { + this.report_unexpected_token (current, "<%s>".printf (tagname)); + return null; + } + + StringBuilder builder = new StringBuilder (); + string url = current.attributes.get ("linkend"); + next (); + + // TODO: check xml + while (current.type != TokenType.XML_CLOSE && current.content != tagname && current.type != TokenType.EOF) { + if (current.type == TokenType.XML_OPEN) { + } else if (current.type == TokenType.XML_CLOSE) { + } else if (current.type == TokenType.XML_COMMENT) { + } else { + builder.append (current.content); + } + + next (); + } + + var link = factory.create_link (); + link.url = url; + + if (builder.len == 0) { + link.content.add (factory.create_text (url)); + } else { + link.content.add (factory.create_text (builder.str)); + } + + if (!check_xml_close_tag (tagname)) { + this.report_unexpected_token (current, "".printf (tagname)); + return link; + } + + next (); + return link; + } + + private InlineTaglet? parse_symbol_link (string tagname) { + if (!check_xml_open_tag (tagname)) { + this.report_unexpected_token (current, "<%s>".printf (tagname)); + return null; + } + + if (next ().type == TokenType.SPACE) { + next (); + } + + InlineTaglet? taglet = null; + + if (current.type == TokenType.GTKDOC_FUNCTION || current.type == TokenType.GTKDOC_CONST || current.type == TokenType.GTKDOC_TYPE || current.type == TokenType.WORD || current.type == TokenType.GTKDOC_PROPERTY || current.type == TokenType.GTKDOC_SIGNAL) { + taglet = this.create_type_link (current.content) as InlineTaglet; + assert (taglet != null); + } + + if (next ().type == TokenType.SPACE) { + next (); + } + + if (!check_xml_close_tag (tagname)) { + this.report_unexpected_token (current, "".printf (tagname)); + return taglet; + } + + next (); + return taglet; + } + + private void parse_anchor () { + if (!check_xml_open_tag ("anchor")) { + this.report_unexpected_token (current, ""); + return; + } + + string id = current.attributes.get ("id"); + next (); + // TODO register xref + + if (!check_xml_close_tag ("anchor")) { + this.report_unexpected_token (current, ""); + return; + } + + next (); + } + + private void parse_xref () { + if (!check_xml_open_tag ("xref")) { + this.report_unexpected_token (current, ""); + return; + } + + string linkend = current.attributes.get ("linkend"); + next (); + // TODO register xref + + if (!check_xml_close_tag ("xref")) { + this.report_unexpected_token (current, ""); + return; + } + + next (); + } + + private Run? parse_highlighted_template (string tag_name, Run.Style style) { + if (!check_xml_open_tag (tag_name)) { + this.report_unexpected_token (current, "<%s>".printf (tag_name)); + return null; + } + + next (); + Run run = parse_inline_content (); + if (run.style != Run.Style.NONE && run.style != style) { + Run tmp = factory.create_run (style); + tmp.content.add (run); + run = tmp; + } else { + run.style = style; + } + + if (!check_xml_close_tag (tag_name)) { + this.report_unexpected_token (current, "".printf (tag_name)); + return run; + } + + next (); + return run; + } + + private ListItem? parse_docbook_listitem () { + if (!check_xml_open_tag ("listitem")) { + this.report_unexpected_token (current, ""); + return null; + } + + next (); + + ListItem item = factory.create_list_item (); + + while (current.type != TokenType.XML_CLOSE && current.type != TokenType.EOF) { + if (current.type == TokenType.XML_OPEN && current.content == "para") { + foreach (Block block in parse_docbook_para ()) { + if (block is Paragraph) { + if (item.content.size > 0) { + item.content.add (factory.create_text ("\n")); + } + + item.content.add_all (((Paragraph) block).content); + } else { + // TODO: extend me + this.report_unexpected_token (current, "|"); + return null; + } + } + } else { + Token tmp_t = current; + parse_inline_content (); + if (tmp_t == current) { + break; + } + } + } + + if (!check_xml_close_tag ("listitem")) { + this.report_unexpected_token (current, ""); + return item; + } + + next (); + return item; + } + + private LinkedList? parse_docbook_information_box_template (string tagname) { + if (!check_xml_open_tag (tagname)) { + this.report_unexpected_token (current, "<%s>".printf (tagname)); + return null; + } + + next (); + parse_docbook_spaces (); + + LinkedList content = new LinkedList (); + + var header_run = factory.create_run (Run.Style.BOLD); + header_run.content.add (factory.create_text ("Note:")); + + while (current.type != TokenType.XML_CLOSE && current.type != TokenType.EOF) { + if (current.type == TokenType.XML_OPEN && current.content == "para") { + var paragraphs = parse_docbook_para (); + if (header_run != null) { + content.add_all (paragraphs); + } else { + Paragraph fp = paragraphs.first (); + fp.content.insert (0, factory.create_text (" ")); + fp.content.insert (0, header_run); + } + } else { + Token tmp_t = current; + + Run? inline_run = parse_inline_content (); + Paragraph p = factory.create_paragraph (); + + if (content != null) { + p.content.add (header_run); + p.content.add (factory.create_text (" ")); + header_run = null; + } + + p.content.add (inline_run); + content.add (p); + + if (tmp_t == current) { + break; + } + } + } + + //parse_block_content (); + parse_docbook_spaces (); + + if (!check_xml_close_tag (tagname)) { + this.report_unexpected_token (current, "".printf (tagname)); + return content; + } + + next (); + return content; + } + + private LinkedList? parse_docbook_note () { + return parse_docbook_information_box_template ("note"); + } + + private LinkedList? parse_docbook_warning () { + return parse_docbook_information_box_template ("warning"); + } + + private Content.List? parse_docbook_itemizedlist () { + if (!check_xml_open_tag ("itemizedlist")) { + this.report_unexpected_token (current, ""); + return null; + } + + next (); + + parse_docbook_spaces (); + + Content.List list = factory.create_list (); + list.bullet = Content.List.Bullet.UNORDERED; + + while (current.type == TokenType.XML_OPEN) { + if (current.content == "listitem") { + list.items.add (parse_docbook_listitem ()); + } else { + break; + } + + parse_docbook_spaces (); + } + + if (!check_xml_close_tag ("itemizedlist")) { + this.report_unexpected_token (current, ""); + return list; + } + + next (); + return list; + } + + private Paragraph? parse_gtkdoc_paragraph () { + if (current.type != TokenType.GTKDOC_PARAGRAPH) { + this.report_unexpected_token (current, ""); + return null; + } + + next (); + + Paragraph p = factory.create_paragraph (); + + Run? run = parse_inline_content (); + p.content.add (run); + return p; + } + + private LinkedList? parse_docbook_para () { + if (!check_xml_open_tag ("para")) { + this.report_unexpected_token (current, ""); + return null; + } + + next (); + + LinkedList content = new LinkedList (); + + Token tmp = null; + while (tmp != current) { + tmp = current; + parse_docbook_spaces (); + + Run? run = parse_inline_content (); + if (run != null && run.content.size > 0) { + Paragraph p = factory.create_paragraph (); + p.content.add (run); + content.add (p); + continue; + } + + LinkedList lst = parse_block_content (); + if (lst != null && run.content.size > 0) { + content.add_all (lst); + continue; + } + } + + if (!check_xml_close_tag ("para")) { + this.report_unexpected_token (current, ""); + return content; + } + + next (); + return content; + } + + private Paragraph? parse_gtkdoc_source () { + if (current.type != TokenType.GTKDOC_SOURCE_OPEN) { + this.report_unexpected_token (current, "|["); + return null; + } + + + StringBuilder builder = new StringBuilder (); + + for (next (); current.type != TokenType.EOF && current.type != TokenType.GTKDOC_SOURCE_CLOSE; next ()) { + if (current.type == TokenType.WORD) { + builder.append (current.content); + } else if (current.type != TokenType.XML_COMMENT) { + builder.append_len (current.start, current.length); + } + } + + SourceCode src = factory.create_source_code (); + src.language = SourceCode.Language.C; + src.code = builder.str; + + Paragraph p = factory.create_paragraph (); + p.content.add (src); + + if (current.type != TokenType.GTKDOC_SOURCE_CLOSE) { + this.report_unexpected_token (current, "|]"); + return p; + } + + next (); + return p; + } + + private Paragraph? parse_docbook_title () { + if (!check_xml_open_tag ("title")) { + this.report_unexpected_token (current, ""); + return null; + } + + next (); + + Paragraph p = factory.create_paragraph (); + Run content = parse_inline_content (); + content.content.add (factory.create_text (":")); + content.style = Run.Style.BOLD; + p.content.add (content); + + if (!check_xml_close_tag ("title")) { + this.report_unexpected_token (current, ""); + return p; + } + + next (); + return p; + } + + private Embedded? parse_docbook_inlinegraphic () { + if (!check_xml_open_tag ("inlinegraphic")) { + this.report_unexpected_token (current, ""); + return null; + } + + Embedded e = factory.create_embedded (); + e.url = current.attributes.get ("fileref"); + + next (); + parse_docbook_spaces (); + + if (!check_xml_close_tag ("inlinegraphic")) { + this.report_unexpected_token (current, ""); + return e; + } + + next (); + return e; + } + + private Paragraph? parse_docbook_programlisting () { + if (!check_xml_open_tag ("programlisting")) { + this.report_unexpected_token (current, ""); + return null; + } + + StringBuilder builder = new StringBuilder (); + + for (next (); current.type != TokenType.EOF && !(current.type == TokenType.XML_CLOSE && current.content == "programlisting"); next ()) { + if (current.type == TokenType.WORD) { + builder.append (current.content); + } else if (current.type != TokenType.XML_COMMENT) { + builder.append_len (current.start, current.length); + } + } + + SourceCode src = factory.create_source_code (); + src.language = SourceCode.Language.C; + src.code = builder.str; + + Paragraph p = factory.create_paragraph (); + p.content.add (src); + + if (!check_xml_close_tag ("programlisting")) { + this.report_unexpected_token (current, ""); + return p; + } + + next (); + return p; + } + + private LinkedList? parse_docbook_informalexample () { + if (!check_xml_open_tag ("informalexample")) { + this.report_unexpected_token (current, ""); + return null; + } + + next (); + + parse_docbook_spaces (); + + LinkedList content = new LinkedList (); + + if (current.type == TokenType.XML_OPEN && current.content == "title") { + append_block_content_not_null (content, parse_docbook_title ()); + parse_docbook_spaces (); + } + + append_block_content_not_null (content, parse_docbook_programlisting ()); + + parse_docbook_spaces (); + + if (!check_xml_close_tag ("informalexample")) { + this.report_unexpected_token (current, ""); + return content; + } + + next (); + return content; + } + + private LinkedList? parse_docbook_example () { + if (!check_xml_open_tag ("example")) { + this.report_unexpected_token (current, ""); + return null; + } + + next (); + + parse_docbook_spaces (); + + LinkedList content = new LinkedList (); + + if (current.type == TokenType.XML_OPEN && current.content == "title") { + append_block_content_not_null (content, parse_docbook_title ()); + parse_docbook_spaces (); + } + + while (current.type == TokenType.XML_OPEN) { + if (current.content == "inlinegraphic") { + Paragraph p = factory.create_paragraph (); + while (current.type == TokenType.XML_OPEN && current.content == "inlinegraphic") { + p.content.add (parse_docbook_inlinegraphic ()); + next (); + parse_docbook_spaces (); + } + } else if (current.content == "programlisting") { + append_block_content_not_null (content, parse_docbook_programlisting ()); + next (); + } else { + break; + } + + parse_docbook_spaces (); + } + + if (!check_xml_close_tag ("example")) { + this.report_unexpected_token (current, ""); + return content; + } + + next (); + return content; + } + + private LinkedList? parse_docbook_refsect2 () { + if (!check_xml_open_tag ("refsect2")) { + this.report_unexpected_token (current, ""); + return null; + } + + // TODO: register id + string id = current.attributes.get ("id"); + next (); + + parse_docbook_spaces (); + + LinkedList content = new LinkedList (); + + if (current.type == TokenType.XML_OPEN && current.content == "title") { + append_block_content_not_null (content, parse_docbook_title ()); + parse_docbook_spaces (); + } + + this.append_block_content_not_null_all (content, parse_block_content ()); + + if (!check_xml_close_tag ("refsect2")) { + this.report_unexpected_token (current, ""); + return content; + } + + next (); + return content; + } + + private inline void append_block_content_not_null_all (LinkedList run, LinkedList? elements) { + if (elements != null) { + run.add_all (elements); + } + } + + private inline void append_block_content_not_null (LinkedList run, Block? element) { + if (element != null) { + run.add (element); + } + } + + private LinkedList parse_block_content () { + LinkedList content = new LinkedList (); + + while (current.type != TokenType.EOF) { + parse_docbook_spaces (false); + + if (current.type == TokenType.XML_OPEN && current.content == "itemizedlist") { + this.append_block_content_not_null (content, parse_docbook_itemizedlist ()); + } else if (current.type == TokenType.XML_OPEN && current.content == "para") { + this.append_block_content_not_null_all (content, parse_docbook_para ()); + } else if (current.type == TokenType.XML_OPEN && current.content == "informalexample") { + this.append_block_content_not_null_all (content, parse_docbook_informalexample ()); + } else if (current.type == TokenType.XML_OPEN && current.content == "example") { + this.append_block_content_not_null_all (content, parse_docbook_example ()); + } else if (current.type == TokenType.XML_OPEN && current.content == "warning") { + this.append_block_content_not_null_all (content, parse_docbook_warning ()); + } else if (current.type == TokenType.XML_OPEN && current.content == "note") { + this.append_block_content_not_null_all (content, parse_docbook_note ()); + } else if (current.type == TokenType.XML_OPEN && current.content == "refsect2") { + this.append_block_content_not_null_all (content, parse_docbook_refsect2 ()); + } else if (current.type == TokenType.GTKDOC_PARAGRAPH) { + this.append_block_content_not_null (content, parse_gtkdoc_paragraph ()); + } else if (current.type == TokenType.GTKDOC_SOURCE_OPEN) { + this.append_block_content_not_null (content, parse_gtkdoc_source ()); + } else { + break; + } + } + + return content; + } + + private void append_inline_content_string (Run run, string current) { + Text last_as_text = null; + + if (run.content.size > 0) { + last_as_text = run.content.last () as Text; + } + + if (last_as_text == null) { + run.content.add (factory.create_text (current)); + } else if (current.has_prefix (" ") && last_as_text.content.has_suffix (" ")) { + last_as_text.content += current.chug (); + } else { + last_as_text.content += current; + } + } + + private Inline create_type_link (string name) { + if (name == "TRUE" || name == "FALSE" || name == "NULL") { + var monospaced = factory.create_run (Run.Style.MONOSPACED); + monospaced.content.add (factory.create_text (name)); + return monospaced; + } else { + Taglets.Link? taglet = factory.create_taglet ("link") as Taglets.Link; + assert (taglet != null); + taglet.symbol_name = "c::"+name; + return taglet; + } + } + + private inline void append_inline_content_not_null (Run run, Inline element) { + if (element != null) { + run.content.add (element); + } + } + + private Run parse_inline_content () { + Run run = factory.create_run (Run.Style.NONE); + + while (current.type != TokenType.EOF) { + if (current.type == TokenType.XML_OPEN && current.content == "firstterm") { + append_inline_content_not_null (run, parse_highlighted_template ("firstterm", Run.Style.ITALIC)); + } else if (current.type == TokenType.XML_OPEN && current.content == "literal") { + append_inline_content_not_null (run, parse_highlighted_template ("literal", Run.Style.ITALIC)); + } else if (current.type == TokenType.XML_OPEN && current.content == "application") { + append_inline_content_not_null (run, parse_highlighted_template ("application", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "emphasis") { + append_inline_content_not_null (run, parse_highlighted_template ("emphasis", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "code") { + append_inline_content_not_null (run, parse_highlighted_template ("code", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "command") { + append_inline_content_not_null (run, parse_highlighted_template ("command", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "option") { + append_inline_content_not_null (run, parse_highlighted_template ("option", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "keycap") { + append_inline_content_not_null (run, parse_highlighted_template ("keycap", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "keycombo") { + append_inline_content_not_null (run, parse_highlighted_template ("keycombo", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "envar") { + append_inline_content_not_null (run, parse_highlighted_template ("envar", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "filename") { + append_inline_content_not_null (run, parse_highlighted_template ("filename", Run.Style.MONOSPACED)); + } else if (current.type == TokenType.XML_OPEN && current.content == "replaceable") { + append_inline_content_not_null (run, parse_highlighted_template ("replaceable", Run.Style.ITALIC)); + } else if (current.type == TokenType.XML_OPEN && current.content == "type") { + append_inline_content_not_null (run, parse_symbol_link ("type")); + } else if (current.type == TokenType.XML_OPEN && current.content == "function") { + append_inline_content_not_null (run, parse_symbol_link ("function")); + } else if (current.type == TokenType.XML_OPEN && current.content == "classname") { + append_inline_content_not_null (run, parse_symbol_link ("classname")); + } else if (current.type == TokenType.XML_OPEN && current.content == "structname") { + append_inline_content_not_null (run, parse_symbol_link ("structname")); + } else if (current.type == TokenType.XML_OPEN && current.content == "structfield") { + append_inline_content_not_null (run, parse_symbol_link ("structfield")); + } else if (current.type == TokenType.XML_OPEN && current.content == "errorcode") { + append_inline_content_not_null (run, parse_symbol_link ("errorcode")); + } else if (current.type == TokenType.XML_OPEN && current.content == "constant") { + append_inline_content_not_null (run, parse_symbol_link ("constant")); + } else if (current.type == TokenType.XML_OPEN && current.content == "anchor") { + parse_anchor (); + } else if (current.type == TokenType.XML_OPEN && current.content == "link") { + append_inline_content_not_null (run, parse_docbook_link_tempalte ("link")); + } else if (current.type == TokenType.XML_OPEN && current.content == "ulink") { + append_inline_content_not_null (run, parse_docbook_link_tempalte ("ulink")); + } else if (current.type == TokenType.XML_OPEN && current.content == "xref") { + parse_xref (); + } else if (current.type == TokenType.GTKDOC_FUNCTION) { + run.content.add (this.create_type_link (current.content)); + next (); + } else if (current.type == TokenType.GTKDOC_PARAM) { + Run current_run = factory.create_run (Run.Style.MONOSPACED); + current_run.content.add (factory.create_text (current.content)); + run.content.add (current_run); + next (); + } else if (current.type == TokenType.GTKDOC_SIGNAL) { + run.content.add (this.create_type_link ("::"+current.content)); + next (); + } else if (current.type == TokenType.GTKDOC_PROPERTY) { + run.content.add (this.create_type_link (":"+current.content)); + next (); + } else if (current.type == TokenType.GTKDOC_CONST) { + run.content.add (this.create_type_link (current.content)); + next (); + } else if (current.type == TokenType.GTKDOC_TYPE) { + run.content.add (this.create_type_link (current.content)); + next (); + } else if (current.type == TokenType.NEWLINE || current.type == TokenType.SPACE) { + append_inline_content_string (run, " "); + next (); + } else if (current.type == TokenType.WORD) { + append_inline_content_string (run, current.content); + next (); + } else if (current.type == TokenType.XML_CLOSE && ignore_current_xml_close ()) { + next (); + } else if (current.type == TokenType.XML_COMMENT) { + next (); + } else { + break; + } + } + + return run; + } + + + + // + // Resource Locator: + // + + public string resolve (string path) { + return path; + } +} + + diff --git a/src/libvaladoc/documentation/gtkdoccommentscanner.vala b/src/libvaladoc/documentation/gtkdoccommentscanner.vala new file mode 100644 index 000000000..ca03b1530 --- /dev/null +++ b/src/libvaladoc/documentation/gtkdoccommentscanner.vala @@ -0,0 +1,644 @@ +/* gtkcommentscanner.vala + * + * Copyright (C) 2011 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 + */ + + +using Valadoc.Gtkdoc; +using Gee; + + + +public enum Valadoc.Gtkdoc.TokenType { + XML_OPEN, + XML_CLOSE, + XML_COMMENT, + GTKDOC_FUNCTION, + GTKDOC_CONST, + GTKDOC_TYPE, + GTKDOC_PARAM, + GTKDOC_SOURCE_OPEN, + GTKDOC_SOURCE_CLOSE, + GTKDOC_SIGNAL, + GTKDOC_PROPERTY, + GTKDOC_PARAGRAPH, + NEWLINE, + SPACE, + WORD, + EOF +} + + +public class Valadoc.Gtkdoc.Token { + public TokenType type; + public string content; + public HashMap? attributes; + public unowned string start; + public int length; + public int line; + public int first_column; + public int last_column; + + public Token (TokenType type, string content, HashMap? attributes, string start, int length, int line, int first_column, int last_column) { + this.attributes = attributes; + this.content = content; + this.length = length; + this.start = start; + this.type = type; + this.line = line; + this.first_column = first_column; + this.last_column = last_column; + } + + public string to_string () { + switch (this.type) { + case TokenType.XML_OPEN: + return "`<%s>'".printf (this.content); + + case TokenType.XML_CLOSE: + return "`<%s>'".printf (this.content); + + case TokenType.XML_COMMENT: + return ""; + + case TokenType.GTKDOC_FUNCTION: + return "`%s ()'".printf (this.content); + + case TokenType.GTKDOC_CONST: + return "`%%%s'".printf (this.content); + + case TokenType.GTKDOC_TYPE: + return "`#%s'".printf (this.content); + + case TokenType.GTKDOC_PARAM: + return ""; + + case TokenType.GTKDOC_SOURCE_OPEN: + return "[|"; + + case TokenType.GTKDOC_SOURCE_CLOSE: + return "|]"; + + case TokenType.GTKDOC_SIGNAL: + return "`::%s'".printf (this.content); + + case TokenType.GTKDOC_PROPERTY: + return "`:%s'".printf (this.content); + + case TokenType.GTKDOC_PARAGRAPH: + return ""; + + case TokenType.NEWLINE: + return ""; + + case TokenType.SPACE: + return ""; + + case TokenType.WORD: + return "`%s'".printf (this.content); + + case TokenType.EOF: + return ""; + + default: + assert_not_reached (); + } + } +} + + +public class Valadoc.Gtkdoc.Scanner { + private unowned string content; + private unowned string pos; + private int column; + private int line; + private Token tmp_token; + + public Scanner () { + } + + public void reset (string content) { + this.content = content; + this.tmp_token = null; + this.pos = content; + this.column = 0; + this.line = 0; + } + + private inline unichar next_char () { + this.pos = this.pos.next_char (); + this.column++; + + return this.pos.get_char (); + } + + private inline unichar get () { + return this.pos.get_char (); + } + + private inline bool letter (unichar c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + private inline bool letter_or_number (unichar c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); + } + + private inline bool space (unichar c) { + return c == ' ' || c == '\t'; + } + + private inline bool space_or_newline (unichar c) { + if (c == '\n') { + this.line++; + this.column = 0; + return true; + } + + return space (c); + } + + private inline int offset (string a, string b) { + return (int) ((char*) a - (char*) b); + } + + private inline int id_prefix () { + if (!letter (get ())) { + return 0; + } + + int start = this.column; + unichar c; + while ((c = next_char ()) == '_' || letter_or_number (c)); + return this.column - start; + } + + private inline int g_id_prefix () { + unowned string start = this.pos; + + if (!letter (get ())) { + return 0; + } + + unichar c; + while ((c = next_char ()) == '_' || c == '-' || letter_or_number (c)); + return offset (this.pos, start); + } + + private inline int skip_spaces_and_newlines () { + unowned string start = this.pos; + if (space_or_newline (get ())) { + while (space_or_newline (next_char ())); + } + + return offset (this.pos, start); + } + + private inline Token? function_prefix () { + unowned string start = this.pos; + int column_start = this.column; + int id_len = 0; + if ((id_len = id_prefix ()) == 0) { + return null; + } + + space_prefix (); + + if (get () != '(') { + this.column = column_start; + this.pos = start; + return null; + } + + next_char (); + space_prefix (); + + if (get () != ')') { + this.column = column_start; + this.pos = start; + return null; + } + + next_char (); + return new Token (TokenType.GTKDOC_FUNCTION, start.substring (0, id_len), null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + private inline Token? gtkdoc_symbolic_link_prefix (unichar c, TokenType type) { + if (get () != c) { + return null; + } + + unowned string start = this.pos; + int column_start = this.column; + next_char (); + + int id_len = 0; + + if ((id_len = id_prefix ()) == 0) { + this.column = column_start; + this.pos = start; + return null; + } + + unowned string separator = this.pos; + if (get () == ':') { + int separator_len = 1; + if (next_char () == ':') { + next_char (); + separator_len++; + } + + int id_len2; + if ((id_len2 = g_id_prefix ()) == 0) { + this.pos = separator; + } else { + id_len += id_len2 + separator_len; + } + } + + return new Token (type, start.substring (1, id_len), null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + private inline Token? gtkdoc_property_prefix () { + if (get () != ':') { + return null; + } + + unowned string start = this.pos; + int column_start = this.column; + next_char (); + + int id_len = 0; + + if ((id_len = g_id_prefix ()) == 0) { + this.column = column_start; + this.pos = start; + return null; + } + + return new Token (TokenType.GTKDOC_PROPERTY, start.substring (1, id_len), null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + private inline Token? gtkdoc_signal_prefix () { + if (get () != ':') { + return null; + } + + unowned string start = this.pos; + int column_start = this.column; + if (next_char () != ':') { + this.column = column_start; + this.pos = start; + return null; + } + + + start = this.pos; + next_char (); + + int id_len = 0; + + if ((id_len = g_id_prefix ()) == 0) { + this.column = column_start; + this.pos = start; + return null; + } + + return new Token (TokenType.GTKDOC_SIGNAL, start.substring (1, id_len), null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + private inline Token? gtkdoc_const_prefix () { + return gtkdoc_symbolic_link_prefix ('%', TokenType.GTKDOC_CONST); + } + + private inline Token? gtkdoc_param_prefix () { + return gtkdoc_symbolic_link_prefix ('@', TokenType.GTKDOC_PARAM); + } + + private inline Token? gtkdoc_type_prefix () { + return gtkdoc_symbolic_link_prefix ('#', TokenType.GTKDOC_TYPE); + } + + private inline Token? xml_prefix () { + if (get () != '<') { + return null; + } + + unowned string start = this.pos; + int line_start = this.line; + int column_start = this.column; + next_char (); + + if (get () == '!') { + // comment + if (next_char () == '-') { + if (next_char () != '-') { + this.column = column_start; + this.pos = start; + return null; + } + + for (unichar c = next_char (); c != '\0'; c = next_char ()) { + if (c == '\n') { + this.line++; + this.column = 0; + } else if (this.pos.has_prefix ("-->")) { + next_char (); + next_char (); + next_char (); + return new Token (TokenType.XML_COMMENT, "", null, start, offset (this.pos, start), this.line, column_start, this.column); + } + } + } else if (this.pos.has_prefix ("[CDATA[")) { + next_char (); + next_char (); + next_char (); + next_char (); + next_char (); + next_char (); + + for (unichar c = next_char (); c != '\0'; c = next_char ()) { + if (c == '\n') { + this.line++; + this.column = 0; + } else if (this.pos.has_prefix ("]]>")) { + string content = start.substring (9, offset (this.pos, start) - 9); + next_char (); + next_char (); + next_char (); + return new Token (TokenType.WORD, content, null, start, offset (this.pos, start), this.line, column_start, this.column); + } + } + } + + this.pos = start; + this.column = column_start; + this.line = line_start; + return null; + } + + bool close = false; + if (get () == '/') { + next_char (); + close = true; + } + + unowned string id_start = this.pos; + + int id_len = 0; + if ((id_len = id_prefix ()) == 0) { + this.column = column_start; + this.pos = start; + return null; + } + + HashMap map = new HashMap (); + + while (close == false && skip_spaces_and_newlines () > 0) { + string name; + string val; + + unowned string att_pos = this.pos; + int att_id_len = 0; + if ((att_id_len = id_prefix ()) == 0) { + break; + } + + name = att_pos.substring (0, att_id_len); + + if (get() != '=') { + break; + } + + next_char (); + skip_spaces_and_newlines (); + + if (get() != '"') { + break; + } + + unichar c = next_char (); + att_pos = this.pos; + for (; c != '\0' && c != '\n' && c != '"' ; c = next_char ()); + + val = att_pos.substring (0, offset (this.pos, att_pos)); + + if (get() != '"') { + break; + } + + next_char (); + + map.set (name, val); + } + + skip_spaces_and_newlines (); + + bool open_and_close = false; + + if (!close && get () == '/') { + open_and_close = true; + next_char (); + } + + if (get () != '>') { + this.line = line_start; + this.column = column_start; + this.pos = start; + return null; + } + + next_char (); + + if (open_and_close) { + this.tmp_token = new Token (TokenType.XML_CLOSE, id_start.substring (0, id_len), null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + if (close) { + return new Token (TokenType.XML_CLOSE, id_start.substring (0, id_len), null, start, offset (this.pos, start), this.line, column_start, this.column); + } else { + return new Token (TokenType.XML_OPEN, id_start.substring (0, id_len), map, start, offset (this.pos, start), this.line, column_start, this.column); + } + } + + private Token? newline_prefix () { + if (get () != '\n') { + return null; + } + + unowned string start = this.pos; + this.line++; + this.column = 0; + + for (unichar c = next_char (); c == ' ' || c == '\t' ; c = next_char ()); + + if (get () == '\n') { + next_char (); + this.line++; + this.column = 0; + return new Token (TokenType.GTKDOC_PARAGRAPH, "\n\n", null, start, offset (this.pos, start), this.line, this.column, this.column); + } else { + return new Token (TokenType.NEWLINE, "\n", null, start, offset (this.pos, start), this.line, this.column, this.column); + } + } + + private Token? eof_prefix () { + if (get () != '\0') { + return null; + } + + return new Token (TokenType.EOF, "", null, this.pos, 1, this.line, this.column, this.column); + } + + private Token? space_prefix () { + unowned string start = this.pos; + int column_start = this.column; + for (unichar c = get (); c == ' ' || c == '\t'; c = next_char ()); + int len = offset (this.pos, start); + if (len == 0) { + this.column = column_start; + this.pos = start; + return null; + } + + return new Token (TokenType.SPACE, start.substring (0, len), null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + private Token? word_prefix () { + unowned string start = this.pos; + int column_start = this.column; + if (get () == '<') { + next_char (); + } + + for (unichar c = get (); c != ' ' && c != '\t' && c != '\n' && c != '\0' && c != '<'; c = next_char ()); + int len = offset (this.pos, start); + if (len == 0) { + this.column = column_start; + this.pos = start; + return null; + } + + return new Token (TokenType.WORD, start.substring (0, len), null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + private Token? gtkdoc_source_open_prefix () { + if (!this.pos.has_prefix ("|[")) { + return null; + } + + unowned string start = this.pos; + int column_start = this.column; + next_char (); + next_char (); + + return new Token (TokenType.GTKDOC_SOURCE_OPEN, "|[", null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + private Token? gtkdoc_source_close_prefix () { + if (!this.pos.has_prefix ("]|")) { + return null; + } + + unowned string start = this.pos; + int column_start = this.column; + next_char (); + next_char (); + + return new Token (TokenType.GTKDOC_SOURCE_CLOSE, "]|", null, start, offset (this.pos, start), this.line, column_start, this.column); + } + + public Token next () { + if (tmp_token != null) { + var tmp = tmp_token; + tmp_token = null; + return tmp; + } + + Token? token = function_prefix (); + if (token != null) { + return token; + } + + token = xml_prefix (); + if (token != null) { + return token; + } + + token = gtkdoc_param_prefix (); + if (token != null) { + return token; + } + + token = gtkdoc_const_prefix (); + if (token != null) { + return token; + } + + token = gtkdoc_type_prefix (); + if (token != null) { + return token; + } + + token = space_prefix (); + if (token != null) { + return token; + } + + token = newline_prefix (); + if (token != null) { + return token; + } + + token = gtkdoc_signal_prefix (); + if (token != null) { + return token; + } + + token = gtkdoc_property_prefix (); + if (token != null) { + return token; + } + + token = gtkdoc_source_open_prefix (); + if (token != null) { + return token; + } + + token = gtkdoc_source_close_prefix (); + if (token != null) { + return token; + } + + token = eof_prefix (); + if (token != null) { + return token; + } + + token = word_prefix (); + if (token != null) { + return token; + } + + assert_not_reached (); + } +} + + diff --git a/src/libvaladoc/importer/valadocdocumentationimporter.vala b/src/libvaladoc/importer/valadocdocumentationimporter.vala index d0cdb84e7..16bb1086d 100755 --- a/src/libvaladoc/importer/valadocdocumentationimporter.vala +++ b/src/libvaladoc/importer/valadocdocumentationimporter.vala @@ -116,7 +116,7 @@ public class Valadoc.Importer.ValadocDocumentationImporter : DocumentationImport Api.Node? symbol = null; if (symbol_name.has_prefix ("c::")) { - symbol = tree.search_symbol_cstr (symbol_name.substring (3)); + symbol = tree.search_symbol_cstr (null, symbol_name.substring (3)); } else { symbol = tree.search_symbol_str (null, symbol_name); } diff --git a/src/libvaladoc/taglets/tagletlink.vala b/src/libvaladoc/taglets/tagletlink.vala index 93ba7ab6e..57b14747c 100755 --- a/src/libvaladoc/taglets/tagletlink.vala +++ b/src/libvaladoc/taglets/tagletlink.vala @@ -47,7 +47,11 @@ public class Valadoc.Taglets.Link : InlineTaglet { public override void check (Api.Tree api_root, Api.Node container, ErrorReporter reporter, Settings settings) { if (symbol_name.has_prefix ("c::")) { _symbol_name = _symbol_name.substring (3); - _symbol = api_root.search_symbol_cstr (symbol_name); + _symbol = api_root.search_symbol_cstr (container, symbol_name); + if (_symbol == null) { + + } + if (_symbol != null) { symbol_name = _symbol.name; } diff --git a/src/libvaladoc/taglets/tagletsee.vala b/src/libvaladoc/taglets/tagletsee.vala index eb4562eae..d97668877 100755 --- a/src/libvaladoc/taglets/tagletsee.vala +++ b/src/libvaladoc/taglets/tagletsee.vala @@ -41,7 +41,7 @@ public class Valadoc.Taglets.See : ContentElement, Taglet, Block { public override void check (Api.Tree api_root, Api.Node container, ErrorReporter reporter, Settings settings) { if (symbol_name.has_prefix ("c::")) { symbol_name = symbol_name.substring (3); - symbol = api_root.search_symbol_cstr (symbol_name); + symbol = api_root.search_symbol_cstr (container, symbol_name); if (symbol != null) { symbol_name = _symbol.name; }