Syntax-Keyword-Match

 view release on metacpan or  search on metacpan

lib/Syntax/Keyword/Match/Deparse.pm  view on Meta::CPAN

#  You may distribute under the terms of either the GNU General Public License
#  or the Artistic License (the same terms as Perl itself)
#
#  (C) Paul Evans, 2024 -- leonerd@leonerd.org.uk

package Syntax::Keyword::Match::Deparse 0.15;

use v5.14;
use warnings;

use B qw( opnumber OPf_KIDS OPf_STACKED );

require B::Deparse;

use constant {
   OP_AND         => opnumber('and'),
   OP_COND_EXPR   => opnumber('cond_expr'),
   OP_CUSTOM      => opnumber('custom'),
   OP_ENTER       => opnumber('enter'),
   OP_LINESEQ     => opnumber('lineseq'),
   OP_MATCH       => opnumber('match'),
   OP_NULL        => opnumber('null'),
   OP_OR          => opnumber('or'),
   OP_PADSV       => opnumber('padsv'),
   OP_PADSV_STORE => opnumber('padsv_store'),
   OP_SASSIGN     => opnumber('sassign'),
};

=head1 NAME

C<Syntax::Keyword::Match::Deparse> - L<B::Deparse> support for L<Syntax::Keyword::Match>

=head1 DESCRIPTION

Loading this module will apply some hacks onto L<B::Deparse> that attempts to
provide deparse support for code which uses the syntax provided by
L<Syntax::Keyword::Match>.

=cut

my $orig_pp_leave;
{
   no warnings 'redefine';
   no strict 'refs';
   $orig_pp_leave = *{"B::Deparse::pp_leave"}{CODE};
   *{"B::Deparse::pp_leave"} = \&pp_leave;
}

sub op_dump
{
   my $o = shift;
   my $ret = $o->name;

   my $kid = $o->flags & OPf_KIDS ? $o->first : undef;
   if( $kid && !B::Deparse::null($kid) ) {
      $ret .= "[\n";
      while( $kid && !B::Deparse::null($kid) ) {
         $ret .= join( "\n", map { "  $_" } split m/\n/, op_dump($kid) ) . "\n";
         $kid = $kid->sibling;
      }
      $ret .= "]";
   }

   return $ret;
}

my %operator_for_name = (
   eq    => "==",
   seq   => "eq",
   match => "=~",
   isa   => "isa",
);

sub operator_name
{
   my ( $o ) = @_;
   my $opname = $o->name;
   return $operator_for_name{$opname} // die "TODO: operator name of $opname";
}

sub is_match_on_topic
{
   my ( $o, $topicix ) = @_;

   $o->type == OP_MATCH or return 0;

   if( $^V ge v5.22.0 ) {
      # Perl 5.22 could do OP_MATCH on targ
      return $o->targ == $topicix;
   }
   elsif( $o->flags & OPf_STACKED ) {
      my $kid = $o->first;
      return $kid->type == OP_PADSV && $kid->targ == $topicix;
   }
   else {
      return 0;
   }
}

sub pp_leave
{
   my $self = shift;
   my ( $op ) = @_;

   my $enter = $op->first;
   $enter->type == OP_ENTER or
      return $self->$orig_pp_leave( @_ );

   my $assign = $enter->sibling;
   my $topicix; my $topicop;
   if( $^V ge v5.38.0 ) {
      # Since perl 5.38.0 we had OP_PADSV_STORE
      $assign->type == OP_PADSV_STORE or
         return $self->$orig_pp_leave( @_ );

      my $varname = $self->padname( $topicix = $assign->targ );
      $varname eq '$(Syntax::Keyword::Match/topic)' or
         return $self->$orig_pp_leave( @_ );



( run in 1.039 second using v1.01-cache-2.11-cpan-71847e10f99 )