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.
pull/2/head
Alex Bethel 2021-10-09 22:31:14 -06:00
parent 3342419242
commit 5c9c759be2
2 changed files with 33 additions and 28 deletions

View File

@ -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;

View File

@ -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<String> = 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");