[perl #31697] [PATCH] B::Showlex::newlex enhancement and pod
[p5sagit/p5-mst-13.2.git] / op.c
diff --git a/op.c b/op.c
index 02144e8..d99045b 100644 (file)
--- a/op.c
+++ b/op.c
  * either way, as the saying is, if you follow me."  --the Gaffer
  */
 
+/* This file contains the functions that create, manipulate and optimize
+ * the OP structures that hold a compiled perl program.
+ *
+ * A Perl program is compiled into a tree of OPs. Each op contains
+ * structural pointers (eg to its siblings and the next op in the
+ * execution sequence), a pointer to the function that would execute the
+ * op, plus any data specific to that op. For example, an OP_CONST op
+ * points to the pp_const() function and to an SV containing the constant
+ * value. When pp_const() is executed, its job is to push that SV onto the
+ * stack.
+ *
+ * OPs are mainly created by the newFOO() functions, which are mainly
+ * called from the parser (in perly.y) as the code is parsed. For example
+ * the Perl code $a + $b * $c would cause the equivalent of the following
+ * to be called (oversimplifying a bit):
+ *
+ *  newBINOP(OP_ADD, flags,
+ *     newSVREF($a),
+ *     newBINOP(OP_MULTIPLY, flags, newSVREF($b), newSVREF($c))
+ *  )
+ *
+ * Note that during the build of miniperl, a temporary copy of this file
+ * is made, called opmini.c.
+ */
 
 #include "EXTERN.h"
 #define PERL_IN_OP_C
@@ -661,6 +685,15 @@ Perl_scalarvoid(pTHX_ OP *o)
            useless = OP_DESC(o);
        break;
 
+    case OP_NOT:
+       kid = cUNOPo->op_first;
+       if (kid->op_type != OP_MATCH && kid->op_type != OP_SUBST &&
+           kid->op_type != OP_TRANS) {
+               goto func_ops;
+       }
+       useless = "negative pattern binding (!~)";
+       break;
+
     case OP_RV2GV:
     case OP_RV2SV:
     case OP_RV2AV:
@@ -3130,6 +3163,7 @@ Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
                && (left->op_private & OPpLVAL_INTRO))
        {
            op_free(right);
+           left->op_flags &= ~(OPf_REF|OPf_SPECIAL);
            return left;
        }
        curop = list(force_list(left));
@@ -4059,11 +4093,19 @@ Perl_newATTRSUB(pTHX_ I32 floor, OP *o, OP *proto, OP *attrs, OP *block)
     char *name;
     char *aname;
     GV *gv;
-    char *ps = proto ? SvPVx(((SVOP*)proto)->op_sv, n_a) : Nullch;
+    char *ps;
     register CV *cv=0;
     SV *const_sv;
 
     name = o ? SvPVx(cSVOPo->op_sv, n_a) : Nullch;
