xref: /Universal-ctags/parsers/lua.c (revision 93b3d55c8341e112733574a8b5539585d3e7efa0)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO *   Copyright (c) 2000-2001, Max Ischenko <mfi@ukr.net>.
33ae02089SMasatake YAMATO *
43ae02089SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
63ae02089SMasatake YAMATO *
73ae02089SMasatake YAMATO *   This module contains functions for generating tags for Lua language.
83ae02089SMasatake YAMATO */
93ae02089SMasatake YAMATO 
103ae02089SMasatake YAMATO /*
113ae02089SMasatake YAMATO *   INCLUDE FILES
123ae02089SMasatake YAMATO */
133ae02089SMasatake YAMATO #include "general.h"  /* must always come first */
143ae02089SMasatake YAMATO 
153ae02089SMasatake YAMATO #include <string.h>
163ae02089SMasatake YAMATO 
171df886f0SMasatake YAMATO #include "debug.h"
189f9a097cSMasatake YAMATO #include "entry.h"
193ae02089SMasatake YAMATO #include "parse.h"
203ae02089SMasatake YAMATO #include "read.h"
213db72c21SMasatake YAMATO #include "routines.h"
223ae02089SMasatake YAMATO #include "vstring.h"
233ae02089SMasatake YAMATO 
243ae02089SMasatake YAMATO /*
253ae02089SMasatake YAMATO *   DATA DEFINITIONS
263ae02089SMasatake YAMATO */
273ae02089SMasatake YAMATO typedef enum {
289f9a097cSMasatake YAMATO 	K_FUNCTION,
299f9a097cSMasatake YAMATO 	K_UNKNOWN,
303ae02089SMasatake YAMATO } luaKind;
313ae02089SMasatake YAMATO 
329f9a097cSMasatake YAMATO typedef enum {
339f9a097cSMasatake YAMATO 	LUA_UNKNOWN_REFERENCED,
349f9a097cSMasatake YAMATO } luaUnknownRole;
359f9a097cSMasatake YAMATO 
369f9a097cSMasatake YAMATO static roleDefinition LuaUnknownRoles [] = {
379f9a097cSMasatake YAMATO 	{ false, "referenced", "referenced somehow" },
389f9a097cSMasatake YAMATO };
399f9a097cSMasatake YAMATO 
40e112e8abSMasatake YAMATO static kindDefinition LuaKinds [] = {
419f9a097cSMasatake YAMATO 	{ true, 'f', "function", "functions" },
429f9a097cSMasatake YAMATO 
439f9a097cSMasatake YAMATO 	/* `unknown' is a kind just for making FQ tag for functions. */
449f9a097cSMasatake YAMATO 	{ false, 'X', "unknown",  "unknown language object",
459f9a097cSMasatake YAMATO 	  .referenceOnly = true, ATTACH_ROLES(LuaUnknownRoles) },
463ae02089SMasatake YAMATO };
473ae02089SMasatake YAMATO 
483ae02089SMasatake YAMATO /*
493ae02089SMasatake YAMATO *   FUNCTION DEFINITIONS
503ae02089SMasatake YAMATO */
513ae02089SMasatake YAMATO 
523ae02089SMasatake YAMATO /*
533ae02089SMasatake YAMATO  * Helper function.
543ae02089SMasatake YAMATO  * Returns 1 if line looks like a line of Lua code.
553ae02089SMasatake YAMATO  *
563ae02089SMasatake YAMATO  * TODO: Recognize UNIX bang notation.
573ae02089SMasatake YAMATO  * (Lua treat first line as a comment if it starts with #!)
583ae02089SMasatake YAMATO  *
593ae02089SMasatake YAMATO  */
is_a_code_line(const unsigned char * line)60ce990805SThomas Braun static bool is_a_code_line (const unsigned char *line)
613ae02089SMasatake YAMATO {
62ce990805SThomas Braun 	bool result;
633ae02089SMasatake YAMATO 	const unsigned char *p = line;
643ae02089SMasatake YAMATO 	while (isspace ((int) *p))
653ae02089SMasatake YAMATO 		p++;
663ae02089SMasatake YAMATO 	if (p [0] == '\0')
67ce990805SThomas Braun 		result = false;
683ae02089SMasatake YAMATO 	else if (p [0] == '-' && p [1] == '-')
69ce990805SThomas Braun 		result = false;
703ae02089SMasatake YAMATO 	else
71ce990805SThomas Braun 		result = true;
723ae02089SMasatake YAMATO 	return result;
733ae02089SMasatake YAMATO }
743ae02089SMasatake YAMATO 
isLuaIdentifier(char c)75ce990805SThomas Braun static bool isLuaIdentifier (char c)
763ae02089SMasatake YAMATO {
77*93b3d55cSMasatake YAMATO 	return (bool) !(isspace(c)  || c == '(' || c == ')' || c == '=' || c == '.' || c == ':'
78*93b3d55cSMasatake YAMATO 					|| c == '{' || c == '}');
79d88f3cdeSMasatake YAMATO }
80d88f3cdeSMasatake YAMATO 
set_scope(int child,int parent)819f9a097cSMasatake YAMATO static void set_scope (int child, int parent)
829f9a097cSMasatake YAMATO {
839f9a097cSMasatake YAMATO 	if (parent == CORK_NIL || child == CORK_NIL)
849f9a097cSMasatake YAMATO 		return;
859f9a097cSMasatake YAMATO 
869f9a097cSMasatake YAMATO 	tagEntryInfo *e = getEntryInCorkQueue (child);
879f9a097cSMasatake YAMATO 	if (!e)
889f9a097cSMasatake YAMATO 		return;
899f9a097cSMasatake YAMATO 
909f9a097cSMasatake YAMATO 	e->extensionFields.scopeIndex = parent;
919f9a097cSMasatake YAMATO }
929f9a097cSMasatake YAMATO 
extract_next_token(const char * begin,const char * end_sentinel,vString * name)93d88f3cdeSMasatake YAMATO static void extract_next_token (const char *begin, const char *end_sentinel, vString *name)
943ae02089SMasatake YAMATO {
95d88f3cdeSMasatake YAMATO 	if (begin == NULL || end_sentinel == NULL)
96d88f3cdeSMasatake YAMATO 		return;
97d88f3cdeSMasatake YAMATO 
981df886f0SMasatake YAMATO 	Assert (begin <= end_sentinel);
991df886f0SMasatake YAMATO 
1001df886f0SMasatake YAMATO 	/* Both on '(' */
1011df886f0SMasatake YAMATO 	if (begin == end_sentinel)
102d88f3cdeSMasatake YAMATO 		return;
1033ae02089SMasatake YAMATO 
1041df886f0SMasatake YAMATO 	/* Trim prefixed white spaces  */
1053ae02089SMasatake YAMATO 	while (isspace ((int) *begin))
106d88f3cdeSMasatake YAMATO 		begin++;
1071df886f0SMasatake YAMATO 
1081df886f0SMasatake YAMATO 	/* Both on '(' */
1091df886f0SMasatake YAMATO 	if (begin == end_sentinel)
1101df886f0SMasatake YAMATO 		return;
1111df886f0SMasatake YAMATO 
1121df886f0SMasatake YAMATO 	const char *end = end_sentinel - 1;
1131df886f0SMasatake YAMATO 
1141df886f0SMasatake YAMATO 	/* Trim suffixed white spaces  */
1151df886f0SMasatake YAMATO 	while (isspace ((int) *end))
1161df886f0SMasatake YAMATO 		end--;
1171df886f0SMasatake YAMATO 
1181df886f0SMasatake YAMATO 	Assert (begin <= end);
1191df886f0SMasatake YAMATO 
1209f9a097cSMasatake YAMATO 	int lastCorkIndx = CORK_NIL;
1211df886f0SMasatake YAMATO 	for (const char *c = begin; c <= end; ++c)
1221df886f0SMasatake YAMATO 	{
123bf8189b4SGregory Anders 		if (*c == '.' || *c == ':')
124bf8189b4SGregory Anders 		{
1259f9a097cSMasatake YAMATO 			int r = makeSimpleRefTag(name,
1269f9a097cSMasatake YAMATO 									 K_UNKNOWN, LUA_UNKNOWN_REFERENCED);
1279f9a097cSMasatake YAMATO 			set_scope(r, lastCorkIndx);
1289f9a097cSMasatake YAMATO 			lastCorkIndx = r;
1299f9a097cSMasatake YAMATO 
130bf8189b4SGregory Anders 			/* Do not include module names in function name */
131bf8189b4SGregory Anders 			vStringClear (name);
132bf8189b4SGregory Anders 		}
133bf8189b4SGregory Anders 		else if (isLuaIdentifier (*c))
1341df886f0SMasatake YAMATO 			vStringPut (name, (int) *c);
1351df886f0SMasatake YAMATO 		else
1361df886f0SMasatake YAMATO 		{
1371df886f0SMasatake YAMATO 			/* An unexpected character is found
1381df886f0SMasatake YAMATO 			 * between "function" and "(" */
1391df886f0SMasatake YAMATO 			vStringClear (name);
140d88f3cdeSMasatake YAMATO 			return;
141d88f3cdeSMasatake YAMATO 		}
142d88f3cdeSMasatake YAMATO 	}
143d88f3cdeSMasatake YAMATO 
1449f9a097cSMasatake YAMATO 	int d = makeSimpleTag (name, K_FUNCTION);
1459f9a097cSMasatake YAMATO 	set_scope(d, lastCorkIndx);
1463ae02089SMasatake YAMATO 	vStringClear (name);
1473ae02089SMasatake YAMATO }
148d88f3cdeSMasatake YAMATO 
extract_prev_token(const char * end,const char * begin_sentinel,vString * name)149d88f3cdeSMasatake YAMATO static void extract_prev_token (const char *end, const char *begin_sentinel, vString *name)
150d88f3cdeSMasatake YAMATO {
151d88f3cdeSMasatake YAMATO 	const char *begin;
152d88f3cdeSMasatake YAMATO 
153d88f3cdeSMasatake YAMATO 	if (end == NULL || begin_sentinel == NULL)
154d88f3cdeSMasatake YAMATO 		return;
155d88f3cdeSMasatake YAMATO 
156d88f3cdeSMasatake YAMATO 	if (! (begin_sentinel <= end))
157d88f3cdeSMasatake YAMATO 		return;
158d88f3cdeSMasatake YAMATO 
159d88f3cdeSMasatake YAMATO 	while (isspace ((int) *end))
160d88f3cdeSMasatake YAMATO 	{
161d88f3cdeSMasatake YAMATO 		end--;
162d88f3cdeSMasatake YAMATO 		if (! (begin_sentinel <= end))
163d88f3cdeSMasatake YAMATO 			return;
164d88f3cdeSMasatake YAMATO 	}
165d88f3cdeSMasatake YAMATO 
166d88f3cdeSMasatake YAMATO 	begin = end;
167d88f3cdeSMasatake YAMATO 	while (begin_sentinel <= begin && isLuaIdentifier (*begin))
168d88f3cdeSMasatake YAMATO 		begin--;
169d88f3cdeSMasatake YAMATO 
1709f9a097cSMasatake YAMATO 	int targetCorkIndex = CORK_NIL;
171d88f3cdeSMasatake YAMATO 	if (end - begin)
172d88f3cdeSMasatake YAMATO 	{
173d88f3cdeSMasatake YAMATO 		vStringNCatS (name, begin + 1, end - begin);
1749f9a097cSMasatake YAMATO 		targetCorkIndex = makeSimpleTag (name, K_FUNCTION);
175d88f3cdeSMasatake YAMATO 		vStringClear (name);
1763ae02089SMasatake YAMATO 	}
1779f9a097cSMasatake YAMATO 
1789f9a097cSMasatake YAMATO 	if (targetCorkIndex == CORK_NIL || begin_sentinel == begin)
1799f9a097cSMasatake YAMATO 		return;
1809f9a097cSMasatake YAMATO 
1819f9a097cSMasatake YAMATO 	/* Fill the scope field of the function. */
1829f9a097cSMasatake YAMATO 	end = begin;
1839f9a097cSMasatake YAMATO 	while (begin_sentinel <= (begin + 1))
1849f9a097cSMasatake YAMATO 	{
1859f9a097cSMasatake YAMATO 		bool on_boundary = false;
1869f9a097cSMasatake YAMATO 		if (begin < begin_sentinel || !isLuaIdentifier (*begin))
1879f9a097cSMasatake YAMATO 		{
1889f9a097cSMasatake YAMATO 			if (end - begin)
1899f9a097cSMasatake YAMATO 			{
1909f9a097cSMasatake YAMATO 				vStringNCatS (name, begin + 1, end - begin);
1919f9a097cSMasatake YAMATO 				int r = makeSimpleRefTag (name,
1929f9a097cSMasatake YAMATO 										  K_UNKNOWN, LUA_UNKNOWN_REFERENCED);
1939f9a097cSMasatake YAMATO 				set_scope (targetCorkIndex, r);
1949f9a097cSMasatake YAMATO 				targetCorkIndex = r;
1959f9a097cSMasatake YAMATO 				vStringClear (name);
1969f9a097cSMasatake YAMATO 			}
1979f9a097cSMasatake YAMATO 			if (begin_sentinel <= begin && ! (*begin == ':' || *begin == '.'))
1989f9a097cSMasatake YAMATO 				break;
1999f9a097cSMasatake YAMATO 			on_boundary = true;
2009f9a097cSMasatake YAMATO 		}
2019f9a097cSMasatake YAMATO 		begin--;
2029f9a097cSMasatake YAMATO 
2039f9a097cSMasatake YAMATO 		if(on_boundary)
2049f9a097cSMasatake YAMATO 			end = begin;
2059f9a097cSMasatake YAMATO 	}
2063ae02089SMasatake YAMATO }
2073ae02089SMasatake YAMATO 
findLuaTags(void)2083ae02089SMasatake YAMATO static void findLuaTags (void)
2093ae02089SMasatake YAMATO {
2103ae02089SMasatake YAMATO 	vString *name = vStringNew ();
2113ae02089SMasatake YAMATO 	const unsigned char *line;
2123ae02089SMasatake YAMATO 
2131b312fe7SMasatake YAMATO 	while ((line = readLineFromInputFile ()) != NULL)
2143ae02089SMasatake YAMATO 	{
2153ae02089SMasatake YAMATO 		const char *p, *q;
2163ae02089SMasatake YAMATO 
2173ae02089SMasatake YAMATO 		if (! is_a_code_line (line))
2183ae02089SMasatake YAMATO 			continue;
2193ae02089SMasatake YAMATO 
2203ae02089SMasatake YAMATO 		p = (const char*) strstr ((const char*) line, "function");
2213ae02089SMasatake YAMATO 		if (p == NULL)
2223ae02089SMasatake YAMATO 			continue;
2233ae02089SMasatake YAMATO 
2243ae02089SMasatake YAMATO 		q = strchr ((const char*) line, '=');
2253ae02089SMasatake YAMATO 
2263ae02089SMasatake YAMATO 		if (q == NULL) {
2271df886f0SMasatake YAMATO 			p = p + 8;  /* skip the `function' word */
2281df886f0SMasatake YAMATO 
2291df886f0SMasatake YAMATO 			/* We expect [ \t(] */
2301df886f0SMasatake YAMATO 			if (! (*p == '(' || isspace ((int)*p)))
2311df886f0SMasatake YAMATO 				continue;
2323ae02089SMasatake YAMATO 			q = strchr ((const char*) p, '(');
233d88f3cdeSMasatake YAMATO 			if (q)
234d88f3cdeSMasatake YAMATO 				extract_next_token (p, q, name);
2352fb42ce6SMasatake YAMATO 		} else if (
2362fb42ce6SMasatake YAMATO 			   (*(q+1) != '=') /* ignore `if type(v) == "function" then ...' */
2372fb42ce6SMasatake YAMATO 			   && (q < p)	   /* ignore "function" ~=  */
2382fb42ce6SMasatake YAMATO 			   ) {
2393ae02089SMasatake YAMATO 			p = (const char*) &line[0];
240d88f3cdeSMasatake YAMATO 			if (p < q)
241d88f3cdeSMasatake YAMATO 				extract_prev_token (q - 1, p, name);
2423ae02089SMasatake YAMATO 		}
2433ae02089SMasatake YAMATO 	}
2443ae02089SMasatake YAMATO 	vStringDelete (name);
2453ae02089SMasatake YAMATO }
2463ae02089SMasatake YAMATO 
LuaParser(void)2473ae02089SMasatake YAMATO extern parserDefinition* LuaParser (void)
2483ae02089SMasatake YAMATO {
2493ae02089SMasatake YAMATO 	static const char* const extensions [] = { "lua", NULL };
2503ae02089SMasatake YAMATO 	parserDefinition* def = parserNew ("Lua");
25109ae690fSMasatake YAMATO 	def->kindTable      = LuaKinds;
2523db72c21SMasatake YAMATO 	def->kindCount  = ARRAY_SIZE (LuaKinds);
2533ae02089SMasatake YAMATO 	def->extensions = extensions;
2543ae02089SMasatake YAMATO 	def->parser     = findLuaTags;
2559f9a097cSMasatake YAMATO 	def->useCork    = CORK_QUEUE;
2569f9a097cSMasatake YAMATO 	def->requestAutomaticFQTag = true;
2573ae02089SMasatake YAMATO 	return def;
2583ae02089SMasatake YAMATO }
259