diff options
author | Ruslan Zakirov <ruz@bestpractical.com> | 2013-02-27 19:39:39 +0400 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2013-09-13 01:25:34 -0700 |
commit | 5cae3edb76796fced1e703fcf4357364c5ddd9b7 (patch) | |
tree | faa8797522872430c4bca7c56c0177c6d69cce87 /pp.c | |
parent | 408dc2ec1c7e0bb6d22bd96e6ffe02473c573470 (diff) | |
download | perl-5cae3edb76796fced1e703fcf4357364c5ddd9b7.tar.gz |
key/value hash slice operation
kvhslice operator that implements %h{1,2,3,4} syntax which
returns list of key value pairs rather than just values
(regular slices).
Diffstat (limited to 'pp.c')
-rw-r--r-- | pp.c | 48 |
1 files changed, 48 insertions, 0 deletions
@@ -4753,6 +4753,54 @@ PP(pp_hslice) RETURN; } +PP(pp_kvhslice) +{ + dVAR; dSP; dMARK; dORIGMARK; + HV * const hv = MUTABLE_HV(POPs); + I32 lval = (PL_op->op_flags & OPf_MOD); + I32 items = SP - MARK; + + if (PL_op->op_private & OPpMAYBE_LVSUB) { + const I32 flags = is_lvalue_sub(); + if (flags) { + if (!(flags & OPpENTERSUB_INARGS)) + Perl_croak(aTHX_ "Can't modify key/value hash slice in list assignment"); + lval = flags; + } + } + + MEXTEND(SP,items); + while (items > 1) { + *(MARK+items*2-1) = *(MARK+items); + items--; + } + items = SP-MARK; + SP += items; + + while (++MARK <= SP) { + SV * const keysv = *MARK; + SV **svp; + HE *he; + + he = hv_fetch_ent(hv, keysv, lval, 0); + svp = he ? &HeVAL(he) : NULL; + + if (lval) { + if (!svp || !*svp || *svp == &PL_sv_undef) { + DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv)); + } + *MARK = sv_mortalcopy(*MARK); + } + *++MARK = svp && *svp ? *svp : &PL_sv_undef; + } + if (GIMME != G_ARRAY) { + MARK = SP - items*2; + *++MARK = items > 0 ? *SP : &PL_sv_undef; + SP = MARK; + } + RETURN; +} + /* List operators. */ PP(pp_list) |