File Coverage

lib/XS/Parse/Infix/FromPerl.xs
Criterion Covered Total %
statement 25 101 24.7
branch 0 86 0.0
condition n/a
subroutine n/a
pod n/a
total 25 187 13.3


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, 2023 -- leonerd@leonerd.org.uk
5             */
6             #include "EXTERN.h"
7             #include "perl.h"
8             #include "XSUB.h"
9              
10             #include "XSParseInfix.h"
11              
12             #include "perl-backcompat.c.inc"
13             #include "perl-additions.c.inc"
14              
15             #include "newSVop.c.inc"
16              
17             struct XPIFPHookdata {
18             /* Phase callbacks */
19             CV *permitcv;
20             CV *new_opcv;
21              
22             SV *hookdata;
23             };
24              
25 0           static bool cb_permit(pTHX_ void *hookdata)
26             {
27 0           struct XPIFPHookdata *data = hookdata;
28              
29 0           dSP;
30              
31 0           ENTER;
32 0           SAVETMPS;
33              
34 0 0         PUSHMARK(SP);
35 0 0         if(data->hookdata)
36 0 0         XPUSHs(sv_mortalcopy(data->hookdata));
37             else
38 0 0         XPUSHs(&PL_sv_undef);
39 0           PUTBACK;
40              
41 0           call_sv((SV *)data->permitcv, G_SCALAR);
42              
43 0           SPAGAIN;
44 0 0         bool ret = SvTRUEx(POPs);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
45              
46 0 0         FREETMPS;
47 0           LEAVE;
48              
49 0           return ret;
50             }
51              
52 0           static OP *cb_new_op(pTHX_ U32 flags, OP *lhs, OP *rhs, SV **parsedata, void *hookdata)
53             {
54 0           struct XPIFPHookdata *data = hookdata;
55              
56 0           dSP;
57              
58 0           ENTER;
59 0           SAVETMPS;
60              
61 0 0         PUSHMARK(SP);
62 0 0         EXTEND(SP, 5);
63 0           mPUSHu(flags);
64 0           PUSHs(sv_2mortal(newSVop(lhs)));
65 0           PUSHs(sv_2mortal(newSVop(rhs)));
66 0           PUSHs(&PL_sv_undef); /* parsedata; ignore for now */
67 0 0         if(data->hookdata)
68 0           PUSHs(sv_mortalcopy(data->hookdata));
69             else
70 0           PUSHs(&PL_sv_undef);
71 0           PUTBACK;
72              
73 0           call_sv((SV *)data->new_opcv, G_SCALAR);
74              
75 0           SPAGAIN;
76 0           OP *ret = SvOPo(POPs);
77              
78 0           PUTBACK;
79              
80 0 0         FREETMPS;
81 0           LEAVE;
82              
83 0           return ret;
84             }
85              
86 3           static void S_setup_constants(pTHX)
87             {
88             HV *stash;
89             AV *export;
90              
91             #define DO_CONSTANT(c) \
92             newCONSTSUB(stash, #c, newSViv(c)); \
93             av_push(export, newSVpv(#c, 0))
94              
95 3           stash = gv_stashpvs("XS::Parse::Infix::FromPerl", TRUE);
96 3           export = get_av("XS::Parse::Infix::FromPerl::EXPORT_OK", TRUE);
97              
98 3           DO_CONSTANT(XPI_CLS_NONE);
99 3           DO_CONSTANT(XPI_CLS_PREDICATE);
100 3           DO_CONSTANT(XPI_CLS_RELATION);
101 3           DO_CONSTANT(XPI_CLS_EQUALITY);
102 3           DO_CONSTANT(XPI_CLS_SMARTMATCH);
103 3           DO_CONSTANT(XPI_CLS_MATCHRE);
104 3           DO_CONSTANT(XPI_CLS_ISA);
105 3           DO_CONSTANT(XPI_CLS_MATCH_MISC);
106 3           DO_CONSTANT(XPI_CLS_ORDERING);
107 3           DO_CONSTANT(XPI_CLS_LOW_MISC);
108 3           DO_CONSTANT(XPI_CLS_LOGICAL_OR_LOW_MISC);
109 3           DO_CONSTANT(XPI_CLS_LOGICAL_AND_LOW_MISC);
110 3           DO_CONSTANT(XPI_CLS_ASSIGN_MISC);
111 3           DO_CONSTANT(XPI_CLS_LOGICAL_OR_MISC);
112 3           DO_CONSTANT(XPI_CLS_LOGICAL_AND_MISC);
113 3           DO_CONSTANT(XPI_CLS_ADD_MISC);
114 3           DO_CONSTANT(XPI_CLS_MUL_MISC);
115 3           DO_CONSTANT(XPI_CLS_POW_MISC);
116 3           DO_CONSTANT(XPI_CLS_HIGH_MISC);
117 3           }
118              
119             MODULE = XS::Parse::Infix::FromPerl PACKAGE = XS::Parse::Infix::FromPerl
120              
121             void
122             register_xs_parse_infix(const char *name, ...)
123             CODE:
124 0           dKWARG(1);
125              
126 0           struct XSParseInfixHooks hooks = {0};
127 0           struct XPIFPHookdata data = {0};
128 0           SV *wrapper_func_namesv = NULL;
129 0           SV *permit_hintkeysv = NULL;
130              
131             static const char *args[] = {
132             "flags",
133             "lhs_flags",
134             "rhs_flags",
135             "cls",
136             "wrapper_func_name",
137             "permit_hintkey",
138             "permit",
139             "new_op",
140             /* TODO: parse? */
141             "hookdata",
142             };
143 0 0         while(KWARG_NEXT(args))
144 0           switch(kwarg) {
145             case 0: /* flags */
146             case 1: /* lhs_flags */
147             case 2: /* rhs_flags */
148 0           croak("TODO: flags not currently supported");
149              
150             case 3: /* cls */
151 0 0         hooks.cls = SvUV(kwval);
152             break;
153              
154             case 4: /* wrapper_func_name */
155 0           wrapper_func_namesv = kwval;
156 0           break;
157              
158             case 5: /* permit_hintkey */
159 0           permit_hintkeysv = kwval;
160 0           break;
161              
162             case 6: /* permit */
163 0 0         if(!SvROK(kwval) || SvTYPE(SvRV(kwval)) != SVt_PVCV)
    0          
164 0           croak("Expected 'permit' to be a CODE ref");
165 0 0         data.permitcv = (CV *)SvREFCNT_inc((SV *)CV_FROM_REF(kwval));
166 0           break;
167              
168             case 7: /* new_op */
169 0 0         if(!SvROK(kwval) || SvTYPE(SvRV(kwval)) != SVt_PVCV)
    0          
170 0           croak("Expected 'new_op' to be a CODE ref");
171 0           data.new_opcv = (CV *)SvREFCNT_inc((SV *)CV_FROM_REF(kwval));
172 0           break;
173              
174             case 8: /* hookdata */
175 0           data.hookdata = newSVsv(kwval);
176 0           break;
177             }
178              
179 0 0         if(!permit_hintkeysv && !data.permitcv)
    0          
180 0           croak("Require at least one of 'permit_hintkey' or 'permit'");
181              
182             struct XSParseInfixHooks *hooksptr;
183 0           Newx(hooksptr, 1, struct XSParseInfixHooks);
184 0           *hooksptr = hooks;
185 0 0         if(wrapper_func_namesv)
186 0 0         hooksptr->wrapper_func_name = savepv(SvPV_nolen(wrapper_func_namesv));
187 0 0         if(permit_hintkeysv)
188 0 0         hooksptr->permit_hintkey = savepv(SvPV_nolen(permit_hintkeysv));
189 0 0         if(data.permitcv)
190 0           hooksptr->permit = &cb_permit;
191 0 0         if(data.new_opcv)
192 0           hooksptr->new_op = &cb_new_op;
193              
194             struct XPIFPHookdata *dataptr;
195 0           Newx(dataptr, 1, struct XPIFPHookdata);
196 0           *dataptr = data;
197              
198 0           register_xs_parse_infix(savepv(name), hooksptr, dataptr);
199              
200             BOOT:
201 3           boot_xs_parse_infix(0);
202              
203 3           S_setup_constants(aTHX);