Add statement continuation in REPL in CLI

Typing ```
var foo = [
``` into the REPL now causes it to prompt you to complete the
statement rather than just printing an "unexpected EOF" error.
This commit is contained in:
Alex Bethel 2021-10-09 22:31:14 -06:00
parent a3b6ae326e
commit 863d03575b
2 changed files with 33 additions and 28 deletions

View file

@ -1,12 +1,12 @@
#![forbid(unsafe_code, clippy::unwrap_used)] #![forbid(unsafe_code, clippy::unwrap_used)]
pub mod ast; pub mod ast;
pub mod error;
pub mod interpret; pub mod interpret;
pub mod parser; pub mod parser;
mod base_55; mod base_55;
mod brian; mod brian;
mod consts; mod consts;
mod error;
mod lexer; mod lexer;
mod variables; mod variables;

View file

@ -6,39 +6,44 @@ use ablescript::parser::Parser;
pub fn repl(ast_print: bool) { pub fn repl(ast_print: bool) {
let mut rl = Editor::<()>::new(); let mut rl = Editor::<()>::new();
let mut env = ExecEnv::new(); let mut env = ExecEnv::new();
// If this is `Some`, the user has previously entered an
// incomplete statement and is now completing it; otherwise, the
// user is entering a completely new statement.
let mut partial: Option<String> = None;
loop { loop {
let readline = rl.readline(":: "); match rl.readline(if partial.is_some() { ">> " } else { ":: " }) {
match readline { Ok(readline) => {
Ok(line) => { let readline = readline.trim_end();
// NOTE(Alex): `readline()` leaves a newline at the let partial_data = match partial {
// end of the string if stdin is connected to a file Some(line) => line + &readline,
// or unsupported terminal; this can interfere with None => readline.to_owned(),
// error printing. };
rl.add_history_entry(&line);
let line = line.trim_end();
if line == "exit" { partial = match Parser::new(&partial_data).init().and_then(|ast| {
println!("bye");
break;
}
let mut parser = Parser::new(line);
let value = parser.init().and_then(|ast| {
if ast_print { if ast_print {
println!("{:#?}", &ast); println!("{:#?}", &ast);
} }
env.eval_stmts(&ast) env.eval_stmts(&ast)
}); }) {
Ok(_) => None,
if let Err(e) = value { Err(ablescript::error::Error {
// Treat "Unexpected EOF" errors as "we need
// more data".
kind: ablescript::error::ErrorKind::UnexpectedEof,
..
}) => Some(partial_data),
Err(e) => {
println!("{}", e); println!("{}", e);
println!(" | {}", line); println!(" | {}", partial_data);
println!( println!(
" {}{}", " {}{}",
" ".repeat(e.span.start), " ".repeat(e.span.start),
"^".repeat((e.span.end - e.span.start).max(1)) "^".repeat((e.span.end - e.span.start).max(1))
); );
None
} }
};
} }
Err(rustyline::error::ReadlineError::Eof) => { Err(rustyline::error::ReadlineError::Eof) => {
println!("bye"); println!("bye");