1acae9f99SDmitri Tikhonov /*
2acae9f99SDmitri Tikhonov * perl6.c -- Perl6 parser.
3acae9f99SDmitri Tikhonov * Author: Dmitri Tikhonov <dmitri@cpan.org>
4acae9f99SDmitri Tikhonov *
5acae9f99SDmitri Tikhonov * This is a very basic Perl 6 parser. It does not know how to:
6acae9f99SDmitri Tikhonov * - skip POD;
7acae9f99SDmitri Tikhonov * - skip multiline comments;
8acae9f99SDmitri Tikhonov * - skip quoted strings;
9acae9f99SDmitri Tikhonov * - generate fully-qualified tags.
10acae9f99SDmitri Tikhonov *
11acae9f99SDmitri Tikhonov * This source code is released for free distribution under the terms of
120ce38835Sviccuad * the GNU General Public License version 2 or (at your option) any later version.
13acae9f99SDmitri Tikhonov */
14acae9f99SDmitri Tikhonov
15792c8196SDmitri Tikhonov #include "general.h" /* must always come first */
16792c8196SDmitri Tikhonov
17acae9f99SDmitri Tikhonov #include <stdio.h>
18acae9f99SDmitri Tikhonov #include <string.h>
19acae9f99SDmitri Tikhonov
20acae9f99SDmitri Tikhonov #include "debug.h"
21acae9f99SDmitri Tikhonov #include "entry.h"
220d502ef0SMasatake YAMATO #include "parse.h"
23acae9f99SDmitri Tikhonov #include "read.h"
24acae9f99SDmitri Tikhonov #include "routines.h"
25acae9f99SDmitri Tikhonov #include "selectors.h"
26acae9f99SDmitri Tikhonov #include "vstring.h"
27acae9f99SDmitri Tikhonov
28acae9f99SDmitri Tikhonov enum perl6Kind {
29acae9f99SDmitri Tikhonov K_NONE = -1,
30acae9f99SDmitri Tikhonov K_CLASS,
31acae9f99SDmitri Tikhonov K_GRAMMAR,
32acae9f99SDmitri Tikhonov K_METHOD,
33acae9f99SDmitri Tikhonov K_MODULE,
34ce3d88feSDmitri Tikhonov K_PACKAGE,
35acae9f99SDmitri Tikhonov K_ROLE,
36acae9f99SDmitri Tikhonov K_RULE,
37acae9f99SDmitri Tikhonov K_SUBMETHOD,
38acae9f99SDmitri Tikhonov K_SUBROUTINE,
39acae9f99SDmitri Tikhonov K_TOKEN,
40acae9f99SDmitri Tikhonov };
41acae9f99SDmitri Tikhonov
42e112e8abSMasatake YAMATO static kindDefinition perl6Kinds[] = {
43ce990805SThomas Braun [K_CLASS] = { true, 'c', "class", "classes" },
44ce990805SThomas Braun [K_GRAMMAR] = { true, 'g', "grammar", "grammars" },
45ce990805SThomas Braun [K_METHOD] = { true, 'm', "method", "methods" },
46ce990805SThomas Braun [K_MODULE] = { true, 'o', "module", "modules" },
47ce990805SThomas Braun [K_PACKAGE] = { true, 'p', "package", "packages" },
48ce990805SThomas Braun [K_ROLE] = { true, 'r', "role", "roles" },
49ce990805SThomas Braun [K_RULE] = { true, 'u', "rule", "rules" },
50ce990805SThomas Braun [K_SUBMETHOD] = { true, 'b', "submethod", "submethods" },
51ce990805SThomas Braun [K_SUBROUTINE] = { true, 's', "subroutine", "subroutines" },
52ce990805SThomas Braun [K_TOKEN] = { true, 't', "token", "tokens" },
53acae9f99SDmitri Tikhonov };
54acae9f99SDmitri Tikhonov
55acae9f99SDmitri Tikhonov enum token {
56acae9f99SDmitri Tikhonov T_CLASS,
57acae9f99SDmitri Tikhonov T_GRAMMAR,
58acae9f99SDmitri Tikhonov T_METHOD,
59acae9f99SDmitri Tikhonov T_MODULE,
60acae9f99SDmitri Tikhonov T_MULTI,
61acae9f99SDmitri Tikhonov T_MY,
62acae9f99SDmitri Tikhonov T_OUR,
63ce3d88feSDmitri Tikhonov T_PACKAGE,
64acae9f99SDmitri Tikhonov T_PROTO,
65acae9f99SDmitri Tikhonov T_ROLE,
66acae9f99SDmitri Tikhonov T_RULE,
67acae9f99SDmitri Tikhonov T_SUB,
68acae9f99SDmitri Tikhonov T_SUBMETHOD,
69acae9f99SDmitri Tikhonov T_UNIT,
70acae9f99SDmitri Tikhonov T_TOKEN,
71acae9f99SDmitri Tikhonov };
72acae9f99SDmitri Tikhonov
73acae9f99SDmitri Tikhonov static const enum perl6Kind token2kind[] = {
74acae9f99SDmitri Tikhonov [T_CLASS] = K_CLASS,
75acae9f99SDmitri Tikhonov [T_GRAMMAR] = K_GRAMMAR,
76acae9f99SDmitri Tikhonov [T_METHOD] = K_METHOD,
77acae9f99SDmitri Tikhonov [T_MODULE] = K_MODULE,
78acae9f99SDmitri Tikhonov [T_MULTI] = K_SUBROUTINE,
79acae9f99SDmitri Tikhonov [T_MY] = K_NONE,
80acae9f99SDmitri Tikhonov [T_OUR] = K_NONE,
81ce3d88feSDmitri Tikhonov [T_PACKAGE] = K_PACKAGE,
82acae9f99SDmitri Tikhonov [T_PROTO] = K_NONE,
83acae9f99SDmitri Tikhonov [T_ROLE] = K_ROLE,
84acae9f99SDmitri Tikhonov [T_RULE] = K_RULE,
85acae9f99SDmitri Tikhonov [T_SUB] = K_SUBROUTINE,
86acae9f99SDmitri Tikhonov [T_SUBMETHOD] = K_SUBMETHOD,
87acae9f99SDmitri Tikhonov [T_UNIT] = K_NONE,
88acae9f99SDmitri Tikhonov [T_TOKEN] = K_TOKEN,
89acae9f99SDmitri Tikhonov };
90acae9f99SDmitri Tikhonov
91acae9f99SDmitri Tikhonov #define STRLEN(s) (sizeof(s) - 1)
92acae9f99SDmitri Tikhonov #define STREQN(s, token) (0 == strncmp(s, token, STRLEN(token)))
93acae9f99SDmitri Tikhonov
94acae9f99SDmitri Tikhonov static enum token
matchToken(const char * s,int len)95acae9f99SDmitri Tikhonov matchToken (const char *s, int len)
96acae9f99SDmitri Tikhonov {
97acae9f99SDmitri Tikhonov switch (len) {
98acae9f99SDmitri Tikhonov case 2:
99acae9f99SDmitri Tikhonov if (STREQN(s, "my")) return T_MY;
100acae9f99SDmitri Tikhonov break;
101acae9f99SDmitri Tikhonov case 3:
102acae9f99SDmitri Tikhonov switch (s[0]) {
103acae9f99SDmitri Tikhonov case 'o':
104acae9f99SDmitri Tikhonov if (STREQN(s, "our")) return T_OUR;
105acae9f99SDmitri Tikhonov break;
106acae9f99SDmitri Tikhonov case 's':
107acae9f99SDmitri Tikhonov if (STREQN(s, "sub")) return T_SUB;
108acae9f99SDmitri Tikhonov break;
109acae9f99SDmitri Tikhonov }
110acae9f99SDmitri Tikhonov break;
111acae9f99SDmitri Tikhonov case 4:
112acae9f99SDmitri Tikhonov switch (s[1]) {
113acae9f99SDmitri Tikhonov case 'o':
114acae9f99SDmitri Tikhonov if (STREQN(s, "role")) return T_ROLE;
115acae9f99SDmitri Tikhonov break;
116acae9f99SDmitri Tikhonov case 'u':
117acae9f99SDmitri Tikhonov if (STREQN(s, "rule")) return T_RULE;
118acae9f99SDmitri Tikhonov break;
119acae9f99SDmitri Tikhonov case 'n':
120acae9f99SDmitri Tikhonov if (STREQN(s, "unit")) return T_UNIT;
121acae9f99SDmitri Tikhonov break;
122acae9f99SDmitri Tikhonov }
123acae9f99SDmitri Tikhonov break;
124acae9f99SDmitri Tikhonov case 5:
125acae9f99SDmitri Tikhonov switch (s[0]) {
126acae9f99SDmitri Tikhonov case 'c':
127acae9f99SDmitri Tikhonov if (STREQN(s, "class")) return T_CLASS;
128acae9f99SDmitri Tikhonov break;
129acae9f99SDmitri Tikhonov case 'm':
130acae9f99SDmitri Tikhonov if (STREQN(s, "multi")) return T_MULTI;
131acae9f99SDmitri Tikhonov break;
132acae9f99SDmitri Tikhonov case 'p':
133acae9f99SDmitri Tikhonov if (STREQN(s, "proto")) return T_PROTO;
134acae9f99SDmitri Tikhonov break;
135acae9f99SDmitri Tikhonov case 't':
136acae9f99SDmitri Tikhonov if (STREQN(s, "token")) return T_TOKEN;
137acae9f99SDmitri Tikhonov break;
138acae9f99SDmitri Tikhonov }
139acae9f99SDmitri Tikhonov break;
140acae9f99SDmitri Tikhonov case 6:
141acae9f99SDmitri Tikhonov switch (s[1]) {
142acae9f99SDmitri Tikhonov case 'e':
143acae9f99SDmitri Tikhonov if (STREQN(s, "method")) return T_METHOD;
144acae9f99SDmitri Tikhonov break;
145acae9f99SDmitri Tikhonov case 'o':
146acae9f99SDmitri Tikhonov if (STREQN(s, "module")) return T_MODULE;
147acae9f99SDmitri Tikhonov break;
148acae9f99SDmitri Tikhonov }
149acae9f99SDmitri Tikhonov break;
150acae9f99SDmitri Tikhonov case 7:
151ce3d88feSDmitri Tikhonov switch (s[0]) {
152ce3d88feSDmitri Tikhonov case 'g':
153acae9f99SDmitri Tikhonov if (STREQN(s, "grammar")) return T_GRAMMAR;
154acae9f99SDmitri Tikhonov break;
155ce3d88feSDmitri Tikhonov case 'p':
156ce3d88feSDmitri Tikhonov if (STREQN(s, "package")) return T_PACKAGE;
157ce3d88feSDmitri Tikhonov break;
158ce3d88feSDmitri Tikhonov }
159ce3d88feSDmitri Tikhonov break;
160acae9f99SDmitri Tikhonov case 9:
161acae9f99SDmitri Tikhonov if (STREQN(s, "submethod")) return T_SUBMETHOD;
162acae9f99SDmitri Tikhonov break;
163acae9f99SDmitri Tikhonov }
164acae9f99SDmitri Tikhonov return -1;
165acae9f99SDmitri Tikhonov }
166acae9f99SDmitri Tikhonov
167792c8196SDmitri Tikhonov static const int validPerl6Identifier[0x100] = {
168acae9f99SDmitri Tikhonov /* r!perl -e "print qq([(int)'\$_'] = 1,\n)for a..z,A..Z,0..9,':','-','_'"|fmt
169acae9f99SDmitri Tikhonov */
170acae9f99SDmitri Tikhonov [(int)'a'] = 1, [(int)'b'] = 1, [(int)'c'] = 1, [(int)'d'] = 1,
171acae9f99SDmitri Tikhonov [(int)'e'] = 1, [(int)'f'] = 1, [(int)'g'] = 1, [(int)'h'] = 1,
172acae9f99SDmitri Tikhonov [(int)'i'] = 1, [(int)'j'] = 1, [(int)'k'] = 1, [(int)'l'] = 1,
173acae9f99SDmitri Tikhonov [(int)'m'] = 1, [(int)'n'] = 1, [(int)'o'] = 1, [(int)'p'] = 1,
174acae9f99SDmitri Tikhonov [(int)'q'] = 1, [(int)'r'] = 1, [(int)'s'] = 1, [(int)'t'] = 1,
175acae9f99SDmitri Tikhonov [(int)'u'] = 1, [(int)'v'] = 1, [(int)'w'] = 1, [(int)'x'] = 1,
176acae9f99SDmitri Tikhonov [(int)'y'] = 1, [(int)'z'] = 1, [(int)'A'] = 1, [(int)'B'] = 1,
177acae9f99SDmitri Tikhonov [(int)'C'] = 1, [(int)'D'] = 1, [(int)'E'] = 1, [(int)'F'] = 1,
178acae9f99SDmitri Tikhonov [(int)'G'] = 1, [(int)'H'] = 1, [(int)'I'] = 1, [(int)'J'] = 1,
179acae9f99SDmitri Tikhonov [(int)'K'] = 1, [(int)'L'] = 1, [(int)'M'] = 1, [(int)'N'] = 1,
180acae9f99SDmitri Tikhonov [(int)'O'] = 1, [(int)'P'] = 1, [(int)'Q'] = 1, [(int)'R'] = 1,
181acae9f99SDmitri Tikhonov [(int)'S'] = 1, [(int)'T'] = 1, [(int)'U'] = 1, [(int)'V'] = 1,
182acae9f99SDmitri Tikhonov [(int)'W'] = 1, [(int)'X'] = 1, [(int)'Y'] = 1, [(int)'Z'] = 1,
183acae9f99SDmitri Tikhonov [(int)'0'] = 1, [(int)'1'] = 1, [(int)'2'] = 1, [(int)'3'] = 1,
184acae9f99SDmitri Tikhonov [(int)'4'] = 1, [(int)'5'] = 1, [(int)'6'] = 1, [(int)'7'] = 1,
185acae9f99SDmitri Tikhonov [(int)'8'] = 1, [(int)'9'] = 1, [(int)':'] = 1, [(int)'-'] = 1,
186acae9f99SDmitri Tikhonov [(int)'_'] = 1,
187acae9f99SDmitri Tikhonov };
188acae9f99SDmitri Tikhonov
189792c8196SDmitri Tikhonov static const int validMethodPrefix[0x100] = {
190acae9f99SDmitri Tikhonov [(int)'!'] = 1, [(int)'^'] = 1,
191acae9f99SDmitri Tikhonov };
192acae9f99SDmitri Tikhonov
193acae9f99SDmitri Tikhonov static const int kindMayHaveMethodPrefix = (1 << K_SUBMETHOD) |
194acae9f99SDmitri Tikhonov (1 << K_METHOD) ;
195acae9f99SDmitri Tikhonov
196acae9f99SDmitri Tikhonov /* Trim identifier pointed to by ps, possibly advancing it, and return
197acae9f99SDmitri Tikhonov * the length of the valid portion. If the returned value is zero, the
198acae9f99SDmitri Tikhonov * identifier is invalid.
199acae9f99SDmitri Tikhonov */
200acae9f99SDmitri Tikhonov static int
trimIdentifier(enum perl6Kind kind,const char ** ps,int len)201acae9f99SDmitri Tikhonov trimIdentifier (enum perl6Kind kind, const char **ps, int len)
202acae9f99SDmitri Tikhonov {
203acae9f99SDmitri Tikhonov Assert(len > 0);
204acae9f99SDmitri Tikhonov const char *const end = *ps + len;
205acae9f99SDmitri Tikhonov const char *s = *ps;
206acae9f99SDmitri Tikhonov /* Trim the front if possible: */
207acae9f99SDmitri Tikhonov s += (kindMayHaveMethodPrefix & (1 << kind)) &&
208acae9f99SDmitri Tikhonov validMethodPrefix[(int)*s];
209acae9f99SDmitri Tikhonov /* Record the start of identifier: */
210acae9f99SDmitri Tikhonov *ps = s;
211acae9f99SDmitri Tikhonov /* Continuous string of valid characters: */
212acae9f99SDmitri Tikhonov while (s < end && validPerl6Identifier[(int)*s])
213acae9f99SDmitri Tikhonov ++s;
214acae9f99SDmitri Tikhonov /* sub multi infix:<...> -- we want the "infix" only */
215acae9f99SDmitri Tikhonov while (s - *ps > 0 && ':' == s[-1])
216acae9f99SDmitri Tikhonov --s;
217acae9f99SDmitri Tikhonov /* It's ok if this is zero: */
218acae9f99SDmitri Tikhonov return s - *ps;
219acae9f99SDmitri Tikhonov }
220acae9f99SDmitri Tikhonov
221acae9f99SDmitri Tikhonov struct p6Ctx {
222acae9f99SDmitri Tikhonov enum token tokens[128 /* unlikely to need more than this */];
223e5f9cc19SMasatake YAMATO unsigned int n_tokens;
224acae9f99SDmitri Tikhonov vString *name;
2251b312fe7SMasatake YAMATO const char *line; /* Saved from readLineFromInputFile() */
226acae9f99SDmitri Tikhonov };
227acae9f99SDmitri Tikhonov
228acae9f99SDmitri Tikhonov static void
makeTag(struct p6Ctx * ctx,int kind,const char * name,int len)229acae9f99SDmitri Tikhonov makeTag (struct p6Ctx *ctx, int kind, const char *name, int len)
230acae9f99SDmitri Tikhonov {
231acae9f99SDmitri Tikhonov tagEntryInfo entry;
232acae9f99SDmitri Tikhonov vStringNCopyS(ctx->name, name, len);
23316a2541cSMasatake YAMATO initTagEntry(&entry, vStringValue(ctx->name), kind);
234acae9f99SDmitri Tikhonov makeTagEntry(&entry);
235acae9f99SDmitri Tikhonov }
236acae9f99SDmitri Tikhonov
237acae9f99SDmitri Tikhonov static void
possiblyMakeTag(struct p6Ctx * ctx,const char * s,int len)238acae9f99SDmitri Tikhonov possiblyMakeTag (struct p6Ctx *ctx, const char *s, int len)
239acae9f99SDmitri Tikhonov {
240acae9f99SDmitri Tikhonov Assert(ctx->n_tokens > 0);
241acae9f99SDmitri Tikhonov enum perl6Kind kind = token2kind[ ctx->tokens[ctx->n_tokens - 1] ];
242acae9f99SDmitri Tikhonov if (K_NONE != kind && perl6Kinds[kind].enabled
243acae9f99SDmitri Tikhonov && (len = trimIdentifier(kind, &s, len)) > 0)
244acae9f99SDmitri Tikhonov makeTag(ctx, kind, s, len);
245acae9f99SDmitri Tikhonov }
246acae9f99SDmitri Tikhonov
247acae9f99SDmitri Tikhonov static void
initP6Ctx(struct p6Ctx * ctx)248acae9f99SDmitri Tikhonov initP6Ctx (struct p6Ctx *ctx)
249acae9f99SDmitri Tikhonov {
250acae9f99SDmitri Tikhonov ctx->n_tokens = 0;
251acae9f99SDmitri Tikhonov ctx->name = vStringNew();
252acae9f99SDmitri Tikhonov ctx->line = NULL;
253acae9f99SDmitri Tikhonov }
254acae9f99SDmitri Tikhonov
255acae9f99SDmitri Tikhonov static void
deinitP6Ctx(struct p6Ctx * ctx)256acae9f99SDmitri Tikhonov deinitP6Ctx (struct p6Ctx *ctx)
257acae9f99SDmitri Tikhonov {
258acae9f99SDmitri Tikhonov vStringDelete(ctx->name);
259acae9f99SDmitri Tikhonov }
260acae9f99SDmitri Tikhonov
261acae9f99SDmitri Tikhonov /* Read next contiguous sequence of non-whitespace characters, store
262acae9f99SDmitri Tikhonov * the address in `ptok', and return its length. Return value of zero
263acae9f99SDmitri Tikhonov * means EOF.
264acae9f99SDmitri Tikhonov *
265acae9f99SDmitri Tikhonov * TODO: Currently, POD and multi-line comments are not handled.
266acae9f99SDmitri Tikhonov */
267acae9f99SDmitri Tikhonov static int
getNonSpaceStr(struct p6Ctx * ctx,const char ** ptok)268acae9f99SDmitri Tikhonov getNonSpaceStr (struct p6Ctx *ctx, const char **ptok)
269acae9f99SDmitri Tikhonov {
270acae9f99SDmitri Tikhonov const char *s = ctx->line;
271acae9f99SDmitri Tikhonov if (!s) {
272acae9f99SDmitri Tikhonov next_line:
2731b312fe7SMasatake YAMATO s = (const char *) readLineFromInputFile();
274acae9f99SDmitri Tikhonov if (!s)
275acae9f99SDmitri Tikhonov return 0; /* EOF */
276acae9f99SDmitri Tikhonov }
277acae9f99SDmitri Tikhonov while (*s && isspace(*s)) /* Skip whitespace */
278acae9f99SDmitri Tikhonov ++s;
279acae9f99SDmitri Tikhonov if ('#' == *s)
280acae9f99SDmitri Tikhonov goto next_line;
281acae9f99SDmitri Tikhonov int non_white_len = strcspn(s, ",; \t");
282acae9f99SDmitri Tikhonov if (non_white_len) {
283acae9f99SDmitri Tikhonov ctx->line = s + non_white_len; /* Save state */
284acae9f99SDmitri Tikhonov *ptok = s;
285acae9f99SDmitri Tikhonov return non_white_len;
286acae9f99SDmitri Tikhonov } else
287acae9f99SDmitri Tikhonov goto next_line;
288acae9f99SDmitri Tikhonov }
289acae9f99SDmitri Tikhonov
290acae9f99SDmitri Tikhonov static void
findPerl6Tags(void)291acae9f99SDmitri Tikhonov findPerl6Tags (void)
292acae9f99SDmitri Tikhonov {
293acae9f99SDmitri Tikhonov struct p6Ctx ctx;
294acae9f99SDmitri Tikhonov
295acae9f99SDmitri Tikhonov #define RESET_TOKENS() do { ctx.n_tokens = 0; } while (0)
296acae9f99SDmitri Tikhonov
297acae9f99SDmitri Tikhonov #define PUSH_TOKEN(_t_) do { \
298158a3387SMasatake YAMATO if (ctx.n_tokens < ARRAY_SIZE(ctx.tokens)) { \
299acae9f99SDmitri Tikhonov ctx.tokens[ ctx.n_tokens ] = _t_; \
300acae9f99SDmitri Tikhonov ++ctx.n_tokens; \
301acae9f99SDmitri Tikhonov } else { \
302acae9f99SDmitri Tikhonov Assert(!"Token stack overflown: this is quite odd"); \
303acae9f99SDmitri Tikhonov RESET_TOKENS(); \
304acae9f99SDmitri Tikhonov } \
305acae9f99SDmitri Tikhonov } while (0)
306acae9f99SDmitri Tikhonov
307acae9f99SDmitri Tikhonov initP6Ctx(&ctx);
308acae9f99SDmitri Tikhonov
309acae9f99SDmitri Tikhonov const char *s;
310acae9f99SDmitri Tikhonov int len;
311acae9f99SDmitri Tikhonov
312acae9f99SDmitri Tikhonov while ((len = getNonSpaceStr(&ctx, &s)) > 0) {
313acae9f99SDmitri Tikhonov enum token token = matchToken(s, len);
314acae9f99SDmitri Tikhonov if ((int) token >= 0) {
315acae9f99SDmitri Tikhonov PUSH_TOKEN(token);
316acae9f99SDmitri Tikhonov } else if (ctx.n_tokens > 0) {
317acae9f99SDmitri Tikhonov possiblyMakeTag(&ctx, s, len);
318acae9f99SDmitri Tikhonov RESET_TOKENS();
319acae9f99SDmitri Tikhonov }
320acae9f99SDmitri Tikhonov }
321acae9f99SDmitri Tikhonov
322acae9f99SDmitri Tikhonov deinitP6Ctx(&ctx);
323acae9f99SDmitri Tikhonov }
324acae9f99SDmitri Tikhonov
325acae9f99SDmitri Tikhonov parserDefinition *
Perl6Parser(void)326acae9f99SDmitri Tikhonov Perl6Parser (void)
327acae9f99SDmitri Tikhonov {
328*af24e4f7SJiří Techet static const char *const extensions[] = { "p6", "pm6", "pm", "pl6",
329*af24e4f7SJiří Techet "t6", "raku", "rakumod", "rakutest", NULL };
3305a38b5ceSMasatake YAMATO static selectLanguage selectors [] = { selectByPickingPerlVersion,
3315a38b5ceSMasatake YAMATO NULL };
332acae9f99SDmitri Tikhonov parserDefinition* def = parserNew("Perl6");
33309ae690fSMasatake YAMATO def->kindTable = perl6Kinds;
3343db72c21SMasatake YAMATO def->kindCount = ARRAY_SIZE(perl6Kinds);
335acae9f99SDmitri Tikhonov def->extensions = extensions;
336acae9f99SDmitri Tikhonov def->parser = findPerl6Tags;
3375a38b5ceSMasatake YAMATO def->selectLanguage = selectors;
338acae9f99SDmitri Tikhonov return def;
339acae9f99SDmitri Tikhonov }
340