1eff0ecc1SMasatake YAMATO /*
2eff0ecc1SMasatake YAMATO *
3eff0ecc1SMasatake YAMATO * Copyright (c) 2017, Red Hat, Inc.
4eff0ecc1SMasatake YAMATO * Copyright (c) 2017, Masatake YAMATO
5eff0ecc1SMasatake YAMATO *
6eff0ecc1SMasatake YAMATO * Author: Masatake YAMATO <yamato@redhat.com>
7eff0ecc1SMasatake YAMATO *
8eff0ecc1SMasatake YAMATO * This program is free software; you can redistribute it and/or
9eff0ecc1SMasatake YAMATO * modify it under the terms of the GNU General Public License
10eff0ecc1SMasatake YAMATO * as published by the Free Software Foundation; either version 2
11eff0ecc1SMasatake YAMATO * of the License, or (at your option) any later version.
12eff0ecc1SMasatake YAMATO *
13eff0ecc1SMasatake YAMATO * This program is distributed in the hope that it will be useful,
14eff0ecc1SMasatake YAMATO * but WITHOUT ANY WARRANTY; without even the implied warranty of
15eff0ecc1SMasatake YAMATO * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16eff0ecc1SMasatake YAMATO * GNU General Public License for more details.
17eff0ecc1SMasatake YAMATO *
18eff0ecc1SMasatake YAMATO * You should have received a copy of the GNU General Public License
19eff0ecc1SMasatake YAMATO * along with this program; if not, write to the Free Software
20eff0ecc1SMasatake YAMATO * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
21eff0ecc1SMasatake YAMATO * USA.
22eff0ecc1SMasatake YAMATO *
23eff0ecc1SMasatake YAMATO * Inspired by the following commit but written from scratch:
24eff0ecc1SMasatake YAMATO * ==========================================================
25eff0ecc1SMasatake YAMATO *
26eff0ecc1SMasatake YAMATO * commit 76dbed4de88875d8c8409dfd65da4f94f901c94a
27eff0ecc1SMasatake YAMATO * Author: Ram Singla <ram.singla@gmail.com>
28eff0ecc1SMasatake YAMATO * Date: Tue Jan 18 13:24:46 2011 +0800
29eff0ecc1SMasatake YAMATO *
30eff0ecc1SMasatake YAMATO * RSpec Code added. Courtesy: mortice
31eff0ecc1SMasatake YAMATO *
32eff0ecc1SMasatake YAMATO * ==========================================================
33eff0ecc1SMasatake YAMATO *
34eff0ecc1SMasatake YAMATO * Reference:
35eff0ecc1SMasatake YAMATO * - https://rubydoc.info/gems/rspec-core/frames
36eff0ecc1SMasatake YAMATO */
37eff0ecc1SMasatake YAMATO
38eff0ecc1SMasatake YAMATO /*
39eff0ecc1SMasatake YAMATO * INCLUDE FILES
40eff0ecc1SMasatake YAMATO */
41eff0ecc1SMasatake YAMATO #include "general.h" /* must always come first */
42eff0ecc1SMasatake YAMATO
43eff0ecc1SMasatake YAMATO #include "entry.h"
44eff0ecc1SMasatake YAMATO #include "kind.h"
45eff0ecc1SMasatake YAMATO #include "numarray.h"
46eff0ecc1SMasatake YAMATO #include "parse.h"
47eff0ecc1SMasatake YAMATO #include "subparser.h"
48eff0ecc1SMasatake YAMATO
49eff0ecc1SMasatake YAMATO #include "ruby.h"
50eff0ecc1SMasatake YAMATO
51eff0ecc1SMasatake YAMATO #include <string.h>
52eff0ecc1SMasatake YAMATO
53eff0ecc1SMasatake YAMATO /*
54eff0ecc1SMasatake YAMATO * DATA STRUCTURES
55eff0ecc1SMasatake YAMATO */
56eff0ecc1SMasatake YAMATO struct sRSpecSubparser {
57eff0ecc1SMasatake YAMATO rubySubparser ruby;
58eff0ecc1SMasatake YAMATO int scope;
59eff0ecc1SMasatake YAMATO };
60eff0ecc1SMasatake YAMATO
61eff0ecc1SMasatake YAMATO typedef enum {
62eff0ecc1SMasatake YAMATO K_DESCRIBE,
63eff0ecc1SMasatake YAMATO K_CONTEXT,
64*e8daccd0SMasatake YAMATO K_IT,
65eff0ecc1SMasatake YAMATO } rspecKind;
66eff0ecc1SMasatake YAMATO
67eff0ecc1SMasatake YAMATO static kindDefinition RSpecKinds [] = {
68eff0ecc1SMasatake YAMATO { true, 'd', "describe", "describes" },
69eff0ecc1SMasatake YAMATO { true, 'c', "context", "contexts" },
70*e8daccd0SMasatake YAMATO { true, 'i', "it", "things described with \"it\"" },
71eff0ecc1SMasatake YAMATO };
72eff0ecc1SMasatake YAMATO
73eff0ecc1SMasatake YAMATO /*
74eff0ecc1SMasatake YAMATO * FUNCTIONS
75eff0ecc1SMasatake YAMATO */
makeSimpleRSpecTag(vString * vstr,int kindIndex,rubySubparser * subparser)76eff0ecc1SMasatake YAMATO static int makeSimpleRSpecTag (vString *vstr, int kindIndex, rubySubparser *subparser)
77eff0ecc1SMasatake YAMATO {
78eff0ecc1SMasatake YAMATO int r = makeSimpleTag (vstr, kindIndex);
79eff0ecc1SMasatake YAMATO tagEntryInfo *e = getEntryInCorkQueue (r);
80eff0ecc1SMasatake YAMATO if (e)
81eff0ecc1SMasatake YAMATO {
82eff0ecc1SMasatake YAMATO struct sRSpecSubparser *rspec = (struct sRSpecSubparser *)subparser;
83eff0ecc1SMasatake YAMATO e->extensionFields.scopeIndex = rspec->scope;
84eff0ecc1SMasatake YAMATO }
85eff0ecc1SMasatake YAMATO return r;
86eff0ecc1SMasatake YAMATO }
87eff0ecc1SMasatake YAMATO
readRest(const unsigned char ** cp)88eff0ecc1SMasatake YAMATO static vString *readRest (const unsigned char **cp)
89eff0ecc1SMasatake YAMATO {
90eff0ecc1SMasatake YAMATO vString *vstr = NULL;
91eff0ecc1SMasatake YAMATO unsigned char b;
92eff0ecc1SMasatake YAMATO
93eff0ecc1SMasatake YAMATO switch (**cp)
94eff0ecc1SMasatake YAMATO {
95eff0ecc1SMasatake YAMATO case '\'':
96eff0ecc1SMasatake YAMATO case '"':
97eff0ecc1SMasatake YAMATO b = **cp;
98eff0ecc1SMasatake YAMATO ++*cp;
99eff0ecc1SMasatake YAMATO vstr = vStringNew ();
100eff0ecc1SMasatake YAMATO if (!rubyParseString (cp, b, vstr))
101eff0ecc1SMasatake YAMATO {
102eff0ecc1SMasatake YAMATO vStringDelete (vstr);
103eff0ecc1SMasatake YAMATO vstr = NULL;
104eff0ecc1SMasatake YAMATO }
105eff0ecc1SMasatake YAMATO break;
106eff0ecc1SMasatake YAMATO case ':':
107eff0ecc1SMasatake YAMATO /* symbol, Should this be part of the Ruby parser side? */
108eff0ecc1SMasatake YAMATO break;
109eff0ecc1SMasatake YAMATO default:
110eff0ecc1SMasatake YAMATO vstr = vStringNew ();
111eff0ecc1SMasatake YAMATO if (!rubyParseModuleName (cp, vstr))
112eff0ecc1SMasatake YAMATO {
113eff0ecc1SMasatake YAMATO vStringDelete (vstr);
114eff0ecc1SMasatake YAMATO vstr = NULL;
115eff0ecc1SMasatake YAMATO }
116eff0ecc1SMasatake YAMATO else if (strcmp (vStringValue (vstr), "do") == 0)
117eff0ecc1SMasatake YAMATO {
118eff0ecc1SMasatake YAMATO vStringDelete (vstr);
119eff0ecc1SMasatake YAMATO vstr = NULL;
120eff0ecc1SMasatake YAMATO *cp += -2; /* push back "do" */
121eff0ecc1SMasatake YAMATO }
122eff0ecc1SMasatake YAMATO
123eff0ecc1SMasatake YAMATO break;
124eff0ecc1SMasatake YAMATO }
125eff0ecc1SMasatake YAMATO
126eff0ecc1SMasatake YAMATO if (vstr)
127eff0ecc1SMasatake YAMATO {
128eff0ecc1SMasatake YAMATO rubySkipWhitespace (cp);
129eff0ecc1SMasatake YAMATO if (**cp == ',')
130eff0ecc1SMasatake YAMATO {
131eff0ecc1SMasatake YAMATO ++*cp;
132eff0ecc1SMasatake YAMATO rubySkipWhitespace (cp);
133eff0ecc1SMasatake YAMATO vString *vstr_rest = readRest (cp);
134eff0ecc1SMasatake YAMATO if (vstr_rest)
135eff0ecc1SMasatake YAMATO {
136eff0ecc1SMasatake YAMATO vStringPut (vstr, ' ');
137eff0ecc1SMasatake YAMATO vStringCat (vstr, vstr_rest);
138eff0ecc1SMasatake YAMATO vStringDelete (vstr_rest);
139eff0ecc1SMasatake YAMATO }
140eff0ecc1SMasatake YAMATO }
141eff0ecc1SMasatake YAMATO }
142eff0ecc1SMasatake YAMATO
143eff0ecc1SMasatake YAMATO return vstr;
144eff0ecc1SMasatake YAMATO }
145eff0ecc1SMasatake YAMATO
146a3baf5deSMasatake YAMATO struct caseType {
147a3baf5deSMasatake YAMATO const char *keyword;
148a3baf5deSMasatake YAMATO rspecKind kind;
149a3baf5deSMasatake YAMATO };
150a3baf5deSMasatake YAMATO
lineNotify(rubySubparser * s,const unsigned char ** cp)151eff0ecc1SMasatake YAMATO static int lineNotify (rubySubparser *s, const unsigned char **cp)
152eff0ecc1SMasatake YAMATO {
153a3baf5deSMasatake YAMATO struct caseType caseTypes [] = {
154a3baf5deSMasatake YAMATO { "describe", K_DESCRIBE },
155a3baf5deSMasatake YAMATO { "RSpec.describe", K_DESCRIBE },
156a3baf5deSMasatake YAMATO { "context", K_CONTEXT },
157*e8daccd0SMasatake YAMATO { "it", K_IT },
158a3baf5deSMasatake YAMATO };
159a3baf5deSMasatake YAMATO
160a3baf5deSMasatake YAMATO for (int i = 0; i < ARRAY_SIZE(caseTypes); i++)
161a3baf5deSMasatake YAMATO {
162a3baf5deSMasatake YAMATO if (rubyCanMatchKeywordWithAssign(cp, caseTypes[i].keyword))
163eff0ecc1SMasatake YAMATO {
164eff0ecc1SMasatake YAMATO vString *vstr = NULL;
165eff0ecc1SMasatake YAMATO rubySkipWhitespace (cp);
166eff0ecc1SMasatake YAMATO vstr = readRest (cp);
167eff0ecc1SMasatake YAMATO if (vstr)
168eff0ecc1SMasatake YAMATO {
169a3baf5deSMasatake YAMATO int r = makeSimpleRSpecTag (vstr, caseTypes[i].kind, s);
170eff0ecc1SMasatake YAMATO vStringDelete (vstr);
171eff0ecc1SMasatake YAMATO return r;
172eff0ecc1SMasatake YAMATO }
173eff0ecc1SMasatake YAMATO }
174eff0ecc1SMasatake YAMATO }
175a3baf5deSMasatake YAMATO
176eff0ecc1SMasatake YAMATO return CORK_NIL;
177eff0ecc1SMasatake YAMATO }
178eff0ecc1SMasatake YAMATO
enterBlockNotify(rubySubparser * s,int corkIndex)179eff0ecc1SMasatake YAMATO static void enterBlockNotify (rubySubparser *s, int corkIndex)
180eff0ecc1SMasatake YAMATO {
181eff0ecc1SMasatake YAMATO struct sRSpecSubparser *rspec = (struct sRSpecSubparser *)s;
182eff0ecc1SMasatake YAMATO rspec->scope = corkIndex;
183eff0ecc1SMasatake YAMATO }
184eff0ecc1SMasatake YAMATO
leaveBlockNotify(rubySubparser * s,int corkIndex)185eff0ecc1SMasatake YAMATO static void leaveBlockNotify (rubySubparser *s, int corkIndex)
186eff0ecc1SMasatake YAMATO {
187eff0ecc1SMasatake YAMATO tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
188eff0ecc1SMasatake YAMATO if (e)
189eff0ecc1SMasatake YAMATO {
190eff0ecc1SMasatake YAMATO struct sRSpecSubparser *rspec = (struct sRSpecSubparser *)s;
191eff0ecc1SMasatake YAMATO rspec->scope = e->extensionFields.scopeIndex;
192eff0ecc1SMasatake YAMATO }
193eff0ecc1SMasatake YAMATO }
194eff0ecc1SMasatake YAMATO
findRSpecTags(void)195eff0ecc1SMasatake YAMATO static void findRSpecTags (void)
196eff0ecc1SMasatake YAMATO {
197eff0ecc1SMasatake YAMATO scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
198eff0ecc1SMasatake YAMATO }
199eff0ecc1SMasatake YAMATO
inputStart(subparser * s)200049011caSMasatake YAMATO static void inputStart (subparser *s)
201049011caSMasatake YAMATO {
202049011caSMasatake YAMATO struct sRSpecSubparser *rspec = (struct sRSpecSubparser *)s;
203049011caSMasatake YAMATO rspec->scope = CORK_NIL;
204049011caSMasatake YAMATO }
205049011caSMasatake YAMATO
RSpecParser(void)206eff0ecc1SMasatake YAMATO extern parserDefinition* RSpecParser (void)
207eff0ecc1SMasatake YAMATO {
208eff0ecc1SMasatake YAMATO static struct sRSpecSubparser rspecSubparser = {
209eff0ecc1SMasatake YAMATO .ruby = {
210eff0ecc1SMasatake YAMATO .subparser = {
211eff0ecc1SMasatake YAMATO .direction = SUBPARSER_BASE_RUNS_SUB,
212049011caSMasatake YAMATO .inputStart = inputStart,
213eff0ecc1SMasatake YAMATO },
214eff0ecc1SMasatake YAMATO .lineNotify = lineNotify,
215eff0ecc1SMasatake YAMATO .enterBlockNotify = enterBlockNotify,
216eff0ecc1SMasatake YAMATO .leaveBlockNotify = leaveBlockNotify,
217eff0ecc1SMasatake YAMATO },
218eff0ecc1SMasatake YAMATO .scope = CORK_NIL,
219eff0ecc1SMasatake YAMATO };
220eff0ecc1SMasatake YAMATO
221eff0ecc1SMasatake YAMATO static parserDependency dependencies [] = {
222eff0ecc1SMasatake YAMATO [0] = { DEPTYPE_SUBPARSER, "Ruby", &rspecSubparser },
223eff0ecc1SMasatake YAMATO };
224eff0ecc1SMasatake YAMATO
225eff0ecc1SMasatake YAMATO parserDefinition* const def = parserNew ("RSpec");
226eff0ecc1SMasatake YAMATO
227eff0ecc1SMasatake YAMATO def->dependencies = dependencies;
228eff0ecc1SMasatake YAMATO def->dependencyCount = ARRAY_SIZE(dependencies);
229eff0ecc1SMasatake YAMATO def->kindTable = RSpecKinds;
230eff0ecc1SMasatake YAMATO def->kindCount = ARRAY_SIZE (RSpecKinds);
231eff0ecc1SMasatake YAMATO def->parser = findRSpecTags;
232eff0ecc1SMasatake YAMATO def->useCork = CORK_QUEUE;
233eff0ecc1SMasatake YAMATO
234eff0ecc1SMasatake YAMATO return def;
235eff0ecc1SMasatake YAMATO }
236