CopSTASH_free(cop);
if (! specialWARN(cop->cop_warnings))
PerlMemShared_free(cop->cop_warnings);
- Perl_refcounted_he_free(aTHX_ cop->cop_hints_hash);
+ cophh_free(CopHINTHASH_get(cop));
}
STATIC void
}
}
-#define LINKLIST(o) ((o)->op_next ? (o)->op_next : linklist((OP*)o))
+/*
+=head1 Optree Manipulation Functions
-static OP *
-S_linklist(pTHX_ OP *o)
+=for apidoc Am|OP*|op_linklist|OP *o
+This function is the implementation of the L</LINKLIST> macro. It should
+not be called directly.
+
+=cut
+*/
+
+OP *
+Perl_op_linklist(pTHX_ OP *o)
{
OP *first;
- PERL_ARGS_ASSERT_LINKLIST;
+ PERL_ARGS_ASSERT_OP_LINKLIST;
if (o->op_next)
return o->op_next;
if (o && o->op_flags & OPf_KIDS) {
OP *kid;
for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
- mod(kid, type);
+ op_lvalue(kid, type);
}
return o;
}
-/* Propagate lvalue ("modifiable") context to an op and its children.
- * 'type' represents the context type, roughly based on the type of op that
- * would do the modifying, although local() is represented by OP_NULL.
- * It's responsible for detecting things that can't be modified, flag
- * things that need to behave specially in an lvalue context (e.g., "$$x = 5"
- * might have to vivify a reference in $x), and so on.
- *
- * For example, "$a+1 = 2" would cause mod() to be called with o being
- * OP_ADD and type being OP_SASSIGN, and would output an error.
- */
+/*
+=for apidoc Amx|OP *|op_lvalue|OP *o|I32 type
+
+Propagate lvalue ("modifiable") context to an op and its children.
+I<type> represents the context type, roughly based on the type of op that
+would do the modifying, although C<local()> is represented by OP_NULL,
+because it has no op type of its own (it is signalled by a flag on
+the lvalue op). This function detects things that can't be modified,
+such as C<$x+1>, and generates errors for them. It also flags things
+that need to behave specially in an lvalue context, such as C<$$x>
+which might have to vivify a reference in C<$x>.
+
+=cut
+*/
OP *
-Perl_mod(pTHX_ OP *o, I32 type)
+Perl_op_lvalue(pTHX_ OP *o, I32 type)
{
dVAR;
OP *kid;
case OP_COND_EXPR:
localize = 1;
for (kid = cUNOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
- mod(kid, type);
+ op_lvalue(kid, type);
break;
case OP_RV2AV:
o->op_targ = pad_alloc(o->op_type, SVs_PADMY);
assert(SvTYPE(PAD_SV(o->op_targ)) == SVt_NULL);
if (o->op_flags & OPf_KIDS)
- mod(cBINOPo->op_first->op_sibling, type);
+ op_lvalue(cBINOPo->op_first->op_sibling, type);
break;
case OP_AELEM:
case OP_LINESEQ:
localize = 0;
if (o->op_flags & OPf_KIDS)
- mod(cLISTOPo->op_last, type);
+ op_lvalue(cLISTOPo->op_last, type);
break;
case OP_NULL:
else if (!(o->op_flags & OPf_KIDS))
break;
if (o->op_targ != OP_LIST) {
- mod(cBINOPo->op_first, type);
+ op_lvalue(cBINOPo->op_first, type);
break;
}
/* FALL THROUGH */
case OP_LIST:
localize = 0;
for (kid = cLISTOPo->op_first; kid; kid = kid->op_sibling)
- mod(kid, type);
+ op_lvalue(kid, type);
break;
case OP_RETURN:
if (type != OP_LEAVESUBLV)
goto nomod;
- break; /* mod()ing was handled by ck_return() */
+ break; /* op_lvalue()ing was handled by ck_return() */
}
/* [20011101.069] File test operators interpret OPf_REF to mean that
rop = NULL;
for (o = cLISTOPo->op_first; o; o=o->op_sibling) {
if (o->op_type == OP_CONST)
- rop = append_elem(OP_LIST, rop,
+ rop = op_append_elem(OP_LIST, rop,
newSVOP(OP_CONST, o->op_flags,
SvREFCNT_inc_NN(cSVOPo->op_sv)));
}
Perl_load_module(aTHX_ PERL_LOADMOD_IMPORT_OPS,
newSVpvs(ATTRSMODULE),
NULL,
- prepend_elem(OP_LIST,
+ op_prepend_elem(OP_LIST,
newSVOP(OP_CONST, 0, stashsv),
- prepend_elem(OP_LIST,
+ op_prepend_elem(OP_LIST,
newSVOP(OP_CONST, 0,
newRV(target)),
dup_attrlist(attrs))));
arg = newOP(OP_PADSV, 0);
arg->op_targ = target->op_targ;
- arg = prepend_elem(OP_LIST,
+ arg = op_prepend_elem(OP_LIST,
newSVOP(OP_CONST, 0, stashsv),
- prepend_elem(OP_LIST,
+ op_prepend_elem(OP_LIST,
newUNOP(OP_REFGEN, 0,
- mod(arg, OP_REFGEN)),
+ op_lvalue(arg, OP_REFGEN)),
dup_attrlist(attrs)));
/* Fake up a method call to import */
meth = newSVpvs_share("import");
imop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL|OPf_WANT_VOID,
- append_elem(OP_LIST,
- prepend_elem(OP_LIST, pack, list(arg)),
+ op_append_elem(OP_LIST,
+ op_prepend_elem(OP_LIST, pack, list(arg)),
newSVOP(OP_METHOD_NAMED, 0, meth)));
imop->op_private |= OPpENTERSUB_NOMOD;
/* Combine the ops. */
- *imopsp = append_elem(OP_LIST, *imopsp, imop);
+ *imopsp = op_append_elem(OP_LIST, *imopsp, imop);
}
/*
if (len) {
const char * const sstr = attrstr;
for (; !isSPACE(*attrstr) && len; --len, ++attrstr) ;
- attrs = append_elem(OP_LIST, attrs,
+ attrs = op_append_elem(OP_LIST, attrs,
newSVOP(OP_CONST, 0,
newSVpvn(sstr, attrstr-sstr)));
}
Perl_load_module(aTHX_ PERL_LOADMOD_IMPORT_OPS,
newSVpvs(ATTRSMODULE),
- NULL, prepend_elem(OP_LIST,
+ NULL, op_prepend_elem(OP_LIST,
newSVOP(OP_CONST, 0, newSVpv(stashpv,0)),
- prepend_elem(OP_LIST,
+ op_prepend_elem(OP_LIST,
newSVOP(OP_CONST, 0,
newRV(MUTABLE_SV(cv))),
attrs)));
o = my_kid(o, attrs, &rops);
if (rops) {
if (maybe_scalar && o->op_type == OP_PADSV) {
- o = scalar(append_list(OP_LIST, (LISTOP*)rops, (LISTOP*)o));
+ o = scalar(op_append_list(OP_LIST, rops, o));
o->op_private |= OPpLVAL_INTRO;
}
else
- o = append_list(OP_LIST, (LISTOP*)o, (LISTOP*)rops);
+ o = op_append_list(OP_LIST, o, rops);
}
PL_parser->in_my = FALSE;
PL_parser->in_my_stash = NULL;
right->op_private & OPpTRANS_IDENTICAL) &&
! (rtype == OP_SUBST &&
(cPMOPx(right)->op_pmflags & PMf_NONDESTRUCT)))
- newleft = mod(left, rtype);
+ newleft = op_lvalue(left, rtype);
else
newleft = left;
if (right->op_type == OP_TRANS)
o = newBINOP(OP_NULL, OPf_STACKED, scalar(newleft), right);
else
- o = prepend_elem(rtype, scalar(newleft), right);
+ o = op_prepend_elem(rtype, scalar(newleft), right);
if (type == OP_NOT)
return newUNOP(OP_NOT, 0, scalar(o));
return o;
return newUNOP(OP_NOT, OPf_SPECIAL, scalar(o));
}
+/*
+=for apidoc Amx|OP *|op_scope|OP *o
+
+Wraps up an op tree with some additional ops so that at runtime a dynamic
+scope will be created. The original ops run in the new dynamic scope,
+and then, provided that they exit normally, the scope will be unwound.
+The additional ops used to create and unwind the dynamic scope will
+normally be an C<enter>/C<leave> pair, but a C<scope> op may be used
+instead if the ops are simple enough to not need the full dynamic scope
+structure.
+
+=cut
+*/
+
OP *
-Perl_scope(pTHX_ OP *o)
+Perl_op_scope(pTHX_ OP *o)
{
dVAR;
if (o) {
if (o->op_flags & OPf_PARENS || PERLDB_NOOPT || PL_tainting) {
- o = prepend_elem(OP_LINESEQ, newOP(OP_ENTER, 0), o);
+ o = op_prepend_elem(OP_LINESEQ, newOP(OP_ENTER, 0), o);
o->op_type = OP_LEAVE;
o->op_ppaddr = PL_ppaddr[OP_LEAVE];
}
SAVECOMPILEWARNINGS();
PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);
- CALL_BLOCK_HOOKS(start, full);
+ CALL_BLOCK_HOOKS(bhk_start, full);
return retval;
}
const int needblockscope = PL_hints & HINT_BLOCK_SCOPE;
OP* retval = scalarseq(seq);
- CALL_BLOCK_HOOKS(pre_end, &retval);
+ CALL_BLOCK_HOOKS(bhk_pre_end, &retval);
LEAVE_SCOPE(floor);
CopHINTS_set(&PL_compiling, PL_hints);
PL_hints |= HINT_BLOCK_SCOPE; /* propagate out */
pad_leavemy();
- CALL_BLOCK_HOOKS(post_end, &retval);
+ CALL_BLOCK_HOOKS(bhk_post_end, &retval);
return retval;
}
PL_eval_root = newUNOP(OP_LEAVEEVAL,
((PL_in_eval & EVAL_KEEPERR)
? OPf_SPECIAL : 0), o);
- PL_eval_start = linklist(PL_eval_root);
+ /* don't use LINKLIST, since PL_eval_root might indirect through
+ * a rather expensive function call and LINKLIST evaluates its
+ * argument more than once */
+ PL_eval_start = op_linklist(PL_eval_root);
PL_eval_root->op_private |= OPpREFCOUNTED;
OpREFCNT_set(PL_eval_root, 1);
PL_eval_root->op_next = 0;
S_op_destroy(aTHX_ o);
return;
}
- PL_main_root = scope(sawparens(scalarvoid(o)));
+ PL_main_root = op_scope(sawparens(scalarvoid(o)));
PL_curcop = &PL_compiling;
PL_main_start = LINKLIST(PL_main_root);
PL_main_root->op_private |= OPpREFCOUNTED;
if (lex)
o = my(o);
else
- o = mod(o, OP_NULL); /* a bit kludgey */
+ o = op_lvalue(o, OP_NULL); /* a bit kludgey */
PL_parser->in_my = FALSE;
PL_parser->in_my_stash = NULL;
return o;
if (o->op_type == OP_LIST) {
OP * const o2
= newSVREF(newGVOP(OP_GV, 0, gv_fetchpvs(";", GV_ADD|GV_NOTQUAL, SVt_PV)));
- o = convert(OP_JOIN, 0, prepend_elem(OP_LIST, o2, o));
+ o = convert(OP_JOIN, 0, op_prepend_elem(OP_LIST, o2, o));
}
return o;
}
case OP_SLE:
case OP_SGE:
case OP_SCMP:
+ case OP_SPRINTF:
/* XXX what about the numeric ops? */
if (PL_hints & HINT_LOCALE)
goto nope;
#else
op_free(curop);
#endif
- linklist(o);
+ LINKLIST(o);
return list(o);
}
return fold_constants(o);
}
+/*
+=head1 Optree Manipulation Functions
+*/
+
/* List constructors */
+/*
+=for apidoc Am|OP *|op_append_elem|I32 optype|OP *first|OP *last
+
+Append an item to the list of ops contained directly within a list-type
+op, returning the lengthened list. I<first> is the list-type op,
+and I<last> is the op to append to the list. I<optype> specifies the
+intended opcode for the list. If I<first> is not already a list of the
+right type, it will be upgraded into one. If either I<first> or I<last>
+is null, the other is returned unchanged.
+
+=cut
+*/
+
OP *
-Perl_append_elem(pTHX_ I32 type, OP *first, OP *last)
+Perl_op_append_elem(pTHX_ I32 type, OP *first, OP *last)
{
if (!first)
return last;
return first;
}
+/*
+=for apidoc Am|OP *|op_append_list|I32 optype|OP *first|OP *last
+
+Concatenate the lists of ops contained directly within two list-type ops,
+returning the combined list. I<first> and I<last> are the list-type ops
+to concatenate. I<optype> specifies the intended opcode for the list.
+If either I<first> or I<last> is not already a list of the right type,
+it will be upgraded into one. If either I<first> or I<last> is null,
+the other is returned unchanged.
+
+=cut
+*/
+
OP *
-Perl_append_list(pTHX_ I32 type, LISTOP *first, LISTOP *last)
+Perl_op_append_list(pTHX_ I32 type, OP *first, OP *last)
{
if (!first)
- return (OP*)last;
+ return last;
if (!last)
- return (OP*)first;
+ return first;
if (first->op_type != (unsigned)type)
- return prepend_elem(type, (OP*)first, (OP*)last);
+ return op_prepend_elem(type, first, last);
if (last->op_type != (unsigned)type)
- return append_elem(type, (OP*)first, (OP*)last);
+ return op_append_elem(type, first, last);
- first->op_last->op_sibling = last->op_first;
- first->op_last = last->op_last;
+ ((LISTOP*)first)->op_last->op_sibling = ((LISTOP*)last)->op_first;
+ ((LISTOP*)first)->op_last = ((LISTOP*)last)->op_last;
first->op_flags |= (last->op_flags & OPf_KIDS);
#ifdef PERL_MAD
- if (last->op_first && first->op_madprop) {
- MADPROP *mp = last->op_first->op_madprop;
+ if (((LISTOP*)last)->op_first && first->op_madprop) {
+ MADPROP *mp = ((LISTOP*)last)->op_first->op_madprop;
if (mp) {
while (mp->mad_next)
mp = mp->mad_next;
mp->mad_next = first->op_madprop;
}
else {
- last->op_first->op_madprop = first->op_madprop;
+ ((LISTOP*)last)->op_first->op_madprop = first->op_madprop;
}
}
first->op_madprop = last->op_madprop;
last->op_madprop = 0;
#endif
- S_op_destroy(aTHX_ (OP*)last);
+ S_op_destroy(aTHX_ last);
- return (OP*)first;
+ return first;
}
+/*
+=for apidoc Am|OP *|op_prepend_elem|I32 optype|OP *first|OP *last
+
+Prepend an item to the list of ops contained directly within a list-type
+op, returning the lengthened list. I<first> is the op to prepend to the
+list, and I<last> is the list-type op. I<optype> specifies the intended
+opcode for the list. If I<last> is not already a list of the right type,
+it will be upgraded into one. If either I<first> or I<last> is null,
+the other is returned unchanged.
+
+=cut
+*/
+
OP *
-Perl_prepend_elem(pTHX_ I32 type, OP *first, OP *last)
+Perl_op_prepend_elem(pTHX_ I32 type, OP *first, OP *last)
{
if (!first)
return last;
else if ((! (PL_hints & HINT_BYTES)) && (PL_hints & HINT_UNI_8_BIT)) {
pmop->op_pmflags |= RXf_PMf_UNICODE;
}
+ if (PL_hints & HINT_RE_FLAGS) {
+ SV *reflags = Perl_refcounted_he_fetch_pvn(aTHX_
+ PL_compiling.cop_hints_hash, STR_WITH_LEN("reflags"), 0, 0
+ );
+ if (reflags && SvOK(reflags)) pmop->op_pmflags |= SvIV(reflags);
+ reflags = Perl_refcounted_he_fetch_pvn(aTHX_
+ PL_compiling.cop_hints_hash, STR_WITH_LEN("reflags_dul"), 0, 0
+ );
+ if (reflags && SvOK(reflags)) {
+ pmop->op_pmflags &= ~(RXf_PMf_LOCALE|RXf_PMf_UNICODE);
+ pmop->op_pmflags |= SvIV(reflags);
+ }
+ }
#ifdef USE_ITHREADS
expr->op_next = (OP*)rcop;
}
- prepend_elem(o->op_type, scalar((OP*)rcop), o);
+ op_prepend_elem(o->op_type, scalar((OP*)rcop), o);
}
if (repl) {
|| RX_EXTFLAGS(PM_GETRE(pm)) & RXf_EVAL_SEEN)))
{
pm->op_pmflags |= PMf_CONST; /* const for long enough */
- prepend_elem(o->op_type, scalar(repl), o);
+ op_prepend_elem(o->op_type, scalar(repl), o);
}
else {
if (curop == repl && !PM_GETRE(pm)) { /* Has variables. */
/* Fake up a method call to VERSION */
meth = newSVpvs_share("VERSION");
veop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL,
- append_elem(OP_LIST,
- prepend_elem(OP_LIST, pack, list(version)),
+ op_append_elem(OP_LIST,
+ op_prepend_elem(OP_LIST, pack, list(version)),
newSVOP(OP_METHOD_NAMED, 0, meth)));
}
}
meth = aver
? newSVpvs_share("import") : newSVpvs_share("unimport");
imop = convert(OP_ENTERSUB, OPf_STACKED|OPf_SPECIAL,
- append_elem(OP_LIST,
- prepend_elem(OP_LIST, pack, list(arg)),
+ op_append_elem(OP_LIST,
+ op_prepend_elem(OP_LIST, pack, list(arg)),
newSVOP(OP_METHOD_NAMED, 0, meth)));
}
newSVOP(OP_CONST, 0, newSVpvs_share("BEGIN")),
NULL,
NULL,
- append_elem(OP_LINESEQ,
- append_elem(OP_LINESEQ,
+ op_append_elem(OP_LINESEQ,
+ op_append_elem(OP_LINESEQ,
newSTATEOP(0, NULL, newUNOP(OP_REQUIRE, 0, idop)),
newSTATEOP(0, NULL, veop)),
newSTATEOP(0, NULL, imop) ));
imop = NULL;
sv = va_arg(*args, SV*);
while (sv) {
- imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv));
+ imop = op_append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv));
sv = va_arg(*args, SV*);
}
}
ENTER;
SAVEVPTR(PL_curcop);
- lex_start(NULL, NULL, FALSE);
+ lex_start(NULL, NULL, 0);
utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0),
veop, modname, imop);
LEAVE;
if (gv && GvCVu(gv) && GvIMPORTED_CV(gv)) {
doop = ck_subr(newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, term,
+ op_append_elem(OP_LIST, term,
scalar(newUNOP(OP_RV2CV, 0,
newGVOP(OP_GV, 0, gv))))));
}
if (optype) {
if (optype == OP_ANDASSIGN || optype == OP_ORASSIGN || optype == OP_DORASSIGN) {
return newLOGOP(optype, 0,
- mod(scalar(left), optype),
+ op_lvalue(scalar(left), optype),
newUNOP(OP_SASSIGN, 0, scalar(right)));
}
else {
return newBINOP(optype, OPf_STACKED,
- mod(scalar(left), optype), scalar(right));
+ op_lvalue(scalar(left), optype), scalar(right));
}
}
/* Grandfathering $[ assignment here. Bletch.*/
/* Only simple assignments like C<< ($[) = 1 >> are allowed */
PL_eval_start = (left->op_type == OP_CONST) ? right : NULL;
- left = mod(left, OP_AASSIGN);
+ left = op_lvalue(left, OP_AASSIGN);
if (PL_eval_start)
PL_eval_start = 0;
else if (left->op_type == OP_CONST) {
right = newOP(OP_UNDEF, 0);
if (right->op_type == OP_READLINE) {
right->op_flags |= OPf_STACKED;
- return newBINOP(OP_NULL, flags, mod(scalar(left), OP_SASSIGN), scalar(right));
+ return newBINOP(OP_NULL, flags, op_lvalue(scalar(left), OP_SASSIGN),
+ scalar(right));
}
else {
PL_eval_start = right; /* Grandfathering $[ assignment here. Bletch.*/
o = newBINOP(OP_SASSIGN, flags,
- scalar(right), mod(scalar(left), OP_SASSIGN) );
+ scalar(right), op_lvalue(scalar(left), OP_SASSIGN) );
if (PL_eval_start)
PL_eval_start = 0;
else {
CopHINTS and a possible value in cop_hints_hash, so no need to copy it.
*/
cop->cop_warnings = DUP_WARNINGS(PL_curcop->cop_warnings);
- cop->cop_hints_hash = PL_curcop->cop_hints_hash;
- if (cop->cop_hints_hash) {
- HINTS_REFCNT_LOCK;
- cop->cop_hints_hash->refcounted_he_refcnt++;
- HINTS_REFCNT_UNLOCK;
- }
+ CopHINTHASH_set(cop, cophh_copy(CopHINTHASH_get(PL_curcop)));
if (label) {
Perl_store_cop_label(aTHX_ cop, label, strlen(label), 0);
if (flags & OPf_SPECIAL)
op_null((OP*)cop);
- return prepend_elem(OP_LINESEQ, (OP*)cop, o);
+ return op_prepend_elem(OP_LINESEQ, (OP*)cop, o);
}
/*
flip = newUNOP(OP_FLIP, flags, (OP*)range);
flop = newUNOP(OP_FLOP, 0, flip);
o = newUNOP(OP_NULL, 0, flop);
- linklist(flop);
+ LINKLIST(flop);
range->op_next = leftstart;
left->op_next = flip;
flip->op_next = o;
if (!flip->op_private || !flop->op_private)
- linklist(o); /* blow off optimizer unless constant */
+ LINKLIST(o); /* blow off optimizer unless constant */
return o;
}
}
}
- /* if block is null, the next append_elem() would put UNSTACK, a scalar
+ /* if block is null, the next op_append_elem() would put UNSTACK, a scalar
* op, in listop. This is wrong. [perl #27024] */
if (!block)
block = newOP(OP_NULL, 0);
- listop = append_elem(OP_LINESEQ, block, newOP(OP_UNSTACK, 0));
+ listop = op_append_elem(OP_LINESEQ, block, newOP(OP_UNSTACK, 0));
o = new_logop(OP_AND, 0, &expr, &listop);
if (listop)
o = newUNOP(OP_NULL, 0, o); /* or do {} while 1 loses outer block */
o->op_flags |= flags;
- o = scope(o);
+ o = op_scope(o);
o->op_flags |= OPf_SPECIAL; /* suppress POPBLOCK curpm restoration*/
return o;
}
/*
-=for apidoc Am|OP *|newWHILEOP|I32 flags|I32 debuggable|LOOP *loop|I32 whileline|OP *expr|OP *block|OP *cont|I32 has_my
+=for apidoc Am|OP *|newWHILEOP|I32 flags|I32 debuggable|LOOP *loop|OP *expr|OP *block|OP *cont|I32 has_my
Constructs, checks, and returns an op tree expressing a C<while> loop.
This is a heavyweight loop, with structure that allows exiting the loop
op and, shifted up eight bits, the eight bits of C<op_private> for
the C<leaveloop> op, except that (in both cases) some bits will be set
automatically. I<debuggable> is currently unused and should always be 1.
-I<whileline> is the line number that should be attributed to the loop's
-controlling expression. I<has_my> can be supplied as true to force the
+I<has_my> can be supplied as true to force the
loop body to be enclosed in its own scope.
=cut
*/
OP *
-Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop, I32
-whileline, OP *expr, OP *block, OP *cont, I32 has_my)
+Perl_newWHILEOP(pTHX_ I32 flags, I32 debuggable, LOOP *loop,
+ OP *expr, OP *block, OP *cont, I32 has_my)
{
dVAR;
OP *redo;
if (!block)
block = newOP(OP_NULL, 0);
else if (cont || has_my) {
- block = scope(block);
+ block = op_scope(block);
}
if (cont) {
OP * const unstack = newOP(OP_UNSTACK, 0);
if (!next)
next = unstack;
- cont = append_elem(OP_LINESEQ, cont, unstack);
+ cont = op_append_elem(OP_LINESEQ, cont, unstack);
}
assert(block);
- listop = append_list(OP_LINESEQ, (LISTOP*)block, (LISTOP*)cont);
+ listop = op_append_list(OP_LINESEQ, block, cont);
assert(listop);
redo = LINKLIST(listop);
if (expr) {
- PL_parser->copline = (line_t)whileline;
scalar(listop);
o = new_logop(OP_AND, 0, &expr, &listop);
if (o == expr && o->op_type == OP_CONST && !SvTRUE(cSVOPo->op_sv)) {
}
/*
-=for apidoc Am|OP *|newFOROP|I32 flags|char *label|line_t forline|OP *sv|OP *expr|OP *block|OP *cont
+=for apidoc Am|OP *|newFOROP|I32 flags|OP *sv|OP *expr|OP *block|OP *cont
Constructs, checks, and returns an op tree expressing a C<foreach>
loop (iteration through a list of values). This is a heavyweight loop,
I<flags> gives the eight bits of C<op_flags> for the C<leaveloop>
op and, shifted up eight bits, the eight bits of C<op_private> for
the C<leaveloop> op, except that (in both cases) some bits will be set
-automatically. I<forline> is the line number that should be attributed
-to the loop's list expression. If I<label> is non-null, it supplies
-the name of a label to attach to the state op at the start of the loop;
-this function takes ownership of the memory pointed at by I<label>,
-and will free it.
+automatically.
=cut
*/
OP *
-Perl_newFOROP(pTHX_ I32 flags, char *label, line_t forline, OP *sv, OP *expr, OP *block, OP *cont)
+Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont)
{
dVAR;
LOOP *loop;
iterpflags |= OPpITER_DEF;
}
if (expr->op_type == OP_RV2AV || expr->op_type == OP_PADAV) {
- expr = mod(force_list(scalar(ref(expr, OP_ITER))), OP_GREPSTART);
+ expr = op_lvalue(force_list(scalar(ref(expr, OP_ITER))), OP_GREPSTART);
iterflags |= OPf_STACKED;
}
else if (expr->op_type == OP_NULL &&
iterflags |= OPf_STACKED;
}
else {
- expr = mod(force_list(expr), OP_GREPSTART);
+ expr = op_lvalue(force_list(expr), OP_GREPSTART);
}
loop = (LOOP*)list(convert(OP_ENTERITER, iterflags,
- append_elem(OP_LIST, expr, scalar(sv))));
+ op_append_elem(OP_LIST, expr, scalar(sv))));
assert(!loop->op_next);
/* for my $x () sets OPpLVAL_INTRO;
* for our $x () sets OPpOUR_INTRO */
loop = (LOOP*)PerlMemShared_realloc(loop, sizeof(LOOP));
#endif
loop->op_targ = padoff;
- wop = newWHILEOP(flags, 1, loop, forline, newOP(OP_ITER, 0), block, cont, 0);
+ wop = newWHILEOP(flags, 1, loop, newOP(OP_ITER, 0), block, cont, 0);
if (madsv)
op_getmad(madsv, (OP*)loop, 'v');
- PL_parser->copline = forline;
- return newSTATEOP(0, label, wop);
+ return wop;
}
/*
/* Check whether it's going to be a goto &function */
if (label->op_type == OP_ENTERSUB
&& !(label->op_flags & OPf_STACKED))
- label = newUNOP(OP_REFGEN, 0, mod(label, OP_REFGEN));
+ label = newUNOP(OP_REFGEN, 0, op_lvalue(label, OP_REFGEN));
o = newUNOP(type, OPf_STACKED, label);
}
PL_hints |= HINT_BLOCK_SCOPE;
|| cond->op_type == OP_RV2HV
|| cond->op_type == OP_PADHV))
- return newUNOP(OP_REFGEN,
- 0, mod(cond, OP_REFGEN));
+ return newUNOP(OP_REFGEN, 0, op_lvalue(cond, OP_REFGEN));
else if(cond
&& (cond->op_type == OP_ASLICE
cond->op_flags |= ~(OPf_WANT_SCALAR | OPf_REF);
cond->op_flags |= OPf_WANT_LIST;
- return newANONLIST(mod(cond, OP_ANONLIST));
+ return newANONLIST(op_lvalue(cond, OP_ANONLIST));
}
else
return newGIVWHENOP(
cond_op,
- append_elem(block->op_type, block, newOP(OP_BREAK, OPf_SPECIAL)),
+ op_append_elem(block->op_type, block, newOP(OP_BREAK, OPf_SPECIAL)),
OP_ENTERWHEN, OP_LEAVEWHEN, 0);
}
pad_fixup_inner_anons(CvPADLIST(cv), PL_compcv, cv);
if (PERLDB_INTER)/* Advice debugger on the new sub. */
++PL_sub_generation;
- if (CvSTASH(cv))
- sv_del_backref(MUTABLE_SV(CvSTASH(cv)), MUTABLE_SV(cv));
}
else {
/* Might have had built-in attributes applied -- propagate them. */
if (!CvGV(cv)) {
CvGV_set(cv, gv);
CvFILE_set_from_cop(cv, PL_curcop);
- CvSTASH(cv) = PL_curstash;
- if (PL_curstash)
- Perl_sv_add_backref(aTHX_ MUTABLE_SV(PL_curstash), MUTABLE_SV(cv));
+ CvSTASH_set(cv, PL_curstash);
}
if (attrs) {
/* Need to do a C<use attributes $stash_of_cv,\&cv,@attrs>. */
PL_breakable_sub_gen++;
if (CvLVALUE(cv)) {
CvROOT(cv) = newUNOP(OP_LEAVESUBLV, 0,
- mod(scalarseq(block), OP_LEAVESUBLV));
+ op_lvalue(scalarseq(block), OP_LEAVESUBLV));
block->op_attached = 1;
}
else {
/* establish postfix order */
enter->op_next = (OP*)enter;
- o = prepend_elem(OP_LINESEQ, (OP*)enter, (OP*)kid);
+ o = op_prepend_elem(OP_LINESEQ, (OP*)enter, (OP*)kid);
o->op_type = OP_LEAVETRY;
o->op_ppaddr = PL_ppaddr[OP_LEAVETRY];
enter->op_other = o;
#endif
kid->op_private = 0;
kid->op_ppaddr = PL_ppaddr[OP_GV];
+ /* FAKE globs in the symbol table cause weird bugs (#77810) */
+ SvFAKE_off(gv);
}
}
return o;
}
else if (kid->op_type != OP_RV2AV && kid->op_type != OP_PADAV)
bad_type(numargs, "array", PL_op_desc[type], kid);
- mod(kid, type);
+ op_lvalue(kid, type);
break;
case OA_HVREF:
if (kid->op_type == OP_CONST &&
}
else if (kid->op_type != OP_RV2HV && kid->op_type != OP_PADHV)
bad_type(numargs, "hash", PL_op_desc[type], kid);
- mod(kid, type);
+ op_lvalue(kid, type);
break;
case OA_CVREF:
{
OP * const newop = newUNOP(OP_NULL, 0, kid);
kid->op_sibling = 0;
- linklist(kid);
+ LINKLIST(kid);
newop->op_next = newop;
kid = newop;
kid->op_sibling = sibl;
name = "__ANONIO__";
len = 10;
}
- mod(kid, type);
+ op_lvalue(kid, type);
}
if (name) {
SV *namesv;
scalar(kid);
break;
case OA_SCALARREF:
- mod(scalar(kid), type);
+ op_lvalue(scalar(kid), type);
break;
}
oa >>= 4;
o = ck_fun(o);
if ((o->op_flags & OPf_KIDS) && !cLISTOPo->op_first->op_sibling)
- append_elem(OP_GLOB, o, newDEFSVOP());
+ op_append_elem(OP_GLOB, o, newDEFSVOP());
if (!((gv = gv_fetchpvs("glob", GV_NOTQUAL, SVt_PVCV))
&& GvCVu(gv) && GvIMPORTED_CV(gv)))
#endif /* PERL_EXTERNAL_GLOB */
if (gv && GvCVu(gv) && GvIMPORTED_CV(gv)) {
- append_elem(OP_GLOB, o,
+ op_append_elem(OP_GLOB, o,
newSVOP(OP_CONST, 0, newSViv(PL_glob_index++)));
o->op_type = OP_LIST;
o->op_ppaddr = PL_ppaddr[OP_LIST];
cLISTOPo->op_first->op_ppaddr = PL_ppaddr[OP_PUSHMARK];
cLISTOPo->op_first->op_targ = 0;
o = newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, o,
+ op_append_elem(OP_LIST, o,
scalar(newUNOP(OP_RV2CV, 0,
newGVOP(OP_GV, 0, gv)))));
o = newUNOP(OP_NULL, 0, ck_subr(o));
}
gv = newGVgen("main");
gv_IOadd(gv);
- append_elem(OP_GLOB, o, newGVOP(OP_GV, 0, gv));
+ op_append_elem(OP_GLOB, o, newGVOP(OP_GV, 0, gv));
scalarkids(o);
return o;
}
if (!kid || !kid->op_sibling)
return too_few_arguments(o,OP_DESC(o));
for (kid = kid->op_sibling; kid; kid = kid->op_sibling)
- mod(kid, OP_GREPSTART);
+ op_lvalue(kid, OP_GREPSTART);
return (OP*)gwop;
}
}
if (!kid)
- append_elem(o->op_type, o, newDEFSVOP());
+ op_append_elem(o->op_type, o, newDEFSVOP());
return listkids(o);
}
op_free(o);
#endif
newop = ck_subr(newUNOP(OP_ENTERSUB, OPf_STACKED,
- append_elem(OP_LIST, kid,
+ op_append_elem(OP_LIST, kid,
scalar(newUNOP(OP_RV2CV, 0,
newGVOP(OP_GV, 0,
gv))))));
kid = cLISTOPo->op_first->op_sibling;
if (CvLVALUE(PL_compcv)) {
for (; kid; kid = kid->op_sibling)
- mod(kid, OP_LEAVESUBLV);
+ op_lvalue(kid, OP_LEAVESUBLV);
} else {
for (; kid; kid = kid->op_sibling)
if ((kid->op_type == OP_NULL)
OP *kid = cUNOPx(firstkid)->op_first; /* get past null */
if (kid->op_type == OP_SCOPE || kid->op_type == OP_LEAVE) {
- linklist(kid);
+ LINKLIST(kid);
if (kid->op_type == OP_SCOPE) {
k = kid->op_next;
kid->op_next = 0;
}
if (!kid->op_sibling)
- append_elem(OP_SPLIT, o, newDEFSVOP());
+ op_append_elem(OP_SPLIT, o, newDEFSVOP());
kid = kid->op_sibling;
scalar(kid);
if (!kid->op_sibling)
- append_elem(OP_SPLIT, o, newSVOP(OP_CONST, 0, newSViv(0)));
+ op_append_elem(OP_SPLIT, o, newSVOP(OP_CONST, 0, newSViv(0)));
assert(kid->op_sibling);
kid = kid->op_sibling;
for (aop = aop->op_sibling; aop->op_sibling; aop = aop->op_sibling) {
if (!(PL_madskills && aop->op_type == OP_STUB)) {
list(aop);
- mod(aop, OP_ENTERSUB);
+ op_lvalue(aop, OP_ENTERSUB);
}
}
return entersubop;
return too_many_arguments(entersubop, gv_ename(namegv));
switch (*proto) {
- case ';':
- optional = 1;
- proto++;
- continue;
- case '_':
- /* _ must be at the end */
- if (proto[1] && proto[1] != ';')
- goto oops;
- case '$':
- proto++;
- arg++;
- scalar(aop);
- break;
- case '%':
- case '@':
- list(aop);
- arg++;
- break;
- case '&':
- proto++;
- arg++;
- if (o3->op_type != OP_REFGEN && o3->op_type != OP_UNDEF)
- bad_type(arg,
- arg == 1 ? "block or sub {}" : "sub {}",
- gv_ename(namegv), o3);
- break;
- case '*':
- /* '*' allows any scalar type, including bareword */
- proto++;
- arg++;
- if (o3->op_type == OP_RV2GV)
- goto wrapref; /* autoconvert GLOB -> GLOBref */
- else if (o3->op_type == OP_CONST)
- o3->op_private &= ~OPpCONST_STRICT;
- else if (o3->op_type == OP_ENTERSUB) {
- /* accidental subroutine, revert to bareword */
- OP *gvop = ((UNOP*)o3)->op_first;
- if (gvop && gvop->op_type == OP_NULL) {
- gvop = ((UNOP*)gvop)->op_first;
- if (gvop) {
- for (; gvop->op_sibling; gvop = gvop->op_sibling)
- ;
- if (gvop &&
- (gvop->op_private & OPpENTERSUB_NOPAREN) &&
- (gvop = ((UNOP*)gvop)->op_first) &&
- gvop->op_type == OP_GV)
- {
- GV * const gv = cGVOPx_gv(gvop);
- OP * const sibling = aop->op_sibling;
- SV * const n = newSVpvs("");
+ case ';':
+ optional = 1;
+ proto++;
+ continue;
+ case '_':
+ /* _ must be at the end */
+ if (proto[1] && proto[1] != ';')
+ goto oops;
+ case '$':
+ proto++;
+ arg++;
+ scalar(aop);
+ break;
+ case '%':
+ case '@':
+ list(aop);
+ arg++;
+ break;
+ case '&':
+ proto++;
+ arg++;
+ if (o3->op_type != OP_REFGEN && o3->op_type != OP_UNDEF)
+ bad_type(arg,
+ arg == 1 ? "block or sub {}" : "sub {}",
+ gv_ename(namegv), o3);
+ break;
+ case '*':
+ /* '*' allows any scalar type, including bareword */
+ proto++;
+ arg++;
+ if (o3->op_type == OP_RV2GV)
+ goto wrapref; /* autoconvert GLOB -> GLOBref */
+ else if (o3->op_type == OP_CONST)
+ o3->op_private &= ~OPpCONST_STRICT;
+ else if (o3->op_type == OP_ENTERSUB) {
+ /* accidental subroutine, revert to bareword */
+ OP *gvop = ((UNOP*)o3)->op_first;
+ if (gvop && gvop->op_type == OP_NULL) {
+ gvop = ((UNOP*)gvop)->op_first;
+ if (gvop) {
+ for (; gvop->op_sibling; gvop = gvop->op_sibling)
+ ;
+ if (gvop &&
+ (gvop->op_private & OPpENTERSUB_NOPAREN) &&
+ (gvop = ((UNOP*)gvop)->op_first) &&
+ gvop->op_type == OP_GV)
+ {
+ GV * const gv = cGVOPx_gv(gvop);
+ OP * const sibling = aop->op_sibling;
+ SV * const n = newSVpvs("");
#ifdef PERL_MAD
- OP * const oldaop = aop;
+ OP * const oldaop = aop;
#else
- op_free(aop);
+ op_free(aop);
#endif
- gv_fullname4(n, gv, "", FALSE);
- aop = newSVOP(OP_CONST, 0, n);
- op_getmad(oldaop,aop,'O');
- prev->op_sibling = aop;
- aop->op_sibling = sibling;
+ gv_fullname4(n, gv, "", FALSE);
+ aop = newSVOP(OP_CONST, 0, n);
+ op_getmad(oldaop,aop,'O');
+ prev->op_sibling = aop;
+ aop->op_sibling = sibling;
+ }
}
}
}
- }
- scalar(aop);
- break;
- case '[': case ']':
- goto oops;
- break;
- case '\\':
- proto++;
- arg++;
- again:
- switch (*proto++) {
- case '[':
- if (contextclass++ == 0) {
- e = strchr(proto, ']');
- if (!e || e == proto)
- goto oops;
- }
- else
- goto oops;
- goto again;
- break;
- case ']':
- if (contextclass) {
- const char *p = proto;
- const char *const end = proto;
- contextclass = 0;
- while (*--p != '[') {}
- bad_type(arg, Perl_form(aTHX_ "one of %.*s",
- (int)(end - p), p),
- gv_ename(namegv), o3);
- } else
- goto oops;
- break;
- case '*':
- if (o3->op_type == OP_RV2GV)
- goto wrapref;
- if (!contextclass)
- bad_type(arg, "symbol", gv_ename(namegv), o3);
- break;
- case '&':
- if (o3->op_type == OP_ENTERSUB)
- goto wrapref;
- if (!contextclass)
- bad_type(arg, "subroutine entry", gv_ename(namegv),
- o3);
- break;
- case '$':
- if (o3->op_type == OP_RV2SV ||
- o3->op_type == OP_PADSV ||
- o3->op_type == OP_HELEM ||
- o3->op_type == OP_AELEM)
- goto wrapref;
- if (!contextclass)
- bad_type(arg, "scalar", gv_ename(namegv), o3);
- break;
- case '@':
+ scalar(aop);
+ break;
+ case '+':
+ proto++;
+ arg++;
if (o3->op_type == OP_RV2AV ||
- o3->op_type == OP_PADAV)
- goto wrapref;
- if (!contextclass)
- bad_type(arg, "array", gv_ename(namegv), o3);
+ o3->op_type == OP_PADAV ||
+ o3->op_type == OP_RV2HV ||
+ o3->op_type == OP_PADHV
+ ) {
+ goto wrapref;
+ }
+ scalar(aop);
break;
- case '%':
- if (o3->op_type == OP_RV2HV ||
- o3->op_type == OP_PADHV)
- goto wrapref;
- if (!contextclass)
- bad_type(arg, "hash", gv_ename(namegv), o3);
+ case '[': case ']':
+ goto oops;
break;
- wrapref:
- {
- OP* const kid = aop;
- OP* const sib = kid->op_sibling;
- kid->op_sibling = 0;
- aop = newUNOP(OP_REFGEN, 0, kid);
- aop->op_sibling = sib;
- prev->op_sibling = aop;
- }
- if (contextclass && e) {
- proto = e + 1;
- contextclass = 0;
+ case '\\':
+ proto++;
+ arg++;
+ again:
+ switch (*proto++) {
+ case '[':
+ if (contextclass++ == 0) {
+ e = strchr(proto, ']');
+ if (!e || e == proto)
+ goto oops;
+ }
+ else
+ goto oops;
+ goto again;
+ break;
+ case ']':
+ if (contextclass) {
+ const char *p = proto;
+ const char *const end = proto;
+ contextclass = 0;
+ while (*--p != '[') {}
+ bad_type(arg, Perl_form(aTHX_ "one of %.*s",
+ (int)(end - p), p),
+ gv_ename(namegv), o3);
+ } else
+ goto oops;
+ break;
+ case '*':
+ if (o3->op_type == OP_RV2GV)
+ goto wrapref;
+ if (!contextclass)
+ bad_type(arg, "symbol", gv_ename(namegv), o3);
+ break;
+ case '&':
+ if (o3->op_type == OP_ENTERSUB)
+ goto wrapref;
+ if (!contextclass)
+ bad_type(arg, "subroutine entry", gv_ename(namegv),
+ o3);
+ break;
+ case '$':
+ if (o3->op_type == OP_RV2SV ||
+ o3->op_type == OP_PADSV ||
+ o3->op_type == OP_HELEM ||
+ o3->op_type == OP_AELEM)
+ goto wrapref;
+ if (!contextclass)
+ bad_type(arg, "scalar", gv_ename(namegv), o3);
+ break;
+ case '@':
+ if (o3->op_type == OP_RV2AV ||
+ o3->op_type == OP_PADAV)
+ goto wrapref;
+ if (!contextclass)
+ bad_type(arg, "array", gv_ename(namegv), o3);
+ break;
+ case '%':
+ if (o3->op_type == OP_RV2HV ||
+ o3->op_type == OP_PADHV)
+ goto wrapref;
+ if (!contextclass)
+ bad_type(arg, "hash", gv_ename(namegv), o3);
+ break;
+ wrapref:
+ {
+ OP* const kid = aop;
+ OP* const sib = kid->op_sibling;
+ kid->op_sibling = 0;
+ aop = newUNOP(OP_REFGEN, 0, kid);
+ aop->op_sibling = sib;
+ prev->op_sibling = aop;
+ }
+ if (contextclass && e) {
+ proto = e + 1;
+ contextclass = 0;
+ }
+ break;
+ default: goto oops;
}
+ if (contextclass)
+ goto again;
break;
- default: goto oops;
- }
- if (contextclass)
- goto again;
- break;
- case ' ':
- proto++;
- continue;
- default:
- oops:
- Perl_croak(aTHX_ "Malformed prototype for %s: %"SVf,
- gv_ename(namegv), SVfARG(protosv));
+ case ' ':
+ proto++;
+ continue;
+ default:
+ oops:
+ Perl_croak(aTHX_ "Malformed prototype for %s: %"SVf,
+ gv_ename(namegv), SVfARG(protosv));
}
- mod(aop, OP_ENTERSUB);
+ op_lvalue(aop, OP_ENTERSUB);
prev = aop;
aop = aop->op_sibling;
}