Perl-LanguageServer

 view release on metacpan or  search on metacpan

lib/Perl/LanguageServer/DebuggerInterface.pm  view on Meta::CPAN

#

# client-specific pre/post-stop actions.
sub cprestop {}
sub cpoststop {}

# client complete startup
sub awaken {}

sub skippkg {
  my $s = shift;
  push @skippkg, @_ if @_;
}

sub evalcode {
  my ($client, $val) = @_;
  if (defined $val) {
    $running = 2;    # hand over to DB() to evaluate in its context
    $ineval->{$client} = $val;
  }
  return $ineval->{$client};
}

sub ready {
  my $s = shift;
  return $ready = 1;
}

# stubs

sub init {}
sub stop {}
sub idle {}
sub cleanup {}
sub output {}

#
# client init
#
for (@clients) { $_->init }

$SIG{'INT'} = \&DB::catch;

# disable this if stepping through END blocks is desired
# (looks scary and deconstructivist with Swat)
END { $ready = 0 }


##############################################################################

package Perl::LanguageServer::DebuggerInterface ;

#use DB;

our @ISA = qw(DB);

use strict ;

use IO::Socket ;
use JSON ;
use PadWalker ;
use Scalar::Util qw{blessed reftype looks_like_number};
use Hash::SafeKeys;
#use Data::Dump qw{pp} ;
use File::Basename ;
use vars qw{@dbline %dbline $dbline} ;

our $max_display = 5 ;
our $debug = 0 ;
our $session = $ENV{PLSDI_SESSION} || 1 ;
our $socket ;
our $json = JSON -> new -> utf8(1) -> ascii(1) ;
our @evalresult ;
our %postponed_breakpoints ;
our $breakpoint_id = 1 ;
our $loaded = 0 ;
our $break_reason ;
our $refresh ;

__PACKAGE__  -> register  ;
__PACKAGE__  -> init  ;

# ---------------------------------------------------------------------------

sub logger
    {
    my $class = shift ;
    print STDERR @_ ;
    }

# ---------------------------------------------------------------------------

use constant SPECIALS => { _ => 1, INC => 1, ARGV => 1, ENV => 1, ARGVOUT => 1, SIG => 1,
                            STDIN => 1, STDOUT => 1, STDERR => 1,
                            stdin => 1, stdout => 1, stderr => 1} ;

use vars qw{%entry @entry $entry %stab} ;

# ---------------------------------------------------------------------------

