Implement Erlang ctags.

Using erlang.c from fishman/ctags.
This commit is contained in:
Beng Tan 2015-03-15 13:41:23 +08:00
parent 8aa4f11cad
commit b0c5d221a5
7 changed files with 200 additions and 2 deletions

View File

@ -172,7 +172,7 @@ static void init_builtin_filetypes(void)
FT_INIT( VERILOG, VERILOG, "Verilog", NULL, SOURCE_FILE, COMPILED );
FT_INIT( DIFF, DIFF, "Diff", NULL, FILE, MISC );
FT_INIT( LISP, NONE, "Lisp", NULL, SOURCE_FILE, SCRIPT );
FT_INIT( ERLANG, NONE, "Erlang", NULL, SOURCE_FILE, COMPILED );
FT_INIT( ERLANG, ERLANG, "Erlang", NULL, SOURCE_FILE, COMPILED );
FT_INIT( CONF, CONF, "Conf", _("Config"), FILE, MISC );
FT_INIT( PO, NONE, "Po", _("Gettext translation"), FILE, MISC );
FT_INIT( HAXE, HAXE, "Haxe", NULL, SOURCE_FILE, COMPILED );

View File

@ -23,6 +23,7 @@ parsers = \
css.c \
diff.c \
docbook.c \
erlang.c \
fortran.c \
go.c \
haskell.c \

194
tagmanager/ctags/erlang.c Normal file
View File

@ -0,0 +1,194 @@
/*
* Copyright (c) 2003, Brent Fulgham <bfulgham@debian.org>
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
*
* This module contains functions for generating tags for Erlang language
* files. Some of the parsing constructs are based on the Emacs 'etags'
* program by Francesco Potori <pot@gnu.org>
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "entry.h"
#include "options.h"
#include "read.h"
// #include "routines.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_MACRO, K_FUNCTION, K_MODULE, K_RECORD, K_TYPE
} erlangKind;
static kindOption ErlangKinds[] = {
{TRUE, 'd', "macro", "macro definitions"},
{TRUE, 'f', "function", "functions"},
{TRUE, 'm', "module", "modules"},
{TRUE, 'r', "record", "record definitions"},
{TRUE, 't', "type", "type definitions"},
};
/*
* FUNCTION DEFINITIONS
*/
/* tagEntryInfo and vString should be preinitialized/preallocated but not
* necessary. If successful you will find class name in vString
*/
static boolean isIdentifierFirstCharacter (int c)
{
return (boolean) (isalpha (c));
}
static boolean isIdentifierCharacter (int c)
{
return (boolean) (isalnum (c) || c == '_' || c == ':');
}
static const unsigned char *skipSpace (const unsigned char *cp)
{
while (isspace ((int) *cp))
++cp;
return cp;
}
static const unsigned char *parseIdentifier (
const unsigned char *cp, vString *const identifier)
{
vStringClear (identifier);
while (isIdentifierCharacter ((int) *cp))
{
vStringPut (identifier, (int) *cp);
++cp;
}
vStringTerminate (identifier);
return cp;
}
static void makeMemberTag (
vString *const identifier, erlangKind kind, vString *const module)
{
if (ErlangKinds [kind].enabled && vStringLength (identifier) > 0)
{
tagEntryInfo tag;
initTagEntry (&tag, vStringValue (identifier));
tag.kindName = ErlangKinds[kind].name;
tag.kind = ErlangKinds[kind].letter;
if (module != NULL && vStringLength (module) > 0)
{
tag.extensionFields.scope [0] = "module";
tag.extensionFields.scope [1] = vStringValue (module);
}
makeTagEntry (&tag);
}
}
static void parseModuleTag (const unsigned char *cp, vString *const module)
{
vString *const identifier = vStringNew ();
parseIdentifier (cp, identifier);
makeSimpleTag (identifier, ErlangKinds, K_MODULE);
/* All further entries go in the new module */
vStringCopy (module, identifier);
vStringDelete (identifier);
}
static void parseSimpleTag (const unsigned char *cp, erlangKind kind)
{
vString *const identifier = vStringNew ();
parseIdentifier (cp, identifier);
makeSimpleTag (identifier, ErlangKinds, kind);
vStringDelete (identifier);
}
static void parseFunctionTag (const unsigned char *cp, vString *const module)
{
vString *const identifier = vStringNew ();
parseIdentifier (cp, identifier);
makeMemberTag (identifier, K_FUNCTION, module);
vStringDelete (identifier);
}
/*
* Directives are of the form:
* -module(foo)
* -define(foo, bar)
* -record(graph, {vtab = notable, cyclic = true}).
* -type some_type() :: any().
* -opaque some_opaque_type() :: any().
*/
static void parseDirective (const unsigned char *cp, vString *const module)
{
/*
* A directive will be either a record definition or a directive.
* Record definitions are handled separately
*/
vString *const directive = vStringNew ();
const char *const drtv = vStringValue (directive);
cp = parseIdentifier (cp, directive);
cp = skipSpace (cp);
if (*cp == '(')
++cp;
if (strcmp (drtv, "record") == 0)
parseSimpleTag (cp, K_RECORD);
else if (strcmp (drtv, "define") == 0)
parseSimpleTag (cp, K_MACRO);
else if (strcmp (drtv, "type") == 0)
parseSimpleTag (cp, K_TYPE);
else if (strcmp (drtv, "opaque") == 0)
parseSimpleTag (cp, K_TYPE);
else if (strcmp (drtv, "module") == 0)
parseModuleTag (cp, module);
/* Otherwise, it was an import, export, etc. */
vStringDelete (directive);
}
static void findErlangTags (void)
{
vString *const module = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
if (*cp == '%') /* skip initial comment */
continue;
if (*cp == '"') /* strings sometimes start in column one */
continue;
if ( *cp == '-')
{
++cp; /* Move off of the '-' */
parseDirective(cp, module);
}
else if (isIdentifierFirstCharacter ((int) *cp))
parseFunctionTag (cp, module);
}
vStringDelete (module);
}
extern parserDefinition *ErlangParser (void)
{
static const char *const extensions[] = { "erl", "ERL", "hrl", "HRL", NULL };
parserDefinition *def = parserNew ("Erlang");
def->kinds = ErlangKinds;
def->kindCount = KIND_COUNT (ErlangKinds);
def->extensions = extensions;
def->parser = findErlangTags;
return def;
}
/* vi:set tabstop=4 shiftwidth=4: */

