Index: entry.c =================================================================== --- entry.c (revision 4038) +++ entry.c (working copy) @@ -739,11 +739,14 @@ tag->extensionFields.scope [1]); if (Option.extensionFields.typeRef && - tag->extensionFields.typeRef [0] != NULL && - tag->extensionFields.typeRef [1] != NULL) - length += fprintf (TagFile.fp, "%s\ttyperef:%s:%s", sep, - tag->extensionFields.typeRef [0], - tag->extensionFields.typeRef [1]); + tag->extensionFields.typeRef [0] != NULL) + if (tag->extensionFields.typeRef [1] != NULL) + length += fprintf (TagFile.fp, "%s\ttyperef:%s:%s", sep, + tag->extensionFields.typeRef [0], + tag->extensionFields.typeRef [1]); + else + length += fprintf (TagFile.fp, "%s\ttyperef:%s", sep, + tag->extensionFields.typeRef [0]); if (Option.extensionFields.fileScope && tag->isFileScope) length += fprintf (TagFile.fp, "%s\tfile:", sep); Index: parsers.h =================================================================== --- parsers.h (revision 4038) +++ parsers.h (working copy) @@ -25,6 +25,7 @@ CsharpParser, \ CobolParser, \ FortranParser, \ + GenieParser, \ HtmlParser, \ JavaParser, \ JavaScriptParser, \ @@ -43,6 +44,7 @@ SmlParser, \ SqlParser, \ TclParser, \ + ValaParser, \ VeraParser, \ VerilogParser, \ VimParser, \ Index: ctags-visitor.vala =================================================================== --- ctags-visitor.vala (revision 0) +++ ctags-visitor.vala (revision 0) @@ -0,0 +1,343 @@ +/* + * ctags-visitor.vala + * + * Copyright 2008 Abderrahim Kitouni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +using Vala; +using GLib; + +public class CTagsEntry { + public int line_number; + public string name; + public string kind_name; + public char kind; + public string access; + public string implementation; + public string inheritance; + public string signature; + public string typeref; +} + +public static delegate void CTagsEntryMaker (CTagsEntry entry); + +public class CTagsVisitor : CodeVisitor { + Parser vala_parser; + Genie.Parser genie_parser; + List taglist; + construct { + vala_parser = new Parser(); + genie_parser = new Genie.Parser(); + } + /* helper functions */ + static string get_access (Symbol sym) { + switch (sym.access) { + case SymbolAccessibility.PRIVATE : return "private"; + case SymbolAccessibility.INTERNAL : return "internal"; + case SymbolAccessibility.PROTECTED : return "protected"; + case SymbolAccessibility.PUBLIC : return "public"; + } + assert_not_reached (); + } + static string to_string (Gee.Iterable seq, string sep = ",") { + var str = new StringBuilder(); + var first = true; + foreach (var type in seq) { + if(first) { + first = false; + } else { + str.append(sep); + } + str.append(type.to_qualified_string()); + } + return str.str; + } + static string? implementation (dynamic Symbol sym) { + assert((sym is Class) || (sym is Vala.Signal) || (sym is Property) + || (sym is Method) || (sym is Delegate)); + var list = new List(); + if (!(sym is Vala.Signal) && (bool)sym.is_abstract) { + list.append("abstract"); + } + if (!(sym is Class) && (bool)sym.is_virtual) { + list.append("virtual"); + } + if (list == null) { + return null; + } + var ret = new StringBuilder(); + var first = true; + foreach (var str in list) { + if(first) { + first = false; + } else { + ret.append(","); + } + ret.append(str); + } + return ret.str; + } + static string signature (Gee.List parameter) { + var ret = new StringBuilder("("); + var first = true; + foreach (var p in parameter) { + if(first) { + first = false; + } else { + ret.append(","); + } + if (p.ellipsis) { + ret.append("..."); + } else { + ret.append (p.parameter_type.to_qualified_string()); + ret.append (" "); + ret.append (p.name); + } + } + ret.append (")"); + return ret.str; + } + /*static void print_tag(CTagsEntry en) { + stdout.printf("%s: %s at %d\n", en.name, en.kind_name, en.line_number); + }*/ + + public override void visit_source_file (SourceFile source_file) { + source_file.accept_children (this); + } + + public override void visit_class (Class cl) { + var entry = new CTagsEntry(); + + entry.line_number = cl.source_reference.first_line; + entry.name = cl.name; + entry.kind_name = "class"; + entry.kind = 'c'; + entry.access = get_access (cl); + entry.implementation = implementation(cl); + entry.inheritance = to_string(cl.get_base_types(), ","); + + taglist.append(entry); +// print_tag(entry); + cl.accept_children(this); + } + public override void visit_struct (Struct st) { + var entry = new CTagsEntry(); + entry.line_number = st.source_reference.first_line; + entry.name = st.name; + entry.kind_name = "struct"; + entry.kind = 's'; + entry.access = get_access (st); + + taglist.append(entry); +// print_tag(entry); + st.accept_children(this); + } + public override void visit_interface (Interface iface) { + var entry = new CTagsEntry(); + + entry.line_number = iface.source_reference.first_line; + entry.name = iface.name; + entry.kind_name = "interface"; + entry.kind = 'i'; + entry.access = get_access (iface); + entry.inheritance = to_string(iface.get_prerequisites()); + + taglist.append(entry); +// print_tag(entry); + iface.accept_children(this); + } + + public override void visit_enum (Enum en) { + var entry = new CTagsEntry(); + + entry.line_number = en.source_reference.first_line; + entry.name = en.name; + entry.kind_name = "enum"; + entry.kind = 'e'; + entry.access = get_access (en); + + taglist.append(entry); +// print_tag(entry); + en.accept_children(this); + } + public override void visit_error_domain (ErrorDomain edomain) { + var entry = new CTagsEntry(); + + entry.line_number = edomain.source_reference.first_line; + entry.name = edomain.name; + entry.kind_name = "errordomain"; + entry.kind = 'E'; + entry.access = get_access (edomain); + + taglist.append(entry); +// print_tag(entry); + edomain.accept_children(this); + } + + public override void visit_enum_value (Vala.EnumValue ev) { + var entry = new CTagsEntry(); + + entry.line_number = ev.source_reference.first_line; + entry.name = ev.name; + entry.kind_name = "enumvalue"; + entry.kind = 'v'; + entry.access = get_access (ev); + + taglist.append(entry); +// print_tag(entry); + } + public override void visit_error_code (ErrorCode ecode) { + var entry = new CTagsEntry(); + + //entry.line_number = ecode.source_reference.first_line; + entry.name = ecode.name; + entry.kind_name = "errorcode"; + entry.kind = 'r'; + entry.access = get_access (ecode); + + taglist.append(entry); +// print_tag(entry); + } + + public override void visit_delegate (Delegate d) { + var entry = new CTagsEntry(); + + entry.line_number = d.source_reference.first_line; + entry.name = d.name; + entry.kind_name = "delegate"; + entry.kind = 'd'; + entry.access = get_access (d); + entry.typeref = d.return_type.to_qualified_string(); + entry.signature = signature(d.get_parameters()); + + taglist.append(entry); +// print_tag(entry); + } + public override void visit_signal (Vala.Signal sig) { + var entry = new CTagsEntry(); + + entry.line_number = sig.source_reference.first_line; + entry.name = sig.name; + entry.kind_name = "signal"; + entry.kind = 'S'; + entry.access = get_access (sig); + entry.implementation = implementation(sig); + entry.typeref = sig.return_type.to_qualified_string(); + entry.signature = signature(sig.get_parameters()); + + taglist.append(entry); +// print_tag(entry); + } + public override void visit_field (Field f) { + var entry = new CTagsEntry(); + + entry.line_number = f.source_reference.first_line; + entry.name = f.name; + entry.kind_name = "field"; + entry.kind = 'f'; + entry.access = get_access (f); + entry.typeref = f.field_type.to_qualified_string(); + + taglist.append(entry); +// print_tag(entry); + } + public override void visit_constant (Constant c) { + var entry = new CTagsEntry(); + + entry.line_number = c.source_reference.first_line; + entry.name = c.name; + entry.kind_name = "field"; + entry.kind = 'f'; + entry.access = get_access (c); + entry.typeref = c.type_reference.to_qualified_string(); + + taglist.append(entry); +// print_tag(entry); + } + public override void visit_property (Property prop) { + var entry = new CTagsEntry(); + + entry.line_number = prop.source_reference.first_line; + entry.name = prop.name; + entry.kind_name = "property"; + entry.kind = 'p'; + entry.access = get_access (prop); + entry.implementation = implementation(prop); + entry.typeref = prop.property_type.to_qualified_string(); + + taglist.append(entry); +// print_tag(entry); + } + + public override void visit_method (Method m) { + var entry = new CTagsEntry(); + + entry.line_number = m.source_reference.first_line; + entry.name = m.name; + entry.kind_name = "method"; + entry.kind = 'm'; + entry.access = get_access (m); + entry.implementation = implementation(m); + entry.typeref = m.return_type.to_qualified_string(); + entry.signature = signature(m.get_parameters()); + + taglist.append(entry); +// print_tag(entry); + } + + public override void visit_local_variable (LocalVariable local) { + var entry = new CTagsEntry(); + + entry.line_number = local.source_reference.first_line; + entry.name = local.name; + entry.kind_name = "local"; + entry.kind = 'l'; + entry.access = get_access (local); + + taglist.append(entry); +// print_tag(entry); + } + + public void parse_vala (string filename, CTagsEntryMaker maker ) { + taglist = new List(); + /* We create a context for every source file so that Parser.parse(context) + * don't parse a file multiple times causing errors. Parser.parse_file(source_file) + * assumes that Parser.context is the same as source_file.context anyway */ + var context = new CodeContext(); + var source_file = new SourceFile(context, filename, filename.has_suffix("vapi")); + context.add_source_file(source_file); + vala_parser.parse(context); + context.accept(this); + foreach (var tagentry in taglist) { + maker(tagentry); + } + taglist = null; + } + public void parse_genie (string filename, CTagsEntryMaker maker ) { + taglist = new List(); + var context = new CodeContext(); + var source_file = new SourceFile(context, filename); + context.add_source_file(source_file); + genie_parser.parse(context); + context.accept(this); + foreach (var tagentry in taglist) { + maker(tagentry); + } + taglist = null; + } +} Index: vala.c =================================================================== --- vala.c (revision 0) +++ vala.c (revision 0) @@ -0,0 +1,100 @@ +/* + * vala.c + * + * Copyright 2008 Abderrahim Kitouni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * INCLUDE FILES + */ +#include "general.h" /* must always come first */ +#include "parse.h" +#include "read.h" + +#include "entry.h" +#include "ctags-visitor.h" + +CTagsVisitor *visitor; +/* using different data structure because fpos_t isn't available in Vala*/ +static void make_ctags_entry (CTagsEntry* entry) { + tagEntryInfo tag; + initTagEntry(&tag, entry->name); + + tag.lineNumberEntry = TRUE; + tag.lineNumber = entry->line_number; + tag.kindName = entry->kind_name; + tag.kind = entry->kind; + /* FIXME: add filePosition */ + tag.extensionFields.access = entry->access; + tag.extensionFields.implementation = entry->implementation; + tag.extensionFields.inheritance = entry->inheritance; + tag.extensionFields.typeRef[0] = entry->typeref; + tag.extensionFields.signature = entry->signature; + makeTagEntry(&tag); +} + +static kindOption ValaKinds [] = { + { TRUE, 'c', "class", "Classes" }, + { TRUE, 's', "struct", "Structures" }, + { TRUE, 'i', "interface", "Interfaces" }, + { TRUE, 'e', "enum", "Enumerations" }, + { TRUE, 'v', "enumvalue", "Enumeration Values" }, + { TRUE, 'E', "errordomain", "Error domains" }, + { TRUE, 'r', "errorcode", "Error codes" }, + { TRUE, 'd', "delegate", "Delegates" }, + { TRUE, 'S', "signal", "Signals" }, + { TRUE, 'f', "field", "Fields" }, + { TRUE, 'p', "property", "Properties" }, + { TRUE, 'm', "method", "Methods" }, + { FALSE, 'l', "local", "Local variables" }, +}; + +static void findValaTags (void) { + if (visitor == NULL) { + visitor = ctags_visitor_new(); + } + ctags_visitor_parse_vala (visitor, getSourceFileName(), (CTagsEntryMaker) make_ctags_entry); +} + +extern parserDefinition *ValaParser(void) { + g_type_init(); + static const char *const extensions [] = { "vala", "vapi", NULL }; + parserDefinition* def = parserNew ("Vala"); + def->kinds = ValaKinds; + def->kindCount = KIND_COUNT (ValaKinds); + def->extensions = extensions; + def->parser = findValaTags; + return def; +} + +static void findGenieTags (void) { + if (visitor == NULL) { + visitor = ctags_visitor_new(); + } + ctags_visitor_parse_genie (visitor, getSourceFileName(), (CTagsEntryMaker) make_ctags_entry); +} + +extern parserDefinition *GenieParser(void) { + static const char *const extensions [] = { "gs", NULL }; + parserDefinition* def = parserNew ("Genie"); + def->kinds = ValaKinds; + def->kindCount = KIND_COUNT (ValaKinds); + def->extensions = extensions; + def->parser = findGenieTags; + return def; +} Index: Makefile.am =================================================================== --- Makefile.am (revision 4038) +++ Makefile.am (working copy) @@ -3,6 +3,7 @@ AM_CPPFLAGS = \ $(GLIB_CFLAGS) \ $(DEPRECATED_FLAGS) \ + $(VALA_CFLAGS) \ -I$(srcdir)/include lib_LTLIBRARIES = libanjuta-ctags.la @@ -74,17 +75,22 @@ tm_workspace.c\ verilog.c\ vim.c\ + ctags-visitor.c \ + vala.c \ vstring.c\ vstring.h\ yacc.c +ctags-visitor.c: ctags-visitor.vala + valac -g -C --pkg vala-1.0 $^ + libanjuta_ctags_la_LDFLAGS = $(ANJUTA_LDFLAGS) -libanjuta_ctags_la_LIBADD = $(GLIB_LIBS) +libanjuta_ctags_la_LIBADD = $(GLIB_LIBS) $(VALA_LIBS) noinst_PROGRAMS = \ test_tm_buffer - + test_tm_buffer_SOURCES = \ test_tm_buffer.c\ entry.h \