sub get_globals
    {
    my ($self, $package) = @_ ;

    my %vars ;

    my $specials = $package?0:1 ;
    $package ||= 'main' ;
    $package .= "::" unless $package =~ /::$/;
no strict ;
    *stab = *{"main::"};
    while ($package =~ /(\w+?::)/g)
        {
        *stab = ${stab}{$1};
        }
use strict ;
    my $key ;
    my $val ;

    while (($key, $val) = each (%stab))
        {

lib/Perl/LanguageServer/DebuggerInterface.pm  view on Meta::CPAN

        {
        $ref = $$ref ;
        #print STDERR "deref ----> ref val=$refexpr ref=$ref refref=", ref ($ref), "reftype=", reftype ($ref), "\n" ;
        $pre = '${' ;
        $post = '}' ;
        }
    if (reftype ($ref) eq 'ARRAY')
        {
        my $n = 0 ;
        foreach my $entry (@$ref)
            {
            $vars{"$n"} = [\$entry, $prefix . $pre . '(' . $refexpr . ')' . $post . '->[' . $n . ']' ] ;
            $n++ ;
            }
        }
    elsif (reftype ($ref) eq 'HASH')
        {
        my $iterator = Hash::SafeKeys::save_iterator_state($ref);
        foreach my $entry (sort keys %$ref)
            {
            $vars{"$entry"} = [\$ref -> {$entry}, $prefix . $pre . '(' . $refexpr . ')' . $post . "->{'" . $entry . "'}" ] ;
            }
        Hash::SafeKeys::restore_iterator_state($ref, $iterator);
        }
    else
        {
        $vars{'$'} = [$ref] ;
        }

    return \%vars ;
    }

# ---------------------------------------------------------------------------

sub get_arguments
    {
    my ($self, $frame) = @_ ;

    my $vars  ;
    my %varsrc ;
    eval
        {
        my @args = _get_caller_args ($frame+2) ;
        $varsrc{"\@_"} =    [\@args, "ea:\$varsrc->{'\@_'}[0]"] ;
        $varsrc{"\@ARGV"} = [\@main::ARGV, 'eg:\\@main::ARGV'] ;
        } ;
    $self -> logger ($@) if ($@) ;
    return (\%varsrc) ;
    }

# ---------------------------------------------------------------------------

sub get_locals
    {
    my ($self, $frame) = @_ ;

    my $vars  ;
    my %varsrc ;
    eval
        {
        $vars = PadWalker::peek_my ($frame) ;
        foreach my $var (keys %$vars)
            {
            $varsrc{$var} =
                [
                $vars->{$var},
                "el:\$varsrc->{'$var'}"
                ] ;
            }
        } ;
    $self -> logger ($@) if ($@) ;
    return (\%varsrc, $vars) ;
    }

# ---------------------------------------------------------------------------

sub _get_caller_args
    {
    my ($caller) = @_ ;

    local @DB::args ;

    my @caller_args ;
        {
        package DB;

        my @call_info = caller ($caller) ;
        #use Data::Dump qw{pp} ;
        #print STDERR "db::args after caller $caller ", pp(\@DB::args), "\n" ;
        @caller_args = @DB::args ;
        }

    return @caller_args ;
    }

# ---------------------------------------------------------------------------

sub _eval_replace
    {
    my ($___di_vars, $___di_sigil, $___di_var, $___di_suffix, $___di_frame) = @_ ;

    #print STDERR "sigil = $___di_sigil var = $___di_var suffix = $___di_suffix\n" ;

    if ($___di_var eq '_')
        {
        my @args = _get_caller_args ($___di_frame + 3) ;
        $___di_vars -> {'@_'} = \@args ;
        }
    #use Data::Dump qw{pp} ;
    #print STDERR "vars ", pp ($___di_vars),"\n" ;
    if ($___di_suffix)
        {
        return "\$___di_vars->{'\%$___di_var'}{" if ($___di_suffix eq '{' && exists $___di_vars->{"\%$___di_var"}) ;
        return "\$___di_vars->{'\@$___di_var'}[" if (exists $___di_vars->{"\@$___di_var"});
        }
    else
        {
        return "\$\#\{\$___di_vars->{'\@$1'}}" if (($___di_var =~ /^#(.+)/) && exists $___di_vars->{"\@$1"}) ;
        #print STDERR "v = $___di_var  1 = $1\n" ;
        return "$___di_sigil\{\$___di_vars->{'$___di_sigil$___di_var'}}" if (exists $___di_vars->{"$___di_sigil$___di_var"}) ;
        }

    return "$___di_sigil$___di_var$___di_suffix" ;
    }

# ---------------------------------------------------------------------------

sub get_eval_result
    {
    my ($self, $frame, $package, $expression) = @_;

    my $___di_vars = PadWalker::peek_my ($frame) ;

    $expression =~ s/([\%\@\$])(#?\w+)\s*([\[\{])?/_eval_replace($___di_vars, $1, $2, $3, $frame)/eg ;

    my $code = "package $package ; no strict ; $expression";
    my %vars ;
    #print STDERR "frame=$frame code = $code\n" ;


    my @result = eval $code;
    if ($@)
        {
        $vars{'ERROR'} = [$@] ;
        }
    else
        {
        if (@result < 2)
            {
            if (ref ($result[0]) eq 'REF')
                {
                push @evalresult, $result[0] ;
                }
            else
                {
                push @evalresult, \$result[0] ;
                }
            }
        elsif ($expression =~ /^\s*\\?\s*\%/)
            {
            push @evalresult, { @result } ;
            }
        else
            {
            push @evalresult, \@result ;
            }
        $vars{'eval'} = [$evalresult[-1], 'eg:$Perl::LanguageServer::DebuggerInterface::evalresult[' . $#evalresult . ']'] ;
        }

    return \%vars ;
    }

# ---------------------------------------------------------------------------

 sub get_scalar
    {
    my $ret = eval
        {
        my ($self, $val) = @_ ;

        return 'undef' if (!defined ($val)) ;
        my $obj = '' ;
        $obj = blessed ($val) . ' ' if (blessed ($val)) ;
        return $obj . '[..]' if (ref ($val) eq 'ARRAY') ;
        return $obj . '{..}' if (ref ($val) eq 'HASH') ;
        my $isnum = looks_like_number ($val);
        $obj . ($isnum?$val:"'$val'") ;
        } ;
    return $@ if ($@) ;
    return $ret ;
    }



( run in 1.830 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )