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