Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 26 additions & 33 deletions src/shell.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
mod helper;

use rustpython_parser::error::{LexicalErrorType, ParseErrorType};
use rustpython_parser::{
error::{LexicalErrorType, ParseErrorType},
token::Tok,
};
use rustpython_vm::{
builtins::PyBaseExceptionRef,
compiler::{self, CompileError, CompileErrorBody, CompileErrorType},
Expand All @@ -19,15 +22,13 @@ fn shell_exec(
vm: &VirtualMachine,
source: &str,
scope: Scope,
last_row: &mut usize,
empty_line_given: bool,
continuing: bool,
) -> ShellExecResult {
match vm.compile(source, compiler::Mode::Single, "<stdin>".to_owned()) {
Ok(code) => {
if empty_line_given || !continuing {
// We want to execute the full code
*last_row = 0;
match vm.run_code_obj(code, scope) {
Ok(_val) => ShellExecResult::Ok,
Err(err) => ShellExecResult::PyErr(err),
Expand All @@ -54,28 +55,30 @@ fn shell_exec(
..
}) => ShellExecResult::Continue,
Err(err) => {
// Indent error or something else?
let indent_error = match err.body.error {
CompileErrorType::Parse(ref p) => p.is_indentation_error(),
_ => false,
// bad_error == true if we are handling an error that should be thrown even if we are continuing
// if its an indentation error, set to true if we are continuing and the error is on column 0,
// since indentations errors on columns other than 0 should be ignored.
// if its an unrecognized token for dedent, set to false

let bad_error = match err.body.error {
CompileErrorType::Parse(ref p) => {
if matches!(
p,
ParseErrorType::Lexical(LexicalErrorType::IndentationError)
) {
continuing && err.body.location.column() != 0
} else {
!matches!(p, ParseErrorType::UnrecognizedToken(Tok::Dedent, _))
}
}
_ => true, // It is a bad error for everything else
};

if indent_error && !empty_line_given {
// The input line is not empty and it threw an indentation error
let l = err.body.location;

// This is how we can mask unnecesary errors
if l.row() > *last_row {
*last_row = l.row();
ShellExecResult::Continue
} else {
*last_row = 0;
ShellExecResult::PyErr(vm.new_syntax_error(&err))
}
} else {
// Throw the error for all other cases
*last_row = 0;
// If we are handling an error on an empty line or an error worthy of throwing
if empty_line_given || bad_error {
ShellExecResult::PyErr(vm.new_syntax_error(&err))
} else {
ShellExecResult::Continue
}
}
}
Expand All @@ -100,7 +103,6 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
}

let mut continuing = false;
let mut last_row: usize = 0;

loop {
let prompt_name = if continuing { "ps2" } else { "ps1" };
Expand Down Expand Up @@ -128,14 +130,7 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
}
full_input.push('\n');

match shell_exec(
vm,
&full_input,
scope.clone(),
&mut last_row,
empty_line_given,
continuing,
) {
match shell_exec(vm, &full_input, scope.clone(), empty_line_given, continuing) {
ShellExecResult::Ok => {
if continuing {
if empty_line_given {
Expand All @@ -150,7 +145,6 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
}
} else {
// We aren't in continue mode so proceed normally
last_row = 0;
continuing = false;
full_input.clear();
Ok(())
Expand All @@ -168,7 +162,6 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
}
}
ReadlineResult::Interrupt => {
last_row = 0;
continuing = false;
full_input.clear();
let keyboard_interrupt =
Expand Down