Skip to content
Merged
Show file tree
Hide file tree
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
22 changes: 17 additions & 5 deletions compiler/parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,23 @@ pub(crate) fn parse_error_from_lalrpop(
source_path,
}
}
LalrpopError::UnrecognizedEOF { location, .. } => ParseError {
error: ParseErrorType::Eof,
location,
source_path,
},
LalrpopError::UnrecognizedEOF { location, expected } => {
// This could be an initial indentation error that we should ignore
let indent_error = expected == ["Indent"];
if indent_error {
ParseError {
error: ParseErrorType::Lexical(LexicalErrorType::IndentationError),
location,
source_path,
}
} else {
ParseError {
error: ParseErrorType::Eof,
location,
source_path,
}
}
}
}
}

Expand Down
94 changes: 76 additions & 18 deletions src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,28 @@ enum ShellExecResult {
Continue,
}

fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> ShellExecResult {
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) => match vm.run_code_obj(code, scope) {
Ok(_val) => ShellExecResult::Ok,
Err(err) => ShellExecResult::PyErr(err),
},
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),
}
} else {
// We can just return an ok result
ShellExecResult::Ok
}
}
Err(CompileError {
body:
CompileErrorBody {
Expand All @@ -37,7 +53,31 @@ fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> ShellExecResul
},
..
}) => ShellExecResult::Continue,
Err(err) => ShellExecResult::PyErr(vm.new_syntax_error(&err)),
Err(err) => {
// Indent error or something else?
let indent_error = match err.body.error {
CompileErrorType::Parse(ref p) => p.is_indentation_error(),
_ => false,
};

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;
ShellExecResult::PyErr(vm.new_syntax_error(&err))
}
}
}
}

Expand All @@ -60,6 +100,7 @@ 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 All @@ -78,7 +119,7 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {

repl.add_history_entry(line.trim_end()).unwrap();

let stop_continuing = line.is_empty();
let empty_line_given = line.is_empty();

if full_input.is_empty() {
full_input = line;
Expand All @@ -87,30 +128,47 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
}
full_input.push('\n');

if continuing {
if stop_continuing {
continuing = false;
} else {
continue;
}
}

match shell_exec(vm, &full_input, scope.clone()) {
match shell_exec(
vm,
&full_input,
scope.clone(),
&mut last_row,
empty_line_given,
continuing,
) {
ShellExecResult::Ok => {
full_input.clear();
Ok(())
if continuing {
if empty_line_given {
// We should be exiting continue mode
continuing = false;
full_input.clear();
Ok(())
} else {
// We should stay in continue mode
continuing = true;
Ok(())
}
} else {
// We aren't in continue mode so proceed normally
last_row = 0;
continuing = false;
full_input.clear();
Ok(())
}
}
ShellExecResult::Continue => {
continuing = true;
Ok(())
}
ShellExecResult::PyErr(err) => {
continuing = false;
full_input.clear();
Err(err)
}
}
}
ReadlineResult::Interrupt => {
last_row = 0;
continuing = false;
full_input.clear();
let keyboard_interrupt =
Expand Down