File Coverage

t/pieces.xs
Criterion Covered Total %
statement 59 59 100.0
branch 10 12 83.3
condition n/a
subroutine n/a
pod n/a
total 69 71 97.1


line stmt bran cond sub pod time code
1             /* You may distribute under the terms of either the GNU General Public License
2             * or the Artistic License (the same terms as Perl itself)
3             *
4             * (C) Paul Evans, 2021-2022 -- leonerd@leonerd.org.uk
5             */
6              
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10              
11             #include "XSParseKeyword.h"
12             #include "XSParseInfix.h"
13              
14             #include "perl-backcompat.c.inc"
15              
16             static const char hintkey[] = "t::pieces/permit";
17              
18 10           static int build_expr(pTHX_ OP **out, XSParseKeywordPiece *arg0, void *hookdata)
19             {
20             /* wrap the result in "("...")" parens so we can unit-test how it parsed */
21 10           *out = newBINOP(OP_CONCAT, 0,
22             newBINOP(OP_CONCAT, 0, newSVOP(OP_CONST, 0, newSVpvs("(")), op_scope(arg0->op)),
23             newSVOP(OP_CONST, 0, newSVpvs(")")));
24 10           return KEYWORD_PLUGIN_EXPR;
25             }
26              
27 1           static int build_prefixedblock(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata)
28             {
29 1           PADOFFSET padix = args[0]->padix;
30 1           OP *value = args[1]->op;
31 1           OP *body = args[2]->op;
32              
33 1           OP *padsvop = newOP(OP_PADSV, OPf_MOD|(OPpLVAL_INTRO<<8));
34 1           padsvop->op_targ = padix;
35              
36 1           *out = op_prepend_elem(OP_LINESEQ,
37             newBINOP(OP_SASSIGN, 0, value, padsvop),
38             body);
39              
40 1           return KEYWORD_PLUGIN_EXPR;
41             }
42              
43 1           static int build_anonsub(pTHX_ OP **out, XSParseKeywordPiece *arg0, void *hookdata)
44             {
45 1           *out = newUNOP(OP_REFGEN, 0,
46             newSVOP(OP_ANONCODE, 0, (SV *)arg0->cv));
47 1           return KEYWORD_PLUGIN_EXPR;
48             }
49              
50 5           static int build_list(pTHX_ OP **out, XSParseKeywordPiece *arg0, void *hookdata)
51             {
52 5           OP *list = arg0->op;
53              
54             /* TODO: Consider always doing this? */
55 5 100         if(list->op_type != OP_LIST)
56 4           list = newLISTOP(OP_LIST, 0, list, NULL);
57              
58             /* unshift $sep */
59             #if HAVE_PERL_VERSION(5, 22, 0)
60 5           op_sibling_splice(list, cUNOPx(list)->op_first, 0, newSVOP(OP_CONST, 0, newSVpvs(",")));
61             #else
62             {
63             OP *o = newSVOP(OP_CONST, 0, newSVpvs(","));
64             o->op_sibling = cUNOPx(list)->op_first->op_sibling;
65             cUNOPx(list)->op_first->op_sibling = o;
66             }
67             #endif
68              
69 5           *out = op_convert_list(OP_JOIN, 0, list);
70              
71 5           return KEYWORD_PLUGIN_EXPR;
72             }
73              
74 6           static int build_constsv(pTHX_ OP **out, XSParseKeywordPiece *arg0, void *hookdata)
75             {
76 6           *out = newSVOP(OP_CONST, 0, arg0->sv);
77 6           return KEYWORD_PLUGIN_EXPR;
78             }
79              
80 4           static int build_constsv_or_undef(pTHX_ OP **out, XSParseKeywordPiece *arg0, void *hookdata)
81             {
82 4 100         if(arg0->sv)
83 2           *out = newSVOP(OP_CONST, 0, arg0->sv);
84             else
85 2           *out = newOP(OP_UNDEF, OPf_WANT_SCALAR);
86 4           return KEYWORD_PLUGIN_EXPR;
87             }
88              
89 1           static int build_constpadix(pTHX_ OP **out, XSParseKeywordPiece *arg0, void *hookdata)
90             {
91 1           *out = newSVOP(OP_CONST, 0, newSVuv(arg0->padix));
92 1           return KEYWORD_PLUGIN_EXPR;
93             }
94              
95 5           static int build_literal(pTHX_ OP **out, XSParseKeywordPiece *arg0, void *hookdata)
96             {
97             /* ignore arg0 */
98              
99 5           *out = newSVOP(OP_CONST, 0, SvREFCNT_inc((SV *)hookdata));
100              
101 5           return KEYWORD_PLUGIN_EXPR;
102             }
103              
104 4           static int build_attrs(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata)
105             {
106 4           int nattrs = args[0]->i;
107              
108 4           SV *retsv = newSV(0);
109 4           sv_setpvs(retsv, "");
110              
111             int argi;
112 11 100         for(argi = 0; argi < nattrs; argi++)
113 9 100         sv_catpvf(retsv, ":%s(%s)",
    50          
114 7           SvPV_nolen(args[argi+1]->attr.name),
115 2 50         SvPOK(args[argi+1]->attr.value) ? SvPV_nolen(args[argi+1]->attr.value) : "");
116              
117 4           *out = newSVOP(OP_CONST, 0, retsv);
118 4           return KEYWORD_PLUGIN_EXPR;
119             }
120              
121 3           static int build_infix_opname(pTHX_ OP **out, XSParseKeywordPiece *arg0, void *hookdata)
122             {
123 3           const char *opname = PL_op_name[arg0->infix->opcode];
124 3           *out = newSVOP(OP_CONST, 0, newSVpvn(opname, strlen(opname)));
125 3           return KEYWORD_PLUGIN_EXPR;
126             }
127              
128 1           static void setup_block_VAR(pTHX_ void *hookdata)
129             {
130             char *varname = hookdata;
131 1           PADOFFSET padix = pad_add_name_pvn(varname, strlen(varname), 0, NULL, NULL);
132 1           intro_my();
133              
134 1           sv_setpvs(PAD_SVl(padix), "Hello");
135 1           }
136              
137             static const struct XSParseKeywordHooks hooks_block = {
138             .permit_hintkey = hintkey,
139              
140             .piece1 = XPK_BLOCK,
141             .build1 = &build_expr,
142             };
143             static const struct XSParseKeywordHooks hooks_block_scalar = {
144             .permit_hintkey = hintkey,
145              
146             .piece1 = XPK_BLOCK_SCALARCTX,
147             .build1 = &build_list,
148             };
149             static const struct XSParseKeywordHooks hooks_block_list = {
150             .permit_hintkey = hintkey,
151              
152             .piece1 = XPK_BLOCK_LISTCTX,
153             .build1 = &build_list,
154             };
155              
156             static const struct XSParseKeywordHooks hooks_prefixedblock = {
157             .permit_hintkey = hintkey,
158              
159             .pieces = (const struct XSParseKeywordPieceType []){
160             XPK_PREFIXED_BLOCK( XPK_LEXVAR_MY(XPK_LEXVAR_SCALAR), XPK_EQUALS, XPK_TERMEXPR_SCALARCTX, XPK_COMMA ),
161             {0}
162             },
163             .build = &build_prefixedblock,
164             };
165              
166             static const struct XSParseKeywordHooks hooks_prefixedblock_VAR = {
167             .permit_hintkey = hintkey,
168              
169             .piece1 = XPK_PREFIXED_BLOCK( XPK_SETUP(&setup_block_VAR) ),
170             .build1 = &build_expr,
171             };
172              
173             static const struct XSParseKeywordHooks hooks_anonsub = {
174             .permit_hintkey = hintkey,
175              
176             .piece1 = XPK_ANONSUB,
177             .build1 = &build_anonsub,
178             };
179              
180             static const struct XSParseKeywordHooks hooks_arithexpr = {
181             .permit_hintkey = hintkey,
182              
183             .piece1 = XPK_ARITHEXPR,
184             .build1 = &build_expr,
185             };
186              
187             static const struct XSParseKeywordHooks hooks_termexpr = {
188             .permit_hintkey = hintkey,
189              
190             .piece1 = XPK_TERMEXPR,
191             .build1 = &build_expr,
192             };
193              
194             static const struct XSParseKeywordHooks hooks_listexpr = {
195             .permit_hintkey = hintkey,
196              
197             .piece1 = XPK_LISTEXPR,
198             .build1 = &build_list,
199             };
200              
201             static const struct XSParseKeywordHooks hooks_ident = {
202             .permit_hintkey = hintkey,
203              
204             .piece1 = XPK_IDENT,
205             .build1 = &build_constsv,
206             };
207              
208             static const struct XSParseKeywordHooks hooks_ident_opt = {
209             .permit_hintkey = hintkey,
210              
211             .piece1 = XPK_IDENT_OPT,
212             .build1 = &build_constsv_or_undef,
213             };
214              
215             static const struct XSParseKeywordHooks hooks_packagename = {
216             .permit_hintkey = hintkey,
217              
218             .piece1 = XPK_PACKAGENAME,
219             .build1 = &build_constsv,
220             };
221              
222             static const struct XSParseKeywordHooks hooks_lexvar_name = {
223             .permit_hintkey = hintkey,
224              
225             .piece1 = XPK_LEXVARNAME(XPK_LEXVAR_ANY),
226             .build1 = &build_constsv,
227             };
228              
229             static const struct XSParseKeywordHooks hooks_lexvar_my = {
230             .permit_hintkey = hintkey,
231              
232             .piece1 = XPK_LEXVAR_MY(XPK_LEXVAR_ANY),
233             .build1 = &build_constpadix,
234             };
235              
236             static const struct XSParseKeywordHooks hooks_attrs = {
237             .permit_hintkey = hintkey,
238              
239             .pieces = (const struct XSParseKeywordPieceType []){
240             XPK_ATTRIBUTES,
241             {0},
242             },
243             .build = &build_attrs,
244             };
245              
246             static const struct XSParseKeywordHooks hooks_vstring = {
247             .permit_hintkey = hintkey,
248              
249             .piece1 = XPK_VSTRING,
250             .build1 = &build_constsv,
251             };
252              
253             static const struct XSParseKeywordHooks hooks_vstring_opt = {
254             .permit_hintkey = hintkey,
255              
256             .piece1 = XPK_VSTRING_OPT,
257             .build1 = &build_constsv_or_undef,
258             };
259              
260             static const struct XSParseKeywordHooks hooks_infix_relation = {
261             .permit_hintkey = hintkey,
262              
263             .piece1 = XPK_INFIX_RELATION,
264             .build1 = &build_infix_opname,
265             };
266              
267             static const struct XSParseKeywordHooks hooks_infix_equality = {
268             .permit_hintkey = hintkey,
269              
270             .piece1 = XPK_INFIX_EQUALITY,
271             .build1 = &build_infix_opname,
272             };
273              
274             static const struct XSParseKeywordHooks hooks_colon = {
275             .permit_hintkey = hintkey,
276              
277             .piece1 = XPK_COLON,
278             .build1 = &build_literal,
279             };
280              
281             static const struct XSParseKeywordHooks hooks_str = {
282             .permit_hintkey = hintkey,
283              
284             .piece1 = XPK_LITERAL("foo"),
285             .build1 = &build_literal,
286             };
287              
288             static const struct XSParseKeywordHooks hooks_kw = {
289             .permit_hintkey = hintkey,
290              
291             .piece1 = XPK_KEYWORD("bar"),
292             .build1 = &build_literal,
293             };
294              
295             static const struct XSParseKeywordHooks hooks_autosemi = {
296             .permit_hintkey = hintkey,
297              
298             .piece1 = XPK_AUTOSEMI,
299             .build1 = &build_literal,
300             };
301              
302             MODULE = t::pieces PACKAGE = t::pieces
303              
304             BOOT:
305 11           boot_xs_parse_keyword(0);
306              
307             register_xs_parse_keyword("pieceblock", &hooks_block, NULL);
308             register_xs_parse_keyword("pieceblock_scalar", &hooks_block_scalar, NULL);
309             register_xs_parse_keyword("pieceblock_list", &hooks_block_list, NULL);
310              
311             register_xs_parse_keyword("pieceprefixedblock", &hooks_prefixedblock, NULL);
312             register_xs_parse_keyword("pieceprefixedblock_VAR", &hooks_prefixedblock_VAR, "$VAR");
313              
314             register_xs_parse_keyword("pieceanonsub", &hooks_anonsub, NULL);
315             register_xs_parse_keyword("piecearithexpr", &hooks_arithexpr, NULL);
316             register_xs_parse_keyword("piecetermexpr", &hooks_termexpr, NULL);
317             register_xs_parse_keyword("piecelistexpr", &hooks_listexpr, NULL);
318              
319             register_xs_parse_keyword("pieceident", &hooks_ident, NULL);
320             register_xs_parse_keyword("pieceident_opt", &hooks_ident_opt, NULL);
321             register_xs_parse_keyword("piecepkg", &hooks_packagename, NULL);
322              
323             register_xs_parse_keyword("piecelexvarname", &hooks_lexvar_name, NULL);
324             register_xs_parse_keyword("piecelexvarmy", &hooks_lexvar_my, NULL);
325              
326             register_xs_parse_keyword("pieceattrs", &hooks_attrs, NULL);
327              
328             register_xs_parse_keyword("piecevstring", &hooks_vstring, NULL);
329             register_xs_parse_keyword("piecevstring_opt", &hooks_vstring_opt, NULL);
330              
331             register_xs_parse_keyword("pieceinfix", &hooks_infix_relation, NULL);
332             register_xs_parse_keyword("pieceinfixeq", &hooks_infix_equality, NULL);
333              
334 11           register_xs_parse_keyword("piececolon", &hooks_colon, newSVpvs("colon"));
335              
336 11           register_xs_parse_keyword("piecestr", &hooks_str, newSVpvs("foo"));
337 11           register_xs_parse_keyword("piecekw", &hooks_kw, newSVpvs("bar"));
338              
339 11           register_xs_parse_keyword("pieceautosemi", &hooks_autosemi, newSVpvs("EOS"));