1 /* Copyright (c) 1997-2021
2 Ewgenij Gawrilow, Michael Joswig, and the polymake team
3 Technische Universität Berlin, Germany
4 https://polymake.org
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version: http://www.gnu.org/licenses/gpl.txt.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 --------------------------------------------------------------------------------
16 */
17
18 #include "polymake/perl/Ext.h"
19
20 namespace pm { namespace perl { namespace glue {
21
22 namespace {
23
24 Perl_ppaddr_t def_pp_LEAVE, def_pp_OPEN;
25
26 template <typename LocalHandler>
27 struct local_wrapper {
undopm::perl::glue::__anon132beb6e0111::local_wrapper28 static void undo(pTHX_ void* p)
29 {
30 // make a local copy because the save stack can be reallocated during execution of undo action
31 const LocalHandler handler(*reinterpret_cast<LocalHandler*>(PL_savestack + (PL_savestack_ix - PTR2IV(p))));
32 handler.undo(aTHX);
33 }
34
allocpm::perl::glue::__anon132beb6e0111::local_wrapper35 static void* alloc(pTHX)
36 {
37 const I32 save_ix = PL_savestack_ix;
38 (void)SSNEWt(1, LocalHandler);
39 save_destructor_x(&undo, NUM2PTR(void*, PL_savestack_ix - save_ix));
40 return &(PL_savestack[save_ix]);
41 }
42 };
43
44 template <typename LocalHandler, typename... Args>
local_do(pTHX_ Args &&...args)45 void local_do(pTHX_ Args&&... args)
46 {
47 new(local_wrapper<LocalHandler>::alloc(aTHX)) LocalHandler(aTHX_ args...);
48 }
49
50 // --------------------
51
52 struct local_ref_handler {
53 SV* var;
54 void* orig_any;
55 U32 orig_flags;
56 char* orig_pv; // as a representative for SV_HEAD_UNION
57 SV* temp_owner;
58
local_ref_handlerpm::perl::glue::__anon132beb6e0111::local_ref_handler59 local_ref_handler(pTHX_ SV* var_, SV* value)
60 : var(var_)
61 , orig_any(SvANY(var_))
62 , orig_flags(SvFLAGS(var_) & ~SVs_TEMP)
63 , orig_pv(var_->sv_u.svu_pv)
64 , temp_owner(value)
65 {
66 var->sv_u.svu_pv = value->sv_u.svu_pv;
67 SvANY(var) = SvANY(value);
68 SvFLAGS(var) = SvFLAGS(value) & ~SVs_TEMP;
69 SvREFCNT_inc_simple_void_NN(var);
70 SvREFCNT_inc_simple_void_NN(value);
71 }
72
undopm::perl::glue::__anon132beb6e0111::local_ref_handler73 void undo(pTHX) const
74 {
75 SvANY(var) = orig_any;
76 SvFLAGS(temp_owner) = SvFLAGS(var);
77 temp_owner->sv_u.svu_pv = var->sv_u.svu_pv;
78 var->sv_u.svu_pv = orig_pv;
79 SvFLAGS(var) = orig_flags;
80 SvREFCNT_dec(var);
81 SvREFCNT_dec(temp_owner);
82 }
83 };
84
85 }
86
parse_expression_in_parens(pTHX)87 OP* parse_expression_in_parens(pTHX)
88 {
89 lex_read_space(0);
90 if (PL_parser->bufptr == PL_parser->bufend || *PL_parser->bufptr != '(')
91 return nullptr;
92 lex_read_to(PL_parser->bufptr+1);
93 OP* o = parse_termexpr(0);
94 if (!o) return nullptr;
95 lex_read_space(0);
96 if (PL_parser->bufptr == PL_parser->bufend || *PL_parser->bufptr != ')') {
97 op_free(o);
98 return nullptr;
99 }
100 lex_read_to(PL_parser->bufptr+1);
101 return o;
102 }
103
104 }
105 namespace ops {
106
107 using namespace pm::perl::glue;
108
local_ref(pTHX)109 OP* local_ref(pTHX)
110 {
111 dSP;
112 SV* left = POPs;
113 SV* right = GIMME_V != G_VOID ? TOPs : POPs;
114 if (!SvROK(right))
115 DIE(aTHX_ "local ref value must be a reference");
116 SV* value = SvRV(right);
117 SV* var;
118 switch (SvTYPE(value)) {
119 case SVt_PVAV:
120 if (SvTYPE(left) == SVt_PVGV) {
121 var = (SV*)GvAV(left);
122 if (!var || !GvIMPORTED_AV(left))
123 DIE(aTHX_ "local ref target array not declared");
124 break;
125 } else if (SvROK(left)) {
126 var = SvRV(left);
127 if (SvTYPE(var) == SVt_PVAV) break;
128 }
129 DIE(aTHX_ "local ref illegal/incompatible arguments: array references expected");
130 case SVt_PVHV:
131 if (SvTYPE(left) == SVt_PVGV) {
132 var = (SV*)GvHV(left);
133 if (!var || !GvIMPORTED_HV(left))
134 DIE(aTHX_ "local ref target hash not declared");
135 break;
136 } else if (SvROK(left)) {
137 var = SvRV(left);
138 if (SvTYPE(var) == SVt_PVHV) break;
139 }
140 DIE(aTHX_ "local ref illegal/incompatible arguments: hash reference expected");
141 case SVt_PVCV:
142 if (SvTYPE(left) == SVt_PVGV) {
143 var = (SV*)GvCV(left);
144 if (!var)
145 DIE(aTHX_ "local ref target sub not defined");
146 break;
147 } else if (SvROK(left)) {
148 var = SvRV(left);
149 if (SvTYPE(var) == SVt_PVCV) break;
150 }
151 DIE(aTHX_ "local ref illegal/incompatible arguments: code reference expected");
152 default:
153 DIE(aTHX_ "local ref unsupported value type: must be an array, hash or code reference");
154 }
155 local_do<local_ref_handler>(aTHX_ var, value);
156 RETURN;
157 }
158
159 }
160 namespace glue { namespace {
161
parse_local_ref(pTHX_ OP ** op_ptr)162 int parse_local_ref(pTHX_ OP** op_ptr)
163 {
164 op_keeper<OP> o(aTHX_ parse_termexpr(0));
165 if (!o || o->op_type != OP_SASSIGN)
166 return KEYWORD_PLUGIN_DECLINE;
167 o->op_ppaddr = ops::local_ref;
168 *op_ptr = o.release();
169 PL_hints |= HINT_BLOCK_SCOPE;
170 return KEYWORD_PLUGIN_EXPR;
171 }
172
173 // --------------------
174
175 struct local_scalar_handler {
176 SV* var;
177 SV orig;
178
local_scalar_handlerpm::perl::glue::__anon132beb6e0211::local_scalar_handler179 local_scalar_handler(pTHX_ SV* var_, SV* value)
180 : var(var_)
181 {
182 orig.sv_any = var->sv_any;
183 orig.sv_refcnt = var->sv_refcnt;
184 orig.sv_flags = var->sv_flags;
185 orig.sv_u.svu_pv = var->sv_u.svu_pv;
186 var->sv_any = nullptr;
187 var->sv_flags = 0;
188 var->sv_refcnt = 1;
189 sv_setsv(var, value);
190 }
191
undopm::perl::glue::__anon132beb6e0211::local_scalar_handler192 void undo(pTHX) const
193 {
194 if (SvREFCNT(var) > 1) {
195 SvREFCNT_dec(var);
196 } else {
197 SvREFCNT(var) = 0;
198 sv_clear(var);
199 }
200 var->sv_any = orig.sv_any;
201 var->sv_refcnt = orig.sv_refcnt;
202 var->sv_flags = orig.sv_flags;
203 var->sv_u.svu_pv = orig.sv_u.svu_pv;
204 }
205 };
206
local_scalar_op(pTHX)207 OP* local_scalar_op(pTHX)
208 {
209 dSP;
210 SV* left = POPs;
211 SV* right = GIMME_V != G_VOID ? TOPs : POPs;
212 local_do<local_scalar_handler>(aTHX_ left, right);
213 RETURN;
214 }
215
216 // --------------------
217
218 } }
219 namespace ops {
220
221 void
localize_scalar(pTHX_ SV * var,SV * value)222 localize_scalar(pTHX_ SV* var, SV* value)
223 {
224 local_do<local_scalar_handler>(aTHX_ var, value);
225 }
226
227 void
localize_scalar(pTHX_ SV * var)228 localize_scalar(pTHX_ SV* var)
229 {
230 localize_scalar(aTHX_ var, sv_mortalcopy(var));
231 }
232
233 }
234 namespace glue { namespace {
235
local_save_scalar_op(pTHX)236 OP* local_save_scalar_op(pTHX)
237 {
238 dSP;
239 SV* var = GIMME_V != G_VOID ? TOPs : POPs;
240 ops::localize_scalar(aTHX_ var);
241 RETURN;
242 }
243
244 // --------------------
245
246 struct local_incr_handler {
247 SV* var;
248 IV incr;
249
local_incr_handlerpm::perl::glue::__anon132beb6e0311::local_incr_handler250 local_incr_handler(pTHX_ SV* var_, IV incr_)
251 : var(var_)
252 , incr(incr_) {}
253
undopm::perl::glue::__anon132beb6e0311::local_incr_handler254 void undo(pTHX) const
255 {
256 if (SvIOK(var))
257 sv_setiv(var, SvIVX(var) - incr);
258 else if (SvNOK(var))
259 sv_setnv(var, SvNVX(var) - NV(incr));
260 else
261 Perl_croak(aTHX_ "undoing local increment: variable is no more numerical");
262 }
263 };
264
local_incr_op(pTHX)265 OP* local_incr_op(pTHX)
266 {
267 dSP;
268 SV* var = GIMME_V != G_VOID ? TOPs : POPs;
269 local_do<local_incr_handler>(aTHX_ var, 1 - PL_op->op_private);
270 RETURN;
271 }
272
parse_local_scalar(pTHX_ OP ** op_ptr)273 int parse_local_scalar(pTHX_ OP** op_ptr)
274 {
275 op_keeper<OP> o(aTHX_ parse_termexpr(0));
276 if (!o) return KEYWORD_PLUGIN_DECLINE;
277 if (o->op_type == OP_SASSIGN) {
278 OP* left = ((BINOP*)o.operator->())->op_last;
279 if (left->op_type != OP_PADSV && left->op_type != OP_ENTERSUB && left->op_type != OP_RV2SV) {
280 report_parse_error("local scalar applicable to lexical variables, scalars delivered by dereferencing or returned from subs");
281 return KEYWORD_PLUGIN_DECLINE;
282 }
283 o->op_ppaddr = local_scalar_op;
284 } else {
285 OP* var = o.release();
286 switch (var->op_type) {
287 case OP_PREINC:
288 case OP_I_PREINC:
289 o = PmNewCustomOP(UNOP, 0, var);
290 o->op_ppaddr = local_incr_op;
291 o->op_private = 0;
292 break;
293 case OP_PREDEC:
294 case OP_I_PREDEC:
295 o = PmNewCustomOP(UNOP, 0, var);
296 o->op_ppaddr = local_incr_op;
297 o->op_private = 2;
298 break;
299 case OP_POSTINC:
300 case OP_I_POSTINC:
301 report_parse_error("local scalar not compatible with post-increment");
302 return KEYWORD_PLUGIN_DECLINE;
303 case OP_POSTDEC:
304 case OP_I_POSTDEC:
305 report_parse_error("local scalar not compatible with post-decrement");
306 return KEYWORD_PLUGIN_DECLINE;
307 default:
308 o = PmNewCustomOP(UNOP, 0, op_lvalue(var, var->op_type));
309 o->op_ppaddr = local_save_scalar_op;
310 break;
311 }
312 }
313 *op_ptr = o.release();
314 PL_hints |= HINT_BLOCK_SCOPE;
315 return KEYWORD_PLUGIN_EXPR;
316 }
317
318 // --------------------
319
320 struct local_push_unshift_handler {
321 AV* av;
322 IV n;
323
local_push_unshift_handlerpm::perl::glue::__anon132beb6e0311::local_push_unshift_handler324 local_push_unshift_handler(AV* av_, IV n_)
325 : av(av_)
326 , n(n_) {}
327
insert_elemspm::perl::glue::__anon132beb6e0311::local_push_unshift_handler328 void insert_elems(pTHX_ SV* const * src, SV** dst)
329 {
330 for (SV* const * const src_end = src + n; src < src_end; ++src, ++dst) {
331 SV* d = *src;
332 if (SvREADONLY(d) || !SvTEMP(d))
333 *dst = newSVsv(d);
334 else
335 *dst = SvREFCNT_inc_simple_NN(d);
336 }
337 AvFILLp(av) += n;
338 }
339 };
340
341 struct local_push_handler : local_push_unshift_handler {
342
local_push_handlerpm::perl::glue::__anon132beb6e0311::local_push_handler343 local_push_handler(pTHX_ AV* av_, SV* const * src, IV n_)
344 : local_push_unshift_handler(av_, n_)
345 {
346 av_extend(av, AvFILLp(av) + n);
347 insert_elems(aTHX_ src, AvARRAY(av)+AvFILLp(av)+1);
348 }
349
undopm::perl::glue::__anon132beb6e0311::local_push_handler350 void undo(pTHX) const
351 {
352 for (SV **e = AvARRAY(av) + AvFILLp(av), **stop = e-n; e > stop; --e) {
353 SvREFCNT_dec(*e);
354 *e = PmEmptyArraySlot;
355 }
356 AvFILLp(av) -= n;
357 }
358 };
359
360 struct local_unshift_handler : local_push_unshift_handler {
361
local_unshift_handlerpm::perl::glue::__anon132beb6e0311::local_unshift_handler362 local_unshift_handler(pTHX_ AV* av_, SV* const * src, IV n_)
363 : local_push_unshift_handler(av_, n_)
364 {
365 av_extend(av, AvFILLp(av)+n);
366 SV** dst = AvARRAY(av);
367 Move(dst, dst + n_, AvFILLp(av)+1, SV*);
368 insert_elems(aTHX_ src, dst);
369 }
370
undopm::perl::glue::__anon132beb6e0311::local_unshift_handler371 void undo(pTHX) const
372 {
373 SV **e, **stop;
374 for (stop = AvARRAY(av)-1, e = stop + n; e > stop; --e)
375 SvREFCNT_dec(*e);
376 AvFILLp(av) -= n;
377 ++stop;
378 Move(stop + n, stop, AvFILLp(av)+1, SV*);
379 for (e = stop + AvFILLp(av)+1, stop = e+n; e < stop; ++e)
380 *e = PmEmptyArraySlot;
381 }
382 };
383
384 template <bool is_unshift>
local_push_unshift_op(pTHX)385 OP* local_push_unshift_op(pTHX)
386 {
387 dSP; dMARK; dORIGMARK;
388 AV* av = (AV*)*++MARK;
389 IV n = SP - MARK;
390 if (n > 0)
391 local_do<std::conditional_t<is_unshift, local_unshift_handler, local_push_handler>>(aTHX_ av, MARK+1, n);
392 SP = ORIGMARK;
393 RETURN;
394 }
395
396 template <bool is_unshift>
parse_local_push_unshift(pTHX_ OP ** op_ptr)397 int parse_local_push_unshift(pTHX_ OP** op_ptr)
398 {
399 OP* o = parse_termexpr(0);
400 if (!o) return KEYWORD_PLUGIN_DECLINE;
401 o->op_ppaddr = local_push_unshift_op<is_unshift>;
402 *op_ptr = o;
403 PL_hints |= HINT_BLOCK_SCOPE;
404 return KEYWORD_PLUGIN_EXPR;
405 }
406
407 // --------------------
408
409 struct local_pop_handler {
410 AV* av;
411 SV* val;
412
local_pop_handlerpm::perl::glue::__anon132beb6e0311::local_pop_handler413 local_pop_handler(pTHX_ AV* av_)
414 : av((AV*)SvREFCNT_inc_simple_NN(av_))
415 {
416 val = av_pop(av);
417 }
418
undopm::perl::glue::__anon132beb6e0311::local_pop_handler419 void undo(pTHX) const
420 {
421 auto localizing = PL_localizing;
422 PL_localizing = 2;
423 av_push(av, val);
424 PL_localizing = localizing;
425 SvREFCNT_dec(av);
426 }
427 };
428
local_pop_op(pTHX)429 OP* local_pop_op(pTHX)
430 {
431 dSP;
432 AV* av = (AV*)POPs;
433 SV* ret = nullptr;
434 if (AvFILLp(av) >= 0) {
435 ret = AvARRAY(av)[AvFILLp(av)];
436 local_do<local_pop_handler>(aTHX_ av);
437 }
438 if (GIMME_V != G_VOID) {
439 if (!ret) ret = &PL_sv_undef;
440 PUSHs(ret);
441 }
442 RETURN;
443 }
444
parse_local_pop(pTHX_ OP ** op_ptr)445 int parse_local_pop(pTHX_ OP** op_ptr)
446 {
447 OP* o = parse_termexpr(0);
448 if (!o) return KEYWORD_PLUGIN_DECLINE;
449 o->op_ppaddr = local_pop_op;
450 o->op_private |= OPpLVAL_INTRO;
451 *op_ptr = o;
452 PL_hints |= HINT_BLOCK_SCOPE;
453 return KEYWORD_PLUGIN_EXPR;
454 }
455
456 // --------------------
457
458 struct local_shift_handler {
459 AV* av;
460 SV* val;
461
local_shift_handlerpm::perl::glue::__anon132beb6e0311::local_shift_handler462 local_shift_handler(pTHX_ AV* av_)
463 : av(av_)
464 {
465 SvREFCNT_inc_simple_void_NN(av);
466 val = av_shift(av);
467 }
468
undopm::perl::glue::__anon132beb6e0311::local_shift_handler469 void undo(pTHX) const
470 {
471 auto localizing = PL_localizing;
472 PL_localizing = 2;
473 av_unshift(av, 1);
474 PL_localizing = localizing;
475 AvARRAY(av)[0] = val;
476 SvREFCNT_dec(av);
477 }
478 };
479
local_shift_op(pTHX)480 OP* local_shift_op(pTHX)
481 {
482 dSP;
483 AV* av = (AV*)POPs;
484 SV* ret = nullptr;
485 if (AvFILLp(av) >= 0) {
486 ret = AvARRAY(av)[0];
487 local_do<local_shift_handler>(aTHX_ av);
488 }
489 if (GIMME_V != G_VOID) {
490 if (!ret) ret = &PL_sv_undef;
491 PUSHs(ret);
492 }
493 RETURN;
494 }
495
parse_local_shift(pTHX_ OP ** op_ptr)496 int parse_local_shift(pTHX_ OP** op_ptr)
497 {
498 OP* o = parse_termexpr(0);
499 if (!o) return KEYWORD_PLUGIN_DECLINE;
500 o->op_ppaddr = local_shift_op;
501 o->op_private |= OPpLVAL_INTRO;
502 *op_ptr = o;
503 PL_hints |= HINT_BLOCK_SCOPE;
504 return KEYWORD_PLUGIN_EXPR;
505 }
506
507 // --------------------
508
509 struct local_splice_handler {
510 AV* av;
511 IV stretch;
512
local_splice_handlerpm::perl::glue::__anon132beb6e0311::local_splice_handler513 local_splice_handler(pTHX_ AV* av_, IV first, IV size)
514 : av(av_)
515 {
516 SvREFCNT_inc_simple_void_NN(av);
517 AvFILLp(av) -= size;
518 if (first == 0) {
519 AvARRAY(av) += size;
520 stretch = size;
521 } else {
522 stretch = -size;
523 }
524 }
525
undopm::perl::glue::__anon132beb6e0311::local_splice_handler526 void undo(pTHX) const
527 {
528 if (stretch > 0) {
529 AvARRAY(av) -= stretch;
530 AvFILLp(av) += stretch;
531 } else {
532 AvFILLp(av) -= stretch;
533 }
534 SvREFCNT_dec(av);
535 }
536 };
537
local_splice_op(pTHX)538 OP* local_splice_op(pTHX)
539 {
540 dSP; dMARK; dORIGMARK;
541 AV* av = (AV*)*++MARK;
542 if (MARK+2 < SP)
543 DIE(aTHX_ "unsupported local splice with insertion");
544 const IV len = AvFILLp(av)+1;
545 IV first, size;
546 if (MARK < SP) {
547 ++MARK;
548 first = SvIV(*MARK);
549 if (first < 0) {
550 first += len;
551 if (first < 0)
552 DIE(aTHX_ "local splice start index too low");
553 } else if (first > len) {
554 first = len;
555 }
556 if (MARK < SP) {
557 if (first != 0)
558 DIE(aTHX_ "unsupported local splice in the middle");
559 ++MARK;
560 size = SvIV(*MARK);
561 if (size < 0) {
562 size += len;
563 if (size < 0)
564 DIE(aTHX_ "local splice size too low");
565 } else if (size > len) {
566 DIE(aTHX_ "local splice size too high");
567 }
568 } else {
569 size = len - first;
570 }
571 } else {
572 first = 0;
573 size = len;
574 }
575
576 SP = ORIGMARK;
577 if (size != 0) {
578 if (GIMME_V == G_ARRAY) {
579 EXTEND(SP, size);
580 Copy(AvARRAY(av) + first, SP+1, size, SV*);
581 SP += size;
582 }
583 local_do<local_splice_handler>(aTHX_ av, first, size);
584 }
585 RETURN;
586 }
587
parse_local_splice(pTHX_ OP ** op_ptr)588 int parse_local_splice(pTHX_ OP** op_ptr)
589 {
590 OP* o = parse_termexpr(0);
591 if (!o) return KEYWORD_PLUGIN_DECLINE;
592 o->op_ppaddr = local_splice_op;
593 *op_ptr = o;
594 PL_hints |= HINT_BLOCK_SCOPE;
595 return KEYWORD_PLUGIN_EXPR;
596 }
597
598 // --------------------
599
600 struct local_swap_handler {
601 AV* av;
602 IV ix1, ix2;
603
local_swap_handlerpm::perl::glue::__anon132beb6e0311::local_swap_handler604 local_swap_handler(pTHX_ AV* av_, IV ix1_, IV ix2_)
605 : av(av_)
606 , ix1(ix1_)
607 , ix2(ix2_)
608 {
609 SvREFCNT_inc_simple_void_NN(av);
610 std::swap(AvARRAY(av)[ix1], AvARRAY(av)[ix2]);
611 }
612
undopm::perl::glue::__anon132beb6e0311::local_swap_handler613 void undo(pTHX) const
614 {
615 std::swap(AvARRAY(av)[ix1], AvARRAY(av)[ix2]);
616 SvREFCNT_dec(av);
617 }
618 };
619
local_swap_op(pTHX)620 OP* local_swap_op(pTHX)
621 {
622 dSP;
623 IV ix2 = POPi;
624 IV ix1 = POPi;
625 AV* av = (AV*)POPs;
626 if (ix1 < 0) ix1 += AvFILL(av)+1;
627 if (ix2 < 0) ix2 += AvFILL(av)+1;
628 if (ix1 > AvFILL(av) || ix2 > AvFILL(av)) DIE(aTHX_ "local swap: index out of range");
629 local_do<local_swap_handler>(aTHX_ av, ix1, ix2);
630 RETURN;
631 }
632
parse_local_swap(pTHX_ OP ** op_ptr)633 int parse_local_swap(pTHX_ OP** op_ptr)
634 {
635 op_keeper<OP> o(aTHX_ parse_listexpr(0));
636 if (!o) return KEYWORD_PLUGIN_DECLINE;
637 o->op_ppaddr = local_swap_op;
638 o->op_type = OP_CUSTOM;
639 LISTOP* lo = (LISTOP*)o.operator->();
640 OP* pushmark = lo->op_first;
641 if (pushmark->op_type != OP_PUSHMARK || !OpHAS_SIBLING(pushmark))
642 return KEYWORD_PLUGIN_DECLINE;
643 OP* avop = OpSIBLING(pushmark);
644 if (avop->op_type != OP_RV2AV && avop->op_type != OP_PADAV || !OpHAS_SIBLING(avop)) {
645 report_parse_error("expected: local swap @array, index1, index2");
646 return KEYWORD_PLUGIN_DECLINE;
647 }
648 OP* ix1op = OpSIBLING(avop);
649 if (!OpHAS_SIBLING(ix1op)) {
650 report_parse_error("expected: local swap @array, index1, index2");
651 return KEYWORD_PLUGIN_DECLINE;
652 }
653 OP* ix2op = OpSIBLING(ix1op);
654 if (OpHAS_SIBLING(ix2op)) {
655 report_parse_error("expected: local swap @array, index1, index2");
656 return KEYWORD_PLUGIN_DECLINE;
657 }
658
659 lo->op_first = doref(avop, OP_NULL, TRUE);
660 op_free(pushmark);
661 *op_ptr = o.release();
662 PL_hints |= HINT_BLOCK_SCOPE;
663 return KEYWORD_PLUGIN_EXPR;
664 }
665
666 // --------------------
667
668 struct local_bless_handler {
669 SV* var;
670 HV* old_stash;
671 I32 mg_flags;
672
local_bless_handlerpm::perl::glue::__anon132beb6e0311::local_bless_handler673 local_bless_handler(pTHX_ SV* ref, HV* stash)
674 : var(SvRV(ref))
675 {
676 SvREFCNT_inc_simple_void_NN(var);
677 old_stash = (HV*)SvREFCNT_inc_NN(SvSTASH(var));
678 mg_flags = SvFLAGS(var) & (SVs_GMG | SVs_SMG | SVs_RMG | SVf_AMAGIC);
679 sv_bless(ref, stash);
680 }
681
undopm::perl::glue::__anon132beb6e0311::local_bless_handler682 void undo(pTHX) const
683 {
684 HV* stash = SvSTASH(var);
685 SvSTASH_set(var, old_stash);
686 SvFLAGS(var) &= ~(SVs_GMG | SVs_SMG | SVs_RMG | SVf_AMAGIC);
687 SvFLAGS(var) |= mg_flags;
688 SvREFCNT_dec(var);
689 SvREFCNT_dec(stash);
690 }
691 };
692
local_bless_op(pTHX)693 OP* local_bless_op(pTHX)
694 {
695 dSP;
696 HV* stash = MAXARG == 1 ? CopSTASH(PL_curcop) : gv_stashsv(POPs, GV_NOADD_NOINIT);
697 SV* sv = TOPs;
698 if (!SvROK(sv) || !SvOBJECT(SvRV(sv)))
699 DIE(aTHX_ "local bless applied to a non-object");
700 local_do<local_bless_handler>(aTHX_ sv, stash);
701 RETURN;
702 }
703
parse_local_bless(pTHX_ OP ** op_ptr)704 int parse_local_bless(pTHX_ OP** op_ptr)
705 {
706 OP* o = parse_termexpr(0);
707 if (!o) return KEYWORD_PLUGIN_DECLINE;
708 o->op_ppaddr = local_bless_op;
709 *op_ptr = o;
710 PL_hints |= HINT_BLOCK_SCOPE;
711 return KEYWORD_PLUGIN_EXPR;
712 }
713
714 // --------------------
715
716 #if PerlVersion >= 5240
717 # define PmCxSaveStackIndex(cx) (cx->blk_oldsaveix)
718 #else
719 # define PmCxSaveStackIndex(cx) (PL_scopestack[cx->blk_oldscopesp-1])
720 #endif
721
save_localizations(pTHX_ I32 & start,I32 & end)722 bool save_localizations(pTHX_ I32& start, I32& end)
723 {
724 PERL_CONTEXT* cx = cxstack + cxstack_ix;
725 assert(CxTYPE(cx) == CXt_BLOCK);
726
727 const I32 save_start = PmCxSaveStackIndex(cx);
728 const I32 save_end = PL_savestack_ix;
729 I32 last_kept = save_end;
730 I32 tmp_save_end = -1;
731
732 while (PL_savestack_ix > save_start) {
733 const UV save_code = PL_savestack[PL_savestack_ix-1].any_uv & SAVE_MASK;
734 int num_words = 0;
735 // all kinds of save operations generated for localizing values
736 switch (save_code) {
737 case SAVEt_GP:
738 case SAVEt_GVSV:
739 case SAVEt_GENERIC_SVREF:
740 case SAVEt_SV:
741 case SAVEt_AV:
742 case SAVEt_HV:
743 case SAVEt_ADELETE:
744 num_words = 3;
745 break;
746 case SAVEt_AELEM:
747 case SAVEt_HELEM:
748 case SAVEt_DELETE:
749 #if PerlVersion >= 5180
750 case SAVEt_GVSLOT:
751 #endif
752 num_words = 4;
753 break;
754 case SAVEt_DESTRUCTOR_X:
755 num_words = 3;
756 if (PL_savestack_ix-4 > save_start) {
757 const UV next_item = PL_savestack[PL_savestack_ix-4].any_uv;
758 if ((next_item & SAVE_MASK) == SAVEt_ALLOC)
759 num_words += 1 + int(next_item >> SAVE_TIGHT_SHIFT);
760 }
761 break;
762 }
763 if (num_words == 0) {
764 // restoring action not related to localization: execute immediately
765 // before that, rescue other actions onto mortals stack, otherwise they could be overwritten if this action triggers other localizations
766 if (tmp_save_end < 0 && last_kept != save_end) {
767 EXTEND_MORTAL(save_end - save_start);
768 PL_tmps_ix += save_end - save_start;
769 tmp_save_end = I32(PL_tmps_ix);
770 const I32 tmp_save_start = tmp_save_end - (save_end - last_kept);
771 Copy(&(PL_savestack[last_kept]), &(PL_tmps_stack[tmp_save_start]), save_end - last_kept, ANY);
772 last_kept = tmp_save_start;
773 }
774 leave_scope(PL_savestack_ix-1);
775 } else {
776 PL_savestack_ix -= num_words;
777 last_kept -= num_words;
778 if (tmp_save_end >= 0) // collecting the items on mortals stack
779 Copy(&(PL_savestack[PL_savestack_ix]), &(PL_tmps_stack[last_kept]), num_words, ANY);
780 }
781 }
782 assert(PL_savestack_ix == save_start);
783 start = last_kept;
784 if (tmp_save_end >= 0) {
785 end = tmp_save_end;
786 PL_tmps_ix -= save_end - save_start;
787 return true;
788 } else {
789 end = save_end;
790 return false;
791 }
792 }
793
794 struct local_magic_t : MAGIC {
795 ANY locals[1];
796 };
797
undo_saved_locals(pTHX_ SV * sv,MAGIC * mg)798 int undo_saved_locals(pTHX_ SV* sv, MAGIC* mg)
799 {
800 const local_magic_t* lmg = static_cast<local_magic_t*>(mg);
801 const I32 save_start = PL_savestack_ix;
802 const I32 num_saved = I32(lmg->mg_len);
803 SSGROW(num_saved);
804 Copy(&(lmg->locals[0]), &(PL_savestack[save_start]), num_saved, ANY);
805 PL_savestack_ix += num_saved;
806 leave_scope(save_start);
807 return 0;
808 }
809
810 const MGVTBL local_magic_vtbl = { 0, 0, 0, 0, &undo_saved_locals };
811
leave_local_block_op(pTHX)812 OP* leave_local_block_op(pTHX)
813 {
814 dSP;
815 dPOPss;
816 I32 save_start, save_end;
817 const bool moved_to_mortals = save_localizations(aTHX_ save_start, save_end);
818 const I32 num_saved = save_end - save_start;
819 if (num_saved > 0) {
820 if (SvTYPE(sv) == SVt_NULL) {
821 (void)SvUPGRADE(sv, SVt_PVMG);
822 } else if (SvOK(sv) || SvTYPE(sv) != SVt_PVMG) {
823 DIE(aTHX_ "local with: wrong storage value");
824 }
825 const size_t mgsz = sizeof(local_magic_t)+(num_saved-1)*sizeof(ANY);
826 char* mg_raw;
827 Newxz(mg_raw, mgsz, char);
828 local_magic_t* lmg = reinterpret_cast<local_magic_t*>(mg_raw);
829 lmg->mg_type = PERL_MAGIC_ext;
830 lmg->mg_virtual = const_cast<MGVTBL*>(&local_magic_vtbl);
831 lmg->mg_len = num_saved;
832 lmg->mg_moremagic = SvMAGIC(sv);
833 SvMAGIC_set(sv, lmg);
834 SvRMAGICAL_on(sv);
835 if (moved_to_mortals)
836 Copy(&(PL_tmps_stack[save_start]), &(lmg->locals[0]), num_saved, ANY);
837 else
838 Copy(&(PL_savestack[save_start]), &(lmg->locals[0]), num_saved, ANY);
839 }
840 PUTBACK;
841 return def_pp_LEAVE(aTHX);
842 }
843
parse_local_block(pTHX_ OP ** op_ptr)844 int parse_local_block(pTHX_ OP** op_ptr)
845 {
846 op_keeper<OP> scope(aTHX_ parse_expression_in_parens(aTHX));
847 if (!scope) {
848 report_parse_error("expected: local with(EXPR) { BLOCK }");
849 return KEYWORD_PLUGIN_DECLINE;
850 }
851 lex_read_space(0);
852 if (PL_parser->bufptr == PL_parser->bufend || *PL_parser->bufptr != '{') {
853 report_parse_error("expected: local with(EXPR) { BLOCK }");
854 return KEYWORD_PLUGIN_DECLINE;
855 }
856 op_keeper<OP> b(aTHX_ parse_block(0));
857 if (!b || b->op_type != OP_LINESEQ)
858 return KEYWORD_PLUGIN_DECLINE;
859 OP* o = op_prepend_elem(OP_LINESEQ, newOP(OP_ENTER, 0), b.release());
860 o = op_append_elem(OP_LINESEQ, o, op_lvalue(scope.release(), OP_SASSIGN));
861 o->op_ppaddr = leave_local_block_op;
862 o->op_type = OP_CUSTOM;
863 *op_ptr = o;
864 return KEYWORD_PLUGIN_STMT;
865 }
866
867 // --------------------
868
leave_local_if_op(pTHX)869 OP* leave_local_if_op(pTHX)
870 {
871 I32 save_start, save_end;
872 const bool moved_to_mortals = save_localizations(aTHX_ save_start, save_end);
873 OP* ret = def_pp_LEAVE(aTHX);
874 const I32 num_words = save_end - save_start;
875 if (num_words != 0) {
876 if (moved_to_mortals)
877 Copy(&(PL_tmps_stack[save_start]), &(PL_savestack[PL_savestack_ix]), num_words, ANY);
878 PL_savestack_ix += num_words;
879 }
880 return ret;
881 }
882
parse_local_if(pTHX_ OP ** op_ptr)883 int parse_local_if(pTHX_ OP** op_ptr)
884 {
885 PL_ppaddr[OP_LEAVE] = leave_local_if_op;
886 OP* o = parse_barestmt(0);
887 PL_ppaddr[OP_LEAVE] = def_pp_LEAVE;
888 if (!o) return KEYWORD_PLUGIN_DECLINE;
889 *op_ptr = o;
890 return KEYWORD_PLUGIN_STMT;
891 }
892
893 // --------------------
894
local_caller_op(pTHX)895 OP* local_caller_op(pTHX)
896 {
897 dSP;
898 dPOPss;
899 OP* op_next_state = (OP*)PL_curcop;
900 while ((op_next_state = OpSIBLING(op_next_state)) && op_next_state->op_type != OP_NEXTSTATE && op_next_state->op_type != OP_DBSTATE) ;
901 if (op_next_state) {
902 HV* src_stash = nullptr;
903 if (SvPOK(sv)) {
904 src_stash = gv_stashsv(sv, GV_ADD);
905 if (GIMME_V != G_VOID) PUSHs(sv_2mortal(newRV((SV*)src_stash)));
906 } else if (!SvROK(sv) || (src_stash = (HV*)SvRV(sv), SvTYPE(src_stash) != SVt_PVHV)) {
907 DIE(aTHX_ "invalid package specified in local caller");
908 } else if (GIMME_V != G_VOID) {
909 ++SP;
910 }
911 #if PerlVersion >= 5180 || !defined(USE_ITHREADS)
912 HV** stashp = &CopSTASH((COP*)op_next_state);
913 save_hptr(stashp);
914 *stashp = src_stash;
915 #else
916 char** stashnamep = &CopSTASHPV((COP*)op_next_state);
917 save_pptr(stashnamep);
918 *stashnamep = HvNAME(src_stash);
919 I32* stashlenp = &CopSTASH_len((COP*)op_next_state);
920 save_I32(stashlenp);
921 *stashlenp = HvNAMELEN(src_stash);
922 #endif
923 }
924 RETURN;
925 }
926
parse_local_caller(pTHX_ OP ** op_ptr)927 int parse_local_caller(pTHX_ OP** op_ptr)
928 {
929 OP* expr = parse_termexpr(0);
930 if (!expr) return KEYWORD_PLUGIN_DECLINE;
931 OP* o = PmNewCustomOP(UNOP, 0, Perl_scalar(aTHX_ expr));
932 o->op_ppaddr = local_caller_op;
933 *op_ptr = o;
934 return KEYWORD_PLUGIN_EXPR;
935 }
936
937 // --------------------
938
939 struct local_saveio_handler {
940 GV* gv;
941 GV* saved;
942
local_saveio_handlerpm::perl::glue::__anon132beb6e0311::local_saveio_handler943 local_saveio_handler(pTHX_ GV* gv_)
944 : gv((GV*)SvREFCNT_inc_simple_NN(gv_))
945 {
946 if (GvIOp(gv)) {
947 saved = (GV*)newSV(0);
948 gv_init(saved, nullptr, "__ANONIO__", 10, 0);
949 if (do_openn(saved, ">&=", 3, FALSE, 0, 0, nullptr, (SV**)&gv, 1)) {
950 do_close(gv, FALSE);
951 } else {
952 SvREFCNT_dec(saved);
953 saved = nullptr;
954 }
955 } else {
956 saved = nullptr;
957 }
958 }
959
undopm::perl::glue::__anon132beb6e0311::local_saveio_handler960 void undo (pTHX) const
961 {
962 if (GvIOp(gv)) do_close(gv, FALSE);
963 if (saved) {
964 (void)do_openn(gv, ">&=", 3, FALSE, 0, 0, nullptr, (SV**)&saved, 1);
965 SvREFCNT_dec(saved);
966 }
967 SvREFCNT_dec(gv);
968 }
969 };
970
local_close_op(pTHX)971 OP* local_close_op(pTHX)
972 {
973 dSP;
974 dPOPss;
975 if (SvTYPE(sv) != SVt_PVGV)
976 DIE(aTHX_ "not an IO handle in local close");
977 local_do<local_saveio_handler>(aTHX_ (GV*)sv);
978 RETURN;
979 }
980
local_open_op(pTHX)981 OP* local_open_op(pTHX)
982 {
983 SV* sv = PL_stack_base[TOPMARK+1];
984 if (SvTYPE(sv) != SVt_PVGV)
985 DIE(aTHX_ "not an IO handle in local open");
986 local_do<local_saveio_handler>(aTHX_ (GV*)sv);
987 return def_pp_OPEN(aTHX);
988 }
989
parse_local_open_close(pTHX_ OP ** op_ptr,OP * (* ppaddr)(pTHX))990 int parse_local_open_close(pTHX_ OP** op_ptr, OP* (*ppaddr)(pTHX))
991 {
992 OP* o = parse_termexpr(0);
993 if (!o) return KEYWORD_PLUGIN_DECLINE;
994 o->op_ppaddr = ppaddr;
995 *op_ptr = o;
996 PL_hints |= HINT_BLOCK_SCOPE;
997 return KEYWORD_PLUGIN_EXPR;
998 }
999
1000 // --------------------
1001
following_keyword(pTHX_ const AnyString & kw,bool skip_it=false)1002 bool following_keyword(pTHX_ const AnyString& kw, bool skip_it = false)
1003 {
1004 if (PL_parser->bufptr + kw.len < PL_parser->bufend
1005 && !strncmp(PL_parser->bufptr, kw.ptr, kw.len)
1006 && !isALNUM(PL_parser->bufptr[kw.len])) {
1007 if (skip_it)
1008 lex_read_to(PL_parser->bufptr + kw.len);
1009 return true;
1010 }
1011 return false;
1012 }
1013
1014 #if defined(POLYMAKE_GATHER_CODE_COVERAGE)
prevent_unnecessary_scope(pTHX_ int (* parse_func)(pTHX_ OP **),OP ** op_ptr)1015 int prevent_unnecessary_scope(pTHX_ int (*parse_func)(pTHX_ OP**), OP** op_ptr)
1016 {
1017 const auto noopt = PERLDB_NOOPT;
1018 PL_perldb &= ~PERLDBf_NOOPT;
1019 const int result = parse_func(aTHX_ op_ptr);
1020 PL_perldb |= noopt;
1021 return result;
1022 }
1023 #else
prevent_unnecessary_scope(pTHX_ int (* parse_func)(pTHX_ OP **),OP ** op_ptr)1024 int prevent_unnecessary_scope(pTHX_ int (*parse_func)(pTHX_ OP**), OP** op_ptr)
1025 {
1026 return parse_func(aTHX_ op_ptr);
1027 }
1028 #endif
1029
1030 }
1031
parse_enhanced_local(pTHX_ OP ** op_ptr)1032 int parse_enhanced_local(pTHX_ OP** op_ptr)
1033 {
1034 lex_read_space(0);
1035 if (PL_parser->bufptr == PL_parser->bufend)
1036 return KEYWORD_PLUGIN_DECLINE;
1037 switch (*PL_parser->bufptr) {
1038 case 'b':
1039 if (following_keyword(aTHX_ "bless"))
1040 return parse_local_bless(aTHX_ op_ptr);
1041 break;
1042 case 'c':
1043 if (following_keyword(aTHX_ "caller", true))
1044 return parse_local_caller(aTHX_ op_ptr);
1045 if (following_keyword(aTHX_ "close"))
1046 return parse_local_open_close(aTHX_ op_ptr, local_close_op);
1047 break;
1048 case 'i':
1049 if (following_keyword(aTHX_ "if"))
1050 return prevent_unnecessary_scope(aTHX_ &parse_local_if, op_ptr);
1051 if (following_keyword(aTHX_ "interrupts", true))
1052 return parse_interrupts_op(aTHX_ true, op_ptr);
1053 break;
1054 case 'o':
1055 if (following_keyword(aTHX_ "open"))
1056 return parse_local_open_close(aTHX_ op_ptr, local_open_op);
1057 break;
1058 case 'p':
1059 if (following_keyword(aTHX_ "pop"))
1060 return parse_local_pop(aTHX_ op_ptr);
1061 if (following_keyword(aTHX_ "push"))
1062 return parse_local_push_unshift<false>(aTHX_ op_ptr);
1063 break;
1064 case 'r':
1065 if (following_keyword(aTHX_ "ref", true))
1066 return parse_local_ref(aTHX_ op_ptr);
1067 break;
1068 case 's':
1069 if (following_keyword(aTHX_ "scalar", true))
1070 return parse_local_scalar(aTHX_ op_ptr);
1071 if (following_keyword(aTHX_ "shift"))
1072 return parse_local_shift(aTHX_ op_ptr);
1073 if (following_keyword(aTHX_ "splice"))
1074 return parse_local_splice(aTHX_ op_ptr);
1075 if (following_keyword(aTHX_ "swap", true))
1076 return parse_local_swap(aTHX_ op_ptr);
1077 break;
1078 case 'u':
1079 if (following_keyword(aTHX_ "unshift"))
1080 return parse_local_push_unshift<true>(aTHX_ op_ptr);
1081 break;
1082 case 'w':
1083 if (following_keyword(aTHX_ "with", true))
1084 return prevent_unnecessary_scope(aTHX_ &parse_local_block, op_ptr);
1085 break;
1086 }
1087 return KEYWORD_PLUGIN_DECLINE;
1088 }
1089
1090 }
1091 namespace ops {
1092
init_globals(pTHX)1093 void init_globals(pTHX)
1094 {
1095 def_pp_LEAVE = PL_ppaddr[OP_LEAVE];
1096 def_pp_OPEN = PL_ppaddr[OP_OPEN];
1097 }
1098
1099 } } }
1100
1101 // Local Variables:
1102 // mode:C++
1103 // c-basic-offset:3
1104 // indent-tabs-mode:nil
1105 // End:
1106