xref: /Universal-ctags/parsers/perl-function-parameters.c (revision 00f9a206b087545f05909e61ef605cf354678961)
1 /*
2  *   Copyright (c) 2021, Masatake YAMATO
3  *   Copyright (c) 2021, Red Hat, Inc.
4  *
5  *   This source code is released for free distribution under the terms of the
6  *   GNU General Public License version 2 or (at your option) any later version.
7  *
8  *   This module contains functions for generating tags for Function::Parameters perl extension.
9  *   https://metacpan.org/pod/Function::Parameters
10  *
11  *   This parser is inspired by the pull request submitted by Jim Butler (@jimmygoogle).
12  */
13 
14 /*
15  *   INCLUDE FILES
16  */
17 #include "general.h"  /* must always come first */
18 
19 #include "entry.h"
20 #include "kind.h"
21 #include "parse.h"
22 #include "perl.h"
23 
24 #include <string.h>
25 
26 /*
27  *   DATA DECLARATIONS
28  */
29 
30 enum FParamsKind {
31 	K_METHOD,
32 	K_FUN,
33 };
34 
35 static kindDefinition FParamsKinds[] = {
36 	{ true, 'm', "method", "methods" },
37 	{ true, 'f', "fun",    "functions" },
38 };
39 
40 struct FParamsSubparser {
41 	perlSubparser perl;
42 	bool notInFParams;
43 	bool inPod;
44 };
45 
46 /*
47  *   FUNCTION PROTOTYPES
48  */
49 
50 static void inputStart (subparser *s);
51 static void makeTagEntryNotify (subparser *s, const tagEntryInfo *tag, int corkIndex);
52 static void enterFParams (struct FParamsSubparser *fparms);
53 static void leaveFParams (struct FParamsSubparser *fparams);
54 static void enteringPodNotify (perlSubparser *perl);
55 static void leavingPodNotify  (perlSubparser *perl);
56 
57 /*
58  *   DATA DEFINITIONS
59  */
60 
61 static struct FParamsSubparser fparamsSubparser = {
62 	.perl = {
63 		.subparser = {
64 			.direction  = SUBPARSER_BI_DIRECTION,
65 			.inputStart = inputStart,
66 			.makeTagEntryNotify = makeTagEntryNotify,
67 		},
68 		.enteringPodNotify = enteringPodNotify,
69 		.leavingPodNotify  = leavingPodNotify,
70 	}
71 };
72 
73 /*
74  *   FUNCTION DEFINITIONS
75  */
76 
inputStart(subparser * s)77 static void inputStart (subparser *s)
78 {
79 	struct FParamsSubparser *fparams = (struct FParamsSubparser *)s;
80 
81 	fparams->notInFParams = true;
82 	fparams->inPod = false;
83 }
84 
makeTagEntryNotify(subparser * s,const tagEntryInfo * tag,int corkIndex)85 static void makeTagEntryNotify (subparser *s, const tagEntryInfo *tag, int corkIndex)
86 {
87 	perlSubparser *perl = (perlSubparser *)s;
88 	struct FParamsSubparser *fparams = (struct FParamsSubparser *)perl;
89 
90 	if (isTagExtraBitMarked(tag, XTAG_QUALIFIED_TAGS))
91 		return;
92 
93 	if (tag->kindIndex == KIND_PERL_MODULE)
94 	{
95 		if (isRoleAssigned(tag, ROLE_PERL_MODULE_USED)
96 			&& strcmp (tag->name, "Function::Parameters") == 0)
97 			enterFParams (fparams);
98 		else if (isRoleAssigned(tag, ROLE_PERL_MODULE_UNUSED)
99 				 && strcmp (tag->name, "Function::Parameters") == 0)
100 			leaveFParams (fparams);
101 	}
102 }
103 
enterFParams(struct FParamsSubparser * fparams)104 static void enterFParams (struct FParamsSubparser *fparams)
105 {
106 	fparams->notInFParams = false;
107 }
108 
leaveFParams(struct FParamsSubparser * fparams)109 static void leaveFParams (struct FParamsSubparser *fparams)
110 {
111 	fparams->notInFParams = true;
112 }
113 
enteringPodNotify(perlSubparser * perl)114 static void enteringPodNotify (perlSubparser *perl)
115 {
116 	struct FParamsSubparser *fparams = (struct FParamsSubparser *)perl;
117 	fparams->inPod = true;
118 }
119 
leavingPodNotify(perlSubparser * perl)120 static void leavingPodNotify  (perlSubparser *perl)
121 {
122 	struct FParamsSubparser *fparams = (struct FParamsSubparser *)perl;
123 	fparams->inPod = false;
124 }
125 
findFParamsObject(const char * line,const regexMatch * matches,unsigned int count,void * userData)126 static bool findFParamsObject (const char * line, const regexMatch *matches, unsigned int count,
127 							   void *userData)
128 {
129 	struct FParamsSubparser *fparams = (struct FParamsSubparser *)userData;
130 
131 	if (fparams->inPod)
132 		return false;
133 
134 
135 	const char *kindHint = line + matches[1].start;
136 	int kind = kindHint [0] == 'm'? K_METHOD: K_FUN;
137 
138 	char *name = eStrndup (line + matches[2].start, matches[2].length);
139 	tagEntryInfo e;
140 	initTagEntry (&e, name, kind);
141 
142 	makeTagEntry (&e);
143 	eFree (name);
144 	return true;
145 }
146 
findFParamsTags(void)147 static void findFParamsTags (void)
148 {
149 	scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
150 }
151 
initializeFParamsParser(langType language)152 static void initializeFParamsParser (langType language)
153 {
154 	addLanguageCallbackRegex (language, "^[ \t]*(method|fun)[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*\\(",
155 							  NULL,
156 							  findFParamsObject, &fparamsSubparser.notInFParams,
157 							  &fparamsSubparser);
158 }
159 
FunctionParametersParser(void)160 extern parserDefinition* FunctionParametersParser (void)
161 {
162 	parserDefinition* const def = parserNew("FunctionParameters");
163 
164 	static parserDependency dependencies [] = {
165 		[0] = { DEPTYPE_SUBPARSER, "Perl", &fparamsSubparser },
166 	};
167 
168 	def->dependencies = dependencies;
169 	def->dependencyCount = ARRAY_SIZE (dependencies);
170 
171 	def->kindTable = FParamsKinds;
172 	def->kindCount = ARRAY_SIZE(FParamsKinds);
173 
174 	def->initialize = initializeFParamsParser;
175 	def->parser = findFParamsTags;
176 
177 	return def;
178 }
179