4 * Copyright (c) 2003, Brent Fulgham <bfulgham@debian.org>
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains functions for generating tags for Erlang language
10 * files. Some of the parsing constructs are based on the Emacs 'etags'
11 * program by Francesco Potori <pot@gnu.org>
16 #include "general.h" /* must always come first */
30 K_MACRO
, K_FUNCTION
, K_MODULE
, K_RECORD
33 static kindOption ErlangKinds
[] = {
34 {TRUE
, 'd', "macro", "macro definitions"},
35 {TRUE
, 'f', "function", "functions"},
36 {TRUE
, 'm', "module", "modules"},
37 {TRUE
, 'r', "record", "record definitions"},
41 * FUNCTION DEFINITIONS
43 /* tagEntryInfo and vString should be preinitialized/preallocated but not
44 * necessary. If successful you will find class name in vString
47 static boolean
isIdentifierFirstCharacter (int c
)
49 return (boolean
) (isalpha (c
));
52 static boolean
isIdentifierCharacter (int c
)
54 return (boolean
) (isalnum (c
) || c
== '_' || c
== ':');
57 static const unsigned char *skipSpace (const unsigned char *cp
)
59 while (isspace ((int) *cp
))
64 static const unsigned char *parseIdentifier (
65 const unsigned char *cp
, vString
*const identifier
)
67 vStringClear (identifier
);
68 while (isIdentifierCharacter ((int) *cp
))
70 vStringPut (identifier
, (int) *cp
);
73 vStringTerminate (identifier
);
77 static void makeMemberTag (
78 vString
*const identifier
, erlangKind kind
, vString
*const module
)
80 if (ErlangKinds
[kind
].enabled
&& vStringLength (identifier
) > 0)
83 initTagEntry (&tag
, vStringValue (identifier
));
84 tag
.kindName
= ErlangKinds
[kind
].name
;
85 tag
.kind
= ErlangKinds
[kind
].letter
;
87 if (module
!= NULL
&& vStringLength (module
) > 0)
89 tag
.extensionFields
.scope
[0] = "module";
90 tag
.extensionFields
.scope
[1] = vStringValue (module
);
96 static void parseModuleTag (const unsigned char *cp
, vString
*const module
)
98 vString
*const identifier
= vStringNew ();
99 parseIdentifier (cp
, identifier
);
100 makeSimpleTag (identifier
, ErlangKinds
, K_MODULE
);
102 /* All further entries go in the new module */
103 vStringCopy (module
, identifier
);
104 vStringDelete (identifier
);
107 static void parseSimpleTag (const unsigned char *cp
, erlangKind kind
)
109 vString
*const identifier
= vStringNew ();
110 parseIdentifier (cp
, identifier
);
111 makeSimpleTag (identifier
, ErlangKinds
, kind
);
112 vStringDelete (identifier
);
115 static void parseFunctionTag (const unsigned char *cp
, vString
*const module
)
117 vString
*const identifier
= vStringNew ();
118 parseIdentifier (cp
, identifier
);
119 makeMemberTag (identifier
, K_FUNCTION
, module
);
120 vStringDelete (identifier
);
124 * Directives are of the form:
127 * -record(graph, {vtab = notable, cyclic = true}).
129 static void parseDirective (const unsigned char *cp
, vString
*const module
)
132 * A directive will be either a record definition or a directive.
133 * Record definitions are handled separately
135 vString
*const directive
= vStringNew ();
136 const char *const drtv
= vStringValue (directive
);
137 cp
= parseIdentifier (cp
, directive
);
142 if (strcmp (drtv
, "record") == 0)
143 parseSimpleTag (cp
, K_RECORD
);
144 else if (strcmp (drtv
, "define") == 0)
145 parseSimpleTag (cp
, K_MACRO
);
146 else if (strcmp (drtv
, "module") == 0)
147 parseModuleTag (cp
, module
);
148 /* Otherwise, it was an import, export, etc. */
150 vStringDelete (directive
);
153 static void findErlangTags (void)
155 vString
*const module
= vStringNew ();
156 const unsigned char *line
;
158 while ((line
= fileReadLine ()) != NULL
)
160 const unsigned char *cp
= line
;
162 if (*cp
== '%') /* skip initial comment */
164 if (*cp
== '"') /* strings sometimes start in column one */
169 ++cp
; /* Move off of the '-' */
170 parseDirective(cp
, module
);
172 else if (isIdentifierFirstCharacter ((int) *cp
))
173 parseFunctionTag (cp
, module
);
175 vStringDelete (module
);
178 extern parserDefinition
*ErlangParser (void)
180 static const char *const extensions
[] = { "erl", "ERL", "hrl", "HRL", NULL
};
181 parserDefinition
*def
= parserNew ("Erlang");
182 def
->kinds
= ErlangKinds
;
183 def
->kindCount
= KIND_COUNT (ErlangKinds
);
184 def
->extensions
= extensions
;
185 def
->parser
= findErlangTags
;
189 /* vi:set tabstop=4 shiftwidth=4: */