This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
deparse subroutine signatures
[perl5.git] / pp.c
diff --git a/pp.c b/pp.c
index 5010065..1fba3d9 100644 (file)
--- a/pp.c
+++ b/pp.c
@@ -809,17 +809,6 @@ S_do_chomp(pTHX_ SV *retval, SV *sv, bool chomping)
             Perl_croak_no_modify();
     }
 
-    if (IN_ENCODING) {
-       if (!SvUTF8(sv)) {
-           /* XXX, here sv is utf8-ized as a side-effect!
-              If encoding.pm is used properly, almost string-generating
-              operations, including literal strings, chr(), input data, etc.
-              should have been utf8-ized already, right?
-           */
-           sv_recode_to_utf8(sv, _get_encoding());
-       }
-    }
-
     s = SvPV(sv, len);
     if (chomping) {
        if (s && len) {
@@ -861,14 +850,6 @@ S_do_chomp(pTHX_ SV *retval, SV *sv, bool chomping)
                        }
                        rsptr = temp_buffer;
                    }
-                   else if (IN_ENCODING) {
-                       /* RS is 8 bit, encoding.pm is used.
-                        * Do not recode PL_rs as a side-effect. */
-                       svrecode = newSVpvn(rsptr, rslen);
-                       sv_recode_to_utf8(svrecode, _get_encoding());
-                       rsptr = SvPV_const(svrecode, rslen);
-                       rs_charlen = sv_len_utf8(svrecode);
-                   }
                    else {
                        /* RS is 8 bit, scalar is utf8.  */
                        temp_buffer = (char*)bytes_to_utf8((U8*)rsptr, &rslen);
@@ -3544,7 +3525,7 @@ PP(pp_index)
     little_utf8 = DO_UTF8(little);
     if (big_utf8 ^ little_utf8) {
        /* One needs to be upgraded.  */
-       if (little_utf8 && !IN_ENCODING) {
+       if (little_utf8) {
            /* Well, maybe instead we might be able to downgrade the small
               string?  */
            char * const pv = (char*)bytes_from_utf8((U8 *)little_p, &llen,
@@ -3566,11 +3547,7 @@ PP(pp_index)
            temp = little_utf8
                ? newSVpvn(big_p, biglen) : newSVpvn(little_p, llen);
 
-           if (IN_ENCODING) {
-               sv_recode_to_utf8(temp, _get_encoding());
-           } else {
-               sv_utf8_upgrade(temp);
-           }
+           sv_utf8_upgrade(temp);
            if (little_utf8) {
                big = temp;
                big_utf8 = TRUE;
@@ -3652,13 +3629,6 @@ PP(pp_ord)
     STRLEN len;
     const U8 *s = (U8*)SvPV_const(argsv, len);
 
-    if (IN_ENCODING && SvPOK(argsv) && !DO_UTF8(argsv)) {
-        SV * const tmpsv = sv_2mortal(newSVsv(argsv));
-        s = (U8*)sv_recode_to_utf8(tmpsv, _get_encoding());
-        len = UTF8SKIP(s);  /* Should be well-formed; so this is its length */
-        argsv = tmpsv;
-    }
-
     SETu(DO_UTF8(argsv)
            ? utf8n_to_uvchr(s, len, 0, UTF8_ALLOW_ANYUV)
            : (UV)(*s));
@@ -3720,22 +3690,6 @@ PP(pp_chr)
     *tmps = '\0';
     (void)SvPOK_only(TARG);
 
-    if (IN_ENCODING && !IN_BYTES) {
-        sv_recode_to_utf8(TARG, _get_encoding());
-       tmps = SvPVX(TARG);
-       if (SvCUR(TARG) == 0
-           || ! is_utf8_string((U8*)tmps, SvCUR(TARG))
-           || UTF8_IS_REPLACEMENT((U8*) tmps, (U8*) tmps + SvCUR(TARG)))
-       {
-           SvGROW(TARG, 2);
-           tmps = SvPVX(TARG);
-           SvCUR_set(TARG, 1);
-           *tmps++ = (char)value;
-           *tmps = '\0';
-           SvUTF8_off(TARG);
-       }
-    }
-
     SETTARG;
     return NORMAL;
 }
@@ -4832,12 +4786,23 @@ PP(pp_akeys)
        PUSHi(av_tindex(array) + 1);
     }
     else if (gimme == G_ARRAY) {
+      if (UNLIKELY(PL_op->op_private & OPpMAYBE_LVSUB)) {
+        const I32 flags = is_lvalue_sub();
+        if (flags && !(flags & OPpENTERSUB_INARGS))
+            /* diag_listed_as: Can't modify %s in %s */
+            Perl_croak(aTHX_
+                      "Can't modify keys on array in list assignment");
+      }
+      {
         IV n = Perl_av_len(aTHX_ array);
         IV i;
 
         EXTEND(SP, n + 1);
 
-       if (PL_op->op_type == OP_AKEYS) {
+       if (  PL_op->op_type == OP_AKEYS
+          || (  PL_op->op_type == OP_AVHVSWITCH
+             && (PL_op->op_private & 3) + OP_AEACH == OP_AKEYS  ))
+       {
            for (i = 0;  i <= n;  i++) {
                mPUSHi(i);
            }
@@ -4848,6 +4813,7 @@ PP(pp_akeys)
                PUSHs(elem ? *elem : &PL_sv_undef);
            }
        }
+      }
     }
     RETURN;
 }
@@ -5158,7 +5124,8 @@ PP(pp_kvhslice)
        if (flags) {
            if (!(flags & OPpENTERSUB_INARGS))
                /* diag_listed_as: Can't modify %s in %s */
-              Perl_croak(aTHX_ "Can't modify key/value hash slice in list assignment");
+              Perl_croak(aTHX_ "Can't modify key/value hash slice in %s assignment",
+                                GIMME_V == G_ARRAY ? "list" : "scalar");
           lval = flags;
        }
     }
@@ -6207,7 +6174,7 @@ PP(pp_lock)
 }
 
 
-/* used for: pp_padany(), pp_mapstart(), pp_custom(); plus any system ops
+/* used for: pp_padany(), pp_custom(); plus any system ops
  * that aren't implemented on a particular platform */
 
 PP(unimplemented_op)
@@ -6228,6 +6195,18 @@ PP(unimplemented_op)
     DIE(aTHX_ "panic: unimplemented op %s (#%d) called", name, op_type);
 }
 
