File Coverage

lib/Devel/CallParser.xs
Criterion Covered Total %
statement 115 122 94.2
branch 72 102 70.5
condition n/a
subroutine n/a
pod n/a
total 187 224 83.4


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT 1
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "callchecker0.h"
5             #include "XSUB.h"
6              
7             #define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
8             #define PERL_DECIMAL_VERSION \
9             PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
10             #define PERL_VERSION_GE(r,v,s) \
11             (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
12              
13             #ifndef op_append_elem
14             # define op_append_elem(t, f, l) THX_op_append_elem(aTHX_ t, f, l)
15             static OP *THX_op_append_elem(pTHX_ I32 type, OP *first, OP *last)
16             {
17             if(!first) return last;
18             if(!last) return first;
19             if(first->op_type != (unsigned)type ||
20             (type == OP_LIST && (first->op_flags & OPf_PARENS)))
21             return newLISTOP(type, 0, first, last);
22             if(first->op_flags & OPf_KIDS) {
23             cLISTOPx(first)->op_last->op_sibling = last;
24             } else {
25             first->op_flags |= OPf_KIDS;
26             cLISTOPx(first)->op_first = last;
27             }
28             cLISTOPx(first)->op_last = last;
29             return first;
30             }
31             #endif /* !op_append_elem */
32              
33             #ifndef qerror
34             # define qerror(m) Perl_qerror(aTHX_ m)
35             #endif /* !qerror */
36              
37             #define QPFX C8K61oRQKxigiqmUlVdk_
38             #define QPFXS STRINGIFY(QPFX)
39             #define QCONCAT0(a,b) a##b
40             #define QCONCAT1(a,b) QCONCAT0(a,b)
41             #define QPFXD(name) QCONCAT1(QPFX, name)
42              
43             #if defined(WIN32) && PERL_VERSION_GE(5,13,6)
44             # define MY_BASE_CALLCONV EXTERN_C
45             # define MY_BASE_CALLCONV_S "EXTERN_C"
46             #else /* !(WIN32 && >= 5.13.6) */
47             # define MY_BASE_CALLCONV PERL_CALLCONV
48             # define MY_BASE_CALLCONV_S "PERL_CALLCONV"
49             #endif /* !(WIN32 && >= 5.13.6) */
50              
51             #define MY_EXPORT_CALLCONV MY_BASE_CALLCONV
52              
53             #if defined(WIN32) || defined(__CYGWIN__)
54             # define MY_IMPORT_CALLCONV_S MY_BASE_CALLCONV_S" __declspec(dllimport)"
55             #else
56             # define MY_IMPORT_CALLCONV_S MY_BASE_CALLCONV_S
57             #endif
58              
59             static MGVTBL mgvtbl_parsecall;
60              
61             typedef OP *(*Perl_call_parser)(pTHX_ GV *, SV *, U32 *);
62              
63             #define CALLPARSER_PARENS 0x00000001
64             #define CALLPARSER_STATEMENT 0x00000002
65              
66             #ifdef parse_fullexpr
67             # define Q_PARSER_AVAILABLE 1
68             #endif /* parse_fullexpr */
69              
70             #if Q_PARSER_AVAILABLE
71              
72             # define Perl_parse_args_parenthesised QPFXD(pac0)
73             # define parse_args_parenthesised(fp) Perl_parse_args_parenthesised(aTHX_ fp)
74 179           MY_EXPORT_CALLCONV OP *QPFXD(pac0)(pTHX_ U32 *flags_p)
75             {
76             OP *argsop;
77 179           lex_read_space(0);
78 179 100         if(lex_peek_unichar(0) != '('/*)*/) {
79 29           qerror(mess("syntax error"));
80 29           return NULL;
81             }
82 150           lex_read_unichar(0);
83 150           argsop = parse_fullexpr(PARSE_OPTIONAL);
84 150           lex_read_space(0);
85 150 50         if(lex_peek_unichar(0) != /*(*/')') {
86 0           qerror(mess("syntax error"));
87 0           return argsop;
88             }
89 150           lex_read_unichar(0);
90 150           *flags_p |= CALLPARSER_PARENS;
91 150           return argsop;
92             }
93              
94             # define Perl_parse_args_nullary QPFXD(paz0)
95             # define parse_args_nullary(fp) Perl_parse_args_nullary(aTHX_ fp)
96 63           MY_EXPORT_CALLCONV OP *QPFXD(paz0)(pTHX_ U32 *flags_p)
97             {
98 63           lex_read_space(0);
99 63 100         if(lex_peek_unichar(0) == '('/*)*/)
100 28           return parse_args_parenthesised(flags_p);
101             return NULL;
102             }
103              
104             # define Perl_parse_args_unary QPFXD(pau0)
105             # define parse_args_unary(fp) Perl_parse_args_unary(aTHX_ fp)
106 95           MY_EXPORT_CALLCONV OP *QPFXD(pau0)(pTHX_ U32 *flags_p)
107             {
108 95           lex_read_space(0);
109 95 100         if(lex_peek_unichar(0) == '('/*)*/)
110 36           return parse_args_parenthesised(flags_p);
111 59           return parse_arithexpr(PARSE_OPTIONAL);
112             }
113              
114             # define Perl_parse_args_list QPFXD(pal0)
115             # define parse_args_list(fp) Perl_parse_args_list(aTHX_ fp)
116 79           MY_EXPORT_CALLCONV OP *QPFXD(pal0)(pTHX_ U32 *flags_p)
117             {
118 79           lex_read_space(0);
119 79 100         if(lex_peek_unichar(0) == '('/*)*/)
120 32           return parse_args_parenthesised(flags_p);
121 47           return parse_listexpr(PARSE_OPTIONAL);
122             }
123              
124             # define Perl_parse_args_block_list QPFXD(pab0)
125             # define parse_args_block_list(fp) Perl_parse_args_block_list(aTHX_ fp)
126 63           MY_EXPORT_CALLCONV OP *QPFXD(pab0)(pTHX_ U32 *flags_p)
127             {
128             OP *blkop, *argsop;
129             I32 c;
130 63           lex_read_space(0);
131 63           c = lex_peek_unichar(0);
132 63 100         if(c == '('/*)*/) return parse_args_parenthesised(flags_p);
133 35 100         if(c == '{'/*}*/) {
134 8           I32 floor = start_subparse(0, CVf_ANON);
135 8           SAVEFREESV(PL_compcv);
136 8           blkop = parse_block(0);
137 8 50         SvREFCNT_inc_simple_void((SV*)PL_compcv);
138 8           blkop = newANONATTRSUB(floor, NULL, NULL, blkop);
139             } else {
140             blkop = NULL;
141             }
142 35           argsop = parse_listexpr(PARSE_OPTIONAL);
143 35           return op_prepend_elem(OP_LIST, blkop, argsop);
144             }
145              
146             # define Perl_parse_args_proto QPFXD(pap0)
147             # define parse_args_proto(gv, sv, fp) Perl_parse_args_proto(aTHX_ gv, sv, fp)
148 80           MY_EXPORT_CALLCONV OP *QPFXD(pap0)(pTHX_ GV *namegv, SV *protosv, U32 *flags_p)
149             {
150             STRLEN proto_len;
151             char const *proto;
152             PERL_UNUSED_ARG(namegv);
153 80 100         if (SvTYPE(protosv) == SVt_PVCV ? !SvPOK(protosv) : !SvOK(protosv))
    100          
    50          
    50          
    100          
154 16           croak("panic: parse_args_proto with no proto");
155             /*
156             * There are variations between Perl versions in the syntactic
157             * interpretation of prototypes, which this code in principle
158             * needs to track. However, from the introduction of the parser
159             * API functions required by this code (5.13.8) to the date
160             * of this note (5.14.0-RC0) there have been no such changes.
161             * With luck there may be no more before this function migrates
162             * into the core.
163             */
164 64 50         proto = SvPV(protosv, proto_len);
165 64 100         if(!proto_len) return parse_args_nullary(flags_p);
166 72 100         while(*proto == ';') proto++;
167 56 100         if(proto[0] == '&') return parse_args_block_list(flags_p);
168 48 100         if(((proto[0] == '$' || proto[0] == '_' ||
    50          
169 48 50         proto[0] == '*' || proto[0] == '+') &&
    50          
170 8 50         !proto[1]) ||
171 0 0         (proto[0] == '\\' && proto[1] && !proto[2]))
    0          
172 40           return parse_args_unary(flags_p);
173 8 50         if(proto[0] == '\\' && proto[1] == '['/*]*/) {
    0          
174 0           proto += 2;
175 0 0         while(*proto && *proto != /*[*/']') proto++;
176 0 0         if(proto[0] == /*[*/']' && !proto[1])
    0          
177 0           return parse_args_unary(flags_p);
178             }
179 8           return parse_args_list(flags_p);
180             }
181              
182             # define Perl_parse_args_proto_or_list QPFXD(pan0)
183             # define parse_args_proto_or_list(gv, sv, fp) \
184             Perl_parse_args_proto_or_list(aTHX_ gv, sv, fp)
185 32           MY_EXPORT_CALLCONV OP *QPFXD(pan0)(pTHX_ GV *namegv, SV *protosv, U32 *flags_p)
186             {
187 32 100         if(SvTYPE(protosv) == SVt_PVCV ? SvPOK(protosv) : SvOK(protosv))
    100          
    50          
    50          
    100          
188 16           return parse_args_proto(namegv, protosv, flags_p);
189             else
190 16           return parse_args_list(flags_p);
191             }
192              
193             #endif /* Q_PARSER_AVAILABLE */
194              
195             #ifndef mg_findext
196             # define mg_findext(sv, type, vtbl) THX_mg_findext(aTHX_ sv, type, vtbl)
197             static MAGIC *THX_mg_findext(pTHX_ SV *sv, int type, MGVTBL const *vtbl)
198             {
199             MAGIC *mg;
200             if(sv)
201             for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic)
202             if(mg->mg_type == type && mg->mg_virtual == vtbl)
203             return mg;
204             return NULL;
205             }
206             #endif /* !mg_findext */
207              
208             #ifndef sv_unmagicext
209             # define sv_unmagicext(sv, type, vtbl) THX_sv_unmagicext(aTHX_ sv, type, vtbl)
210             static int THX_sv_unmagicext(pTHX_ SV *sv, int type, MGVTBL const *vtbl)
211             {
212             MAGIC *mg, **mgp;
213             if((vtbl && vtbl->svt_free) || type == PERL_MAGIC_regex_global)
214             /* exceeded intended usage of this reserve implementation */
215             return 0;
216             if(SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv)) return 0;
217             mgp = NULL;
218             for(mg = mgp ? *mgp : SvMAGIC(sv); mg; mg = mgp ? *mgp : SvMAGIC(sv)) {
219             if(mg->mg_type == type && mg->mg_virtual == vtbl) {
220             if(mgp)
221             *mgp = mg->mg_moremagic;
222             else
223             SvMAGIC_set(sv, mg->mg_moremagic);
224             if(mg->mg_flags & MGf_REFCOUNTED)
225             SvREFCNT_dec(mg->mg_obj);
226             Safefree(mg);
227             } else {
228             mgp = &mg->mg_moremagic;
229             }
230             }
231             SvMAGICAL_off(sv);
232             mg_magical(sv);
233             return 0;
234             }
235             #endif /* !sv_unmagicext */
236              
237 622           MY_EXPORT_CALLCONV void QPFXD(gcp0)(pTHX_ CV *cv,
238             Perl_call_parser *psfun_p, SV **psobj_p)
239             {
240 622           MAGIC *callmg = SvMAGICAL((SV*)cv) ?
241 622 100         mg_findext((SV*)cv, PERL_MAGIC_ext, &mgvtbl_parsecall) : NULL;
242 622 100         if(callmg) {
243 397           *psfun_p = DPTR2FPTR(Perl_call_parser, callmg->mg_ptr);
244 397           *psobj_p = callmg->mg_obj;
245             } else {
246 225           *psfun_p = DPTR2FPTR(Perl_call_parser, NULL);
247 225           *psobj_p = NULL;
248             }
249 622           }
250              
251 48           MY_EXPORT_CALLCONV void QPFXD(scp0)(pTHX_ CV *cv,
252             Perl_call_parser psfun, SV *psobj)
253             {
254 48 100         if(
255 48           (!psfun && !psobj)
256             #if Q_PARSER_AVAILABLE
257 46 100         || (psfun == Perl_parse_args_proto_or_list && psobj == (SV*)cv)
    100          
258             #endif /* Q_PARSER_AVAILABLE */
259             ) {
260 4 50         if(SvMAGICAL((SV*)cv))
261 4           sv_unmagicext((SV*)cv, PERL_MAGIC_ext,
262             &mgvtbl_parsecall);
263             } else {
264 44           MAGIC *callmg =
265             mg_findext((SV*)cv, PERL_MAGIC_ext, &mgvtbl_parsecall);
266 44 100         if(!callmg)
267 33           callmg = sv_magicext((SV*)cv, &PL_sv_undef,
268             PERL_MAGIC_ext, &mgvtbl_parsecall, NULL, 0);
269 44 50         if(callmg->mg_flags & MGf_REFCOUNTED) {
270 44           SvREFCNT_dec(callmg->mg_obj);
271 44           callmg->mg_flags &= ~MGf_REFCOUNTED;
272             }
273 44           callmg->mg_ptr = FPTR2DPTR(char *, psfun);
274 44           callmg->mg_obj = psobj;
275 44 50         if(psobj != (SV*)cv) {
276             SvREFCNT_inc(psobj);
277 44           callmg->mg_flags |= MGf_REFCOUNTED;
278             }
279             }
280 48           }
281              
282             #if Q_PARSER_AVAILABLE
283              
284 10           MY_EXPORT_CALLCONV void QPFXD(gcp1)(pTHX_ CV *cv,
285             Perl_call_parser *psfun_p, SV **psobj_p)
286             {
287 10           QPFXD(gcp0)(aTHX_ cv, psfun_p, psobj_p);
288 10 100         if(!*psfun_p && !*psobj_p) {
    50          
289 6           *psfun_p = Perl_parse_args_proto_or_list;
290 6           *psobj_p = (SV*)cv;
291             }
292 10           }
293              
294 41           MY_EXPORT_CALLCONV void QPFXD(scp1)(pTHX_ CV *cv,
295             Perl_call_parser psfun, SV *psobj)
296             {
297 41 50         if(!psobj) croak("null object for cv_set_call_parser");
298 41           QPFXD(scp0)(aTHX_ cv, psfun, psobj);
299 41           }
300              
301             #endif /* Q_PARSER_AVAILABLE */
302              
303             static int (*next_keyword_plugin)(pTHX_ char *, STRLEN, OP **);
304 6801           static int my_keyword_plugin(pTHX_
305             char *keyword_ptr, STRLEN keyword_len, OP **op_ptr)
306             {
307             OP *nmop, *cvop, *argsop;
308             CV *cv;
309             GV *namegv;
310             Perl_call_parser psfun;
311             SV *psobj;
312             U32 parser_flags;
313             /*
314             * Creation of the rv2cv op below (or more precisely its gv op
315             * child created during checking) uses a pad slot under threads.
316             * Normally this is fine, but early versions of the padrange
317             * mechanism make assumptions about pad slots being contiguous
318             * that this breaks. On the affected perl versions, therefore,
319             * we watch for the pad slot being consumed, and restore the
320             * pad's fill pointer if we throw the op away (upon declining
321             * to handle the keyword).
322             *
323             * The core bug was supposedly fixed in Perl 5.19.4, but actually
324             * that version exhibits a different bug also apparently related
325             * to padrange. Restoring the pad's fill pointer works around
326             * this bug too.
327             *
328             * The other padrange bug was fixed in Perl 5.19.5 (commit aa033da),
329             * so the workaround is no longer needed after that, but it remains
330             * harmless until v5.21.4 (commit c9859fb) where it starts breaking
331             * (see t/pad2.t.) */
332             #define MUST_RESTORE_PAD_FILL USE_THREADS && PERL_VERSION_GE(5,17,6) && ! PERL_VERSION_GE(5,19,5)
333             #if MUST_RESTORE_PAD_FILL
334             I32 padfill = av_len(PL_comppad);
335             #endif /* MUST_RESTORE_PAD_FILL */
336             /*
337             * If Devel::Declare happens to be loaded, it triggers magic
338             * upon building of an rv2cv op, assuming that it's being built
339             * by the lexer. Since we're about to build such an op here,
340             * replicating what the lexer will normally do shortly after,
341             * there's a risk that Devel::Declare could fire here, ultimately
342             * firing twice for a single appearance of a name it's interested
343             * in. To suppress Devel::Declare, therefore, we temporarily
344             * set PL_parser to null. The same goes for Data::Alias and
345             * some other modules that use similar techniques.
346             *
347             * Unfortunately Devel::Declare prior to 0.006004 still does some
348             * work at the wrong time if PL_parser is null, and Data::Alias
349             * prior to 1.13 crashes if PL_parser is null. So this module
350             * is not compatible with earlier versions of those modules,
351             * and can't be made compatible.
352             */
353 6801           ENTER;
354 6801           SAVEVPTR(PL_parser);
355 6801           PL_parser = NULL;
356 6801           nmop = newSVOP(OP_CONST, 0, newSVpvn(keyword_ptr, keyword_len));
357 6801           nmop->op_private = OPpCONST_BARE;
358 6801           cvop = newCVREF(0, nmop);
359 6801           LEAVE;
360 6801 100         if(!(cv = rv2cv_op_cv(cvop, 0))) {
361             decline:
362 6412           op_free(cvop);
363             #if MUST_RESTORE_PAD_FILL
364             av_fill(PL_comppad, padfill);
365             #endif /* MUST_RESTORE_PAD_FILL */
366 6412           return next_keyword_plugin(aTHX_
367             keyword_ptr, keyword_len, op_ptr);
368             }
369 602           QPFXD(gcp0)(aTHX_ cv, &psfun, &psobj);
370 602 100         if(!psfun && !psobj) goto decline;
    50          
371 389           namegv = (GV*)rv2cv_op_cv(cvop,
372             RV2CVOPCV_MARK_EARLY|RV2CVOPCV_RETURN_NAME_GV);
373 389           parser_flags = 0;
374 389           argsop = psfun(aTHX_ namegv, psobj, &parser_flags);
375 373 100         if(!(parser_flags & CALLPARSER_PARENS))
376 221           cvop->op_private |= OPpENTERSUB_NOPAREN;
377 373           *op_ptr = newUNOP(OP_ENTERSUB, OPf_STACKED,
378             op_append_elem(OP_LIST, argsop, cvop));
379 373           return (parser_flags & CALLPARSER_STATEMENT) ?
380 373 100         KEYWORD_PLUGIN_STMT : KEYWORD_PLUGIN_EXPR;
381             }
382              
383             #define fmt_header(n, content) THX_fmt_header(aTHX_ n, content)
384             static SV *THX_fmt_header(pTHX_ char n, char const *content)
385             {
386 6           return newSVpvf(
387             "/* DO NOT EDIT -- generated "
388             "by Devel::CallParser version "XS_VERSION" */\n"
389             "#ifndef "QPFXS"INCLUDED_callparser%c\n"
390             "#define "QPFXS"INCLUDED_callparser%c 1\n"
391             "#ifndef PERL_VERSION\n"
392             " #error you must include perl.h before callparser%c.h\n"
393             "#elif !(PERL_REVISION == "STRINGIFY(PERL_REVISION)
394             " && PERL_VERSION == "STRINGIFY(PERL_VERSION)
395             #if PERL_VERSION & 1
396             " && PERL_SUBVERSION == "STRINGIFY(PERL_SUBVERSION)
397             #endif /* PERL_VERSION & 1 */
398             ")\n"
399             " #error this callparser%c.h is for Perl "
400             STRINGIFY(PERL_REVISION)"."STRINGIFY(PERL_VERSION)
401             #if PERL_VERSION & 1
402             "."STRINGIFY(PERL_SUBVERSION)
403             #endif /* PERL_VERSION & 1 */
404             " only\n"
405             "#endif /* Perl version mismatch */\n"
406             "%s"
407             "#endif /* !"QPFXS"INCLUDED_callparser%c */\n",
408             n, n, n, n, content, n);
409             }
410              
411             #define DEFFN(RETTYPE, PUBNAME, PRIVNAME, ARGTYPES, ARGNAMES) \
412             MY_IMPORT_CALLCONV_S" "RETTYPE" "QPFXS PRIVNAME"(pTHX_ "ARGTYPES");\n" \
413             "#define Perl_"PUBNAME" "QPFXS PRIVNAME"\n" \
414             "#define "PUBNAME"("ARGNAMES") Perl_"PUBNAME"(aTHX_ "ARGNAMES")\n"
415              
416             #define DEFCALLBACK \
417             "typedef OP *(*Perl_call_parser)(pTHX_ GV *, SV *, U32 *);\n" \
418             "#define CALLPARSER_PARENS 0x00000001\n" \
419             "#define CALLPARSER_STATEMENT 0x00000002\n"
420              
421             MODULE = Devel::CallParser PACKAGE = Devel::CallParser
422              
423             PROTOTYPES: DISABLE
424              
425             BOOT:
426 9           next_keyword_plugin = PL_keyword_plugin;
427 9           PL_keyword_plugin = my_keyword_plugin;
428              
429             SV *
430             callparser0_h()
431             CODE:
432             RETVAL = fmt_header('0',
433             DEFCALLBACK
434             DEFFN("void", "cv_get_call_parser", "gcp0",
435             "CV *, Perl_call_parser *, SV **", "cv, fp, op")
436             DEFFN("void", "cv_set_call_parser", "scp0",
437             "CV *, Perl_call_parser, SV *", "cv, f, o")
438             );
439             OUTPUT:
440             RETVAL
441              
442             SV *
443             callparser1_h()
444             CODE:
445             #if Q_PARSER_AVAILABLE
446             RETVAL = fmt_header('1',
447             DEFFN("OP *", "parse_args_parenthesised", "pac0", "U32 *", "fp")
448             DEFFN("OP *", "parse_args_nullary", "paz0", "U32 *", "fp")
449             DEFFN("OP *", "parse_args_unary", "pau0", "U32 *", "fp")
450             DEFFN("OP *", "parse_args_list", "pal0", "U32 *", "fp")
451             DEFFN("OP *", "parse_args_block_list", "pab0", "U32 *", "fp")
452             DEFFN("OP *", "parse_args_proto", "pap0",
453             "GV *, SV *, U32 *", "gv, sv, fp")
454             DEFFN("OP *", "parse_args_proto_or_list", "pan0",
455             "GV *, SV *, U32 *", "gv, sv, fp")
456             DEFCALLBACK
457             DEFFN("void", "cv_get_call_parser", "gcp1",
458             "CV *, Perl_call_parser *, SV **", "cv, fp, op")
459             DEFFN("void", "cv_set_call_parser", "scp1",
460             "CV *, Perl_call_parser, SV *", "cv, f, o")
461             );
462             #else /* !Q_PARSER_AVAILABLE */
463             croak("callparser1.h not available on this version of Perl");
464             #endif /* !Q_PARSER_AVAILABLE */
465             OUTPUT:
466             RETVAL