Merge the common code from Perl_vdie and Perl_vwarner into a
[p5sagit/p5-mst-13.2.git] / op.c
diff --git a/op.c b/op.c
index d4c2887..9b33ff2 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
@@ -1737,7 +1761,7 @@ Perl_bind_match(pTHX_ I32 type, OP *left, OP *right)
     }
     else
        return bind_match(type, left,
-               pmruntime(newPMOP(OP_MATCH, 0), right, Nullop));
+               pmruntime(newPMOP(OP_MATCH, 0), right, 0));
 }
 
 OP *
@@ -2636,15 +2660,56 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags)
     return CHECKOP(type, pmop);
 }
 
+/* Given some sort of match op o, and an expression expr containing a
+ * pattern, either compile expr into a regex and attach it to o (if it's
+ * constant), or convert expr into a runtime regcomp op sequence (if it's
+ * not)
+ *
+ * isreg indicates that the pattern is part of a regex construct, eg
+ * $x =~ /pattern/ or split /pattern/, as opposed to $x =~ $pattern or
+ * split "pattern", which aren't. In the former case, expr will be a list
+ * if the pattern contains more than one term (eg /a$b/) or if it contains
+ * a replacement, ie s/// or tr///.
+ */
+
 OP *
-Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
+Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg)
 {
     PMOP *pm;
     LOGOP *rcop;
     I32 repl_has_vars = 0;
+    OP* repl  = Nullop;
+    bool reglist;
 
-    if (o->op_type == OP_TRANS)
+    if (o->op_type == OP_SUBST || o->op_type == OP_TRANS) {
+       /* last element in list is the replacement; pop it */
+       OP* kid;
+       repl = cLISTOPx(expr)->op_last;
+       kid = cLISTOPx(expr)->op_first;
+       while (kid->op_sibling != repl)
+           kid = kid->op_sibling;
+       kid->op_sibling = Nullop;
+       cLISTOPx(expr)->op_last = kid;
+    }
+
+    if (isreg && expr->op_type == OP_LIST &&
+       cLISTOPx(expr)->op_first->op_sibling == cLISTOPx(expr)->op_last)
+    {
+       /* convert single element list to element */
+       OP* oe = expr;
+       expr = cLISTOPx(oe)->op_first->op_sibling;
+       cLISTOPx(oe)->op_first->op_sibling = Nullop;
+       cLISTOPx(oe)->op_last = Nullop;
+       op_free(oe);
+    }
+
+    if (o->op_type == OP_TRANS) {
        return pmtrans(o, expr, repl);
+    }
+
+    reglist = isreg && expr->op_type == OP_LIST;
+    if (reglist)
+       op_null(expr);
 
     PL_hints |= HINT_BLOCK_SCOPE;
     pm = (PMOP*)o;
@@ -2675,11 +2740,14 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl)
        rcop->op_type = OP_REGCOMP;
        rcop->op_ppaddr = PL_ppaddr[OP_REGCOMP];
        rcop->op_first = scalar(expr);
-       rcop->op_flags |= ((PL_hints & HINT_RE_EVAL)
-                          ? (OPf_SPECIAL | OPf_KIDS)
-                          : OPf_KIDS);
+       rcop->op_flags |= OPf_KIDS
+                           | ((PL_hints & HINT_RE_EVAL) ? OPf_SPECIAL : 0)
+                           | (reglist ? OPf_STACKED : 0);
        rcop->op_private = 1;
        rcop->op_other = o;
+       if (reglist)
+           rcop->op_targ = pad_alloc(rcop->op_type, SVs_PADTMP);
+
        /* /$x/ may cause an eval, since $x might be qr/(?{..})/  */
        PL_cv_has_eval = 1;
 
@@ -5995,7 +6063,7 @@ Perl_ck_split(pTHX_ OP *o)
     if (kid->op_type != OP_MATCH || kid->op_flags & OPf_STACKED) {
        OP *sibl = kid->op_sibling;
        kid->op_sibling = 0;
-       kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, Nullop);
+       kid = pmruntime( newPMOP(OP_MATCH, OPf_SPECIAL), kid, 0);
        if (cLISTOPo->op_first == cLISTOPo->op_last)
            cLISTOPo->op_last = kid;
        cLISTOPo->op_first = kid;
@@ -6576,7 +6644,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;
@@ -6596,9 +6666,88 @@ 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_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;
@@ -6719,7 +6868,8 @@ Perl_peep(pTHX_ register OP *o)
        }
 
        case OP_REVERSE: {
-           OP *ourmark, *theirmark, *ourlast, *iter;
+           OP *ourmark, *theirmark, *ourlast, *iter, *expushmark, *rv2av;
+           OP *gvop = NULL;
            LISTOP *enter, *exlist;
            o->op_opt = 1;
 
@@ -6731,6 +6881,20 @@ Perl_peep(pTHX_ register OP *o)
                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;
 
@@ -6738,7 +6902,12 @@ Perl_peep(pTHX_ register OP *o)
            if (!iter || iter->op_type != OP_ITER)
                break;
            
-           exlist = (LISTOP *) enter->op_last;
+           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;
@@ -6751,26 +6920,35 @@ Perl_peep(pTHX_ register OP *o)
            if (!theirmark || theirmark->op_type != OP_PUSHMARK)
                break;
 
-           ourmark = ((LISTOP *)o)->op_first;
-           if (!ourmark || ourmark->op_type != OP_PUSHMARK)
-               break;
-
-           if (ourmark->op_next != o) {
+           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 = (OP *) enter;
+           ourlast->op_next = gvop ? gvop : (OP *) enter;
            op_null(ourmark);
            op_null(o);
            enter->op_private |= OPpITER_REVERSED;