Merge pull request #11 from esorton/bugfix/add-constexpr-keyword-to-arduino-ctags
[arduino-ctags.git] / erlang.c
blob23469aa737bb25e19e16a33fe2616a812be2a711
1 /*
2 * $Id: erlang.c 443 2006-05-30 04:37:13Z darren $
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>
14 * INCLUDE FILES
16 #include "general.h" /* must always come first */
18 #include <string.h>
20 #include "entry.h"
21 #include "options.h"
22 #include "read.h"
23 #include "routines.h"
24 #include "vstring.h"
27 * DATA DEFINITIONS
29 typedef enum {
30 K_MACRO, K_FUNCTION, K_MODULE, K_RECORD
31 } erlangKind;
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))
60 ++cp;
61 return 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);
71 ++cp;
73 vStringTerminate (identifier);
74 return cp;
77 static void makeMemberTag (
78 vString *const identifier, erlangKind kind, vString *const module)
80 if (ErlangKinds [kind].enabled && vStringLength (identifier) > 0)
82 tagEntryInfo tag;
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);
92 makeTagEntry (&tag);
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:
125 * -module(foo)
126 * -define(foo, bar)
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);
138 cp = skipSpace (cp);
139 if (*cp == '(')
140 ++cp;
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 */
163 continue;
164 if (*cp == '"') /* strings sometimes start in column one */
165 continue;
167 if ( *cp == '-')
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;
186 return def;
189 /* vi:set tabstop=4 shiftwidth=4: */