1*197e8d50SMasatake YAMATO /*
2*197e8d50SMasatake YAMATO * A parser for RUBYGEM's specification
3*197e8d50SMasatake YAMATO *
4*197e8d50SMasatake YAMATO * Copyright (c) 2021, Red Hat, Inc.
5*197e8d50SMasatake YAMATO * Copyright (c) 2021, Masatake YAMATO
6*197e8d50SMasatake YAMATO *
7*197e8d50SMasatake YAMATO * Author: Masatake YAMATO <yamato@redhat.com>
8*197e8d50SMasatake YAMATO *
9*197e8d50SMasatake YAMATO * This program is free software; you can redistribute it and/or
10*197e8d50SMasatake YAMATO * modify it under the terms of the GNU General Public License
11*197e8d50SMasatake YAMATO * as published by the Free Software Foundation; either version 2
12*197e8d50SMasatake YAMATO * of the License, or (at your option) any later version.
13*197e8d50SMasatake YAMATO *
14*197e8d50SMasatake YAMATO * This program is distributed in the hope that it will be useful,
15*197e8d50SMasatake YAMATO * but WITHOUT ANY WARRANTY; without even the implied warranty of
16*197e8d50SMasatake YAMATO * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17*197e8d50SMasatake YAMATO * GNU General Public License for more details.
18*197e8d50SMasatake YAMATO *
19*197e8d50SMasatake YAMATO * You should have received a copy of the GNU General Public License
20*197e8d50SMasatake YAMATO * along with this program; if not, write to the Free Software
21*197e8d50SMasatake YAMATO * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22*197e8d50SMasatake YAMATO * USA.
23*197e8d50SMasatake YAMATO *
24*197e8d50SMasatake YAMATO * Reference:
25*197e8d50SMasatake YAMATO * - https://guides.rubygems.org/specification-reference/
26*197e8d50SMasatake YAMATO *
27*197e8d50SMasatake YAMATO * See also:
28*197e8d50SMasatake YAMATO * - https://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
29*197e8d50SMasatake YAMATO */
30*197e8d50SMasatake YAMATO
31*197e8d50SMasatake YAMATO /*
32*197e8d50SMasatake YAMATO * INCLUDE FILES
33*197e8d50SMasatake YAMATO */
34*197e8d50SMasatake YAMATO #include "general.h" /* must always come first */
35*197e8d50SMasatake YAMATO
36*197e8d50SMasatake YAMATO #include "entry.h"
37*197e8d50SMasatake YAMATO #include "parse.h"
38*197e8d50SMasatake YAMATO #include "subparser.h"
39*197e8d50SMasatake YAMATO
40*197e8d50SMasatake YAMATO #include "ruby.h"
41*197e8d50SMasatake YAMATO
42*197e8d50SMasatake YAMATO #include <string.h>
43*197e8d50SMasatake YAMATO
44*197e8d50SMasatake YAMATO /*
45*197e8d50SMasatake YAMATO * DATA STRUCTURES
46*197e8d50SMasatake YAMATO */
47*197e8d50SMasatake YAMATO struct sGemSpecSubparser {
48*197e8d50SMasatake YAMATO rubySubparser ruby;
49*197e8d50SMasatake YAMATO vString *var_name;
50*197e8d50SMasatake YAMATO };
51*197e8d50SMasatake YAMATO
52*197e8d50SMasatake YAMATO typedef enum {
53*197e8d50SMasatake YAMATO K_GEM,
54*197e8d50SMasatake YAMATO } gemspecKind;
55*197e8d50SMasatake YAMATO
56*197e8d50SMasatake YAMATO typedef enum {
57*197e8d50SMasatake YAMATO R_GEM_RUNTIME_DEP,
58*197e8d50SMasatake YAMATO R_GEM_DEVEL_DEP,
59*197e8d50SMasatake YAMATO } gemspecGemRole;
60*197e8d50SMasatake YAMATO
61*197e8d50SMasatake YAMATO static roleDefinition GemSpecGemRoles [] = {
62*197e8d50SMasatake YAMATO { true, "runtimeDep", "specifying runtime dependency" },
63*197e8d50SMasatake YAMATO { true, "develDep", "specifying development dependency" },
64*197e8d50SMasatake YAMATO };
65*197e8d50SMasatake YAMATO
66*197e8d50SMasatake YAMATO static kindDefinition GemSpecKinds [] = {
67*197e8d50SMasatake YAMATO { true, 'g', "gem", "gems",
68*197e8d50SMasatake YAMATO .referenceOnly = false, ATTACH_ROLES(GemSpecGemRoles)},
69*197e8d50SMasatake YAMATO };
70*197e8d50SMasatake YAMATO
71*197e8d50SMasatake YAMATO /*
72*197e8d50SMasatake YAMATO * FUNCTIONS
73*197e8d50SMasatake YAMATO */
findGemSpecTags(void)74*197e8d50SMasatake YAMATO static void findGemSpecTags (void)
75*197e8d50SMasatake YAMATO {
76*197e8d50SMasatake YAMATO scheduleRunningBaseparser (0);
77*197e8d50SMasatake YAMATO }
78*197e8d50SMasatake YAMATO
lineNotify(rubySubparser * s,const unsigned char ** cp)79*197e8d50SMasatake YAMATO static int lineNotify (rubySubparser *s, const unsigned char **cp)
80*197e8d50SMasatake YAMATO {
81*197e8d50SMasatake YAMATO struct sGemSpecSubparser *gemspec = (struct sGemSpecSubparser *)s;
82*197e8d50SMasatake YAMATO const unsigned char *p = *cp;
83*197e8d50SMasatake YAMATO
84*197e8d50SMasatake YAMATO if (vStringLength (gemspec->var_name) > 0
85*197e8d50SMasatake YAMATO && (strncmp ((char *)p, vStringValue (gemspec->var_name),
86*197e8d50SMasatake YAMATO vStringLength (gemspec->var_name)) == 0))
87*197e8d50SMasatake YAMATO {
88*197e8d50SMasatake YAMATO int kind = K_GEM;
89*197e8d50SMasatake YAMATO int role = ROLE_DEFINITION_INDEX;
90*197e8d50SMasatake YAMATO bool is_attr = true;
91*197e8d50SMasatake YAMATO
92*197e8d50SMasatake YAMATO p += vStringLength (gemspec->var_name);
93*197e8d50SMasatake YAMATO
94*197e8d50SMasatake YAMATO if (strncmp ((const char *)p, "name", 4) == 0)
95*197e8d50SMasatake YAMATO p += 4;
96*197e8d50SMasatake YAMATO else if (strncmp ((const char *)p, "add_runtime_dependency", 22) == 0)
97*197e8d50SMasatake YAMATO {
98*197e8d50SMasatake YAMATO p += 22;
99*197e8d50SMasatake YAMATO role = R_GEM_RUNTIME_DEP;
100*197e8d50SMasatake YAMATO is_attr = false;
101*197e8d50SMasatake YAMATO }
102*197e8d50SMasatake YAMATO else if (strncmp ((const char *)p, "add_development_dependency", 26) == 0)
103*197e8d50SMasatake YAMATO {
104*197e8d50SMasatake YAMATO p += 26;
105*197e8d50SMasatake YAMATO role = R_GEM_DEVEL_DEP;
106*197e8d50SMasatake YAMATO is_attr = false;
107*197e8d50SMasatake YAMATO }
108*197e8d50SMasatake YAMATO else
109*197e8d50SMasatake YAMATO p = NULL;
110*197e8d50SMasatake YAMATO
111*197e8d50SMasatake YAMATO if (p)
112*197e8d50SMasatake YAMATO {
113*197e8d50SMasatake YAMATO rubySkipWhitespace (&p);
114*197e8d50SMasatake YAMATO if ((!is_attr) || *p == '=')
115*197e8d50SMasatake YAMATO {
116*197e8d50SMasatake YAMATO if (is_attr)
117*197e8d50SMasatake YAMATO {
118*197e8d50SMasatake YAMATO p++;
119*197e8d50SMasatake YAMATO rubySkipWhitespace (&p);
120*197e8d50SMasatake YAMATO }
121*197e8d50SMasatake YAMATO if (*p == '"' || *p == '\'')
122*197e8d50SMasatake YAMATO {
123*197e8d50SMasatake YAMATO unsigned char b = *p;
124*197e8d50SMasatake YAMATO vString *gem = vStringNew ();
125*197e8d50SMasatake YAMATO p++;
126*197e8d50SMasatake YAMATO if (rubyParseString (&p, b, gem))
127*197e8d50SMasatake YAMATO {
128*197e8d50SMasatake YAMATO if (role == ROLE_DEFINITION_INDEX)
129*197e8d50SMasatake YAMATO makeSimpleTag (gem, kind);
130*197e8d50SMasatake YAMATO else
131*197e8d50SMasatake YAMATO makeSimpleRefTag (gem, kind, role);
132*197e8d50SMasatake YAMATO }
133*197e8d50SMasatake YAMATO vStringDelete (gem);
134*197e8d50SMasatake YAMATO }
135*197e8d50SMasatake YAMATO }
136*197e8d50SMasatake YAMATO }
137*197e8d50SMasatake YAMATO }
138*197e8d50SMasatake YAMATO else if (rubyCanMatchKeywordWithAssign (&p, "Gem::Specification.new"))
139*197e8d50SMasatake YAMATO {
140*197e8d50SMasatake YAMATO vString *vstr = vStringNew ();
141*197e8d50SMasatake YAMATO bool curly_bracket = false;
142*197e8d50SMasatake YAMATO
143*197e8d50SMasatake YAMATO rubySkipWhitespace (&p);
144*197e8d50SMasatake YAMATO
145*197e8d50SMasatake YAMATO curly_bracket = (*p == '{');
146*197e8d50SMasatake YAMATO if (curly_bracket
147*197e8d50SMasatake YAMATO || (rubyParseMethodName (&p, vstr)
148*197e8d50SMasatake YAMATO && vStringLength (vstr) == 2
149*197e8d50SMasatake YAMATO && strcmp (vStringValue(vstr), "do") == 0))
150*197e8d50SMasatake YAMATO {
151*197e8d50SMasatake YAMATO if (curly_bracket)
152*197e8d50SMasatake YAMATO p++;
153*197e8d50SMasatake YAMATO
154*197e8d50SMasatake YAMATO rubySkipWhitespace (&p);
155*197e8d50SMasatake YAMATO if (*p == '|')
156*197e8d50SMasatake YAMATO {
157*197e8d50SMasatake YAMATO p++;
158*197e8d50SMasatake YAMATO rubySkipWhitespace (&p);
159*197e8d50SMasatake YAMATO vStringClear (vstr);
160*197e8d50SMasatake YAMATO if (rubyParseMethodName (&p, vstr))
161*197e8d50SMasatake YAMATO {
162*197e8d50SMasatake YAMATO vStringPut (vstr, '.');
163*197e8d50SMasatake YAMATO vStringCopy(gemspec->var_name, vstr);
164*197e8d50SMasatake YAMATO }
165*197e8d50SMasatake YAMATO }
166*197e8d50SMasatake YAMATO }
167*197e8d50SMasatake YAMATO vStringDelete (vstr);
168*197e8d50SMasatake YAMATO }
169*197e8d50SMasatake YAMATO return CORK_NIL;
170*197e8d50SMasatake YAMATO }
171*197e8d50SMasatake YAMATO
inputStart(subparser * s)172*197e8d50SMasatake YAMATO static void inputStart (subparser *s)
173*197e8d50SMasatake YAMATO {
174*197e8d50SMasatake YAMATO struct sGemSpecSubparser *gemspec = (struct sGemSpecSubparser *)s;
175*197e8d50SMasatake YAMATO
176*197e8d50SMasatake YAMATO gemspec->var_name = vStringNew ();
177*197e8d50SMasatake YAMATO }
178*197e8d50SMasatake YAMATO
inputEnd(subparser * s)179*197e8d50SMasatake YAMATO static void inputEnd (subparser *s)
180*197e8d50SMasatake YAMATO {
181*197e8d50SMasatake YAMATO struct sGemSpecSubparser *gemspec = (struct sGemSpecSubparser *)s;
182*197e8d50SMasatake YAMATO
183*197e8d50SMasatake YAMATO vStringDelete (gemspec->var_name); /* NULL is acceptable. */
184*197e8d50SMasatake YAMATO gemspec->var_name = NULL;
185*197e8d50SMasatake YAMATO }
186*197e8d50SMasatake YAMATO
GemSpecParser(void)187*197e8d50SMasatake YAMATO extern parserDefinition* GemSpecParser (void)
188*197e8d50SMasatake YAMATO {
189*197e8d50SMasatake YAMATO static const char *const extensions [] = { "gemspec", NULL };
190*197e8d50SMasatake YAMATO static struct sGemSpecSubparser gemspecSubparser = {
191*197e8d50SMasatake YAMATO .ruby = {
192*197e8d50SMasatake YAMATO .subparser = {
193*197e8d50SMasatake YAMATO .direction = SUBPARSER_SUB_RUNS_BASE,
194*197e8d50SMasatake YAMATO .inputStart = inputStart,
195*197e8d50SMasatake YAMATO .inputEnd = inputEnd,
196*197e8d50SMasatake YAMATO },
197*197e8d50SMasatake YAMATO .lineNotify = lineNotify,
198*197e8d50SMasatake YAMATO },
199*197e8d50SMasatake YAMATO .var_name = NULL,
200*197e8d50SMasatake YAMATO };
201*197e8d50SMasatake YAMATO
202*197e8d50SMasatake YAMATO static parserDependency dependencies [] = {
203*197e8d50SMasatake YAMATO [0] = { DEPTYPE_SUBPARSER, "Ruby", &gemspecSubparser },
204*197e8d50SMasatake YAMATO };
205*197e8d50SMasatake YAMATO
206*197e8d50SMasatake YAMATO parserDefinition* const def = parserNew ("GemSpec");
207*197e8d50SMasatake YAMATO
208*197e8d50SMasatake YAMATO def->dependencies = dependencies;
209*197e8d50SMasatake YAMATO def->dependencyCount = ARRAY_SIZE(dependencies);
210*197e8d50SMasatake YAMATO def->kindTable = GemSpecKinds;
211*197e8d50SMasatake YAMATO def->kindCount = ARRAY_SIZE (GemSpecKinds);
212*197e8d50SMasatake YAMATO def->extensions = extensions;
213*197e8d50SMasatake YAMATO def->parser = findGemSpecTags;
214*197e8d50SMasatake YAMATO def->useCork = CORK_QUEUE;
215*197e8d50SMasatake YAMATO
216*197e8d50SMasatake YAMATO return def;
217*197e8d50SMasatake YAMATO }
218