From 863d03575ba1423bce7fcb1070f04848ed2fe0b8 Mon Sep 17 00:00:00 2001 From: Alex Bethel Date: Sat, 9 Oct 2021 22:31:14 -0600 Subject: [PATCH] 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. --- ablescript/src/lib.rs | 2 +- ablescript_cli/src/repl.rs | 59 +++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/ablescript/src/lib.rs b/ablescript/src/lib.rs index 7a4e40b2..a7335344 100644 --- a/ablescript/src/lib.rs +++ b/ablescript/src/lib.rs @@ -1,12 +1,12 @@ #![forbid(unsafe_code, clippy::unwrap_used)] pub mod ast; +pub mod error; pub mod interpret; pub mod parser; mod base_55; mod brian; mod consts; -mod error; mod lexer; mod variables; diff --git a/ablescript_cli/src/repl.rs b/ablescript_cli/src/repl.rs index c98a31ea..ce1ab652 100644 --- a/ablescript_cli/src/repl.rs +++ b/ablescript_cli/src/repl.rs @@ -6,39 +6,44 @@ use ablescript::parser::Parser; pub fn repl(ast_print: bool) { let mut rl = Editor::<()>::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 = None; loop { - let readline = rl.readline(":: "); - match readline { - Ok(line) => { - // NOTE(Alex): `readline()` leaves a newline at the - // end of the string if stdin is connected to a file - // or unsupported terminal; this can interfere with - // error printing. - rl.add_history_entry(&line); - let line = line.trim_end(); + match rl.readline(if partial.is_some() { ">> " } else { ":: " }) { + Ok(readline) => { + let readline = readline.trim_end(); + let partial_data = match partial { + Some(line) => line + &readline, + None => readline.to_owned(), + }; - if line == "exit" { - println!("bye"); - break; - } - - let mut parser = Parser::new(line); - let value = parser.init().and_then(|ast| { + partial = match Parser::new(&partial_data).init().and_then(|ast| { if ast_print { println!("{:#?}", &ast); } env.eval_stmts(&ast) - }); - - if let Err(e) = value { - println!("{}", e); - println!(" | {}", line); - println!( - " {}{}", - " ".repeat(e.span.start), - "^".repeat((e.span.end - e.span.start).max(1)) - ); - } + }) { + Ok(_) => None, + 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!(" | {}", partial_data); + println!( + " {}{}", + " ".repeat(e.span.start), + "^".repeat((e.span.end - e.span.start).max(1)) + ); + None + } + }; } Err(rustyline::error::ReadlineError::Eof) => { println!("bye");