File Coverage

lib/Signature/Attribute/Checked.xs
Criterion Covered Total %
statement 25 26 96.1
branch 4 6 66.6
condition n/a
subroutine n/a
pod n/a
total 29 32 90.6


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             #define PERL_NO_GET_CONTEXT
7              
8             #include "EXTERN.h"
9             #include "perl.h"
10             #include "XSUB.h"
11              
12             #include "XSParseSublike.h"
13              
14             #define HAVE_PERL_VERSION(R, V, S) \
15             (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S))))))
16              
17             #include "compilerun_sv.c.inc"
18              
19             #include "check.h"
20              
21 9           static void apply_Checked(pTHX_ struct XPSSignatureParamContext *ctx, SV *attrvalue, void **attrdata_ptr, void *funcdata)
22             {
23 9           PADNAME *pn = PadnamelistARRAY(PL_comppad_name)[ctx->padix];
24 9 50         if(PadnamePV(pn)[0] != '$')
25 0           croak("Can only apply the :Checked attribute to scalar parameters");
26              
27             SV *checker;
28              
29             {
30             dSP;
31              
32 9           ENTER;
33 9           SAVETMPS;
34              
35             /* eval_sv() et.al. will forgets what package we're actually running in
36             * because during compiletime, CopSTASH(PL_curcop == &PL_compiling) isn't
37             * accurate. We need to help it along
38             */
39              
40 9           SAVECOPSTASH_FREE(PL_curcop);
41 9           CopSTASH_set(PL_curcop, PL_curstash);
42              
43 9           compilerun_sv(attrvalue, G_SCALAR);
44              
45 9           SPAGAIN;
46              
47 9           checker = SvREFCNT_inc(POPs);
48              
49 9 50         FREETMPS;
50 9           LEAVE;
51             }
52              
53 9           struct CheckData *data = make_checkdata(checker);
54              
55 9           data->assertmess =
56 9 100         newSVpvf(
57 9           ctx->is_named ? "Named parameter :%s requires a value satisfying :Checked(%" SVf ")"
58             : "Parameter %s requires a value satisfying :Checked(%" SVf ")",
59             PadnamePV(pn), SVfARG(attrvalue));
60              
61 9           *attrdata_ptr = data;
62 9           }
63              
64             #ifndef newPADxVOP
65             # define newPADxVOP(type, flags, padix) S_newPADxVOP(aTHX_ type, flags, padix)
66             static OP *S_newPADxVOP(pTHX_ I32 type, I32 flags, PADOFFSET padix)
67             {
68 9           OP *op = newOP(type, flags);
69 9           op->op_targ = padix;
70             return op;
71             }
72             #endif
73              
74 9           static void post_defop_Checked(pTHX_ struct XPSSignatureParamContext *ctx, void *attrdata, void *funcdata)
75             {
76             struct CheckData *data = attrdata;
77              
78 9           OP *assertop = make_assertop(data, newPADxVOP(OP_PADSV, 0, ctx->padix));
79              
80 9           ctx->op = op_append_elem(OP_SCOPE,
81             ctx->op, assertop);
82 9           }
83              
84             static void free_Checked(pTHX_ struct XPSSignatureParamContext *ctx, void *attrdata, void *funcdata)
85             {
86             struct CheckData *data = attrdata;
87              
88             SvREFCNT_dec(data->assertmess);
89              
90             Safefree(data);
91             }
92              
93             static const struct XPSSignatureAttributeFuncs funcs_Checked = {
94             .ver = XSPARSESUBLIKE_ABI_VERSION,
95             .permit_hintkey = "Signature::Attribute::Checked/Checked",
96              
97             .apply = apply_Checked,
98             .post_defop = post_defop_Checked,
99             };
100              
101             MODULE = Signature::Attribute::Checked PACKAGE = Signature::Attribute::Checked
102              
103             BOOT:
104 4           boot_xs_parse_sublike(0.19);
105              
106             register_xps_signature_attribute("Checked", &funcs_Checked, NULL);