choroba has asked for the wisdom of the Perl Monks concerning the following question:

This was started by yitzchak in the CB several days ago, but I haven't noticed any conclusion. Is this a bug?
(1) $ perl -MO=Deparse -e 'do("foo")->{bar};' do $foo{'bar'}; -e syntax OK (2) $ perl -MO=Deparse -e '(do "foo")->{bar};' do('foo')->{'bar'}; -e syntax OK (3) $ perl -MO=Deparse -Mstrict -e 'do("foo")->{bar};' Global symbol "%foo" requires explicit package name at -e line 1. -e had compilation errors. use strict 'refs'; do $<none>::foo{'bar'}; ERROR CODE: [34] (4) $ perl -MO=Deparse -Mstrict -e '(do "foo")->{bar};' use strict 'refs'; do('foo')->{'bar'}; -e syntax OK

So, (2) deparses to (1). (3) is not permitted under strict. (4) is permitted, but deparses to (3). What's going on here? (v5.14.4 under cygwin)

لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

Replies are listed 'Best First'.
Re: B::Deparse weirdness (parser weirdness!)
by LanX (Saint) on Oct 13, 2014 at 11:35 UTC
    Rephrased:

    B::Deparse thinks (and I expected) that parens have priority to capture function arguments and that

    do('foo')->{'bar'};

    is analogous to

    (do 'foo') -> {bar}

    but the weird parser rather sees

    do ('foo' -> {bar})

    see the difference in priority of parens around arguments by comparing print() vs do()

    lanx@nc10-ubuntu:/tmp$ perl -MO=Concise, -e 'do ($foo)->{bar};' 9 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 8 <1> dofile vK/1 ->9 # do file 7 <2> helem sK/2 ->8 # hash-elem returns fi +le 5 <1> rv2hv[t2] sKR/1 ->6 4 <1> rv2sv sKPM/DREFHV,1 ->5 3 <#> gv[*foo] s ->4 6 <$> const[PV "bar"] s/BARE ->7 -e syntax OK lanx@nc10-ubuntu:/tmp$ perl -MO=Concise, -e 'print ($foo)->{bar};' 9 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 8 <2> helem vK/2 ->9 # hash-element 6 <1> rv2hv[t2] sKR/1 ->7 5 <@> print sK ->6 # print returns hashre +f 3 <0> pushmark s ->4 - <1> ex-rv2sv sK/1 ->5 4 <#> gvsv[*foo] s ->5 7 <$> const[PV "bar"] s/BARE ->8 -e syntax OK

    just remember the common trap when people try writing something like

     print (caller)[5]

    $ perl -c -e 'print (caller)[5]' syntax error at -e line 1, near ")[" -e had compilation errors.

    while

    $ perl -c -e 'do (L,I,S,T)[5]' -e syntax OK

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

      OK I wasn't sure if comparing do EXPR with print LIST was fair, so I tried something more similar with eval EXPR

      sorry but that's really ridiculous, the priority of parens is handled the other way round.

      $ perl -MO=Concise -e 'eval ($foo)->{bar};' 8 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 7 <2> helem vK/2 ->8 5 <1> rv2hv[t2] sKR/1 ->6 4 <1> entereval[t256] sK/1 ->5 - <1> ex-rv2sv sK/1 ->4 3 <#> gvsv[*foo] s ->4 6 <$> const[PV "bar"] s/BARE ->7 -e syntax OK $ perl -MO=Concise -e 'do ($foo)->{bar};' 9 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v:{ ->3 8 <1> dofile vK/1 ->9 7 <2> helem sK/2 ->8 5 <1> rv2hv[t2] sKR/1 ->6 4 <1> rv2sv sKPM/DREFHV,1 ->5 3 <#> gv[*foo] s ->4 6 <$> const[PV "bar"] s/BARE ->7 -e syntax OK

      I can't really blame B::Deparse for failing to guess this parser weirdness.

      It's using heuristics to produce readable code without too many parens to group obvious precedence.

      How are the authors supposed to known that do is special?

      update

      in hindsight it would be safer if B::Deparse was grouping complex LHS of the arrow OP into parens.

      even if this is correct

      $ perl -MO=Deparse -e '(eval $foo)->{bar};' eval($foo)->{'bar'};

      nobody would mind getting this instead.

      (eval($foo))->{'bar'};

      Cheers Rolf

      (addicted to the Perl Programming Language and ☆☆☆☆ :)

        > in hindsight it would be safer if B::Deparse was grouping complex LHS of the arrow OP into parens.

        here a possible patch to do this. It introduces a call to a new routine maybe_parens_lhs_arrow() into the return statement of elem().

        Complex LHS-> is determined by not starting with a sigil or paren.

        sub elem { my $self = shift; my ($op, $cx, $left, $right, $padname) = @_; my($array, $idx) = ($op->first, $op->first->sibling); $idx = $self->elem_or_slice_single_index($idx); unless ($array->name eq $padname) { # Maybe this has been fixed + $array = $array->first; # skip rv2av (or ex-rv2av in _53+) } if (my $array_name=$self->elem_or_slice_array_name ($array, $left, $padname, 1)) { return "\$" . $array_name . $left . $idx . $right; } else { # $x[20][3]{hi} or expr->[20] my $arrow = is_subscriptable($array) ? "" : "->"; return maybe_parens_lhs_arrow($self->deparse($array, 24), $arrow) . $left . $idx . $right; } } sub maybe_parens_lhs_arrow { my ($lhs, $arrow) = @_; return "($lhs)$arrow" if ($arrow eq "->" and $lhs !~ /^[$@%&(*]/); return "$lhs$arrow"; }

        Looks like a weird hack ... much like most of B::Deparse ! :)

        That's teh result then:

        $ perl -I. -MO=Deparse -e '(do $foo)->{$bar}' (do($foo))->{$bar}; -e syntax OK $ perl -I. -MO=Deparse -e '$foo->{$bar}' $$foo{$bar}; -e syntax OK

        Cheers Rolf

        (addicted to the Perl Programming Language and ☆☆☆☆ :)

Re: B::Deparse weirdness (updated)
by LanX (Saint) on Oct 13, 2014 at 11:06 UTC
    Sorry what is the intention of the code?

    My biological parser is guessing that "foo" is a file to be evaled via do and has to return a hashref?

    Correct?

    You might wanna use B::Concise to inspect the op-codes.

    update

    my guess w/o further inspection is that the do is differently parsed than e.g. print where the parens have priority to capture the EXPR part.

    (thats actually what B::Deparse is assuming when generating the second output)

    So w/o strictures something like ("foo")->{bla} is parsed as a whole EXPR to be passed to do. (i.e. bareword as reference)

    So it's not really B::Deparse 's fault that Perl's parser is inconsistent.

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)