This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Merge branch 'blead' into smartmatch
[perl5.git] / pp_ctl.c
index d85ec11..5e8d557 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -3999,43 +3999,6 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
     
     SV *e = TOPs;      /* e is for 'expression' */
     SV *d = TOPm1s;    /* d is for 'default', as in PL_defgv */
-    SV *This, *Other;  /* 'This' (and Other to match) to play with C++ */
-    REGEXP *this_regex, *other_regex;
-
-#   define NOT_EMPTY_PROTO(cv) (!SvPOK(cv) || SvCUR(cv) == 0)
-
-#   define SM_REF(type) ( \
-          (SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_##type) && (Other = e)) \
-       || (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_##type) && (Other = d)))
-
-#   define SM_CV_NEP   /* Find a code ref without an empty prototype */ \
-       ((SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_PVCV)              \
-           && NOT_EMPTY_PROTO(This) && (Other = e))                    \
-       || (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_PVCV)            \
-           && NOT_EMPTY_PROTO(This) && (Other = d)))
-
-#   define SM_REGEX ( \
-          (SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_REGEXP)          \
-       && (this_regex = (REGEXP*) This)                                \
-       && (Other = e))                                                 \
-    ||                                                                 \
-          (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_REGEXP)          \
-       && (this_regex = (REGEXP*) This)                                \
-       && (Other = d)) )
-       
-
-#   define SM_OBJECT ( \
-          (sv_isobject(d) && (SvTYPE(SvRV(d)) != SVt_REGEXP))          \
-    ||                                                                 \
-          (sv_isobject(e) && (SvTYPE(SvRV(e)) != SVt_REGEXP)) )        \
-
-#   define SM_OTHER_REF(type) \
-       (SvROK(Other) && SvTYPE(SvRV(Other)) == SVt_##type)
-
-#   define SM_OTHER_REGEX (SvROK(Other)                                        \
-       && (SvTYPE(SvRV(Other)) == SVt_REGEXP)                          \
-       && (other_regex = (REGEXP*) SvRV(Other)))
-
 
 #   define SM_SEEN_THIS(sv) hv_exists_ent(seen_this, \
        sv_2mortal(newSViv(PTR2IV(sv))), 0)
@@ -4043,8 +4006,16 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
 #   define SM_SEEN_OTHER(sv) hv_exists_ent(seen_other, \
        sv_2mortal(newSViv(PTR2IV(sv))), 0)
 
-    tryAMAGICbinSET(smart, 0);
-    
+    if (SvAMAGIC(d) || SvAMAGIC(e)) {
+       SV * const tmpsv = amagic_call(d, e, smart_amg, 0);
+       if (tmpsv) {
+           SPAGAIN;
+           (void)POPs;
+           SETs(tmpsv);
+           RETURN;
+       }
+    }
+
     SP -= 2;   /* Pop the values */
 
     /* Take care only to invoke mg_get() once for each argument. 
@@ -4060,76 +4031,138 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
     if (SvGMAGICAL(e))
        e = sv_mortalcopy(e);
 
-    if (SM_OBJECT) {
-       if (!SvOK(d) || !SvOK(e))
+    /* ~~ undef */
+    if (!SvOK(e)) {
+       if (SvOK(d))
            RETPUSHNO;
        else
-           Perl_croak(aTHX_ "Smart matching a non-overloaded object breaks encapsulation");
+           RETPUSHYES;
     }
 
