Merge pull request #3916 from techee/symtree_icons
[geany-mirror.git] / ctags / parsers / lua.c
blob865379085b174be7ce6e1c1502841633c2f8765e
1 /*
2 * Copyright (c) 2000-2001, Max Ischenko <mfi@ukr.net>.
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 Lua language.
8 */
11 * INCLUDE FILES
13 #include "general.h" /* must always come first */
15 #include <string.h>
17 #include "debug.h"
18 #include "entry.h"
19 #include "parse.h"
20 #include "read.h"
21 #include "routines.h"
22 #include "vstring.h"
25 * DATA DEFINITIONS
27 typedef enum {
28 K_FUNCTION,
29 K_UNKNOWN,
30 } luaKind;
32 typedef enum {
33 LUA_UNKNOWN_REFERENCED,
34 } luaUnknownRole;
36 static roleDefinition LuaUnknownRoles [] = {
37 { false, "referenced", "referenced somehow" },
40 static kindDefinition LuaKinds [] = {
41 { true, 'f', "function", "functions" },
43 /* `unknown' is a kind just for making FQ tag for functions. */
44 { false, 'Y', "unknown", "unknown language object",
45 .referenceOnly = true, ATTACH_ROLES(LuaUnknownRoles) },
49 * FUNCTION DEFINITIONS
53 * Helper function.
54 * Returns 1 if line looks like a line of Lua code.
56 * TODO: Recognize UNIX bang notation.
57 * (Lua treat first line as a comment if it starts with #!)
60 static bool is_a_code_line (const unsigned char *line)
62 bool result;
63 const unsigned char *p = line;
64 while (isspace (*p))
65 p++;
66 if (p [0] == '\0')
67 result = false;
68 else if (p [0] == '-' && p [1] == '-')
69 result = false;
70 else
71 result = true;
72 return result;
75 static bool isLuaIdentifier (char c)
77 return (bool) !(isspace((unsigned char) c) || c == '(' || c == ')'
78 || c == '=' || c == '.' || c == ':' || c == '{'
79 || c == '}');
82 static void set_scope (int child, int parent)
84 if (parent == CORK_NIL || child == CORK_NIL)
85 return;
87 tagEntryInfo *e = getEntryInCorkQueue (child);
88 if (!e)
89 return;
91 e->extensionFields.scopeIndex = parent;
94 static void extract_next_token (const char *begin, const char *end_sentinel, vString *name)
96 if (begin == NULL || end_sentinel == NULL)
97 return;
99 Assert (begin <= end_sentinel);
101 /* Both on '(' */
102 if (begin == end_sentinel)
103 return;
105 /* Trim prefixed white spaces */
106 while (isspace ((unsigned char) *begin))
107 begin++;
109 /* Both on '(' */
110 if (begin == end_sentinel)
111 return;
113 const char *end = end_sentinel - 1;
115 /* Trim suffixed white spaces */
116 while (isspace ((unsigned char) *end))
117 end--;
119 Assert (begin <= end);
121 int lastCorkIndx = CORK_NIL;
122 for (const char *c = begin; c <= end; ++c)
124 if (*c == '.' || *c == ':')
126 int r = makeSimpleRefTag(name,
127 K_UNKNOWN, LUA_UNKNOWN_REFERENCED);
128 set_scope(r, lastCorkIndx);
129 lastCorkIndx = r;
131 /* Do not include module names in function name */
132 vStringClear (name);
134 else if (isLuaIdentifier (*c))
135 vStringPut (name, *c);
136 else
138 /* An unexpected character is found
139 * between "function" and "(" */
140 vStringClear (name);
141 return;
145 int d = makeSimpleTag (name, K_FUNCTION);
146 set_scope(d, lastCorkIndx);
147 vStringClear (name);
150 static void extract_prev_token (const char *end, const char *begin_sentinel, vString *name)
152 const char *begin;
154 if (end == NULL || begin_sentinel == NULL)
155 return;
157 if (! (begin_sentinel <= end))
158 return;
160 while (isspace ((unsigned char) *end))
162 end--;
163 if (! (begin_sentinel <= end))
164 return;
167 begin = end;
168 while (begin_sentinel <= begin && isLuaIdentifier (*begin))
169 begin--;
171 int targetCorkIndex = CORK_NIL;
172 if (end - begin)
174 vStringNCatS (name, begin + 1, end - begin);
175 targetCorkIndex = makeSimpleTag (name, K_FUNCTION);
176 vStringClear (name);
179 if (targetCorkIndex == CORK_NIL || begin_sentinel == begin)
180 return;
182 /* Fill the scope field of the function. */
183 end = begin;
184 while (begin_sentinel <= (begin + 1))
186 bool on_boundary = false;
187 if (begin < begin_sentinel || !isLuaIdentifier (*begin))
189 if (end - begin)
191 vStringNCatS (name, begin + 1, end - begin);
192 int r = makeSimpleRefTag (name,
193 K_UNKNOWN, LUA_UNKNOWN_REFERENCED);
194 set_scope (targetCorkIndex, r);
195 targetCorkIndex = r;
196 vStringClear (name);
198 if (begin_sentinel <= begin && ! (*begin == ':' || *begin == '.'))
199 break;
200 on_boundary = true;
202 begin--;
204 if(on_boundary)
205 end = begin;
209 static void findLuaTags (void)
211 vString *name = vStringNew ();
212 const unsigned char *line;
214 while ((line = readLineFromInputFile ()) != NULL)
216 const char *p, *q;
218 if (! is_a_code_line (line))
219 continue;
221 p = (const char*) strstr ((const char*) line, "function");
222 if (p == NULL)
223 continue;
225 q = strchr ((const char*) line, '=');
227 if (q == NULL) {
228 p = p + 8; /* skip the `function' word */
230 /* We expect [ \t(] */
231 if (! (*p == '(' || isspace ((unsigned char) *p)))
232 continue;
233 q = strchr ((const char*) p, '(');
234 if (q)
235 extract_next_token (p, q, name);
236 } else if (
237 (*(q+1) != '=') /* ignore `if type(v) == "function" then ...' */
238 && (q < p) /* ignore "function" ~= */
240 p = (const char*) &line[0];
241 if (p < q)
242 extract_prev_token (q - 1, p, name);
245 vStringDelete (name);
248 extern parserDefinition* LuaParser (void)
250 static const char* const extensions [] = { "lua", NULL };
251 parserDefinition* def = parserNew ("Lua");
252 def->kindTable = LuaKinds;
253 def->kindCount = ARRAY_SIZE (LuaKinds);
254 def->extensions = extensions;
255 def->parser = findLuaTags;
256 def->useCork = CORK_QUEUE;
257 def->requestAutomaticFQTag = true;
258 return def;