View File

@ -44,7 +44,7 @@ all: $(COMPLIB)
clean:
-$(RM) deps.mak *.o $(COMPLIB)
$(COMPLIB): abaqus.o abc.o args.o c.o cobol.o fortran.o make.o conf.o pascal.o perl.o php.o diff.o vhdl.o verilog.o lua.o js.o \
$(COMPLIB): abaqus.o abc.o args.o c.o cobol.o erlang.o fortran.o make.o conf.o pascal.o perl.o php.o diff.o vhdl.o verilog.o lua.o js.o \
actionscript.o nsis.o objc.o \
haskell.o haxe.o html.o python.o lregex.o asciidoc.o rest.o sh.o ctags.o entry.o get.o keyword.o nestlevel.o \
options.o \

View File

@ -29,6 +29,7 @@
ConfParser, \
SqlParser, \
DocBookParser, \
ErlangParser, \
CssParser, \
RubyParser, \
TclParser, \

View File

@ -35,6 +35,7 @@ typedef enum
TM_PARSER_CONF,
TM_PARSER_SQL,
TM_PARSER_DOCBOOK,
TM_PARSER_ERLANG,
TM_PARSER_CSS,
TM_PARSER_RUBY,
TM_PARSER_TCL,

View File

@ -79,6 +79,7 @@ ctags_sources = set([
'tagmanager/ctags/ctags.c',
'tagmanager/ctags/diff.c',
'tagmanager/ctags/docbook.c',
'tagmanager/ctags/erlang.c',
'tagmanager/ctags/entry.c',
'tagmanager/ctags/fortran.c',
'tagmanager/ctags/get.c',