File Coverage

lib/B/Tap.xs
Criterion Covered Total %
statement 65 69 94.2
branch 32 46 69.5
condition n/a
subroutine n/a
pod n/a
total 97 115 84.3


line stmt bran cond sub pod time code
1             #ifdef __cplusplus
2             extern "C" {
3             #endif
4              
5             #define PERL_NO_GET_CONTEXT /* we want efficiency */
6             #include
7             #include
8             #include
9              
10             #ifdef __cplusplus
11             } /* extern "C" */
12             #endif
13              
14             #define NEED_newSVpvn_flags
15             #include "ppport.h"
16              
17             static XOP my_xop_tap;
18             static XOP my_xop_push_sv;
19              
20 6           static OP *XS_B_Tap_pp_push_sv(pTHX) {
21 12           dXSARGS; dORIGMARK;
22              
23 6           SV* const sv = cSVOP_sv;
24             /* I know what this temporary variable is ugly. Patches welcome. */
25 6           SV * tmp = get_sv("B::Tap::_TMP", GV_ADD);
26 6           sv_setsv(tmp, sv);
27              
28             /* Restore mark after work. */
29 6 50         PUSHMARK(ORIGMARK);
30              
31 6           RETURN;
32             }
33              
34 6           static OP *XS_B_Tap_pp_tap(pTHX) {
35 12           dXSARGS; dORIGMARK;
36             int i;
37             SV *tmp;
38 6           AV *ret = newAV();
39              
40 6 100         av_push(ret, newSViv(GIMME_V));
41 6 100         if (GIMME_V == G_SCALAR) {
    100          
42 5           SvREFCNT_inc(ST(0));
43 5           av_push(ret, ST(0));
44 1 50         } else if (GIMME_V == G_VOID) {
    50          
45             /* do nothing */
46             } else {
47 1           AV * av = newAV();
48 5 100         for (i=0; i
49 4           SvREFCNT_inc(ST(i));
50 4           av_push(av, ST(i));
51             }
52 1           av_push(ret, newRV_noinc((SV*)av));
53             }
54              
55             /* I know what this temporary variable is ugly. Patches welcome. */
56 6           tmp = get_sv("B::Tap::_TMP", GV_ADD);
57 6 50         if (SvROK(tmp) && SvTYPE(SvRV(tmp)) == SVt_PVAV) {
    50          
58 6           av_push((AV*)SvRV(tmp), newRV_noinc((SV*)ret));
59             } else {
60 0           sv_dump(tmp);
61 0           croak("ArrayRef is expected, but it's not ArrayRef.");
62             }
63              
64             /* restore mark */
65 6 50         PUSHMARK(ORIGMARK);
66              
67 6           RETURN;
68             }
69              
70             /* characters, compatible with B::Concise */
71             static char tap_oa_char(int oa_class) {
72             switch (oa_class) {
73             /*
74             case OA_OP:
75             return '0'; */
76             case OA_UNOP:
77             return '1';
78             case OA_BINOP:
79             return '2';
80             case OA_LOGOP:
81             return '|';
82             case OA_LISTOP:
83             return '@';
84             case OA_PMOP:
85             return '/';
86             case OA_SVOP:
87             return '$';
88             /*
89             case OA_PVOP:
90             return '"'; */
91             case OA_LOOP:
92             return '{';
93             case OA_COP:
94             return ';';
95             case OA_PADOP:
96             return '#';
97             default:
98             return '-'; /* unknown */
99             }
100             }
101              
102             #define OP_CLASS_EX(op) \
103             ((op)->op_type == OP_NULL ? (PL_opargs[(op)->op_targ] & OA_CLASS_MASK) : OP_CLASS((op)))
104              
105             static char OA_CHAR(pTHX_ OP *op) {
106             return tap_oa_char(OP_CLASS_EX(op));
107             }
108              
109             #define TAP_TRACE(op, depth) \
110             { \
111             int i; \
112             for (i=0;i
113             PerlIO_printf(PerlIO_stderr(), " "); \
114             } \
115             PerlIO_printf(PerlIO_stderr(), " rewriting: <%c", OA_CHAR(aTHX_ op)); \
116             PerlIO_printf(PerlIO_stderr(), "> "); \
117             if (op->op_type == OP_NULL) { \
118             PerlIO_printf(PerlIO_stderr(), "ex-%s", PL_op_name[op->op_targ]); \
119             } else { \
120             PerlIO_printf(PerlIO_stderr(), "%s", OP_NAME(op)); \
121             } \
122             PerlIO_printf(PerlIO_stderr(), "\n"); \
123             }
124              
125              
126             #define RECURSE(next) rewrite_op(aTHX_ (OP*)next, orig, replacement, depth+1)
127             #define REPLACE(type, meth) \
128             if (((type)target)->meth == orig) { \
129             ((type)target)->meth = replacement; \
130             } else {\
131             RECURSE(((type)target)->meth); \
132             }
133              
134 120           static void rewrite_op(pTHX_ OP* target, OP* orig, OP* replacement, int depth) {
135             /* TAP_TRACE(target, depth); */
136              
137 104 100         switch (OP_CLASS_EX(target)) {
    100          
138             case OA_UNOP:
139 19 50         REPLACE(UNOP*, op_first);
140             break;
141             case OA_BINOP:
142 19 100         REPLACE(BINOP*, op_first);
143             break;
144             case OA_LOGOP:
145 0 0         REPLACE(LOGOP*, op_first);
146 0 0         REPLACE(LOGOP*, op_other);
147             break;
148             case OA_LISTOP:
149 18 50         REPLACE(LOGOP*, op_first);
150             break;
151             }
152              
153 104 100         if (OpSIBLING(target)) {
    100          
154 48 50         if (OpSIBLING(target) == orig) {
    100          
155 4           OpMORESIB_set(target, replacement);
156             } else {
157 44 50         rewrite_op(aTHX_ (OP*)OpSIBLING(target), orig, replacement, depth);
158             }
159             }
160 60           }
161              
162             #undef RECURSE
163              
164             MODULE = B::Tap PACKAGE = B::Tap
165              
166             PROTOTYPES: DISABLE
167              
168             BOOT:
169             /* Register custom ops */
170 7           XopENTRY_set(&my_xop_tap, xop_name, "b_tap_tap");
171 7           XopENTRY_set(&my_xop_tap, xop_desc, "b_tap_tap");
172 7           XopENTRY_set(&my_xop_tap, xop_class, OA_BINOP);
173 7           Perl_custom_op_register(aTHX_ XS_B_Tap_pp_tap, &my_xop_tap);
174              
175 7           XopENTRY_set(&my_xop_push_sv, xop_name, "b_tap_push_sv");
176 7           XopENTRY_set(&my_xop_push_sv, xop_desc, "b_Tap_push_sv");
177 7           XopENTRY_set(&my_xop_push_sv, xop_class, OA_SVOP);
178 7           Perl_custom_op_register(aTHX_ XS_B_Tap_pp_push_sv, &my_xop_push_sv);
179              
180             /* Register constats */
181 7           HV* stash = gv_stashpvn("B::Tap", strlen("B::Tap"), TRUE);
182 7           newCONSTSUB(stash, "G_SCALAR", newSViv(G_SCALAR));
183 7           newCONSTSUB(stash, "G_ARRAY", newSViv(G_ARRAY));
184 7           newCONSTSUB(stash, "G_VOID", newSViv(G_VOID));
185              
186             void
187             _tap(opp, root_opp, buf)
188             void* opp;
189             void* root_opp;
190             SV * buf;
191             CODE:
192             {
193             /* Rewrite op tree. */
194             OP * orig_op = (OP*)opp;
195 6           OP * next_op = orig_op->op_next;
196 6 100         OP * sibling_op = OpSIBLING(orig_op);
197              
198             /*
199             * Before:
200             *
201             * (orig_op
202             * next:next_op
203             * sibling:sibling_op)
204             *
205             * After:
206             *
207             * (b_tap
208             * first:(orig_op next:(push_sv next:b_tap))
209             * last:(b_tap_push_sv next:b_tap)
210             * next:next_op
211             * sibling:sibling_op
212             * )
213             */
214              
215             /* Create 'b_tap_push_sv' node */
216 6           SVOP * push_sv = (SVOP*)newSVOP(OP_CONST, 0, buf);
217 6           push_sv->op_type = OP_CUSTOM;
218 6           push_sv->op_ppaddr = XS_B_Tap_pp_push_sv;
219 6           push_sv->op_flags = OPf_WANT_LIST;
220 6           push_sv->op_sv = buf;
221             SvREFCNT_inc(buf);
222              
223 6           BINOP * b_tap = (BINOP*)newBINOP(OP_NULL, 0, orig_op, (OP*)push_sv);
224 6           b_tap->op_type = OP_CUSTOM;
225 6           b_tap->op_ppaddr = XS_B_Tap_pp_tap;
226 6           b_tap->op_flags = (orig_op->op_flags & OPf_WANT) | OPf_KIDS;
227 6           b_tap->op_first = orig_op;
228 6           b_tap->op_last = (OP*)push_sv;
229 6           OpMORESIB_set(b_tap, sibling_op);
230              
231 6           orig_op->op_next = (OP*)push_sv;
232 6           push_sv->op_next = (OP*)b_tap;
233 6           b_tap->op_next = next_op;
234              
235 6           rewrite_op(aTHX_ (OP*)root_opp, (OP*)orig_op, (OP*)b_tap, 0);
236             }
237