File Coverage

t/func.xs
Criterion Covered Total %
statement 25 25 100.0
branch 2 2 100.0
condition n/a
subroutine n/a
pod n/a
total 27 27 100.0


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, 2020-2023 -- leonerd@leonerd.org.uk
5             */
6              
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10              
11             #include "XSParseSublike.h"
12              
13             #if PERL_REVISION > 5 || (PERL_REVISION == 5 && PERL_VERSION >= 26)
14             # define HAVE_SUB_PARAM_ATTRIBUTES
15             #endif
16              
17             static const struct XSParseSublikeHooks parse_func_hooks = {
18             .ver = XSPARSESUBLIKE_ABI_VERSION,
19             .permit_hintkey = "t::func/func",
20             .flags = XS_PARSE_SUBLIKE_FLAG_ALLOW_PKGNAME,
21             };
22              
23             static const struct XSParseSublikeHooks parse_nfunc_hooks = {
24             .ver = XSPARSESUBLIKE_ABI_VERSION,
25             .permit_hintkey = "t::func/nfunc",
26             .flags = XS_PARSE_SUBLIKE_FLAG_SIGNATURE_NAMED_PARAMS,
27             };
28              
29             static const struct XSParseSublikeHooks parse_afunc_hooks = {
30             .ver = XSPARSESUBLIKE_ABI_VERSION,
31             .permit_hintkey = "t::func/afunc",
32             .flags = XS_PARSE_SUBLIKE_FLAG_SIGNATURE_PARAM_ATTRIBUTES,
33             };
34              
35             static const struct XSParseSublikeHooks parse_rfunc_hooks = {
36             .ver = XSPARSESUBLIKE_ABI_VERSION,
37             .permit_hintkey = "t::func/rfunc",
38             .flags = XS_PARSE_SUBLIKE_FLAG_SIGNATURE_NAMED_PARAMS|XS_PARSE_SUBLIKE_FLAG_SIGNATURE_REFALIAS,
39             };
40              
41             static const struct XSParseSublikeHooks parse_nafunc_hooks = {
42             .ver = XSPARSESUBLIKE_ABI_VERSION,
43             .permit_hintkey = "t::func/nafunc",
44             .flags = XS_PARSE_SUBLIKE_FLAG_SIGNATURE_NAMED_PARAMS|XS_PARSE_SUBLIKE_FLAG_SIGNATURE_PARAM_ATTRIBUTES,
45             };
46              
47             static const struct XSParseSublikeHooks parse_nopkgfunc_hooks = {
48             .ver = XSPARSESUBLIKE_ABI_VERSION,
49             .permit_hintkey = "t::func/func",
50             };
51              
52             #ifdef HAVE_SUB_PARAM_ATTRIBUTES
53 8           static void apply_Attribute(pTHX_ struct XPSSignatureParamContext *ctx, SV *attrvalue, void **attrdata_ptr, void *funcdata)
54             {
55             /* TODO: maybe the context should store a lexname string? */
56 8           PADNAME *pn = PadnamelistARRAY(PL_comppad_name)[ctx->padix];
57              
58 8           AV *av = get_av("main::ATTRIBUTE_APPLIED", GV_ADD);
59              
60 13 100         av_push(av, newSVpvf("%s%" SVf,
61             ctx->is_named ? ":" : "", PadnameSV(pn)));
62 8           av_push(av, newSVsv(attrvalue));
63 8           }
64              
65              
66 8           static void post_defop_Attribute(pTHX_ struct XPSSignatureParamContext *ctx, void *attrdata, void *funcdata)
67             {
68             /* OP* pointer values won't mean much to pureperl code, but we can at least
69             * store UVs and assert them not zero
70             */
71              
72 8           HV *n = newHV();
73 8           hv_stores(n, "op", newSVuv(PTR2UV(ctx->op)));
74 8           hv_stores(n, "varop", newSVuv(PTR2UV(ctx->varop)));
75 8           hv_stores(n, "defop", newSVuv(PTR2UV(ctx->defop)));
76              
77 8           AV *av = get_av("main::ATTRIBUTE_SAW_OPTREES", GV_ADD);
78              
79 8           av_push(av, newRV_noinc((SV *)n));
80              
81             /* Give the attribute a runtime side-effect so we can test that our returned
82             * optree is invoked
83             */
84 8           GV *countergv = gv_fetchpvs("main::ATTRIBUTE_INVOKED", GV_ADD, SVt_IV);
85 8           OP *incop = newUNOP(OP_PREINC, 0,
86             newUNOP(OP_RV2SV, 0,
87             newGVOP(OP_GV, 0, (GV *)SvREFCNT_inc(countergv))));
88              
89 8           ctx->op = op_append_elem(OP_LINESEQ, ctx->op, incop);
90 8           }
91              
92             static const struct XPSSignatureAttributeFuncs attr_funcs = {
93             .ver = XSPARSESUBLIKE_ABI_VERSION,
94             .permit_hintkey = "t::func/Attribute",
95              
96             .apply = apply_Attribute,
97             .post_defop = post_defop_Attribute,
98             };
99             #endif
100              
101             MODULE = t::func PACKAGE = t::func
102              
103             BOOT:
104 9           boot_xs_parse_sublike(0);
105              
106 9           register_xs_parse_sublike("func", &parse_func_hooks, NULL);
107 9           register_xs_parse_sublike("nfunc", &parse_nfunc_hooks, NULL);
108 9           register_xs_parse_sublike("afunc", &parse_afunc_hooks, NULL);
109 9           register_xs_parse_sublike("rfunc", &parse_rfunc_hooks, NULL);
110 9           register_xs_parse_sublike("nafunc", &parse_nafunc_hooks, NULL);
111              
112 9           register_xs_parse_sublike("nopkgfunc", &parse_nopkgfunc_hooks, NULL);
113             #ifdef HAVE_SUB_PARAM_ATTRIBUTES
114 9           register_xps_signature_attribute("Attribute", &attr_funcs, NULL);
115             #endif