2 * Copyright (c) 2003, Brent Fulgham <bfulgham@debian.org>
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains functions for generating tags for Erlang language
8 * files. Some of the parsing constructs are based on the Emacs 'etags'
9 * program by Francesco Potori <pot@gnu.org>
14 #include "general.h" /* must always come first */
28 K_MACRO
, K_FUNCTION
, K_MODULE
, K_RECORD
, K_TYPE
31 static kindDefinition ErlangKinds
[] = {
32 {true, 'd', "macro", "macro definitions"},
33 {true, 'f', "function", "functions"},
34 {true, 'm', "module", "modules"},
35 {true, 'r', "record", "record definitions"},
36 {true, 't', "type", "type definitions"},
40 * FUNCTION DEFINITIONS
42 /* tagEntryInfo and vString should be preinitialized/preallocated but not
43 * necessary. If successful you will find class name in vString
46 static bool isIdentifierFirstCharacter (int c
)
48 return (bool) (isalpha (c
));
51 static bool isIdentifierCharacter (int c
)
53 return (bool) (isalnum (c
) || c
== '_' || c
== ':');
56 static const unsigned char *skipSpace (const unsigned char *cp
)
58 while (isspace ((int) *cp
))
63 static const unsigned char *parseIdentifier (
64 const unsigned char *cp
, vString
*const identifier
)
66 vStringClear (identifier
);
67 while (isIdentifierCharacter ((int) *cp
))
69 vStringPut (identifier
, (int) *cp
);
75 static void makeMemberTag (
76 vString
*const identifier
, erlangKind kind
, vString
*const module
)
78 if (ErlangKinds
[kind
].enabled
&& vStringLength (identifier
) > 0)
81 initTagEntry (&tag
, vStringValue (identifier
), kind
);
83 if (module
!= NULL
&& vStringLength (module
) > 0)
85 tag
.extensionFields
.scopeKindIndex
= K_MODULE
;
86 tag
.extensionFields
.scopeName
= vStringValue (module
);
92 static void parseModuleTag (const unsigned char *cp
, vString
*const module
)
94 vString
*const identifier
= vStringNew ();
95 parseIdentifier (cp
, identifier
);
96 makeSimpleTag (identifier
, K_MODULE
);
98 /* All further entries go in the new module */
99 vStringCopy (module
, identifier
);
100 vStringDelete (identifier
);
103 static void parseSimpleTag (const unsigned char *cp
, erlangKind kind
)
105 vString
*const identifier
= vStringNew ();
106 parseIdentifier (cp
, identifier
);
107 makeSimpleTag (identifier
, kind
);
108 vStringDelete (identifier
);
111 static void parseFunctionTag (const unsigned char *cp
, vString
*const module
)
113 vString
*const identifier
= vStringNew ();
114 parseIdentifier (cp
, identifier
);
115 makeMemberTag (identifier
, K_FUNCTION
, module
);
116 vStringDelete (identifier
);
120 * Directives are of the form:
123 * -record(graph, {vtab = notable, cyclic = true}).
124 * -type some_type() :: any().
125 * -opaque some_opaque_type() :: any().
127 static void parseDirective (const unsigned char *cp
, vString
*const module
)
130 * A directive will be either a record definition or a directive.
131 * Record definitions are handled separately
133 vString
*const directive
= vStringNew ();
134 const char *const drtv
= vStringValue (directive
);
135 cp
= parseIdentifier (cp
, directive
);
140 if (strcmp (drtv
, "record") == 0)
141 parseSimpleTag (cp
, K_RECORD
);
142 else if (strcmp (drtv
, "define") == 0)
143 parseSimpleTag (cp
, K_MACRO
);
144 else if (strcmp (drtv
, "type") == 0)
145 parseSimpleTag (cp
, K_TYPE
);
146 else if (strcmp (drtv
, "opaque") == 0)
147 parseSimpleTag (cp
, K_TYPE
);
148 else if (strcmp (drtv
, "module") == 0)
149 parseModuleTag (cp
, module
);
150 /* Otherwise, it was an import, export, etc. */
152 vStringDelete (directive
);
155 static void findErlangTags (void)
157 vString
*const module
= vStringNew ();
158 const unsigned char *line
;
160 while ((line
= readLineFromInputFile ()) != NULL
)
162 const unsigned char *cp
= line
;
164 if (*cp
== '%') /* skip initial comment */
166 if (*cp
== '"') /* strings sometimes start in column one */
171 ++cp
; /* Move off of the '-' */
172 parseDirective(cp
, module
);
174 else if (isIdentifierFirstCharacter ((int) *cp
))
175 parseFunctionTag (cp
, module
);
177 vStringDelete (module
);
180 extern parserDefinition
*ErlangParser (void)
182 static const char *const extensions
[] = { "erl", "ERL", "hrl", "HRL", NULL
};
183 parserDefinition
*def
= parserNew ("Erlang");
184 def
->kindTable
= ErlangKinds
;
185 def
->kindCount
= ARRAY_SIZE (ErlangKinds
);
186 def
->extensions
= extensions
;
187 def
->parser
= findErlangTags
;