+static void
+S_maybe_unwind_defav(pTHX)
+{
+    if (CX_CUR()->cx_type & CXp_HASARGS) {
+       PERL_CONTEXT *cx = CX_CUR();
+
+        assert(CxHASARGS(cx));
+        cx_popsub_args(cx);
+       cx->cx_type &= ~CXp_HASARGS;
+    }
+}
+
 /* For sorting out arguments passed to a &CORE:: subroutine */
 PP(pp_coreargs)
 {
@@ -6298,13 +6277,39 @@ PP(pp_coreargs)
                svp++;
            }
            RETURN;
+       case OA_AVREF:
+           if (!numargs) {
+               GV *gv;
+               if (CvUNIQUE(find_runcv_where(FIND_RUNCV_level_eq,1,NULL)))
+                   gv = PL_argvgv;
+               else {
+                   S_maybe_unwind_defav(aTHX);
+                   gv = PL_defgv;
+               }
+               PUSHs((SV *)GvAVn(gv));
+               break;
+           }
+           if (!svp || !*svp || !SvROK(*svp)
+            || SvTYPE(SvRV(*svp)) != SVt_PVAV)
+               DIE(aTHX_
+               /* diag_listed_as: Type of arg %d to &CORE::%s must be %s*/
+                "Type of arg %d to &CORE::%s must be array reference",
+                 whicharg, PL_op_desc[opnum]
+               );
+           PUSHs(SvRV(*svp));
+           break;
        case OA_HVREF:
            if (!svp || !*svp || !SvROK(*svp)
-            || SvTYPE(SvRV(*svp)) != SVt_PVHV)
+            || (  SvTYPE(SvRV(*svp)) != SVt_PVHV
+               && (  opnum == OP_DBMCLOSE || opnum == OP_DBMOPEN
+                  || SvTYPE(SvRV(*svp)) != SVt_PVAV  )))
                DIE(aTHX_
                /* diag_listed_as: Type of arg %d to &CORE::%s must be %s*/
-                "Type of arg %d to &CORE::%s must be hash reference",
-                 whicharg, OP_DESC(PL_op->op_next)
+                "Type of arg %d to &CORE::%s must be hash%s reference",
+                 whicharg, PL_op_desc[opnum],
+                 opnum == OP_DBMCLOSE || opnum == OP_DBMOPEN
+                    ? ""
+                    : " or array"
                );
            PUSHs(SvRV(*svp));
            break;
