xref: /Universal-ctags/parsers/sml.c (revision 16a2541c0698bd8ee03c1be8172ef3191f6e695a)
1 /*
2 *   Copyright (c) 2002, Venkatesh Prasad Ranganath and Darren Hiebert
3 *
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.
6 *
7 *   This module contains functions for generating tags for SML language files.
8 */
9 
10 /*
11  *   INCLUDE FILES
12  */
13 #include "general.h"  /* must always come first */
14 
15 #include <string.h>
16 
17 #include "debug.h"
18 #include "entry.h"
19 #include "parse.h"
20 #include "read.h"
21 #include "routines.h"
22 #include "vstring.h"
23 
24 /*
25  *   DATA DECLARATIONS
26  */
27 typedef enum {
28 	K_AND = -2,
29 	K_NONE = -1,
30 	K_EXCEPTION,
31 	K_FUNCTION,
32 	K_FUNCTOR,
33 	K_SIGNATURE,
34 	K_STRUCTURE,
35 	K_TYPE,
36 	K_VAL,
37 	K_COUNT			/* must be last */
38 } smlKind;
39 
40 /*
41  *   DATA DEFINITIONS
42  */
43 static kindDefinition SmlKinds[] = {
44 	{ true, 'e', "exception", "exception declarations" },
45 	{ true, 'f', "function",  "function definitions" },
46 	{ true, 'c', "functor",   "functor definitions" },
47 	{ true, 's', "signature", "signature declarations" },
48 	{ true, 'r', "structure", "structure declarations" },
49 	{ true, 't', "type",      "type definitions" },
50 	{ true, 'v', "value",     "value bindings" }
51 };
52 
53 static struct {
54 	const char *keyword;
55 	smlKind kind;
56 } SmlKeywordTypes [] = {
57 	{ "abstype",   K_TYPE      },
58 	{ "and",       K_AND       },
59 	{ "datatype",  K_TYPE      },
60 	{ "exception", K_EXCEPTION },
61 	{ "functor",   K_FUNCTOR   },
62 	{ "fun",       K_FUNCTION  },
63 	{ "signature", K_SIGNATURE },
64 	{ "structure", K_STRUCTURE },
65 	{ "type",      K_TYPE      },
66 	{ "val",       K_VAL       }
67 };
68 
69 static unsigned int CommentLevel = 0;
70 
71 /*
72  * FUNCTION DEFINITIONS
73  */
74 
makeSmlTag(smlKind type,vString * name)75 static void makeSmlTag (smlKind type, vString *name)
76 {
77 	tagEntryInfo tag;
78 
79 	Assert (0 <= type && type < K_COUNT);
80 	if (! SmlKinds [type].enabled)
81 		return;
82 
83 	initTagEntry (&tag, vStringValue (name), type);
84 	makeTagEntry (&tag);
85 }
86 
skipSpace(const unsigned char * cp)87 static const unsigned char *skipSpace (const unsigned char *cp)
88 {
89 	while (isspace ((int) *cp))
90 		++cp;
91 	return cp;
92 }
93 
isIdentifier(int c)94 static bool isIdentifier (int c)
95 {
96 	bool result = false;
97 	/* Consider '_' as an delimiter to aid user in tracking it's usage. */
98 	const char *const alternateIdentifiers = "!%&$#+-<>=/?@\\~'^|*_";
99 	if (isalnum (c))
100 		result = true;
101 	else if (c != '\0'  &&  strchr (alternateIdentifiers, c) != NULL)
102 		result = true;
103 	return result;
104 }
105 
parseIdentifier(const unsigned char * cp,vString * const identifier)106 static const unsigned char *parseIdentifier (
107 		const unsigned char *cp, vString *const identifier)
108 {
109 	bool stringLit = false;
110 	vStringClear (identifier);
111 	while (*cp != '\0'  &&  (!isIdentifier ((int) *cp) || stringLit))
112 	{
113 		int oneback = *cp;
114 		cp++;
115 		if (oneback == '('  &&  *cp == '*'  &&  stringLit == false)
116 		{
117 			CommentLevel++;
118 			return ++cp;
119 		}
120 		if (*cp == '"' && oneback != '\\')
121 		{
122 			stringLit = true;
123 			continue;
124 		}
125 		if (stringLit && *cp == '"' && oneback != '\\')
126 			stringLit = false;
127 	}
128 	if (strcmp ((const char *) cp, "") == 0 || cp == NULL)
129 		return cp;
130 
131 	while (isIdentifier ((int) *cp))
132 	{
133 		vStringPut (identifier, (int) *cp);
134 		cp++;
135 	}
136 	return cp;
137 }
138 
findNextIdentifier(const unsigned char ** cp)139 static smlKind findNextIdentifier (const unsigned char **cp)
140 {
141 	smlKind result = K_NONE;
142 	vString *const identifier = vStringNew ();
143 	unsigned int count = ARRAY_SIZE (SmlKeywordTypes);
144 	unsigned int i;
145 	*cp = parseIdentifier (*cp, identifier);
146 	for (i = 0  ;  i < count  &&  result == K_NONE ;  ++i)
147 	{
148 		const char *id = vStringValue (identifier);
149 		if (strcmp (id, SmlKeywordTypes [i].keyword) == 0)
150 			result = SmlKeywordTypes [i].kind;
151 	}
152 	vStringDelete (identifier);
153 	return result;
154 }
155 
findSmlTags(void)156 static void findSmlTags (void)
157 {
158 	vString *const identifier = vStringNew ();
159 	const unsigned char *line;
160 	smlKind lastTag = K_NONE;
161 
162 	while ((line = readLineFromInputFile ()) != NULL)
163 	{
164 		const unsigned char *cp = skipSpace (line);
165 		do
166 		{
167 			smlKind foundTag;
168 			if (CommentLevel != 0)
169 			{
170 				cp = (const unsigned char *) strstr ((const char *) cp, "*)");
171 				if (cp == NULL)
172 					continue;
173 				else
174 				{
175 					--CommentLevel;
176 					cp += 2;
177 				}
178 			}
179 			foundTag = findNextIdentifier (&cp);
180 			if (foundTag != K_NONE)
181 			{
182 				cp = skipSpace (cp);
183 				cp = parseIdentifier (cp, identifier);
184 				if (foundTag == K_AND)
185 				{
186 					if (lastTag != K_NONE)
187 						makeSmlTag (lastTag, identifier);
188 				}
189 				else
190 				{
191 					makeSmlTag (foundTag, identifier);
192 					lastTag = foundTag;
193 				}
194 			}
195 			if (strstr ((const char *) cp, "(*") != NULL)
196 			{
197 				cp += 2;
198 				cp = (const unsigned char *) strstr ((const char *) cp, "*)");
199 				if (cp == NULL)
200 					++CommentLevel;
201 			}
202 		} while (cp != NULL  &&  strcmp ((const char *) cp, "") != 0);
203 	}
204 	vStringDelete (identifier);
205 }
206 
SmlParser(void)207 extern parserDefinition *SmlParser (void)
208 {
209 	static const char *const extensions[] = { "sml", "sig", NULL };
210 	parserDefinition *def = parserNew ("SML");
211 	def->kindTable = SmlKinds;
212 	def->kindCount = ARRAY_SIZE (SmlKinds);
213 	def->extensions = extensions;
214 	def->parser = findSmlTags;
215 	return def;
216 }
217