2 * Copyright (c) 2000-2002, Darren Hiebert
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 LISP files.
13 #include "general.h" /* must always come first */
18 #include "selectors.h"
34 static kindDefinition LispKinds
[] = {
35 { true, 'u', "unknown", "unknown type of definitions" },
36 { true, 'f', "function", "functions" },
37 { true, 'v', "variable", "variables" },
38 { true, 'm', "macro", "macros" },
39 { true, 'c', "const", "constants" },
62 /* Following macro/builtin doesn't define a name appeared
63 * at car. So this parser doesn't handle it well.
64 * -----------------------------------------------------
65 * defadvice (=> cadadr)
66 * defconst-mode-local (=> cadr)
67 * defvar-mode-local (=> cadr)
69 static kindDefinition EmacsLispKinds
[] = {
70 { true, 'u', "unknown", "unknown type of definitions" },
71 { true, 'f', "function", "functions" },
72 { true, 'v', "variable", "variables" },
73 { true, 'c', "const", "constants" },
74 { true, 'm', "macro", "macros" },
75 { true, 'a', "alias", "aliases for functions" },
76 { true, 'V', "varalias", "aliases for variables" },
77 { true, 's', "subst", "inline function" },
78 { true, 'i', "inline", "inline function" },
79 { true, 'e', "error", "errors" },
80 { true, 'M', "minorMode", "minor modes" },
81 { true, 'D', "derivedMode", "derived major mode" },
83 { true, 'C', "custom", "customizable variables" },
84 { true, 'G', "group", "customization groups" },
85 { true, 'H', "face", "customizable faces" }, /* 'F' is reserved by ctags */
86 { true, 'T', "theme", "custom themes" },
90 * FUNCTION DEFINITIONS
95 * look for (def or (DEF, quote or QUOTE
97 static int L_isdef (const unsigned char *strp
, bool case_insensitive
)
99 bool cis
= case_insensitive
; /* Renaming for making code short */
101 return ( (strp
[1] == 'd' || (cis
&& strp
[1] == 'D'))
102 && (strp
[2] == 'e' || (cis
&& strp
[2] == 'E'))
103 && (strp
[3] == 'f' || (cis
&& strp
[3] == 'F')));
106 static int L_isquote (const unsigned char *strp
, bool case_insensitive
)
108 bool cis
= case_insensitive
; /* Renaming for making code short */
110 return ( (*(++strp
) == 'q' || (cis
&& *strp
== 'Q'))
111 && (*(++strp
) == 'u' || (cis
&& *strp
== 'U'))
112 && (*(++strp
) == 'o' || (cis
&& *strp
== 'O'))
113 && (*(++strp
) == 't' || (cis
&& *strp
== 'T'))
114 && (*(++strp
) == 'e' || (cis
&& *strp
== 'E'))
115 && isspace (*(++strp
)));
118 static int lisp_hint2kind (const vString
*const hint
)
123 /* 4 means strlen("(def"). */
124 #define EQN(X) strncmp(vStringValue (hint) + 4, &X[3], n) == 0
125 switch (vStringLength (hint
) - 4)
144 if (EQN("DEFCONSTANT"))
152 /* TODO: implement this in hashtable. */
153 static int elisp_hint2kind (const vString
*const hint
)
158 /* 4 means strlen("(def"). */
159 #define EQN(X) strncmp(vStringValue (hint) + 4, &X[3], n) == 0
160 switch (vStringLength (hint
) - 4)
171 else if (EQN("defun*"))
182 else if (EQN("defmacro"))
184 else if (EQN("defalias"))
186 else if (EQN("defsubst"))
188 else if (EQN("defgroup"))
190 else if (EQN("deftheme"))
195 if (EQN("defcustom"))
197 else if (EQN("defsubst*"))
199 else if (EQN("defmacro*"))
204 if (EQN("define-key"))
205 k
= KIND_GHOST_INDEX
;
209 if (EQN("defvar-local"))
211 else if (EQN("define-error"))
216 if (EQN("defvaralias"))
221 if (EQN("define-inline"))
226 if (EQN("define-minor-mode"))
231 if (EQN("define-derived-mode"))
236 if (EQN("define-global-minor-mode"))
241 if (EQN("define-globalized-minor-mode"))
246 if (EQN("define-obsolete-function-alias"))
254 static void L_getit (vString
*const name
, const unsigned char *dbp
,
255 bool case_insensitive
,
256 int (*hint2kind
) (const vString
*),
257 const vString
*const kind_hint
)
259 const unsigned char *p
;
261 if (*dbp
== '\'') /* Skip prefix quote */
263 else if (*dbp
== '(' && L_isquote (dbp
, case_insensitive
)) /* Skip "(quote " */
266 while (isspace (*dbp
))
269 for (p
=dbp
; *p
!='\0' && *p
!='(' && !isspace ((int) *p
) && *p
!=')' ; p
++)
270 vStringPut (name
, *p
);
272 if (vStringLength (name
) > 0)
274 int kind
= hint2kind (kind_hint
);
275 if (kind
!= KIND_GHOST_INDEX
)
276 makeSimpleTag (name
, kind
);
281 /* Algorithm adapted from from GNU etags.
283 static void findLispTagsCommon (bool case_insensitive
,
285 int (*hint2kind
) (const vString
*))
287 vString
*name
= vStringNew ();
288 vString
*kind_hint
= vStringNew ();
289 const unsigned char* p
;
292 while ((p
= readLineFromInputFile ()) != NULL
)
296 if (L_isdef (p
, case_insensitive
))
298 vStringClear (kind_hint
);
299 while (*p
!= '\0' && !isspace ((int) *p
))
301 vStringPut (kind_hint
,
302 case_insensitive
? toupper((int)*p
): *p
);
305 while (isspace ((int) *p
))
307 L_getit (name
, p
, case_insensitive
, hint2kind
, kind_hint
);
309 else if (has_namespace
)
313 while (*p
!= '\0' && !isspace ((int) *p
)
314 && *p
!= ':' && *p
!= '(' && *p
!= ')');
321 if (L_isdef (p
- 1, case_insensitive
))
323 vStringClear (kind_hint
);
324 while (*p
!= '\0' && !isspace ((int) *p
))
326 vStringPut (kind_hint
,
327 case_insensitive
? toupper((int)*p
): *p
);
332 L_getit (name
, p
, case_insensitive
, hint2kind
, kind_hint
);
338 vStringDelete (name
);
339 vStringDelete (kind_hint
);
342 static void findLispTags (void)
344 findLispTagsCommon (true, true, lisp_hint2kind
);
347 static void findEmacsLispTags (void)
349 findLispTagsCommon (false, false, elisp_hint2kind
);
352 extern parserDefinition
* LispParser (void)
354 static const char *const extensions
[] = {
355 "cl", "clisp", "l", "lisp", "lsp", NULL
357 static const char *const aliases
[] = {
361 static selectLanguage selectors
[] = { selectLispOrLEXByLEXMarker
, NULL
};
363 parserDefinition
* def
= parserNew ("Lisp");
364 def
->kindTable
= LispKinds
;
365 def
->kindCount
= ARRAY_SIZE (LispKinds
);
366 def
->extensions
= extensions
;
367 def
->aliases
= aliases
;
368 def
->parser
= findLispTags
;
369 def
->selectLanguage
= selectors
;
373 extern parserDefinition
* EmacsLispParser (void)
375 static const char *const extensions
[] = {
378 static const char *const aliases
[] = {
382 parserDefinition
* def
= parserNew ("EmacsLisp");
383 def
->kindTable
= EmacsLispKinds
;
384 def
->kindCount
= ARRAY_SIZE (EmacsLispKinds
);
385 def
->extensions
= extensions
;
386 def
->aliases
= aliases
;
387 def
->parser
= findEmacsLispTags
;