@@ -6349,15 +6354,10 @@ PP(pp_coreargs)
                       : "reference to one of [$@%*]"
                );
            PUSHs(SvRV(*svp));
-           if (opnum == OP_UNDEF && SvRV(*svp) == (SV *)PL_defgv
-            && CX_CUR()->cx_type & CXp_HASARGS) {
+           if (opnum == OP_UNDEF && SvRV(*svp) == (SV *)PL_defgv) {
                /* Undo @_ localisation, so that sub exit does not undo
                   part of our undeffing. */
-               PERL_CONTEXT *cx = CX_CUR();
-
-                assert(CxHASARGS(cx));
-                cx_popsub_args(cx);;
-               cx->cx_type &= ~CXp_HASARGS;
+               S_maybe_unwind_defav(aTHX);
            }
          }
          break;
@@ -6370,6 +6370,15 @@ PP(pp_coreargs)
     RETURN;
 }
 
+PP(pp_avhvswitch)
+{
+    dVAR; dSP;
+    return PL_ppaddr[
+               (SvTYPE(TOPs) == SVt_PVAV ? OP_AEACH : OP_EACH)
+                   + (PL_op->op_private & 3)
+          ](aTHX);
+}
+
 PP(pp_runcv)
 {
     dSP;
@@ -6606,6 +6615,212 @@ PP(pp_anonconst)
     RETURN;
 }
 
