xref: /Universal-ctags/parsers/robot.c (revision e852ee0e939802331dc3117fd85a31b243c3d04f)
17b447529Sdriechers /*
27b447529Sdriechers  *   Copyright (c) 2017, Daniel Riechers
37b447529Sdriechers  *
47b447529Sdriechers  *   This source code is released for free distribution under the terms of the
57b447529Sdriechers  *   GNU General Public License version 2 or (at your option) any later version.
67b447529Sdriechers  *
77b447529Sdriechers  *   Parser from Robot Framework http://robotframework.org
87b447529Sdriechers  */
97b447529Sdriechers 
107b447529Sdriechers #include "general.h"
117b447529Sdriechers 
127b447529Sdriechers #include <string.h>
137b447529Sdriechers 
14950e3d50SMasatake YAMATO #include "entry.h"
157b447529Sdriechers #include "parse.h"
167b447529Sdriechers #include "vstring.h"
177b447529Sdriechers #include "routines.h"
187b447529Sdriechers 
197b447529Sdriechers typedef enum {
207b447529Sdriechers         K_TESTCASE,
217b447529Sdriechers         K_KEYWORD,
227b447529Sdriechers         K_VARIABLE,
237b447529Sdriechers         COUNT_KIND
247b447529Sdriechers } RobotKind;
257b447529Sdriechers 
267b447529Sdriechers static RobotKind section = -1;
277b447529Sdriechers 
28e112e8abSMasatake YAMATO static kindDefinition RobotKinds[COUNT_KIND] = {
297b447529Sdriechers 	{true, 't', "testcase",   "testcases"},
307b447529Sdriechers 	{true, 'k', "keyword",    "keywords"},
317b447529Sdriechers 	{true, 'v', "variable",   "variables"},
327b447529Sdriechers };
337b447529Sdriechers 
343bb8a657SMasatake YAMATO typedef enum {
353bb8a657SMasatake YAMATO 	X_WHITESPACE_SWAPPED,
363bb8a657SMasatake YAMATO } robotXtag;
373bb8a657SMasatake YAMATO 
38e3712f53SMasatake YAMATO static xtagDefinition RobotXtags [] = {
393bb8a657SMasatake YAMATO 	{
403bb8a657SMasatake YAMATO 		.enabled = true,
413bb8a657SMasatake YAMATO 		.name = "whitespaceSwapped",
423bb8a657SMasatake YAMATO 		.description = "Include tags swapping whitespace and underscore chars",
433bb8a657SMasatake YAMATO 	},
443bb8a657SMasatake YAMATO };
453bb8a657SMasatake YAMATO 
463bb8a657SMasatake YAMATO 
findRobotTags(void)477b447529Sdriechers static void findRobotTags (void)
487b447529Sdriechers {
497b447529Sdriechers 	findRegexTags ();
507b447529Sdriechers }
517b447529Sdriechers 
whitespaceSwap(vString * const s)527b447529Sdriechers static bool whitespaceSwap (vString *const s)
537b447529Sdriechers {
547b447529Sdriechers         char replaceWith = '_';
557b447529Sdriechers         char toReplace = ' ';
567b447529Sdriechers 		char changed = false;
577b447529Sdriechers 
58*e852ee0eSMasatake YAMATO         if(strchr(vStringValue (s), '_'))
597b447529Sdriechers         {
607b447529Sdriechers             replaceWith = ' ';
617b447529Sdriechers             toReplace = '_';
627b447529Sdriechers         }
637b447529Sdriechers 
6446ab94ccSMasatake YAMATO         for(unsigned int i=0; i < vStringLength(s); i++)
65*e852ee0eSMasatake YAMATO             if(vStringChar(s, i) == toReplace)
667b447529Sdriechers 			{
67*e852ee0eSMasatake YAMATO                 vStringChar (s, i) = replaceWith;
687b447529Sdriechers 				changed = true;
697b447529Sdriechers 			}
707b447529Sdriechers 
717b447529Sdriechers 		return changed;
727b447529Sdriechers }
737b447529Sdriechers 
changeSection(const char * const line,const regexMatch * const matches,const unsigned int count CTAGS_ATTR_UNUSED,void * data CTAGS_ATTR_UNUSED)7418480890SMasatake YAMATO static bool changeSection (const char *const line, const regexMatch *const matches,
75e4d16241SMasatake YAMATO                                const unsigned int count CTAGS_ATTR_UNUSED, void *data CTAGS_ATTR_UNUSED)
767b447529Sdriechers {
777b447529Sdriechers     const char * const matchedSection = line + matches[1].start;
787b447529Sdriechers 
797b447529Sdriechers     if(strncasecmp(matchedSection, "test cases", matches[1].length) == 0)
807b447529Sdriechers     {
817b447529Sdriechers         section = K_TESTCASE;
827b447529Sdriechers     }
837b447529Sdriechers     else if(strncasecmp(matchedSection, "keywords", matches[1].length) == 0)
847b447529Sdriechers     {
857b447529Sdriechers         section = K_KEYWORD;
867b447529Sdriechers     }
877b447529Sdriechers     else if(strncasecmp(matchedSection, "variables", matches[1].length) == 0)
887b447529Sdriechers     {
897b447529Sdriechers         section = K_VARIABLE;
907b447529Sdriechers     }
9118480890SMasatake YAMATO 	return true;
927b447529Sdriechers }
937b447529Sdriechers 
makeSimpleXTag(const vString * const name,const int kind,unsigned int xtagType)94f92e6bf2SMasatake YAMATO static void makeSimpleXTag (const vString* const name, const int kind,
95950e3d50SMasatake YAMATO 							unsigned int xtagType)
96950e3d50SMasatake YAMATO {
97950e3d50SMasatake YAMATO 	tagEntryInfo e;
98950e3d50SMasatake YAMATO 
9916a2541cSMasatake YAMATO 	initTagEntry (&e, vStringValue(name), kind);
100950e3d50SMasatake YAMATO 	markTagExtraBit (&e, xtagType);
101950e3d50SMasatake YAMATO 	makeTagEntry (&e);
102950e3d50SMasatake YAMATO }
103950e3d50SMasatake YAMATO 
tagKeywordsAndTestCases(const char * const line,const regexMatch * const matches,const unsigned int count,void * data CTAGS_ATTR_UNUSED)10418480890SMasatake YAMATO static bool tagKeywordsAndTestCases (const char *const line, const regexMatch *const matches,
105e4d16241SMasatake YAMATO                                const unsigned int count, void *data CTAGS_ATTR_UNUSED)
1067b447529Sdriechers {
1077b447529Sdriechers     if (count > 1 && ( section == K_KEYWORD || section == K_TESTCASE) )
1087b447529Sdriechers     {
1097b447529Sdriechers         vString *const name = vStringNew ();
1107b447529Sdriechers         vStringNCopyS (name, line + matches [1].start, matches [1].length);
11116a2541cSMasatake YAMATO         makeSimpleTag (name, section);
1123bb8a657SMasatake YAMATO         if (isXtagEnabled (RobotXtags[X_WHITESPACE_SWAPPED].xtype)
1133bb8a657SMasatake YAMATO 			&& whitespaceSwap(name))
114f92e6bf2SMasatake YAMATO 			makeSimpleXTag (name, section,
115950e3d50SMasatake YAMATO 							RobotXtags[X_WHITESPACE_SWAPPED].xtype);
1167b447529Sdriechers         vStringDelete (name);
11718480890SMasatake YAMATO 		return true;
1187b447529Sdriechers     }
11918480890SMasatake YAMATO 	return false;
1207b447529Sdriechers }
1217b447529Sdriechers 
tagVariables(const char * const line,const regexMatch * const matches,const unsigned int count,void * data CTAGS_ATTR_UNUSED)12218480890SMasatake YAMATO static bool tagVariables (const char *const line, const regexMatch *const matches,
123e4d16241SMasatake YAMATO                                const unsigned int count, void *data CTAGS_ATTR_UNUSED)
1247b447529Sdriechers {
1257b447529Sdriechers     if (count > 1 && section == K_VARIABLE)
1267b447529Sdriechers     {
1277b447529Sdriechers         vString *const name = vStringNew ();
1287b447529Sdriechers         vStringNCopyS (name, line + matches [1].start, matches [1].length);
12916a2541cSMasatake YAMATO         makeSimpleTag (name, K_VARIABLE);
1303bb8a657SMasatake YAMATO         if (isXtagEnabled (RobotXtags[X_WHITESPACE_SWAPPED].xtype)
1313bb8a657SMasatake YAMATO 			&& whitespaceSwap(name))
132f92e6bf2SMasatake YAMATO 			makeSimpleXTag (name, K_VARIABLE,
133950e3d50SMasatake YAMATO 							RobotXtags[X_WHITESPACE_SWAPPED].xtype);
1347b447529Sdriechers         vStringDelete (name);
13518480890SMasatake YAMATO 		return true;
1367b447529Sdriechers     }
13718480890SMasatake YAMATO 	return false;
1387b447529Sdriechers }
1397b447529Sdriechers 
initialize(const langType language)1407b447529Sdriechers static void initialize (const langType language)
1417b447529Sdriechers {
14253dda59eSMasatake YAMATO     addLanguageCallbackRegex (language, "^\\*+ *([^* ].+[^* ]) *\\*+$",
1437b447529Sdriechers             "{exclusive}", changeSection, NULL, NULL);
1440e230a14SMasatake YAMATO 
1450e230a14SMasatake YAMATO     addLanguageCallbackRegex (
1460e230a14SMasatake YAMATO 		language,
1470e10675cSDerek Schrock 		"(^([A-Za-z0-9]+|\\$\\{[_A-Za-z0-9][' _A-Za-z0-9]*(:([^}]|\\\\)+)*\\})([${}' _]([-_$A-Za-z0-9]+|\\{[_A-Za-z0-9][' _A-Za-z0-9]*(:([^}]|\\\\)+)*\\})+)*)",
1487b447529Sdriechers 		"{exclusive}", tagKeywordsAndTestCases, NULL, NULL);
1490e230a14SMasatake YAMATO 
15053dda59eSMasatake YAMATO     addLanguageCallbackRegex (language, "^[$@]\\{([_A-Za-z0-9][' _A-Za-z0-9]+)\\}  [ ]*.+",
1517b447529Sdriechers             "{exclusive}", tagVariables, NULL, NULL);
1527b447529Sdriechers }
1537b447529Sdriechers 
RobotParser(void)1547b447529Sdriechers extern parserDefinition* RobotParser (void)
1557b447529Sdriechers {
1567b447529Sdriechers 	static const char *const extensions[] = { "robot", NULL };
1577b447529Sdriechers 	parserDefinition *def = parserNew ("Robot");
15809ae690fSMasatake YAMATO     def->kindTable      = RobotKinds;
1597b447529Sdriechers     def->kindCount  = COUNT_KIND;
1607b447529Sdriechers 	def->extensions = extensions;
1617b447529Sdriechers 	def->initialize = initialize;
1627b447529Sdriechers     def->parser     = findRobotTags;
163a02a9600SMasatake YAMATO 	def->xtagTable = RobotXtags;
164a02a9600SMasatake YAMATO 	def->xtagCount = ARRAY_SIZE (RobotXtags);
1657b447529Sdriechers 	return def;
1667b447529Sdriechers }
167