Update for last 2 commits.
[geany-mirror.git] / tagmanager / haskell.c
blob09ccf9f23f081d755d0f864169fdc9771128770b
2 /*
3 * Copyright (c) 2003, Peter Strand <peter@zarquon.se>
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
8 * This module contains functions for generating tags for Haskell language
9 * files.
13 * Does not handle operators or infix definitions like:
14 * a `f` b = ...
20 * INCLUDE FILES
23 #include "general.h" /* must always come first */
25 #include <string.h>
27 #include "parse.h"
28 #include "read.h"
29 #include "vstring.h"
33 * DATA DEFINITIONS
35 typedef enum {
36 K_TYPE, K_CONSTRUCTOR, K_FUNCTION, K_MODULE
37 } haskellKind;
39 static kindOption HaskellKinds [] = {
40 { TRUE, 't', "typedef", "types" },
41 { TRUE, 'c', "macro", "type constructors" },
42 { TRUE, 'f', "function", "functions" },
43 { TRUE, 'm', "namespace", "modules"}
47 typedef const unsigned char *custr;
50 * FUNCTION DEFINITIONS
54 static void skip_rest_of_line(void)
56 int c;
57 do {
58 c = fileGetc();
59 } while (c != EOF && c != '\n');
62 static int get_line(char *buf)
64 int i = 0;
65 int c;
66 do {
67 c = fileGetc();
68 buf[i++] = c;
69 } while (c != EOF && c != '\n' && i < 1000);
70 buf[i] = '\0';
71 return i;
74 static int get_next_char(void)
76 int c, nxt;
77 c = fileGetc();
78 if (c == EOF)
79 return c;
80 nxt = fileGetc();
81 if (nxt == EOF)
82 return c;
83 fileUngetc(nxt);
85 if (c == '-' && nxt == '-') {
86 skip_rest_of_line();
87 return get_next_char();
89 if (c == '{' && nxt == '-') {
90 int last = '\0';
91 do {
92 last = c;
93 c = get_next_char();
94 } while (! (c == EOF || (last == '-' && c == '}')));
95 return get_next_char();
97 return c;
100 static void add_tag(const char *token, haskellKind kind, vString *name)
102 int i;
103 for (i = 0; token[i] != '\0'; ++i)
104 vStringPut(name, token[i]);
106 vStringTerminate(name);
107 makeSimpleTag(name, HaskellKinds, kind);
108 vStringClear(name);
111 static int isident(char c)
113 return isalnum(c) || c == '_' || c == '\'' || c == '$';
116 static int get_token(char *token, int n)
118 int c = fileGetc();
119 int i = n;
120 while (c != EOF && isident(c) && i < 1000) {
121 token[i] = c;
122 i++;
123 c = fileGetc();
125 if (c == EOF)
126 return 0;
127 if (i != n) {
128 token[i] = '\0';
129 fileUngetc(c);
130 return 1;
131 } else {
132 return 0;
136 enum Find_State { Find_Eq, Find_Constr, Get_Extr, Find_Extr, Find_Bar };
138 static int inside_datatype(vString *name)
140 enum Find_State st = Find_Eq;
141 int c;
142 char token[1001];
144 while (1) {
145 if (st == Find_Eq)
147 do {
148 c = get_next_char();
149 if (c == '\n') {
150 c = get_next_char();
151 if (! (c == ' ' || c == '\t')) {
152 return c;
155 } while (c != EOF && c != '=');
156 st = Find_Constr;
158 else if (st == Find_Constr)
160 do {
161 c = get_next_char();
162 } while (isspace(c));
163 if (!isupper(c)) {
164 skip_rest_of_line();
165 return '\n';
167 token[0] = c;
168 if (!get_token(token, 1))
169 return '\n';
170 add_tag(token, K_CONSTRUCTOR, name);
171 st = Find_Extr;
173 else if (st == Find_Extr)
175 c = get_next_char();
176 if (c == '{')
177 st = Get_Extr;
178 else if (c == '|')
179 st = Find_Constr;
180 else if (c == '\n') {
181 c = get_next_char();
182 if (! (c == ' ' || c == '\t')) {
183 return c;
186 else if (!isspace(c))
187 st = Find_Bar;
189 else if (st == Get_Extr)
191 do {
192 c = fileGetc();
193 } while (isspace(c));
194 if (c == EOF)
195 return c;
196 token[0] = c;
197 get_token(token, 1);
198 add_tag(token, K_FUNCTION, name);
199 do {
200 c = get_next_char();
201 if (c == '}') {
202 st = Find_Bar;
203 break;
205 } while (c != EOF && c != ',');
207 else if (st == Find_Bar)
209 do {
210 c = get_next_char();
211 if (c == '\n') {
212 c = get_next_char();
213 if (! (c == ' ' || c == '\t')) {
214 return c;
217 } while (c != EOF && c != '|');
218 st = Find_Constr;
221 return '\n';
224 static void findHaskellTags (int is_literate)
226 vString *name = vStringNew ();
227 char token[1001], arg[1001];
228 int c;
229 int in_tex_lit_code = 0;
230 c = get_next_char();
232 while (c != EOF)
234 if (c == '\n') {
235 c = get_next_char();
236 continue;
239 if (isspace(c)) {
240 skip_rest_of_line();
241 c = get_next_char();
242 continue;
244 if (is_literate && !in_tex_lit_code) {
245 if (c == '>') {
246 c = fileGetc();
247 if (c == ' ') {
248 c = get_next_char();
249 if (!isident(c)) {
250 skip_rest_of_line();
251 c = get_next_char();
252 continue;
254 } else {
255 skip_rest_of_line();
256 c = get_next_char();
257 continue;
259 } else if (c == '\\') {
260 int n = get_line(token);
261 if (strncmp(token, "begin{code}", 11) == 0) {
262 in_tex_lit_code = 1;
263 c = get_next_char();
264 continue;
265 } else {
266 if (n > 0 && token[n-1] != '\n')
267 skip_rest_of_line();
268 else
269 c = get_next_char();
271 continue;
272 } else {
273 skip_rest_of_line();
274 c = get_next_char();
275 continue;
278 if (is_literate && in_tex_lit_code && c == '\\') {
279 if (strncmp(token, "end{code}", 9) == 0) {
280 in_tex_lit_code = 0;
281 c = get_next_char();
282 continue;
285 token[0] = c;
286 token[1] = '\0';
287 if (!isident(c)) {
288 skip_rest_of_line();
289 c = get_next_char();
290 continue;
292 if (!get_token(token, 1)) {
293 c = get_next_char();
294 continue;
296 do {
297 if ((c = fileGetc()) == EOF)
298 return;
299 } while (c == ' ' || c == '\t');
300 arg[0] = c;
301 get_token(arg, 1);
302 if (strcmp(token, "data") == 0 || strcmp(token, "newtype") == 0) {
303 add_tag(arg, K_TYPE, name);
304 c = inside_datatype(name);
305 continue;
307 if (strcmp(token, "type") == 0)
308 add_tag(arg, K_TYPE, name);
309 else if (strcmp(token, "module") == 0)
310 add_tag(arg, K_MODULE, name);
311 else if (strcmp(token, "instance") == 0 ||
312 strcmp(token, "foreign") == 0 ||
313 strcmp(token, "import") == 0)
315 else {
316 if (arg[0] != ':')
317 add_tag(token, K_FUNCTION, name);
319 skip_rest_of_line();
320 c = get_next_char();
322 vStringDelete(name);
325 static void findNormalHaskellTags (void)
327 findHaskellTags (0);
330 static void findLiterateHaskellTags (void)
332 findHaskellTags (1);
335 extern parserDefinition* HaskellParser (void)
337 static const char *const extensions [] = { "hs", NULL };
338 parserDefinition* def = parserNew ("Haskell");
340 def->kinds = HaskellKinds;
341 def->kindCount = KIND_COUNT(HaskellKinds);
342 def->extensions = extensions;
343 def->parser = findNormalHaskellTags;
344 return def;
347 extern parserDefinition* LiterateHaskellParser (void)
349 static const char *const extensions [] = { "lhs", NULL };
350 parserDefinition* def = parserNew ("Literate Haskell");
351 def->kinds = HaskellKinds;
352 def->kindCount = KIND_COUNT(HaskellKinds);
353 def->extensions = extensions;
354 def->parser = findLiterateHaskellTags;
355 return def;
358 /* vi:set expandtab tabstop=8 shiftwidth=4: */