-    if (SM_CV_NEP) {
+    if ((sv_isobject(d) && (SvTYPE(SvRV(d)) != SVt_REGEXP))
+           || (sv_isobject(e) && (SvTYPE(SvRV(e)) != SVt_REGEXP)))
+       Perl_croak(aTHX_ "Smart matching a non-overloaded object breaks encapsulation");
+
+    /* ~~ sub */
+    if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVCV) {
        I32 c;
-       
-       if ( SM_OTHER_REF(PVCV) && NOT_EMPTY_PROTO(SvRV(Other)) )
-       {
-           if (This == SvRV(Other))
+       if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
+           /* Test sub truth for each key */
+           HE *he;
+           bool andedresults = TRUE;
+           HV *hv = (HV*) SvRV(d);
+           I32 numkeys = hv_iterinit(hv);
+           if (numkeys == 0)
+               RETPUSHYES;
+           while ( (he = hv_iternext(hv)) ) {
+               ENTER;
+               SAVETMPS;
+               PUSHMARK(SP);
+               PUSHs(hv_iterkeysv(he));
+               PUTBACK;
+               c = call_sv(e, G_SCALAR);
+               SPAGAIN;
+               if (c == 0)
+                   andedresults = FALSE;
+               else
+                   andedresults = SvTRUEx(POPs) && andedresults;
+               FREETMPS;
+               LEAVE;
+           }
+           if (andedresults)
                RETPUSHYES;
            else
                RETPUSHNO;
        }
-       
-       ENTER;
-       SAVETMPS;
-       PUSHMARK(SP);
-       PUSHs(Other);
-       PUTBACK;
-       c = call_sv(This, G_SCALAR);
-       SPAGAIN;
-       if (c == 0)
-           PUSHs(&PL_sv_no);
-       else if (SvTEMP(TOPs))
-           SvREFCNT_inc_void(TOPs);
-       FREETMPS;
-       LEAVE;
-       RETURN;
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+           /* Test sub truth for each element */
+           I32 i;
+           bool andedresults = TRUE;
+           AV *av = (AV*) SvRV(d);
+           const I32 len = av_len(av);
+           if (len == -1)
+               RETPUSHYES;
+           for (i = 0; i <= len; ++i) {
+               SV * const * const svp = av_fetch(av, i, FALSE);
+               ENTER;
+               SAVETMPS;
+               PUSHMARK(SP);
+               if (svp)
+                   PUSHs(*svp);
+               PUTBACK;
+               c = call_sv(e, G_SCALAR);
+               SPAGAIN;
+               if (c == 0)
+                   andedresults = FALSE;
+               else
+                   andedresults = SvTRUEx(POPs) && andedresults;
+               FREETMPS;
+               LEAVE;
+           }
+           if (andedresults)
+               RETPUSHYES;
+           else
+               RETPUSHNO;
+       }
+       else {
+           ENTER;
+           SAVETMPS;
+           PUSHMARK(SP);
+           PUSHs(d);
+           PUTBACK;
+           c = call_sv(e, G_SCALAR);
+           SPAGAIN;
+           if (c == 0)
+               PUSHs(&PL_sv_no);
+           else if (SvTEMP(TOPs))
+               SvREFCNT_inc_void(TOPs);
+           FREETMPS;
+           LEAVE;
+           RETURN;
+       }
     }
