3 #include "callchecker0.h"
4 #include "callparser.h"
7 typedef struct payload_St {
12 #define SVt_PADNAME SVt_PVMG
14 #ifndef COP_SEQ_RANGE_LOW_set
15 # define COP_SEQ_RANGE_LOW_set(sv,val) \
16 do { ((XPVNV*)SvANY(sv))->xnv_u.xpad_cop_seq.xlow = val; } while(0)
17 # define COP_SEQ_RANGE_HIGH_set(sv,val) \
18 do { ((XPVNV*)SvANY(sv))->xnv_u.xpad_cop_seq.xhigh = val; } while(0)
19 #endif /* !COP_SEQ_RANGE_LOW_set */
21 #ifndef PERL_PADSEQ_INTRO
22 # define PERL_PADSEQ_INTRO I32_MAX
23 #endif /* !PERL_PADSEQ_INTRO */
25 #define pad_add_my_scalar_pvn(namepv, namelen) \
26 THX_pad_add_my_scalar_pvn(aTHX_ namepv, namelen)
28 THX_pad_add_my_scalar_pvn(pTHX_ char const *namepv, STRLEN namelen)
32 myvar = *av_fetch(PL_comppad, AvFILLp(PL_comppad) + 1, 1);
33 offset = AvFILLp(PL_comppad);
35 PL_curpad = AvARRAY(PL_comppad);
36 namesv = newSV_type(SVt_PADNAME);
37 sv_setpvn(namesv, namepv, namelen);
38 COP_SEQ_RANGE_LOW_set(namesv, PL_cop_seqmax);
39 COP_SEQ_RANGE_HIGH_set(namesv, PERL_PADSEQ_INTRO);
41 av_store(PL_comppad_name, offset, namesv);
45 #define DEMAND_IMMEDIATE 0x00000001
46 #define DEMAND_NOCONSUME 0x00000002
47 #define demand_unichar(c, f) THX_demand_unichar(aTHX_ c, f)
49 THX_demand_unichar (pTHX_ I32 c, U32 flags)
51 if(!(flags & DEMAND_IMMEDIATE))
54 if(lex_peek_unichar(0) != c)
55 croak("syntax error");
57 if(!(flags & DEMAND_NOCONSUME))
68 register PERL_CONTEXT *cx;
69 const I32 gimme = GIMME_V;
71 if ((0 == (PL_op->op_flags & OPf_SPECIAL)) && !SvTRUEx(POPs))
72 RETURNOP(cLOGOP->op_other->op_next);
76 PUSHBLOCK(cx, CXt_KOOH, SP);
77 cx->blk_givwhen.leave_op = cLOGOP->op_other;
83 S_dopoptogather(pTHX_ I32 startingblock)
87 for (i = startingblock; i >= 0; i--) {
88 register const PERL_CONTEXT *cx = &cxstack[i];
93 DEBUG_l( Perl_deb(aTHX_ "(dopoptogiven(): found given at cx=%ld)\n", (long)i));
97 assert(!CxFOREACHDEF(cx));
100 case CXt_LOOP_LAZYSV:
101 case CXt_LOOP_FOR:/* FIXME */
102 if (CxFOREACHDEF(cx)) {
103 DEBUG_l( Perl_deb(aTHX_ "(dopoptogiven(): found foreach at cx=%ld)\n", (long)i));
116 register PERL_CONTEXT *cx;
121 cxix = S_dopoptogather(aTHX_ cxstack_ix);
123 /* diag_listed_as: Can't "when" outside a topicalizer */
124 DIE(aTHX_ "Can't \"%s\" outside a topicalizer",
125 PL_op->op_flags & OPf_SPECIAL ? "default" : "when");
128 assert(CxTYPE(cx) == CXt_KOOH);
132 if (cxix < cxstack_ix)
137 RETURNOP(cx->blk_givwhen.leave_op);
141 myparse_args_take (pTHX_ GV *namegv, SV *args, U32 *flagsp)
143 OP *condop, *blkop, *leaveop;
145 SV *predicate_cv_ref;
149 PERL_UNUSED_ARG(namegv);
150 PERL_UNUSED_ARG(flagsp);
152 demand_unichar('(', 0);
153 condop = parse_fullexpr(0);
154 demand_unichar(')', 0);
156 demand_unichar('{', DEMAND_NOCONSUME);
157 blk_floor = Perl_block_start(aTHX_ 1);
158 blkop = parse_block(0);
159 blkop = Perl_block_end(aTHX_ blk_floor, blkop);
161 NewOp(1101, enterop, 1, LOGOP);
162 enterop->op_type = OP_ENTERWHEN;
163 enterop->op_ppaddr = pp_entertake;
164 enterop->op_flags = OPf_KIDS;
165 enterop->op_targ = -1;
166 enterop->op_private = 0;
168 leaveop = newUNOP(OP_LEAVEWHEN, 0, (OP *)enterop);
169 leaveop->op_ppaddr = pp_leavetake;
171 topicalise = SvTRUE(*av_fetch((AV *)SvRV(args), 0, 0));
175 pvarop = newOP(OP_PADSV, 0);
176 pvarop->op_targ = pad_findmy("$Gather::Once::current_topic",
177 sizeof("$Gather::Once::current_topic")-1, 0);
179 if (pvarop->op_targ == NOT_IN_PAD)
180 croak("outside topicaliser"); /* FIXME */
182 condop = op_append_elem(OP_LIST, condop, pvarop);
185 predicate_cv_ref = *av_fetch((AV *)SvRV(args), 1, 0);
186 condop = newUNOP(OP_ENTERSUB, OPf_STACKED,
187 op_append_elem(OP_LIST, condop,
188 newCVREF(0, newSVOP(OP_CONST, 0,
189 predicate_cv_ref))));
191 enterop->op_first = condop;
192 enterop->op_first->op_sibling = op_scope(blkop);
193 leaveop->op_next = LINKLIST(enterop->op_first);
194 enterop->op_first->op_next = (OP *)enterop;
196 enterop->op_next = LINKLIST(enterop->op_first->op_sibling);
197 enterop->op_first->op_sibling->op_next = enterop->op_other = leaveop;
203 pp_entergather (pTHX)
206 register PERL_CONTEXT *cx;
207 const I32 gimme = GIMME_V;
210 if (PL_op->op_targ != NOT_IN_PAD)
211 sv_setsv(TARG, POPs);
213 PUSHBLOCK(cx, CXt_MOO, SP);
214 cx->blk_givwhen.leave_op = cLOGOP->op_other;
220 pp_leavegather (pTHX)
223 register PERL_CONTEXT *cx;
229 assert(CxTYPE(cx) == CXt_MOO);
231 //SP = adjust_stack_on_leave(newsp, SP, newsp, gimme, SVs_PADTMP|SVs_TEMP);
232 //PL_curpm = newpm; /* Don't pop $1 et al till now */
239 myparse_args_gather (pTHX_ GV *namegv, SV *topicalise, U32 *flagsp)
241 OP *topicaliser, *blkop, *initop = NULL;
244 PERL_UNUSED_ARG(namegv);
245 PERL_UNUSED_ARG(flagsp);
247 if (SvTRUE(topicalise)) {
248 demand_unichar('(', 0);
249 topicaliser = parse_fullexpr(0);
250 demand_unichar(')', 0);
253 demand_unichar('{', DEMAND_NOCONSUME);
254 blk_floor = Perl_block_start(aTHX_ 1);
255 if (SvTRUE(topicalise)) {
256 initop = newOP(OP_PADSV, (OPpLVAL_INTRO<<8));
257 initop->op_targ = pad_add_my_scalar_pvn("$Gather::Once::current_topic",
258 sizeof("$Gather::Once::current_topic")-1);
261 blkop = parse_block(0);
263 blkop = op_prepend_elem(OP_LINESEQ, initop, blkop);
265 blkop = Perl_block_end(aTHX_ blk_floor, blkop);
268 NewOp(1101, enterop, 1, LOGOP);
269 enterop->op_type = OP_ENTERGIVEN;
270 enterop->op_ppaddr = pp_entergather;
271 enterop->op_flags = OPf_KIDS;
272 enterop->op_targ = SvTRUE(topicalise) ? initop->op_targ : NOT_IN_PAD;
273 enterop->op_private = 0;
276 leaveop = newUNOP(OP_LEAVEGIVEN, 0, (OP *)enterop);
277 leaveop->op_ppaddr = pp_leavegather;
279 enterop->op_first = SvTRUE(topicalise) ? topicaliser : newOP(OP_NULL, 0);
280 enterop->op_first->op_sibling = op_scope(blkop);
281 leaveop->op_next = LINKLIST(enterop->op_first);
282 enterop->op_first->op_next = (OP *)enterop;
284 enterop->op_next = LINKLIST(enterop->op_first->op_sibling);
285 enterop->op_first->op_sibling->op_next = enterop->op_other = leaveop;
291 myck_gathertake (pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
293 OP *rv2cvop, *pushop, *blkop;
295 PERL_UNUSED_ARG(namegv);
296 PERL_UNUSED_ARG(ckobj);
298 pushop = cUNOPx(entersubop)->op_first;
299 if (!pushop->op_sibling)
300 pushop = cUNOPx(pushop)->op_first;
302 blkop = pushop->op_sibling;
304 rv2cvop = blkop->op_sibling;
305 blkop->op_sibling = NULL;
306 pushop->op_sibling = rv2cvop;
312 MODULE = Gather::Once PACKAGE = Gather::Once
315 setup_gather_hook (CV *gather_cv, SV *topicalise)
317 cv_set_call_parser(gather_cv, myparse_args_gather, topicalise);
318 cv_set_call_checker(gather_cv, myck_gathertake, &PL_sv_undef);
321 setup_take_hook (CV *take_cv, SV *args)
323 cv_set_call_parser(take_cv, myparse_args_take, args);
324 cv_set_call_checker(take_cv, myck_gathertake, &PL_sv_undef);