xref: /Universal-ctags/parsers/rake.c (revision 460d235dfdc27bd7dfabbd6b24958a32ca5b3fa8)
14088430eSMasatake YAMATO /*
24088430eSMasatake YAMATO *   Copyright (c) 2022 Masatake YAMATO <yamato@redhat.com>
34088430eSMasatake YAMATO *
44088430eSMasatake YAMATO *   This source code is released for free distribution under the terms of the
54088430eSMasatake YAMATO *   GNU General Public License version 2 or (at your option) any later version.
64088430eSMasatake YAMATO *
74088430eSMasatake YAMATO *   This module contains functions for generating tags for Rakefile.
84088430eSMasatake YAMATO *
94088430eSMasatake YAMATO *   Reference:
104088430eSMasatake YAMATO *   - https://ruby.github.io/rake/doc/rakefile_rdoc.html
114088430eSMasatake YAMATO */
124088430eSMasatake YAMATO 
134088430eSMasatake YAMATO /*
144088430eSMasatake YAMATO *   INCLUDE FILES
154088430eSMasatake YAMATO */
164088430eSMasatake YAMATO #include "general.h"  /* must always come first */
174088430eSMasatake YAMATO 
184088430eSMasatake YAMATO #include "entry.h"
194088430eSMasatake YAMATO #include "kind.h"
204088430eSMasatake YAMATO #include "numarray.h"
214088430eSMasatake YAMATO #include "parse.h"
224088430eSMasatake YAMATO #include "subparser.h"
234088430eSMasatake YAMATO 
244088430eSMasatake YAMATO #include "ruby.h"
254088430eSMasatake YAMATO 
262e8e12f8SMasatake YAMATO #include <string.h>
272e8e12f8SMasatake YAMATO 
284088430eSMasatake YAMATO /*
294088430eSMasatake YAMATO * DATA STRUCTURES
304088430eSMasatake YAMATO */
314088430eSMasatake YAMATO struct sRakeSubparser {
324088430eSMasatake YAMATO 	rubySubparser ruby;
334088430eSMasatake YAMATO 	intArray *namespaces;
344088430eSMasatake YAMATO };
354088430eSMasatake YAMATO 
364088430eSMasatake YAMATO typedef enum {
374088430eSMasatake YAMATO 	K_TASK,
384088430eSMasatake YAMATO 	K_NAMESPACE,
394088430eSMasatake YAMATO 	K_FILE,
404088430eSMasatake YAMATO 	K_DIRECTORY,
414088430eSMasatake YAMATO 	K_MULTITASK,
42d6e25171SMasatake YAMATO 	K_XTASK,
434088430eSMasatake YAMATO } rakeKind;
444088430eSMasatake YAMATO 
454088430eSMasatake YAMATO /*
464088430eSMasatake YAMATO * DATA DEFINITIONS
474088430eSMasatake YAMATO */
484088430eSMasatake YAMATO static scopeSeparator RakeGenericSeparators [] = {
494088430eSMasatake YAMATO 	{ KIND_WILDCARD_INDEX, ":" },
504088430eSMasatake YAMATO };
514088430eSMasatake YAMATO 
524088430eSMasatake YAMATO static kindDefinition RakeKinds [] = {
534088430eSMasatake YAMATO 	{ true, 't', "task", "tasks",
544088430eSMasatake YAMATO 	  ATTACH_SEPARATORS(RakeGenericSeparators)},
554088430eSMasatake YAMATO 	{ true, 'n', "namespace", "namespaces",
564088430eSMasatake YAMATO 	  ATTACH_SEPARATORS(RakeGenericSeparators)},
574088430eSMasatake YAMATO 	/* F/file is reserved in the main part. */
584088430eSMasatake YAMATO 	{ true, 'f', "File", "file tasks",
594088430eSMasatake YAMATO 	  ATTACH_SEPARATORS(RakeGenericSeparators)},
604088430eSMasatake YAMATO 	{ true, 'd', "directory", "directory tasks",
614088430eSMasatake YAMATO 	  ATTACH_SEPARATORS(RakeGenericSeparators)},
624088430eSMasatake YAMATO 	{ true, 'm', "multitask", "multi tasks",
634088430eSMasatake YAMATO 	  ATTACH_SEPARATORS(RakeGenericSeparators)},
64d6e25171SMasatake YAMATO 	{ true, 'x', "xtask", "tasks defined with special constructor",
65d6e25171SMasatake YAMATO 	  ATTACH_SEPARATORS(RakeGenericSeparators)},
664088430eSMasatake YAMATO };
674088430eSMasatake YAMATO 
684088430eSMasatake YAMATO /*
694088430eSMasatake YAMATO * FUNCTIONS
704088430eSMasatake YAMATO */
findRakeTags(void)714088430eSMasatake YAMATO static void findRakeTags (void)
724088430eSMasatake YAMATO {
734088430eSMasatake YAMATO 	scheduleRunningBaseparser (0);
744088430eSMasatake YAMATO }
754088430eSMasatake YAMATO 
readTask(const unsigned char ** cp,bool * variable)762e8e12f8SMasatake YAMATO static vString *readTask (const unsigned char **cp, bool *variable)
774088430eSMasatake YAMATO {
784088430eSMasatake YAMATO 	vString *vstr = NULL;
794088430eSMasatake YAMATO 	unsigned char b;
802e8e12f8SMasatake YAMATO 	const unsigned char *start;
814088430eSMasatake YAMATO 
824088430eSMasatake YAMATO 	switch (**cp)
834088430eSMasatake YAMATO 	{
844088430eSMasatake YAMATO 	case '\'':
854088430eSMasatake YAMATO 	case '"':
864088430eSMasatake YAMATO 		b = **cp;
874088430eSMasatake YAMATO 		++*cp;
884088430eSMasatake YAMATO 		vstr = vStringNew ();
894088430eSMasatake YAMATO 		if (!rubyParseString (cp, b, vstr))
904088430eSMasatake YAMATO 		{
914088430eSMasatake YAMATO 			vStringDelete (vstr);
924088430eSMasatake YAMATO 			vstr = NULL;
934088430eSMasatake YAMATO 		}
944088430eSMasatake YAMATO 		break;
954088430eSMasatake YAMATO 	case ':':
964088430eSMasatake YAMATO 		++*cp;
974088430eSMasatake YAMATO 		vstr = vStringNew ();
984088430eSMasatake YAMATO 		if (!rubyParseMethodName (cp, vstr))
994088430eSMasatake YAMATO 		{
1004088430eSMasatake YAMATO 			vStringDelete (vstr);
1014088430eSMasatake YAMATO 			vstr = NULL;
1024088430eSMasatake YAMATO 		}
1034088430eSMasatake YAMATO 		break;
1044088430eSMasatake YAMATO 	default:
1054088430eSMasatake YAMATO 		vstr = vStringNew ();
1062e8e12f8SMasatake YAMATO 		start = *cp;
1074088430eSMasatake YAMATO 		if (!rubyParseMethodName (cp, vstr))
1084088430eSMasatake YAMATO 		{
1094088430eSMasatake YAMATO 			vStringDelete (vstr);
1104088430eSMasatake YAMATO 			vstr = NULL;
1114088430eSMasatake YAMATO 		}
112*460d235dSMasatake YAMATO 		else
1132e8e12f8SMasatake YAMATO 		{
1142e8e12f8SMasatake YAMATO 			const char *end = strstr((const char *)start, vStringValue (vstr));
1152e8e12f8SMasatake YAMATO 			if (end)
1162e8e12f8SMasatake YAMATO 			{
1172e8e12f8SMasatake YAMATO 				end += vStringLength (vstr);
1182e8e12f8SMasatake YAMATO 				if (*end != ':')
1192e8e12f8SMasatake YAMATO 					*variable = true;
1202e8e12f8SMasatake YAMATO 			}
1212e8e12f8SMasatake YAMATO 		}
1224088430eSMasatake YAMATO 		break;
1234088430eSMasatake YAMATO 	}
1244088430eSMasatake YAMATO 	return vstr;
1254088430eSMasatake YAMATO }
1264088430eSMasatake YAMATO 
makeSimpleRakeTag(vString * vstr,int kindIndex,rubySubparser * subparser,bool anonymous)1272e8e12f8SMasatake YAMATO static int makeSimpleRakeTag (vString *vstr, int kindIndex, rubySubparser *subparser,
1282e8e12f8SMasatake YAMATO 							  bool anonymous)
1294088430eSMasatake YAMATO {
1302e8e12f8SMasatake YAMATO 	if (anonymous)
1312e8e12f8SMasatake YAMATO 	{
1322e8e12f8SMasatake YAMATO 		vStringPut (vstr, '_');
1332e8e12f8SMasatake YAMATO 		anonConcat (vstr, kindIndex);
1342e8e12f8SMasatake YAMATO 	}
1352e8e12f8SMasatake YAMATO 
1364088430eSMasatake YAMATO 	int r = makeSimpleTag (vstr, kindIndex);
1374088430eSMasatake YAMATO 	tagEntryInfo *e = getEntryInCorkQueue (r);
1384088430eSMasatake YAMATO 	if (e)
1394088430eSMasatake YAMATO 	{
1404088430eSMasatake YAMATO 		struct sRakeSubparser *rake = (struct sRakeSubparser *)subparser;
1414088430eSMasatake YAMATO 		if (!intArrayIsEmpty (rake->namespaces))
1424088430eSMasatake YAMATO 			e->extensionFields.scopeIndex = intArrayLast(rake->namespaces);
1432e8e12f8SMasatake YAMATO 		if (anonymous)
1442e8e12f8SMasatake YAMATO 			markTagExtraBit (e, XTAG_ANONYMOUS);
1454088430eSMasatake YAMATO 	}
1464088430eSMasatake YAMATO 	return r;
1474088430eSMasatake YAMATO }
1484088430eSMasatake YAMATO 
149d6e25171SMasatake YAMATO struct taskType {
150d6e25171SMasatake YAMATO 	const char *keyword;
151d6e25171SMasatake YAMATO 	rakeKind    kind;
152d6e25171SMasatake YAMATO };
153d6e25171SMasatake YAMATO 
parseTask(rubySubparser * s,int kind,const unsigned char ** cp)1544088430eSMasatake YAMATO static int parseTask (rubySubparser *s, int kind, const unsigned char **cp)
1554088430eSMasatake YAMATO {
1564088430eSMasatake YAMATO 	vString *vstr = NULL;
1572e8e12f8SMasatake YAMATO 	bool variable = false;
1584088430eSMasatake YAMATO 	rubySkipWhitespace (cp);
1592e8e12f8SMasatake YAMATO 	vstr = readTask (cp, &variable);
1604088430eSMasatake YAMATO 	if (vstr)
1614088430eSMasatake YAMATO 	{
1622e8e12f8SMasatake YAMATO 		int r = makeSimpleRakeTag (vstr, kind, s, variable);
1634088430eSMasatake YAMATO 		vStringDelete (vstr);
1644088430eSMasatake YAMATO 		return r;
1654088430eSMasatake YAMATO 	}
1664088430eSMasatake YAMATO 	return CORK_NIL;
1674088430eSMasatake YAMATO }
1684088430eSMasatake YAMATO 
parseXTask(rubySubparser * s,struct taskType * xtask,const unsigned char ** cp)169d6e25171SMasatake YAMATO static int parseXTask (rubySubparser *s, struct taskType *xtask, const unsigned char **cp)
170d6e25171SMasatake YAMATO {
171d6e25171SMasatake YAMATO 	rubySkipWhitespace (cp);
172d6e25171SMasatake YAMATO 	if (**cp == '(')
173d6e25171SMasatake YAMATO 	{
174d6e25171SMasatake YAMATO 		vString *vstr = NULL;
1752e8e12f8SMasatake YAMATO 		bool variable = false;
176d6e25171SMasatake YAMATO 		++*cp;
177d6e25171SMasatake YAMATO 		rubySkipWhitespace (cp);
1782e8e12f8SMasatake YAMATO 		vstr = readTask (cp, &variable);
179d6e25171SMasatake YAMATO 		if (vstr)
180d6e25171SMasatake YAMATO 		{
1812e8e12f8SMasatake YAMATO 			int r = makeSimpleRakeTag (vstr, xtask->kind, s, variable);
182d6e25171SMasatake YAMATO 			vStringDelete (vstr);
183d6e25171SMasatake YAMATO 			tagEntryInfo *e = getEntryInCorkQueue (r);
184d6e25171SMasatake YAMATO 			e->extensionFields.typeRef [0] = eStrdup ("typename");
185d6e25171SMasatake YAMATO 			e->extensionFields.typeRef [1] = eStrdup (xtask->keyword);
186d6e25171SMasatake YAMATO 			return r;
187d6e25171SMasatake YAMATO 		}
188d6e25171SMasatake YAMATO 	}
189d6e25171SMasatake YAMATO 	return CORK_NIL;
190d6e25171SMasatake YAMATO }
191d6e25171SMasatake YAMATO 
lineNotify(rubySubparser * s,const unsigned char ** cp)1924088430eSMasatake YAMATO static int lineNotify (rubySubparser *s, const unsigned char **cp)
1934088430eSMasatake YAMATO {
194d6e25171SMasatake YAMATO 	struct taskType taskTypes [] = {
1954088430eSMasatake YAMATO 		{ "task",       K_TASK      },
1964088430eSMasatake YAMATO 		{ "namespace",  K_NAMESPACE },
1974088430eSMasatake YAMATO 		{ "file",       K_FILE      },
1984088430eSMasatake YAMATO 		{ "directory",  K_DIRECTORY },
1994088430eSMasatake YAMATO 		{ "multitask",  K_MULTITASK },
2004088430eSMasatake YAMATO 	};
2014088430eSMasatake YAMATO 
2024088430eSMasatake YAMATO 	for (int i = 0; i < ARRAY_SIZE(taskTypes); i++)
2034088430eSMasatake YAMATO 	{
2044088430eSMasatake YAMATO 		if (rubyCanMatchKeywordWithAssign (cp, taskTypes[i].keyword))
2051d2e56b6SMasatake YAMATO 			return parseTask (s, taskTypes[i].kind, cp);
2064088430eSMasatake YAMATO 	}
2074088430eSMasatake YAMATO 
208d6e25171SMasatake YAMATO 	struct taskType xtaskTypes [] = {
209d6e25171SMasatake YAMATO 		{ "RSpec::Core::RakeTask.new", K_XTASK },
210d6e25171SMasatake YAMATO 		{ "Cucumber::Rake::Task.new",  K_XTASK },
211d6e25171SMasatake YAMATO 		{ "Rake::TestTask.new",        K_XTASK },
212d6e25171SMasatake YAMATO 		{ "Rake::PackageTask.new",     K_XTASK },
213d6e25171SMasatake YAMATO 		/* ... */
214d6e25171SMasatake YAMATO 	};
215d6e25171SMasatake YAMATO 
216d6e25171SMasatake YAMATO 	for (int i = 0; i < ARRAY_SIZE(xtaskTypes); i++)
2174088430eSMasatake YAMATO 	{
218d6e25171SMasatake YAMATO 		if (rubyCanMatchKeywordWithAssign (cp, xtaskTypes[i].keyword))
219d6e25171SMasatake YAMATO 			return parseXTask (s, xtaskTypes + i, cp);;
2204088430eSMasatake YAMATO 	}
2214088430eSMasatake YAMATO 
2221d2e56b6SMasatake YAMATO 	return CORK_NIL;
2234088430eSMasatake YAMATO }
2244088430eSMasatake YAMATO 
inputStart(subparser * s)2254088430eSMasatake YAMATO static void inputStart (subparser *s)
2264088430eSMasatake YAMATO {
2274088430eSMasatake YAMATO 	struct sRakeSubparser *rake = (struct sRakeSubparser *)s;
2284088430eSMasatake YAMATO 
2294088430eSMasatake YAMATO 	intArrayClear (rake->namespaces);
2304088430eSMasatake YAMATO }
2314088430eSMasatake YAMATO 
enterBlockNotify(rubySubparser * s,int corkIndex)2324088430eSMasatake YAMATO static void enterBlockNotify (rubySubparser *s, int corkIndex)
2334088430eSMasatake YAMATO {
2344088430eSMasatake YAMATO 	tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
2354088430eSMasatake YAMATO 
2364088430eSMasatake YAMATO 	if (e && e->kindIndex == K_NAMESPACE)
2374088430eSMasatake YAMATO 	{
2384088430eSMasatake YAMATO 		struct sRakeSubparser *rake = (struct sRakeSubparser *)s;
2394088430eSMasatake YAMATO 		intArrayAdd (rake->namespaces, corkIndex);
2404088430eSMasatake YAMATO 	}
2414088430eSMasatake YAMATO }
2424088430eSMasatake YAMATO 
leaveBlockNotify(rubySubparser * s,int corkIndex)2434088430eSMasatake YAMATO static void leaveBlockNotify (rubySubparser *s, int corkIndex)
2444088430eSMasatake YAMATO {
2454088430eSMasatake YAMATO 	tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
2464088430eSMasatake YAMATO 
2474088430eSMasatake YAMATO 	if (e && e->kindIndex == K_NAMESPACE)
2484088430eSMasatake YAMATO 	{
2494088430eSMasatake YAMATO 		struct sRakeSubparser *rake = (struct sRakeSubparser *)s;
2504088430eSMasatake YAMATO 		intArrayRemoveLast (rake->namespaces);
2514088430eSMasatake YAMATO 	}
2524088430eSMasatake YAMATO }
2534088430eSMasatake YAMATO 
2544088430eSMasatake YAMATO static struct sRakeSubparser rakeSubparser = {
2554088430eSMasatake YAMATO 	.ruby = {
2564088430eSMasatake YAMATO 		.subparser = {
2574088430eSMasatake YAMATO 			.direction = SUBPARSER_SUB_RUNS_BASE,
2584088430eSMasatake YAMATO 			.inputStart = inputStart,
2594088430eSMasatake YAMATO 		},
2604088430eSMasatake YAMATO 		.lineNotify = lineNotify,
2614088430eSMasatake YAMATO 		.enterBlockNotify = enterBlockNotify,
2624088430eSMasatake YAMATO 		.leaveBlockNotify = leaveBlockNotify,
2634088430eSMasatake YAMATO 	},
2644088430eSMasatake YAMATO 	.namespaces = NULL,
2654088430eSMasatake YAMATO };
2664088430eSMasatake YAMATO 
initialize(const langType language CTAGS_ATTR_UNUSED)2674088430eSMasatake YAMATO static void initialize (const langType language CTAGS_ATTR_UNUSED)
2684088430eSMasatake YAMATO {
2694088430eSMasatake YAMATO 	rakeSubparser.namespaces = intArrayNew ();
2704088430eSMasatake YAMATO }
2714088430eSMasatake YAMATO 
finalize(langType language CTAGS_ATTR_UNUSED,bool initialized)2724088430eSMasatake YAMATO static void finalize (langType language CTAGS_ATTR_UNUSED, bool initialized)
2734088430eSMasatake YAMATO {
2744088430eSMasatake YAMATO 	if (rakeSubparser.namespaces)
2754088430eSMasatake YAMATO 		intArrayDelete (rakeSubparser.namespaces);
2764088430eSMasatake YAMATO }
2774088430eSMasatake YAMATO 
RakeParser(void)2784088430eSMasatake YAMATO extern parserDefinition* RakeParser (void)
2794088430eSMasatake YAMATO {
2804088430eSMasatake YAMATO 	static const char *const extensions [] = { "rake", NULL };
2814088430eSMasatake YAMATO 	static const char *const patterns [] = { "Rakefile", NULL };
2824088430eSMasatake YAMATO 
2834088430eSMasatake YAMATO 	static parserDependency dependencies [] = {
2844088430eSMasatake YAMATO 		[0] = { DEPTYPE_SUBPARSER, "Ruby", &rakeSubparser },
2854088430eSMasatake YAMATO 	};
2864088430eSMasatake YAMATO 
2874088430eSMasatake YAMATO 	parserDefinition* const def = parserNew ("Rake");
2884088430eSMasatake YAMATO 
2894088430eSMasatake YAMATO 	def->dependencies = dependencies;
2904088430eSMasatake YAMATO 	def->dependencyCount = ARRAY_SIZE(dependencies);
2914088430eSMasatake YAMATO 	def->kindTable  = RakeKinds;
2924088430eSMasatake YAMATO 	def->kindCount  = ARRAY_SIZE (RakeKinds);
2934088430eSMasatake YAMATO 	def->extensions = extensions;
2944088430eSMasatake YAMATO 	def->patterns   = patterns;
2954088430eSMasatake YAMATO 	def->parser     = findRakeTags;
2964088430eSMasatake YAMATO 	def->initialize = initialize;
2974088430eSMasatake YAMATO 	def->finalize   = finalize;
2984088430eSMasatake YAMATO 	def->useCork    = CORK_QUEUE;
2994088430eSMasatake YAMATO 	def->requestAutomaticFQTag = true;
3004088430eSMasatake YAMATO 
3014088430eSMasatake YAMATO 	return def;
3024088430eSMasatake YAMATO }
303