-    else if (SM_REF(PVHV)) {
-       if (SM_OTHER_REF(PVHV)) {
+    /* ~~ %hash */
+    else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVHV) {
+       if (!SvOK(d)) {
+           RETPUSHNO;
+       }
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
            /* Check that the key-sets are identical */
            HE *he;
-           HV *other_hv = MUTABLE_HV(SvRV(Other));
+           HV *other_hv = MUTABLE_HV(SvRV(d));
            bool tied = FALSE;
            bool other_tied = FALSE;
            U32 this_key_count  = 0,
                other_key_count = 0;
+           HV *hv = MUTABLE_HV(SvRV(e));
            
            /* Tied hashes don't know how many keys they have. */
-           if (SvTIED_mg(This, PERL_MAGIC_tied)) {
+           if (SvTIED_mg((SV*)hv, PERL_MAGIC_tied)) {
                tied = TRUE;
            }
            else if (SvTIED_mg((const SV *)other_hv, PERL_MAGIC_tied)) {
                HV * const temp = other_hv;
-               other_hv = MUTABLE_HV(This);
-               This  = MUTABLE_SV(temp);
+               other_hv = hv;
+               hv = temp;
                tied = TRUE;
            }
            if (SvTIED_mg((const SV *)other_hv, PERL_MAGIC_tied))
                other_tied = TRUE;
            
-           if (!tied && HvUSEDKEYS((const HV *) This) != HvUSEDKEYS(other_hv))
+           if (!tied && HvUSEDKEYS((const HV *) hv) != HvUSEDKEYS(other_hv))
                RETPUSHNO;
 
            /* The hashes have the same number of keys, so it suffices
               to check that one is a subset of the other. */
-           (void) hv_iterinit(MUTABLE_HV(This));
-           while ( (he = hv_iternext(MUTABLE_HV(This))) ) {
+           (void) hv_iterinit(hv);
+           while ( (he = hv_iternext(hv)) ) {
                I32 key_len;
                char * const key = hv_iterkey(he, &key_len);
                
                ++ this_key_count;
                
                if(!hv_exists(other_hv, key, key_len)) {
-                   (void) hv_iterinit(MUTABLE_HV(This));       /* reset iterator */
+                   (void) hv_iterinit(hv);     /* reset iterator */
                    RETPUSHNO;
                }
            }
@@ -4147,10 +4180,11 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
            else
                RETPUSHYES;
        }
-       else if (SM_OTHER_REF(PVAV)) {
-           AV * const other_av = MUTABLE_AV(SvRV(Other));
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+           AV * const other_av = MUTABLE_AV(SvRV(d));
            const I32 other_len = av_len(other_av) + 1;
            I32 i;
+           HV *hv = MUTABLE_HV(SvRV(e));
 
            for (i = 0; i < other_len; ++i) {
                SV ** const svp = av_fetch(other_av, i, FALSE);
@@ -4159,20 +4193,21 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
 
                if (svp) {      /* ??? When can this not happen? */
                    key = SvPV(*svp, key_len);
-                   if (hv_exists(MUTABLE_HV(This), key, key_len))
+                   if (hv_exists(hv, key, key_len))
                        RETPUSHYES;
                }
            }
            RETPUSHNO;
        }
-       else if (SM_OTHER_REGEX) {
-           PMOP * const matcher = make_matcher(other_regex);
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_REGEXP) {
+           PMOP * const matcher = make_matcher((REGEXP*) SvRV(d));
            HE *he;
+           HV *hv = MUTABLE_HV(SvRV(e));
 
-           (void) hv_iterinit(MUTABLE_HV(This));
-           while ( (he = hv_iternext(MUTABLE_HV(This))) ) {
+           (void) hv_iterinit(hv);
+           while ( (he = hv_iternext(hv)) ) {
                if (matcher_matches_sv(matcher, hv_iterkeysv(he))) {
-                   (void) hv_iterinit(MUTABLE_HV(This));
+                   (void) hv_iterinit(hv);
                    destroy_matcher(matcher);
                    RETPUSHYES;
                }
@@ -4181,16 +4216,35 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
            RETPUSHNO;
        }
        else {
-           if (hv_exists_ent(MUTABLE_HV(This), Other, 0))
+           if (hv_exists_ent(MUTABLE_HV(SvRV(e)), d, 0))
                RETPUSHYES;
            else
                RETPUSHNO;
        }
     }
-    else if (SM_REF(PVAV)) {
-       if (SM_OTHER_REF(PVAV)) {
-           AV *other_av = MUTABLE_AV(SvRV(Other));
-           if (av_len(MUTABLE_AV(This)) != av_len(other_av))
+    /* ~~ @array */
+    else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVAV) {
+       if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
+           AV * const other_av = MUTABLE_AV(SvRV(e));
+           const I32 other_len = av_len(other_av) + 1;
+           I32 i;
+
+           for (i = 0; i < other_len; ++i) {
+               SV ** const svp = av_fetch(other_av, i, FALSE);
+               char *key;
+               STRLEN key_len;
+
+               if (svp) {      /* ??? When can this not happen? */
+                   key = SvPV(*svp, key_len);
+                   if (hv_exists(MUTABLE_HV(SvRV(d)), key, key_len))
+                       RETPUSHYES;
+               }
+           }
+           RETPUSHNO;
+       }
+       if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+           AV *other_av = MUTABLE_AV(SvRV(d));
+           if (av_len(MUTABLE_AV(SvRV(e))) != av_len(other_av))
                RETPUSHNO;
            else {
                I32 i;
@@ -4205,7 +4259,7 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
                    (void) sv_2mortal(MUTABLE_SV(seen_other));
                }
                for(i = 0; i <= other_len; ++i) {
-                   SV * const * const this_elem = av_fetch(MUTABLE_AV(This), i, FALSE);
+                   SV * const * const this_elem = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
                    SV * const * const other_elem = av_fetch(other_av, i, FALSE);
 
                    if (!this_elem || !other_elem) {
@@ -4225,8 +4279,8 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
                        (void)hv_store_ent(seen_other,
                                sv_2mortal(newSViv(PTR2IV(*other_elem))),
                                &PL_sv_undef, 0);
-                       PUSHs(*this_elem);
                        PUSHs(*other_elem);
+                       PUSHs(*this_elem);
                        
                        PUTBACK;
                        (void) do_smartmatch(seen_this, seen_other);
@@ -4239,13 +4293,13 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
                RETPUSHYES;
            }
        }
-       else if (SM_OTHER_REGEX) {
-           PMOP * const matcher = make_matcher(other_regex);
-           const I32 this_len = av_len(MUTABLE_AV(This));
+       else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_REGEXP) {
+           PMOP * const matcher = make_matcher((REGEXP*) SvRV(d));
+           const I32 this_len = av_len(MUTABLE_AV(SvRV(e)));
            I32 i;
 
            for(i = 0; i <= this_len; ++i) {
-               SV * const * const svp = av_fetch(MUTABLE_AV(This), i, FALSE);
+               SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
                if (svp && matcher_matches_sv(matcher, *svp)) {
                    destroy_matcher(matcher);
                    RETPUSHYES;
@@ -4254,15 +4308,15 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
            destroy_matcher(matcher);
            RETPUSHNO;
        }
-       else if (SvIOK(Other) || SvNOK(Other)) {
+       else if (SvNIOK(d)) {
            I32 i;
 
-           for(i = 0; i <= AvFILL(MUTABLE_AV(This)); ++i) {
-               SV * const * const svp = av_fetch(MUTABLE_AV(This), i, FALSE);
+           for(i = 0; i <= AvFILL(MUTABLE_AV(SvRV(e))); ++i) {
+               SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
                if (!svp)
                    continue;
                
-               PUSHs(Other);
+               PUSHs(d);
                PUSHs(*svp);
                PUTBACK;
                if (CopHINTS_get(PL_curcop) & HINT_INTEGER)
@@ -4275,16 +4329,16 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
            }
            RETPUSHNO;
        }
-       else if (SvPOK(Other)) {
-           const I32 this_len = av_len(MUTABLE_AV(This));
+       else if (SvPOK(d)) {
+           const I32 this_len = av_len(MUTABLE_AV(SvRV(e)));
            I32 i;
 
            for(i = 0; i <= this_len; ++i) {
-               SV * const * const svp = av_fetch(MUTABLE_AV(This), i, FALSE);
+               SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
                if (!svp)
                    continue;
                
-               PUSHs(Other);
+               PUSHs(d);
                PUSHs(*svp);
                PUTBACK;
                (void) pp_seq();
@@ -4295,68 +4349,21 @@ S_do_smartmatch(pTHX_ HV *seen_this, HV *seen_other)
            RETPUSHNO;
        }
     }
-    else if (!SvOK(d) || !SvOK(e)) {
-       if (!SvOK(d) && !SvOK(e))
-           RETPUSHYES;
-       else
-           RETPUSHNO;
-    }
-    else if (SM_REGEX) {
-       PMOP * const matcher = make_matcher(this_regex);
+    /* ~~ qr// */
+    else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_REGEXP) {
+       PMOP * const matcher = make_matcher((REGEXP*) SvRV(e));
 
        PUTBACK;
-       PUSHs(matcher_matches_sv(matcher, Other)
+       PUSHs(matcher_matches_sv(matcher, d)
            ? &PL_sv_yes
            : &PL_sv_no);
        destroy_matcher(matcher);
        RETURN;
     }
-    else if (SM_REF(PVCV)) {
-       I32 c;
-       /* This must be a null-prototyped sub, because we
-          already checked for the other kind. */
-       
-       ENTER;
-       SAVETMPS;
-       PUSHMARK(SP);
-       PUTBACK;
-       c = call_sv(This, G_SCALAR);
-       SPAGAIN;
-       if (c == 0)
-           PUSHs(&PL_sv_undef);
-       else if (SvTEMP(TOPs))
-           SvREFCNT_inc_void(TOPs);
-
-       if (SM_OTHER_REF(PVCV)) {
-           /* This one has to be null-proto'd too.
-              Call both of 'em, and compare the results */
-           PUSHMARK(SP);
-           c = call_sv(SvRV(Other), G_SCALAR);
-           SPAGAIN;
-           if (c == 0)
-               PUSHs(&PL_sv_undef);
-           else if (SvTEMP(TOPs))
-               SvREFCNT_inc_void(TOPs);
-           FREETMPS;
-           LEAVE;
-           PUTBACK;
-           return pp_eq();
-       }
-       
-       FREETMPS;
-       LEAVE;
-       RETURN;
-    }
-    else if ( ((SvIOK(d) || SvNOK(d)) && (This = d) && (Other = e))
-         ||   ((SvIOK(e) || SvNOK(e)) && (This = e) && (Other = d)) )
-    {
-       if (SvPOK(Other) && !looks_like_number(Other)) {
-           /* String comparison */
-           PUSHs(d); PUSHs(e);
-           PUTBACK;
-           return pp_seq();
-       }
-       /* Otherwise, numeric comparison */
+    /* ~~ X..Y TODO */
+    /* ~~ scalar */
+    else if (SvNIOK(e) || (SvPOK(e) && looks_like_number(e) && SvNIOK(d))) {
+       /* numeric comparison */
        PUSHs(d); PUSHs(e);
        PUTBACK;
        if (CopHINTS_get(PL_curcop) & HINT_INTEGER)