2008-06-13 20:41:30 -04:00
|
|
|
#!/usr/bin/env perl
|
2008-05-15 03:20:41 -04:00
|
|
|
#
|
|
|
|
# by Erik Osheim
|
|
|
|
#
|
|
|
|
# licensed under the GNU GPL version 2
|
|
|
|
|
2008-05-16 09:24:17 -04:00
|
|
|
# try not to pollute the namespace
|
|
|
|
use Data::Dumper qw(Dumper);
|
|
|
|
use File::Basename qw();
|
|
|
|
use Getopt::Long qw();
|
|
|
|
use Scalar::Util qw();
|
2008-05-18 10:39:08 -04:00
|
|
|
|
|
|
|
# NOTE: some Term::ReadLine implementations don't support features that we sort
|
2008-11-12 15:48:37 -05:00
|
|
|
# of need. Term::ReadLine::Gnu is strongly recommended.
|
2008-05-15 03:20:41 -04:00
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# globals
|
2008-05-15 03:20:41 -04:00
|
|
|
Getopt::Long::Configure('bundling');
|
|
|
|
$| = 1;
|
|
|
|
$Data::Dumper::Terse = 1;
|
|
|
|
$Data::Dumper::Indent = 1;
|
2008-05-16 16:27:03 -04:00
|
|
|
my $PIPE;
|
2008-05-30 02:27:42 -04:00
|
|
|
my $PKG = __PACKAGE__;
|
2008-05-15 03:20:41 -04:00
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# usage function
|
2008-05-15 03:20:41 -04:00
|
|
|
sub usage {
|
|
|
|
my($status) = @_;
|
2008-05-16 09:24:17 -04:00
|
|
|
my $prog = File::Basename::basename($0);
|
2008-05-15 03:20:41 -04:00
|
|
|
print <<EOT;
|
|
|
|
usage: $prog [options]
|
|
|
|
-h,--help show this message
|
|
|
|
-e,--eval STR eval STR before interaction
|
2008-05-19 10:51:10 -04:00
|
|
|
-p,--pipe run in pipe mode
|
|
|
|
-q,--quiet hide undef eval output
|
2008-05-15 03:20:41 -04:00
|
|
|
-r,--run PATH run PATH before interaction
|
2008-05-19 10:51:10 -04:00
|
|
|
-v,--verbose output all eval results (default)
|
2008-05-15 03:20:41 -04:00
|
|
|
|
|
|
|
perl needs a good interpreter.
|
|
|
|
EOT
|
|
|
|
exit($status);
|
|
|
|
}
|
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# handy function for printing nice representations of data
|
|
|
|
sub repr {
|
2008-05-15 03:20:41 -04:00
|
|
|
my ($item) = @_;
|
|
|
|
if(!defined($item)) {
|
|
|
|
return 'undef';
|
|
|
|
} elsif(Scalar::Util::blessed($item)) {
|
|
|
|
return "$item";
|
|
|
|
} elsif(ref($item) eq 'CODE') {
|
|
|
|
return "$item";
|
|
|
|
} else {
|
|
|
|
my $s = Dumper($item);
|
|
|
|
$s =~ s/\n+$//;
|
|
|
|
return $s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-18 10:39:08 -04:00
|
|
|
# find the object referenced by a name
|
|
|
|
sub resolve_ref {
|
|
|
|
my ($name) = @_;
|
|
|
|
my ($obj, $reftype, $package);
|
|
|
|
$obj = eval("$name");
|
|
|
|
my $reftype = $obj ? Scalar::Util::reftype($obj) : '';
|
|
|
|
my $package = $obj ? ref($obj) : '';
|
|
|
|
return ($obj, $reftype, $package);
|
|
|
|
}
|
|
|
|
|
2008-05-30 02:27:42 -04:00
|
|
|
# the completer used by readline
|
|
|
|
sub readline_complete {
|
2008-05-20 09:54:19 -04:00
|
|
|
my ($word, $line, $x) = @_;
|
2008-05-30 02:27:42 -04:00
|
|
|
my $full_word = readline_full_word($word, $line, $x);
|
2008-06-05 21:55:17 -04:00
|
|
|
my $delta = length($full_word) - length($word);
|
2008-06-18 11:19:12 -04:00
|
|
|
#print STDERR "XYZ '$word' '$full_word' '$delta'\n";
|
2008-05-30 02:27:42 -04:00
|
|
|
my @candidates = complete($full_word);
|
|
|
|
return map { substr($_, $delta) } @candidates;
|
|
|
|
}
|
2008-05-20 09:54:19 -04:00
|
|
|
|
2008-05-30 02:27:42 -04:00
|
|
|
# some handy regexs
|
|
|
|
my $name_re = qr/[a-zA-Z_][a-zA-Z0-9_]*/;
|
|
|
|
my $name2_re = qr/(?:[a-zA-Z_][a-zA-Z0-9_]*)?/;
|
|
|
|
my $sub_pkg_re = qr/(?:${name_re}::)*/;
|
|
|
|
my $pkg_re = qr/(?:${name_re}::)*${name_re}/;
|
2008-05-20 09:54:19 -04:00
|
|
|
|
2008-05-30 02:27:42 -04:00
|
|
|
my $hash_re = qr/\$(${pkg_re}){/;
|
|
|
|
my $hash_ref_re = qr/\$(${pkg_re})->{/;
|
|
|
|
my $obj_method_re = qr/(\$${pkg_re})->/;
|
|
|
|
my $cls_method_re = qr/(${pkg_re})->/;
|
|
|
|
my $default_re1 = qr/([\@\$\%\&\*]?)()()(${name_re})/;
|
|
|
|
my $default_re2 = qr/([\@\$\%\&\*]?)(${pkg_re})(::)(${name_re})/;
|
|
|
|
my $default_re3 = qr/([\@\$\%\&\*]?)(${pkg_re})(:{0,2})()/;
|
2008-05-19 01:53:31 -04:00
|
|
|
|
2008-05-30 02:27:42 -04:00
|
|
|
# XYZ
|
|
|
|
sub isa_complete {
|
|
|
|
my ($var_name, $pkg, $method_name) = @_;
|
|
|
|
my $names = {};
|
|
|
|
_isa_complete($pkg, $method_name, {}, $names);
|
|
|
|
return map { "${var_name}->$_" } keys(%$names);
|
|
|
|
}
|
|
|
|
sub _isa_complete {
|
|
|
|
my ($pkg, $name, $proc, $names) = @_;
|
|
|
|
return if $proc->{$pkg};
|
|
|
|
$proc->{$pkg} = 1;
|
|
|
|
map { _isa_complete($_, $name, $proc, $names) } (eval("\@${pkg}::ISA"));
|
|
|
|
foreach my $item (eval("keys(\%${pkg}::)")) {
|
|
|
|
next unless $item =~ m/^${name_re}$/;
|
|
|
|
if(!$names->{$item} && $item =~ m/^$name/) {
|
|
|
|
$names->{$item} = 1 if eval("defined(&::${pkg}::${item})");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sub sigil_complete {
|
|
|
|
my ($type, $sigil, $pkg, $sep, $name) = @_;
|
2008-06-05 21:55:17 -04:00
|
|
|
#print STDERR " $type|$sigil|$pkg|$sep|$name\n";
|
2008-05-30 02:27:42 -04:00
|
|
|
my $base = $pkg . $sep . $name;
|
|
|
|
my @names;
|
|
|
|
my @pkgs = _pkg_complete($pkg, $sep, $name, 1);
|
|
|
|
foreach my $pkg2 (@pkgs) {
|
|
|
|
#print " XYZ '$type' '$name' '$pkg2'\n";
|
|
|
|
foreach my $item (eval("\%${pkg2}::")) {
|
|
|
|
next unless $item =~ m/^${name_re}$/;
|
|
|
|
my $base2 = $pkg2 . ($pkg2 ? '::' : '') . $item;
|
|
|
|
next unless $base2 =~ m/^$base/;
|
|
|
|
#print " OOP defined(${type}::${base2})\n";
|
|
|
|
if(eval("defined(${type}::${base2})\n")) {
|
|
|
|
#print " YES ${sigil}${base2}\n";
|
|
|
|
push(@names, $sigil . $base2);
|
|
|
|
}
|
|
|
|
}
|
2008-05-19 01:53:31 -04:00
|
|
|
}
|
2008-05-30 02:27:42 -04:00
|
|
|
return @names;
|
|
|
|
}
|
|
|
|
sub pkg_complete {
|
2008-06-18 11:19:12 -04:00
|
|
|
my ($pkg, $sep, $name, $returnself) = @_;
|
|
|
|
$returnself = defined($returnself) ? $returnself : !($pkg && $sep);
|
|
|
|
my @pkgs = _pkg_complete($pkg, $sep, $name, $returnself);
|
2008-05-30 02:27:42 -04:00
|
|
|
my $base = $pkg . $sep . $name;
|
|
|
|
return grep {$_ =~ m/^$base/ } @pkgs;
|
|
|
|
}
|
|
|
|
sub _pkg_complete {
|
|
|
|
my ($pkg, $sep, $name, $returnself) = @_;
|
|
|
|
my @pkgs = $returnself ? ($pkg) : ();
|
|
|
|
foreach my $item (eval("\%${pkg}::")) {
|
|
|
|
next unless $item =~ m/^(${name_re})::$/;
|
|
|
|
my $item2 = $1;
|
|
|
|
next if $pkg =~ m/::$item2$/;
|
|
|
|
if($item =~ m/^$name/) {
|
|
|
|
my $pkg2 = ($pkg ? "${pkg}::" : "") . $item2;
|
|
|
|
push(@pkgs, _pkg_complete($pkg2, undef, "", 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return @pkgs;
|
|
|
|
}
|
2008-05-19 01:53:31 -04:00
|
|
|
|
2008-05-30 02:27:42 -04:00
|
|
|
sub complete {
|
|
|
|
my ($word) = @_;
|
|
|
|
|
|
|
|
my @words;
|
|
|
|
if($word =~ m/^${obj_method_re}(${name2_re})$/) {
|
|
|
|
# obj dereference
|
|
|
|
my ($obj_name, $method_name) = ($1, $2);
|
|
|
|
my($obj, $reftype, $package) = resolve_ref($obj_name);
|
2008-05-18 10:39:08 -04:00
|
|
|
if($reftype eq $package) {
|
2008-05-30 02:27:42 -04:00
|
|
|
unless($method_name) {
|
|
|
|
if($reftype eq 'CODE') {
|
|
|
|
@words = ("$word\(");
|
|
|
|
} elsif($reftype eq 'HASH') {
|
|
|
|
@words = ("$word\{");
|
|
|
|
} elsif($reftype eq 'ARRAY') {
|
|
|
|
@words = ("$word\[");
|
|
|
|
}
|
2008-05-18 10:39:08 -04:00
|
|
|
}
|
|
|
|
} else {
|
2008-05-30 02:27:42 -04:00
|
|
|
@words = isa_complete($obj_name, $package, $method_name);
|
2008-05-18 10:39:08 -04:00
|
|
|
}
|
2008-05-30 02:27:42 -04:00
|
|
|
} elsif($word =~ m/^${cls_method_re}(${name2_re})$/) {
|
2008-05-18 10:39:08 -04:00
|
|
|
# package dereference
|
2008-05-30 02:27:42 -04:00
|
|
|
my ($cls_name, $method_name) = ($1, $2);
|
|
|
|
@words = isa_complete($cls_name, $cls_name, $method_name);
|
|
|
|
} elsif($word =~ m/^${hash_re}(.*)$/) {
|
|
|
|
# literal hash
|
|
|
|
my ($hash, $key) = ($1, $2);
|
|
|
|
my $obj = eval("\\\%$hash");
|
2008-06-18 11:19:12 -04:00
|
|
|
my @keys = keys(%$obj);
|
|
|
|
unless(@keys) {
|
|
|
|
$obj = eval("\\\%${PKG}::${hash}");
|
|
|
|
@keys = keys(%$obj);
|
2008-05-30 02:27:42 -04:00
|
|
|
}
|
2008-06-18 11:19:12 -04:00
|
|
|
@words = map { "\$${hash}{$_" } grep { $_ =~ m/^$key/ } @keys;
|
2008-05-30 02:27:42 -04:00
|
|
|
} elsif($word =~ m/^${hash_ref_re}(.*)$/) {
|
|
|
|
# hashref
|
|
|
|
my ($hash, $key) = ($1, $2);
|
|
|
|
my $obj = eval("\$$hash");
|
|
|
|
if($obj) {
|
|
|
|
@words = map { "\$${hash}->{$_" } grep { $_ =~ m/^$key/ } keys(%$obj);
|
|
|
|
}
|
|
|
|
} elsif($word =~ m/^${default_re1}$/ || $word =~ m/^${default_re2}$/ || $word =~ m/^${default_re3}$/) {
|
|
|
|
# package or simple var
|
|
|
|
my($sigil, $pkg, $sep, $name) = ($1, $2, $3, $4);
|
2008-06-05 21:55:17 -04:00
|
|
|
#print STDERR "\n$sigil|$pkg|$sep|$name\n";
|
2008-05-30 02:27:42 -04:00
|
|
|
my($oldpkg, $oldsep) = ($pkg, $sep);
|
|
|
|
if($PKG && $pkg eq '' && $sep eq '') {
|
|
|
|
($pkg, $sep) = ($PKG, '::');
|
|
|
|
}
|
|
|
|
if($sigil eq '$') {
|
2008-06-05 21:55:17 -04:00
|
|
|
foreach my $pair ([$pkg, $sep], ['', '']) {
|
|
|
|
my ($_pkg, $_sep) = @$pair;
|
|
|
|
push(@words, sigil_complete('$', '$', $_pkg, $_sep, $name));
|
|
|
|
push(@words, map {"$_\["} sigil_complete('@', '$', $_pkg, $_sep, $name));
|
|
|
|
push(@words, map {"$_\{"} sigil_complete('%', '$', $_pkg, $_sep, $name));
|
|
|
|
}
|
2008-05-30 02:27:42 -04:00
|
|
|
} elsif($sigil) {
|
|
|
|
@words = sigil_complete($sigil, $sigil, $pkg, $sep, $name);
|
2008-05-18 10:39:08 -04:00
|
|
|
} else {
|
2008-05-30 02:27:42 -04:00
|
|
|
push(@words, pkg_complete($pkg, $sep, $name));
|
2008-06-18 11:19:12 -04:00
|
|
|
push(@words, pkg_complete($name, '', '', 0)) unless $oldpkg;
|
2008-05-30 02:27:42 -04:00
|
|
|
push(@words, sigil_complete('&', '', $pkg, $sep, $name));
|
2008-05-18 10:39:08 -04:00
|
|
|
}
|
2008-05-30 02:27:42 -04:00
|
|
|
if($oldpkg ne $pkg) {
|
2008-06-18 11:19:12 -04:00
|
|
|
@words = map { $_ =~ s/${pkg}${sep}//; $_ } @words;
|
2008-05-30 02:27:42 -04:00
|
|
|
}
|
|
|
|
}
|
2008-06-18 11:19:12 -04:00
|
|
|
#print STDERR "XYZ" . join("|", @words) . "\n";
|
2008-05-30 02:27:42 -04:00
|
|
|
return sort(@words);
|
|
|
|
}
|
|
|
|
|
|
|
|
# use sigilfind to get completions for particular word(s)
|
|
|
|
sub readline_full_word {
|
|
|
|
my ($word, $line, $x) = @_;
|
|
|
|
my $pre = substr($line, 0, $x);
|
|
|
|
if(length($line) == $x && $pre =~ m/^[ \t]*$/) {
|
|
|
|
return undef;
|
|
|
|
} elsif($pre =~ m/$obj_method_re$/) {
|
|
|
|
return $1 . "->" . $word;
|
|
|
|
} elsif($pre =~ m/$cls_method_re$/) {
|
|
|
|
return $1 . "->" . $word;
|
|
|
|
} elsif($pre =~ m/$hash_re$/) {
|
|
|
|
return '$' . $1 . "{" . $word;
|
|
|
|
} elsif($pre =~ m/$hash_ref_re$/) {
|
|
|
|
return '$' . $1 . "->{" . $word;
|
|
|
|
} else {
|
|
|
|
return $word;
|
2008-05-18 10:39:08 -04:00
|
|
|
}
|
2008-05-15 03:20:41 -04:00
|
|
|
}
|
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# display completions to the user
|
|
|
|
sub draw_completions {
|
|
|
|
my (@items) = @_;
|
2008-05-20 09:54:19 -04:00
|
|
|
my($prefix, $delim) = $pipe ? ("COMPLETIONS:", "|") : ("", "\n");
|
2008-05-16 16:27:03 -04:00
|
|
|
print $prefix . join($delim, @items) . "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
# some help text
|
2008-05-15 03:20:41 -04:00
|
|
|
my $HELP = <<EOT;
|
|
|
|
Greetings!
|
|
|
|
|
|
|
|
I'm program is designed to help you write Perl. Like the "perl" command,
|
|
|
|
I can parse and execute Perl code. Unlike it, I can execute perl code
|
|
|
|
interactively, allowing you to call functions, save their results, inspect
|
2008-05-16 16:27:03 -04:00
|
|
|
the results, and repeat. I also support tab-completion!
|
2008-05-15 03:20:41 -04:00
|
|
|
|
|
|
|
I contain a lot of tricky functionality.
|
|
|
|
|
|
|
|
One side-note: I can't be run under the "strict" pragma; thus, you don't
|
|
|
|
need to use my() or our() to declare variables. The reaon for this has to
|
2008-05-16 16:27:03 -04:00
|
|
|
do with the way I evaluate blocks. Sorry.
|
2008-05-15 03:20:41 -04:00
|
|
|
EOT
|
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# the big one!
|
2008-05-28 14:58:55 -04:00
|
|
|
sub run {
|
2008-05-18 10:39:08 -04:00
|
|
|
# ugh stupid fucking Term::ReadLine's automatic escapes
|
2008-05-20 08:55:13 -04:00
|
|
|
my ($prompt1, $prompt2) = (">>>", '..>');
|
|
|
|
#my ($prompt1, $prompt2) = ("\001\033[24m\002>>>", "\001\033[24m\002..>");
|
2008-05-18 10:39:08 -04:00
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# process the arguments provided; save original @ARGV for use later
|
2008-05-19 10:51:10 -04:00
|
|
|
my $quiet;
|
2008-05-16 16:27:03 -04:00
|
|
|
my @preload;
|
|
|
|
my @oldargv = @ARGV;
|
|
|
|
Getopt::Long::GetOptions(
|
|
|
|
'help|h' => sub { usage(0); },
|
|
|
|
'eval|e=s' => sub { push(@preload, ['eval', $_[1]]); },
|
|
|
|
'pipe|p' => sub { $pipe = 'line' },
|
|
|
|
'run|r=s' => sub { push(@preload, ['run', $_[1]]); },
|
|
|
|
'use|u=s' => sub { push(@preload, ['use', $_[1]]); },
|
2008-05-19 10:51:10 -04:00
|
|
|
'quiet|q' => sub { $quiet = 1; },
|
|
|
|
'verbose|v' => sub { $quiet = undef; },
|
2008-05-16 16:27:03 -04:00
|
|
|
) || usage(1);
|
|
|
|
|
|
|
|
# let's display a nice banner to the user
|
2008-05-18 10:39:08 -04:00
|
|
|
my ($prompt, $input, $term) = ($prompt1, "", undef);
|
2008-05-16 16:27:03 -04:00
|
|
|
unless($pipe) {
|
|
|
|
print "Welcome to Erik's Perl Interpreter\n";
|
|
|
|
print "(Type \":help\", \":exit\", or something else)\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
# for every file or perl string we were given, eval them in order; we should
|
|
|
|
# die if any of them fail to load.
|
2008-05-15 03:20:41 -04:00
|
|
|
foreach my $pair (@preload) {
|
|
|
|
if($pair->[0] eq 'eval') {
|
2008-05-30 02:27:42 -04:00
|
|
|
$PKG = eval "$pair->[1]; return __PACKAGE__";
|
2008-05-15 03:20:41 -04:00
|
|
|
die "failed to eval '$pair->[1]': $@" if $@;
|
|
|
|
} elsif($pair->[0] eq 'run') {
|
|
|
|
die "no path named $pair->[1] found" unless -e $pair->[1];
|
2008-06-19 22:05:28 -04:00
|
|
|
open(FH, $pair->[1]);
|
|
|
|
my $data = join("", <FH>);
|
|
|
|
close(FH);
|
2008-05-30 02:27:42 -04:00
|
|
|
$PKG = eval "$data; return __PACKAGE__";
|
2008-05-15 03:20:41 -04:00
|
|
|
die "failed to run $pair->[1]: $@" if $@;
|
|
|
|
} elsif($pair->[0] eq 'use') {
|
|
|
|
eval "use $pair->[1]";
|
|
|
|
die "failed to use $pair->[1]: $@" if $@;
|
|
|
|
}
|
|
|
|
}
|
2008-05-16 16:27:03 -04:00
|
|
|
|
|
|
|
# set up readline if necessary
|
2008-05-15 03:20:41 -04:00
|
|
|
unless($pipe) {
|
2008-06-17 19:00:06 -04:00
|
|
|
require Term::ReadLine;
|
2008-05-15 03:20:41 -04:00
|
|
|
$term = Term::ReadLine->new('IPERL');
|
|
|
|
my $attribs = $term->Attribs();
|
|
|
|
$attribs->{special_prefixes} = '$@%*&';
|
2008-05-30 02:27:42 -04:00
|
|
|
$attribs->{completion_function} = \&readline_complete;
|
2008-05-18 10:39:08 -04:00
|
|
|
$attribs->{completion_append_character} = '';
|
2008-05-15 03:20:41 -04:00
|
|
|
}
|
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# the mighty read-exec-print loop!
|
2008-05-15 03:20:41 -04:00
|
|
|
while(1) {
|
2008-05-16 16:27:03 -04:00
|
|
|
# display the prompt and read some input
|
2008-05-15 03:20:41 -04:00
|
|
|
my $line;
|
|
|
|
if($pipe) {
|
2008-05-26 23:57:09 -04:00
|
|
|
print "\nPROMPT:$prompt\n";
|
2008-05-15 03:20:41 -04:00
|
|
|
$line = <STDIN>;
|
|
|
|
} else {
|
|
|
|
$line = $term->readline("$prompt ");
|
|
|
|
}
|
|
|
|
last unless defined($line);
|
|
|
|
chomp($line);
|
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# if we're in pipe-mode then we expect input in a special form
|
2008-05-15 03:20:41 -04:00
|
|
|
if($pipe) {
|
2008-05-20 09:54:19 -04:00
|
|
|
if($line =~ m/^ENTER:(.*)$/) {
|
2008-05-15 03:20:41 -04:00
|
|
|
$line = $1;
|
2008-05-30 02:27:42 -04:00
|
|
|
} elsif($line =~ m/^COMPLETE:(.*)$/) {
|
|
|
|
my @candidates = complete($1);
|
|
|
|
draw_completions(@candidates);
|
|
|
|
next;
|
|
|
|
} elsif($line =~ m/^READLINE:(\d+):(\d+):(.*)$/) {
|
2008-05-20 09:54:19 -04:00
|
|
|
my $x = $2;
|
|
|
|
my $line = $3;
|
|
|
|
my $word = substr($line, $1, $x - $1);
|
2008-06-18 11:19:12 -04:00
|
|
|
#print STDERR "ABC '$1' '$2' '$3' '$word'\n";
|
|
|
|
my @candidates = readline_complete($word, $line, $x);
|
2008-05-30 02:27:42 -04:00
|
|
|
draw_completions(@candidates);
|
2008-05-16 16:27:03 -04:00
|
|
|
next;
|
2008-05-15 03:20:41 -04:00
|
|
|
} else {
|
2008-05-20 09:54:19 -04:00
|
|
|
print "malformed pipe input line: $line\n";
|
2008-05-15 03:20:41 -04:00
|
|
|
next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-16 16:27:03 -04:00
|
|
|
# process the line of input
|
2008-05-15 03:20:41 -04:00
|
|
|
if($line eq '') {
|
2008-05-16 16:27:03 -04:00
|
|
|
} elsif($line eq ':exit' || $line eq ':quit') {
|
2008-05-15 03:20:41 -04:00
|
|
|
last;
|
2008-05-16 16:27:03 -04:00
|
|
|
} elsif($line eq ':help') {
|
2008-05-18 10:39:08 -04:00
|
|
|
($input, $prompt) = ("", $prompt1);
|
2008-05-16 09:24:17 -04:00
|
|
|
print $HELP;
|
2008-05-16 16:27:03 -04:00
|
|
|
} elsif($line eq ':reload') {
|
2008-05-18 10:39:08 -04:00
|
|
|
($input, $prompt) = ("", $prompt1);
|
2008-05-16 09:24:17 -04:00
|
|
|
print "reloading...\n";
|
2008-05-16 16:27:03 -04:00
|
|
|
exec($0, @oldargv);
|
|
|
|
} elsif($line eq ':sh') {
|
2008-05-18 10:39:08 -04:00
|
|
|
($input, $prompt) = ("", $prompt1);
|
2008-05-15 03:20:41 -04:00
|
|
|
system("bash") unless $pipe;
|
2008-05-16 16:27:03 -04:00
|
|
|
} elsif($line =~ m/^:sh (.+)$/) {
|
2008-05-18 10:39:08 -04:00
|
|
|
($input, $prompt) = ("", $prompt1);
|
2008-05-15 03:20:41 -04:00
|
|
|
system($1) unless $pipe;
|
|
|
|
} elsif($line eq ':code') {
|
2008-05-30 02:27:42 -04:00
|
|
|
draw_completions(sort(sigil_complete('&', '&', $PKG, '', '')));
|
2008-05-15 03:20:41 -04:00
|
|
|
} elsif($line eq ':scalar') {
|
2008-05-30 02:27:42 -04:00
|
|
|
draw_completions(sort(sigil_complete('$', '$', $PKG, '', '')));
|
2008-05-15 03:20:41 -04:00
|
|
|
} elsif($line eq ':hash') {
|
2008-05-30 02:27:42 -04:00
|
|
|
draw_completions(sort(sigil_complete('%', '%', $PKG, '', '')));
|
2008-05-15 03:20:41 -04:00
|
|
|
} elsif($line eq ':array') {
|
2008-05-30 02:27:42 -04:00
|
|
|
draw_completions(sort(sigil_complete('@', '@', $PKG, '', '')));
|
2008-05-15 03:20:41 -04:00
|
|
|
} elsif($line eq ':glob') {
|
2008-05-30 02:27:42 -04:00
|
|
|
draw_completions(sort(sigil_complete('*', '*', $PKG, '', '')));
|
|
|
|
} elsif($line =~ m/^\:isa (${pkg_re})$/) {
|
|
|
|
draw_completions(sort(isa_complete($1, $1, '')));
|
2008-05-16 16:27:03 -04:00
|
|
|
} elsif($line =~ m/^[\t ]/ || $line =~ m/\{ *$/ || m/\\ *$/) {
|
|
|
|
# we're dealing with an incomplete statement, so defer execution
|
2008-05-15 03:20:41 -04:00
|
|
|
$line =~ s/\\ *$//;
|
|
|
|
$input .= $line;
|
2008-05-18 10:39:08 -04:00
|
|
|
$prompt = $prompt2;
|
2008-05-15 03:20:41 -04:00
|
|
|
} else {
|
2008-05-16 16:27:03 -04:00
|
|
|
# we're dealing with a complete statement, so execute and display
|
2008-05-15 03:20:41 -04:00
|
|
|
$input .= $line;
|
2008-06-18 11:19:12 -04:00
|
|
|
my @results = map { repr($_) } eval("package $PKG; $input");
|
2008-05-15 03:20:41 -04:00
|
|
|
if($@) {
|
2008-05-16 09:24:17 -04:00
|
|
|
print $@;
|
2008-05-16 16:27:03 -04:00
|
|
|
} elsif(scalar(@results) == 0) {
|
|
|
|
} elsif(scalar(@results) == 1) {
|
2008-05-19 10:51:10 -04:00
|
|
|
if(!$quiet || $results[0] ne 'undef') {
|
|
|
|
print $results[0] . "\n";
|
|
|
|
}
|
2008-05-15 03:20:41 -04:00
|
|
|
} else {
|
2008-05-16 09:24:17 -04:00
|
|
|
print join(", ", @results) . "\n";
|
2008-05-15 03:20:41 -04:00
|
|
|
}
|
2008-05-18 10:39:08 -04:00
|
|
|
($input, $prompt) = ("", $prompt1);
|
2008-05-15 03:20:41 -04:00
|
|
|
}
|
|
|
|
}
|
2008-05-16 09:24:17 -04:00
|
|
|
print "Bye.\n";
|
2008-05-15 03:20:41 -04:00
|
|
|
}
|
2008-05-28 14:58:55 -04:00
|
|
|
run();
|