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
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
newSVOP(OP_CONST, 0, stashsv),
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 */
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)
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) {
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;
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 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
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 (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);
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) {
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,
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
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 {
#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:
{
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;
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;
}
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)
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;
}