+
+    if (proto) {
+       assert(proto->op_type == OP_CONST);
+       ps = SvPVx(((SVOP*)proto)->op_sv, n_a);
+    }
+    else
+       ps = Nullch;
+
     if (!name && PERLDB_NAMEANON && CopLINE(PL_curcop)) {
        SV *sv = sv_newmortal();
        Perl_sv_setpvf(aTHX_ sv, "%s[%s:%"IVdf"]",
@@ -5895,7 +5937,7 @@ S_simplify_sort(pTHX_ OP *o)
 {
     register OP *kid = cLISTOPo->op_first->op_sibling; /* get past pushmark */
     OP *k;
-    int reversed;
+    int descending;
     GV *gv;
     if (!(o->op_flags & OPf_STACKED))
        return;
@@ -5924,11 +5966,12 @@ S_simplify_sort(pTHX_ OP *o)
     if (GvSTASH(gv) != PL_curstash)
        return;
     if (strEQ(GvNAME(gv), "a"))
-       reversed = 0;
+       descending = 0;
     else if (strEQ(GvNAME(gv), "b"))
-       reversed = 1;
+       descending = 1;
     else
        return;
+
     kid = k;                                           /* back to cmp */
     if (kBINOP->op_last->op_type != OP_RV2SV)
        return;
@@ -5938,13 +5981,13 @@ S_simplify_sort(pTHX_ OP *o)
     kid = kUNOP->op_first;                             /* get past rv2sv */
     gv = kGVOP_gv;
     if (GvSTASH(gv) != PL_curstash
-       || ( reversed
+       || ( descending
            ? strNE(GvNAME(gv), "a")
            : strNE(GvNAME(gv), "b")))
        return;
     o->op_flags &= ~(OPf_STACKED | OPf_SPECIAL);
-    if (reversed)
-       o->op_private |= OPpSORT_REVERSE;
+    if (descending)
+       o->op_private |= OPpSORT_DESCEND;
     if (k->op_type == OP_NCMP)
        o->op_private |= OPpSORT_NUMERIC;
     if (k->op_type == OP_I_NCMP)
@@ -6557,7 +6600,9 @@ Perl_peep(pTHX_ register OP *o)
            break;
 
        case OP_HELEM: {
+           UNOP *rop;
             SV *lexname;
+           GV **fields;
            SV **svp, *sv;
            char *key = NULL;
            STRLEN keylen;
@@ -6577,22 +6622,121 @@ Perl_peep(pTHX_ register OP *o)
                SvREFCNT_dec(sv);
                *svp = lexname;
            }
+
+           if ((o->op_private & (OPpLVAL_INTRO)))
+               break;
+
+           rop = (UNOP*)((BINOP*)o)->op_first;
+           if (rop->op_type != OP_RV2HV || rop->op_first->op_type != OP_PADSV)
+               break;
+           lexname = *av_fetch(PL_comppad_name, rop->op_first->op_targ, TRUE);
+           if (!(SvFLAGS(lexname) & SVpad_TYPED))
+               break;
+           fields = (GV**)hv_fetch(SvSTASH(lexname), "FIELDS", 6, FALSE);
+           if (!fields || !GvHV(*fields))
+               break;
+           key = SvPV(*svp, keylen);
+           if (!hv_fetch(GvHV(*fields), key,
+                       SvUTF8(*svp) ? -(I32)keylen : keylen, FALSE))
+           {
+               Perl_croak(aTHX_ "No such class field \"%s\" " 
+                          "in variable %s of type %s", 
+                     key, SvPV_nolen(lexname), HvNAME(SvSTASH(lexname)));
+           }
+
             break;
         }
 
-       case OP_SORT: {
-           /* make @a = sort @a act in-place */
+       case OP_HSLICE: {
+           UNOP *rop;
+           SV *lexname;
+           GV **fields;
+           SV **svp;
+           char *key;
+           STRLEN keylen;
+           SVOP *first_key_op, *key_op;
 
+           if ((o->op_private & (OPpLVAL_INTRO))
+               /* I bet there's always a pushmark... */
+               || ((LISTOP*)o)->op_first->op_sibling->op_type != OP_LIST)
+               /* hmmm, no optimization if list contains only one key. */
+               break;
+           rop = (UNOP*)((LISTOP*)o)->op_last;
+           if (rop->op_type != OP_RV2HV)
+               break;
+           if (rop->op_first->op_type == OP_PADSV)
+               /* @$hash{qw(keys here)} */
+               rop = (UNOP*)rop->op_first;
+           else {
+               /* @{$hash}{qw(keys here)} */
+               if (rop->op_first->op_type == OP_SCOPE 
+                   && cLISTOPx(rop->op_first)->op_last->op_type == OP_PADSV)
+               {
+                   rop = (UNOP*)cLISTOPx(rop->op_first)->op_last;
+               }
+               else
+                   break;
+           }
+                   
+           lexname = *av_fetch(PL_comppad_name, rop->op_targ, TRUE);
+           if (!(SvFLAGS(lexname) & SVpad_TYPED))
+               break;
+           fields = (GV**)hv_fetch(SvSTASH(lexname), "FIELDS", 6, FALSE);
+           if (!fields || !GvHV(*fields))
+               break;
+           /* Again guessing that the pushmark can be jumped over.... */
+           first_key_op = (SVOP*)((LISTOP*)((LISTOP*)o)->op_first->op_sibling)
+               ->op_first->op_sibling;
+           for (key_op = first_key_op; key_op;
+                key_op = (SVOP*)key_op->op_sibling) {
+               if (key_op->op_type != OP_CONST)
+                   continue;
+               svp = cSVOPx_svp(key_op);
+               key = SvPV(*svp, keylen);
+               if (!hv_fetch(GvHV(*fields), key, 
+                           SvUTF8(*svp) ? -(I32)keylen : keylen, FALSE))
+               {
+                   Perl_croak(aTHX_ "No such class field \"%s\" "
+                              "in variable %s of type %s",
+                         key, SvPV_nolen(lexname), HvNAME(SvSTASH(lexname)));
+               }
+           }
+           break;
+       }
+
+       case OP_SORT: {
            /* will point to RV2AV or PADAV op on LHS/RHS of assign */
            OP *oleft, *oright;
            OP *o2;
 
-           o->op_opt = 1;
-
            /* check that RHS of sort is a single plain array */
            oright = cUNOPo->op_first;
            if (!oright || oright->op_type != OP_PUSHMARK)
                break;
+
+           /* reverse sort ... can be optimised.  */
+           if (!cUNOPo->op_sibling) {
+               /* Nothing follows us on the list. */
+               OP *reverse = o->op_next;
+
+               if (reverse->op_type == OP_REVERSE &&
+                   (reverse->op_flags & OPf_WANT) == OPf_WANT_LIST) {
+                   OP *pushmark = cUNOPx(reverse)->op_first;
+                   if (pushmark && (pushmark->op_type == OP_PUSHMARK)
+                       && (cUNOPx(pushmark)->op_sibling == o)) {
+                       /* reverse -> pushmark -> sort */
+                       o->op_private |= OPpSORT_REVERSE;
+                       op_null(reverse);
+                       pushmark->op_next = oright->op_next;
+                       op_null(oright);
+                   }
+               }
+           }
+
+           /* make @a = sort @a act in-place */
+
+           o->op_opt = 1;
+
            oright = cUNOPx(oright)->op_sibling;
            if (!oright)
                break;
@@ -6632,6 +6776,17 @@ Perl_peep(pTHX_ register OP *o)
                    || (o2->op_flags & OPf_WANT) != OPf_WANT_VOID)
                break;
 
+           /* check that the sort is the first arg on RHS of assign */
+
+           o2 = cUNOPx(o2)->op_first;
+           if (!o2 || o2->op_type != OP_NULL)
+               break;
+           o2 = cUNOPx(o2)->op_first;
+           if (!o2 || o2->op_type != OP_PUSHMARK)
+               break;
+           if (o2->op_sibling != o)
+               break;
+
            /* check the array is the same on both sides */
            if (oleft->op_type == OP_RV2AV) {
                if (oright->op_type != OP_RV2AV
@@ -6667,9 +6822,97 @@ Perl_peep(pTHX_ register OP *o)
 
            break;
        }
-       
 
+       case OP_REVERSE: {
+           OP *ourmark, *theirmark, *ourlast, *iter, *expushmark, *rv2av;
+           OP *gvop = NULL;
+           LISTOP *enter, *exlist;
+           o->op_opt = 1;
+
+           enter = (LISTOP *) o->op_next;
+           if (!enter)
+               break;
+           if (enter->op_type == OP_NULL) {
+               enter = (LISTOP *) enter->op_next;
+               if (!enter)
+                   break;
+           }
+           /* for $a (...) will have OP_GV then OP_RV2GV here.
+              for (...) just has an OP_GV.  */
+           if (enter->op_type == OP_GV) {
+               gvop = (OP *) enter;
+               enter = (LISTOP *) enter->op_next;
+               if (!enter)
+                   break;
+               if (enter->op_type == OP_RV2GV) {
+                 enter = (LISTOP *) enter->op_next;
+                 if (!enter)
+                   break;
+               }
+           }
 
+           if (enter->op_type != OP_ENTERITER)
+               break;
+
+           iter = enter->op_next;
+           if (!iter || iter->op_type != OP_ITER)
+               break;
+           
+           expushmark = enter->op_first;
+           if (!expushmark || expushmark->op_type != OP_NULL
+               || expushmark->op_targ != OP_PUSHMARK)
+               break;
+
+           exlist = (LISTOP *) expushmark->op_sibling;
+           if (!exlist || exlist->op_type != OP_NULL
+               || exlist->op_targ != OP_LIST)
+               break;
+
+           if (exlist->op_last != o) {
+               /* Mmm. Was expecting to point back to this op.  */
+               break;
+           }
+           theirmark = exlist->op_first;
+           if (!theirmark || theirmark->op_type != OP_PUSHMARK)
+               break;
+
+           if (theirmark->op_sibling != o) {
+               /* There's something between the mark and the reverse, eg
+                  for (1, reverse (...))
+                  so no go.  */
+               break;
+           }
+
+           ourmark = ((LISTOP *)o)->op_first;
+           if (!ourmark || ourmark->op_type != OP_PUSHMARK)
+               break;
+
+           ourlast = ((LISTOP *)o)->op_last;
+           if (!ourlast || ourlast->op_next != o)
+               break;
+
+           rv2av = ourmark->op_sibling;
+           if (rv2av && rv2av->op_type == OP_RV2AV && rv2av->op_sibling == 0
+               && rv2av->op_flags == (OPf_WANT_LIST | OPf_KIDS)
+               && enter->op_flags == (OPf_WANT_LIST | OPf_KIDS)) {
+               /* We're just reversing a single array.  */
+               rv2av->op_flags = OPf_WANT_SCALAR | OPf_KIDS | OPf_REF;
+               enter->op_flags |= OPf_STACKED;
+           }
+
+           /* We don't have control over who points to theirmark, so sacrifice
+              ours.  */
+           theirmark->op_next = ourmark->op_next;
+           theirmark->op_flags = ourmark->op_flags;
+           ourlast->op_next = gvop ? gvop : (OP *) enter;
+           op_null(ourmark);
+           op_null(o);
+           enter->op_private |= OPpITER_REVERSED;
+           iter->op_private |= OPpITER_REVERSED;
+           
+           break;
+       }
+       
        default:
            o->op_opt = 1;
            break;