Skip to content

Commit 817ed3d

Browse files
committed
changed the shell logic for handling indents
1 parent b6c9882 commit 817ed3d

File tree

2 files changed

+81
-20
lines changed

2 files changed

+81
-20
lines changed

compiler/parser/src/error.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,22 @@ pub(crate) fn parse_error_from_lalrpop(
205205
source_path,
206206
}
207207
}
208-
LalrpopError::UnrecognizedEOF { location, .. } => ParseError {
209-
error: ParseErrorType::Eof,
210-
location,
211-
source_path,
208+
LalrpopError::UnrecognizedEOF { location, expected } => {
209+
// This could be an initial indentation error that we should ignore
210+
let indent_error = expected == ["Indent"];
211+
if indent_error {
212+
ParseError {
213+
error: ParseErrorType::Lexical(LexicalErrorType::IndentationError),
214+
location,
215+
source_path,
216+
}
217+
} else {
218+
ParseError {
219+
error: ParseErrorType::Eof,
220+
location,
221+
source_path,
222+
}
223+
}
212224
},
213225
}
214226
}

src/shell.rs

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,20 @@ enum ShellExecResult {
1515
Continue,
1616
}
1717

18-
fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> ShellExecResult {
18+
fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope, last_row: &mut usize, empty_line_given: bool, continuing: bool) -> ShellExecResult {
1919
match vm.compile(source, compiler::Mode::Single, "<stdin>".to_owned()) {
20-
Ok(code) => match vm.run_code_obj(code, scope) {
21-
Ok(_val) => ShellExecResult::Ok,
22-
Err(err) => ShellExecResult::PyErr(err),
20+
Ok(code) => {
21+
if empty_line_given || !continuing {
22+
// We want to execute the full code
23+
*last_row = 0;
24+
match vm.run_code_obj(code, scope) {
25+
Ok(_val) => ShellExecResult::Ok,
26+
Err(err) => ShellExecResult::PyErr(err),
27+
}
28+
} else {
29+
// We can just return an ok result
30+
ShellExecResult::Ok
31+
}
2332
},
2433
Err(CompileError {
2534
body:
@@ -37,7 +46,31 @@ fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> ShellExecResul
3746
},
3847
..
3948
}) => ShellExecResult::Continue,
40-
Err(err) => ShellExecResult::PyErr(vm.new_syntax_error(&err)),
49+
Err(err) => {
50+
// Indent error or something else?
51+
let indent_error = match err.body.error {
52+
CompileErrorType::Parse(ref p) => p.is_indentation_error(),
53+
_ => false
54+
};
55+
56+
if indent_error && !empty_line_given {
57+
// The input line is not empty and it threw an indentation error
58+
let l = err.body.location;
59+
60+
// This is how we can mask unnecesary errors
61+
if l.row() > *last_row {
62+
*last_row = l.row();
63+
ShellExecResult::Continue
64+
} else {
65+
*last_row = 0;
66+
ShellExecResult::PyErr(vm.new_syntax_error(&err))
67+
}
68+
} else {
69+
// Throw the error for all other cases
70+
*last_row = 0;
71+
ShellExecResult::PyErr(vm.new_syntax_error(&err))
72+
}
73+
}
4174
}
4275
}
4376

@@ -60,6 +93,7 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
6093
}
6194

6295
let mut continuing = false;
96+
let mut last_row: usize = 0;
6397

6498
loop {
6599
let prompt_name = if continuing { "ps2" } else { "ps1" };
@@ -78,7 +112,7 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
78112

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

81-
let stop_continuing = line.is_empty();
115+
let empty_line_given = line.is_empty();
82116

83117
if full_input.is_empty() {
84118
full_input = line;
@@ -87,30 +121,45 @@ pub fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> {
87121
}
88122
full_input.push('\n');
89123

90-
if continuing {
91-
if stop_continuing {
92-
continuing = false;
93-
} else {
94-
continue;
95-
}
96-
}
97124

98-
match shell_exec(vm, &full_input, scope.clone()) {
125+
match shell_exec(vm, &full_input, scope.clone(), &mut last_row, empty_line_given, continuing) {
99126
ShellExecResult::Ok => {
100-
full_input.clear();
101-
Ok(())
127+
if continuing {
128+
129+
if empty_line_given {
130+
// We should be exiting continue mode
131+
continuing = false;
132+
full_input.clear();
133+
Ok(())
134+
} else {
135+
// We should stay in continue mode
136+
continuing = true;
137+
Ok(())
138+
}
139+
140+
} else {
141+
142+
// We aren't in continue mode so proceed normally
143+
last_row = 0;
144+
continuing = false;
145+
full_input.clear();
146+
Ok(())
147+
148+
}
102149
}
103150
ShellExecResult::Continue => {
104151
continuing = true;
105152
Ok(())
106153
}
107154
ShellExecResult::PyErr(err) => {
155+
continuing = false;
108156
full_input.clear();
109157
Err(err)
110158
}
111159
}
112160
}
113161
ReadlineResult::Interrupt => {
162+
last_row = 0;
114163
continuing = false;
115164
full_input.clear();
116165
let keyboard_interrupt =

0 commit comments

Comments
 (0)