Skip to content

Commit

Permalink
Make the REPL a little bit smarter
Browse files Browse the repository at this point in the history
Basically, any line that does *not* create any direct output to
STDOUT, becomes part of the code that will be executed whenever
the next line is input.  This is a behaviour similar to what is
done when a line is deemed incomplete.  The only difference is,
is that this new behaviour will not be visible because of a prompt
change.

This fixes a number of issues with information being lost between
lines, makes a TODO pass in t/02-rakudo/repl.t and is basically a
fix for issues #2284 and #3925.  Matias Linares++ Altai-man++ for
keeping me tortured :-)

Please be aware that this potentially opens a whole new nest of
REPL bugs.  We'll cross that bridge when we get there.
  • Loading branch information
lizmat committed Nov 22, 2020
1 parent 15ec4fe commit 7c0a81f
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 16 deletions.
49 changes: 34 additions & 15 deletions src/core.c/REPL.pm6
Expand Up @@ -358,29 +358,44 @@ do {
next;
}

if $*MAIN_CTX {
$!save_ctx := $*MAIN_CTX;
}

reset;

# Print the result if:
# - there wasn't some other output
# - the result is an *unhandled* Failure
# - print an exception if one had occured
# Handle problems
if $exception.DEFINITE {
self.repl-print($exception);
}
elsif $initial_out_position == $*OUT.tell
or nqp::istype($output, Failure) and not $output.handled {
elsif nqp::istype($output, Failure) and not $output.handled {
self.repl-print($output);
}

# If there was no explicit output (and no error seen yet),
# then assume something was being set up (such as a multi
# candidate) which would need to be included in any
# subsequent input. Basically treat this as an incomplete
# input so that it will be part of the next line entered.
# But only do this *if* printing the output was succesful!
# If the output was e.g. a lazy Seq that blows up the moment
# it gets stringified, then we treat it as an error by
# falling through after all.
elsif $initial_out_position == $*OUT.tell {
if self.repl-print($output) {
$code ~= ";"; # make sure statement is finished
next;
}
}

# Start with clean slate otherwise
if $*MAIN_CTX {
$!save_ctx := $*MAIN_CTX;
}
reset;

# Why doesn't the catch-default in repl-eval catch all?
# Because the return value can be something lazy that blows
# up on stringification. But that should be handled by
# the CATCH in repl-print. So this CATCH is really only
# a fallback for the case that something goes awry in here.
CATCH {
default { say $_; reset }
}

}

self.teardown;
Expand All @@ -402,15 +417,19 @@ do {
and $value.WHERE == $!control-not-allowed.WHERE
}

method repl-print(Mu $value --> Nil) {
method repl-print(Mu $value --> Bool:D) {
my $method := %*ENV<RAKU_REPL_OUTPUT_METHOD> // "gist";
nqp::can($value,$method)
and say $value."$method"()
or say "(low-level object `$value.^name()`)";

CATCH {
default { say ."$method"() }
default {
say ."$method"();
return False;
}
}
True
}

method history-file(--> Str:D) {
Expand Down
1 change: 0 additions & 1 deletion t/02-rakudo/repl.t
Expand Up @@ -220,7 +220,6 @@ is-run-repl ['Nil'], /Nil/, 'REPL outputs Nil as a Nil';
'num32 $i, num64 $j,',
') = 1, 2, 3, 4, 5, 6, 7, 8, 9e0, 10e0;';

todo 'https://github.com/Raku/old-issue-tracker/issues/5245';
is-run-repl "$code\nsay 'test is good';\n",
:err(''),
:out(/'(1 2 3 4 5 6 7 8 9 10)' .* 'test is good'/),
Expand Down

0 comments on commit 7c0a81f

Please sign in to comment.