+
+/* process one subroutine argument - typically when the sub has a signature:
+ * introduce PL_curpad[op_targ] and assign to it the value
+ *  for $:   (OPf_STACKED ? *sp : $_[N])
+ *  for @/%: @_[N..$#_]
+ *
+ * It's equivalent to 
+ *    my $foo = $_[N];
+ * or
+ *    my $foo = (value-on-stack)
+ * or
+ *    my @foo = @_[N..$#_]
+ * etc
+ *
+ * It assumes that the pad var is currently uninitialised, so this op
+ * should only be used at the start of a sub, where its not possible to
+ * skip the op (e.g. no 'my $x if $cond' stuff for example).
+ */
+
+PP(pp_argelem)
+{
+    dTARG;
+    SV *val;
+    SV ** padentry;
+    OP *o = PL_op;
+    AV *defav = GvAV(PL_defgv); /* @_ */
+    UV ix = PTR2UV(cUNOP_AUXo->op_aux);
+    IV argc;
+    SV **argv;
+
+    assert(!SvMAGICAL(defav));
+
+    /* do 'my $var, @var or %var' action */
+    padentry = &(PAD_SVl(o->op_targ));
+    save_clearsv(padentry);
+    targ = *padentry;
+
+    if ((o->op_private & OPpARGELEM_MASK) == OPpARGELEM_SV) {
+        if (o->op_flags & OPf_STACKED) {
+            dSP;
+            val = POPs;
+            PUTBACK;
+        }
+        else {
+            /* should already have been checked */
+            assert(ix < I32_MAX && AvFILLp(defav) >= (I32)ix);
+            val = AvARRAY(defav)[ix];
+            if (UNLIKELY(!val))
+                val = &PL_sv_undef;
+        }
+
+        /* $var = $val */
+
+        /* cargo-culted from pp_sassign */
+        assert(TAINTING_get || !TAINT_get);
+        if (UNLIKELY(TAINT_get) && !SvTAINTED(val))
+            TAINT_NOT;
+
+        /* Short-cut assignment of IV and RV values as these are
+         * common and simple. For RVs, it's likely that on
+         * subsequent calls to a function, targ is already of the
+         * correct storage class */
+        if (LIKELY(!SvMAGICAL(val))) {
+            /* just an IV */
+            if ((SvFLAGS(val) & (SVf_IOK|SVf_NOK|SVf_POK|SVf_IVisUV)) == SVf_IOK) {
+                IV i = SvIVX(val);
+                if (LIKELY(SvTYPE(targ) == SVt_IV)) {
+                    assert(!SvOK(targ));
+                    assert(!SvMAGICAL(targ));
+                    (void)SvIOK_only(targ);
+                    SvIV_set(targ, i);
+                }
+                else
+                    sv_setiv(targ, i);
+            }
+            else if (SvROK(val) && SvTYPE(targ) == SVt_IV) {
+                /* quick ref assignment */
+                assert(!SvOK(targ));
+                SvRV_set(targ, SvREFCNT_inc(SvRV(val)));
+                SvROK_on(targ);
+            }
+            else
+                sv_setsv(targ, val);
+        }
+        else
+            sv_setsv(targ, val);
+        return o->op_next;
+    }
+
+    /* must be AV or HV */
+
+    assert(!(o->op_flags & OPf_STACKED));
+    argc = ((IV)AvFILLp(defav) + 1) - (IV)ix;
+    assert(!SvMAGICAL(targ));
+    if (argc <= 0)
+        return o->op_next;
+    argv = AvARRAY(defav) + ix;
+    assert(argv);
+
+    /* This is a copy of the relevant parts of pp_aassign().
+     * We *know* that @foo / %foo is a plain empty lexical at this point,
+     * so we can avoid a lot of the extra baggage.
+     * We know, because all the usual tricks like 'my @a if 0',
+     * 'foo: my @a = ...; goto foo' can't be done with signatures.
+     */
+    if ((o->op_private & OPpARGELEM_MASK) == OPpARGELEM_AV) {
+        UV i = 0;
+
+        assert(AvFILLp((AV*)targ) == -1); /* can skip av_clear() */
+        av_extend((AV*)targ, argc);
+
+        while (argc--) {
+            SV *tmpsv;
+            SV *arg = *argv++;
+            tmpsv = newSV(0);
+            sv_setsv(tmpsv, arg);
+            av_store((AV*)targ, i++, tmpsv);
+            TAINT_NOT;
+        }
+
+    }
+    else {
+        assert((o->op_private & OPpARGELEM_MASK) == OPpARGELEM_HV);
+
+        assert(argc % 2 == 0);
+        assert(!HvTOTALKEYS(targ)); /* can skip hv_clear() */
+
+        while (argc) {
+            SV *tmpsv;
+            SV *key = *argv++;
+            SV *val = *argv++;
+
+            assert(key); assert(val);
+            argc -= 2;
+            if (UNLIKELY(SvGMAGICAL(key)))
+                key = sv_mortalcopy(key);
+            tmpsv = newSV(0);
+            sv_setsv(tmpsv, val);
+            hv_store_ent((HV*)targ, key, tmpsv, 0);
+            TAINT_NOT;
+        }
+    }
+
+    return o->op_next;
+}
+
+/* Handle a default value for one subroutine argument (typically as part
+ * of a subroutine signature).
+ * It's equivalent to
+ *    @_ > op_targ ? $_[op_targ] : result_of(op_other)
+ *
+ * Intended to be used where op_next is an OP_ARGELEM
+ *
+ * We abuse the op_targ field slightly: it's an index into @_ rather than
+ * into PL_curpad.
+ */
+
+PP(pp_argdefelem)
+{
+    OP * const o = PL_op;
+    AV *defav = GvAV(PL_defgv); /* @_ */
+    PADOFFSET ix = o->op_targ;
+
+    assert(!SvMAGICAL(defav));
+    assert(ix < I32_MAX);
+    if (AvFILLp(defav) >= (I32)ix) {
+        dSP;
+        XPUSHs(AvARRAY(defav)[ix]);
+        RETURN;
+    }
+    return cLOGOPo->op_other;
+}
+
+
+
+/* Check a  a subs arguments - i.e. that it has the correct number of args
+ * (and anything else we might think of in future). Typically used with
+ * signatured subs.
+ */
+
+PP(pp_argcheck)
+{
+    OP * const o       = PL_op;
+    UNOP_AUX_item *aux = cUNOP_AUXo->op_aux;
+    UV   params        = aux[0].uv;
+    UV   opt_params    = aux[1].uv;
+    char slurpy        = (char)(aux[2].iv);
+    AV  *defav         = GvAV(PL_defgv); /* @_ */
+    UV argc;
+    bool too_few;
+
+    assert(!SvMAGICAL(defav));
+    argc = (UV)(AvFILLp(defav) + 1);
+    too_few = (argc < (params - opt_params));
+
+    if (UNLIKELY(too_few || (!slurpy && argc > params)))
+        Perl_croak_caller("Too %s arguments for subroutine",
+                            too_few ? "few" : "many");
+
+    if (UNLIKELY(slurpy == '%' && argc > params && (argc - params) % 2))
+        Perl_croak_caller("Odd name/value argument for subroutine");
+
+
+    return NORMAL;
+}
+
 /*
  * ex: set ts=8 sts=4 sw=4 et:
  */