Support multiline repl input

This commit is contained in:
Richard Feldman 2020-04-21 23:35:39 -04:00
parent 1bb99bc490
commit 526d7cb4ba

View file

@ -22,7 +22,7 @@ use roc_mono::expr::Procs;
use roc_mono::layout::Layout; use roc_mono::layout::Layout;
use roc_parse::ast::{self, Attempting}; use roc_parse::ast::{self, Attempting};
use roc_parse::blankspace::space0_before; use roc_parse::blankspace::space0_before;
use roc_parse::parser::{loc, Fail, Parser, State}; use roc_parse::parser::{loc, Fail, FailReason, Parser, State};
use roc_problem::can::Problem; use roc_problem::can::Problem;
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
use roc_solve::solve; use roc_solve::solve;
@ -44,8 +44,15 @@ pub fn main() -> io::Result<()> {
// Loop // Loop
let mut pending_src = String::new();
let mut prev_line_blank = false;
loop { loop {
print!("\n\u{001b}[36m▶\u{001b}[0m "); if pending_src.is_empty() {
print!("\n\u{001b}[36m▶\u{001b}[0m ");
} else {
print!("\u{001b}[36m…\u{001b}[0m ");
}
io::stdout().flush().unwrap(); io::stdout().flush().unwrap();
@ -62,17 +69,68 @@ pub fn main() -> io::Result<()> {
println!("Use :exit to exit."); println!("Use :exit to exit.");
} }
"" => { "" => {
println!("\n{}", WELCOME_MESSAGE); if pending_src.is_empty() {
println!("\n{}", WELCOME_MESSAGE);
} else if prev_line_blank {
// After two blank lines in a row, give up and try parsing it
// even though it's going to fail. This way you don't get stuck.
match print_output(pending_src.as_str()) {
Ok(output) => {
println!("{}", output);
}
Err(fail) => {
report_parse_error(fail);
}
}
pending_src.clear();
} else {
pending_src.push('\n');
prev_line_blank = true;
continue; // Skip the part where we reset prev_line_blank to false
}
} }
":exit" => { ":exit" => {
break; break;
} }
line => { line => {
let (answer, answer_type) = gen(line, Triple::host(), OptLevel::Normal); let result = if pending_src.is_empty() {
print_output(line)
} else {
pending_src.push('\n');
pending_src.push_str(line);
println!("\n{} \u{001b}[35m:\u{001b}[0m {}", answer, answer_type); print_output(pending_src.as_str())
};
match result {
Ok(output) => {
println!("{}", output);
pending_src.clear();
}
Err(Fail {
reason: FailReason::Eof(_),
..
}) => {
// If we hit an eof, and we're allowed to keep going,
// append the str to the src we're building up and continue.
// (We only need to append it here if it was empty before;
// otherwise, we already appended it before calling print_output.)
if pending_src.is_empty() {
pending_src.push_str(line);
}
}
Err(fail) => {
report_parse_error(fail);
pending_src.clear();
}
}
} }
} }
prev_line_blank = false;
} }
Ok(()) Ok(())
@ -81,11 +139,21 @@ pub fn main() -> io::Result<()> {
const WELCOME_MESSAGE: &str = const WELCOME_MESSAGE: &str =
"Enter an expression, or :help for a list of commands, or :exit to exit."; "Enter an expression, or :help for a list of commands, or :exit to exit.";
fn report_parse_error(fail: Fail) {
println!("TODO Gracefully report parse error in repl: {:?}", fail);
}
fn print_output(src: &str) -> Result<String, Fail> {
gen(src, Triple::host(), OptLevel::Normal).map(|(answer, answer_type)| {
format!("\n{} \u{001b}[35m:\u{001b}[0m {}", answer, answer_type)
})
}
pub fn repl_home() -> ModuleId { pub fn repl_home() -> ModuleId {
ModuleIds::default().get_or_insert(&"REPL".into()) ModuleIds::default().get_or_insert(&"REPL".into())
} }
pub fn gen(src: &str, target: Triple, opt_level: OptLevel) -> (String, String) { pub fn gen(src: &str, target: Triple, opt_level: OptLevel) -> Result<(String, String), Fail> {
use roc_reporting::report::{can_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE}; use roc_reporting::report::{can_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE};
// Look up the types and expressions of the `provided` values // Look up the types and expressions of the `provided` values
@ -100,7 +168,7 @@ pub fn gen(src: &str, target: Triple, opt_level: OptLevel) -> (String, String) {
interns, interns,
problems: can_problems, problems: can_problems,
.. ..
} = can_expr(src); } = can_expr(src)?;
let subs = Subs::new(var_store.into()); let subs = Subs::new(var_store.into());
let mut type_problems = Vec::new(); let mut type_problems = Vec::new();
let (content, mut subs) = infer_expr(subs, &mut type_problems, &constraint, var); let (content, mut subs) = infer_expr(subs, &mut type_problems, &constraint, var);
@ -271,7 +339,7 @@ pub fn gen(src: &str, target: Triple, opt_level: OptLevel) -> (String, String) {
.ok_or(format!("Unable to JIT compile `{}`", main_fn_name)) .ok_or(format!("Unable to JIT compile `{}`", main_fn_name))
.expect("errored"); .expect("errored");
(format!("{}", main.call()), expr_type_str) Ok((format!("{}", main.call()), expr_type_str))
} }
} }
@ -292,10 +360,6 @@ pub fn infer_expr(
(content, solved.into_inner()) (content, solved.into_inner())
} }
pub fn parse_with<'a>(arena: &'a Bump, input: &'a str) -> Result<ast::Expr<'a>, Fail> {
parse_loc_with(arena, input).map(|loc_expr| loc_expr.value)
}
pub fn parse_loc_with<'a>(arena: &'a Bump, input: &'a str) -> Result<Located<ast::Expr<'a>>, Fail> { pub fn parse_loc_with<'a>(arena: &'a Bump, input: &'a str) -> Result<Located<ast::Expr<'a>>, Fail> {
let state = State::new(&input, Attempting::Module); let state = State::new(&input, Attempting::Module);
let parser = space0_before(loc(roc_parse::expr::expr(0)), 0); let parser = space0_before(loc(roc_parse::expr::expr(0)), 0);
@ -306,22 +370,25 @@ pub fn parse_loc_with<'a>(arena: &'a Bump, input: &'a str) -> Result<Located<ast
.map_err(|(fail, _)| fail) .map_err(|(fail, _)| fail)
} }
pub fn can_expr(expr_str: &str) -> CanExprOut { pub fn can_expr(expr_str: &str) -> Result<CanExprOut, Fail> {
can_expr_with(&Bump::new(), repl_home(), expr_str) can_expr_with(&Bump::new(), repl_home(), expr_str)
} }
pub fn uniq_expr( pub fn uniq_expr(
expr_str: &str, expr_str: &str,
) -> ( ) -> Result<
Located<roc_can::expr::Expr>, (
Output, Located<roc_can::expr::Expr>,
Vec<Problem>, Output,
Subs, Vec<Problem>,
Variable, Subs,
Constraint, Variable,
ModuleId, Constraint,
Interns, ModuleId,
) { Interns,
),
Fail,
> {
let declared_idents: &ImMap<Ident, (Symbol, Region)> = &ImMap::default(); let declared_idents: &ImMap<Ident, (Symbol, Region)> = &ImMap::default();
uniq_expr_with(&Bump::new(), expr_str, declared_idents) uniq_expr_with(&Bump::new(), expr_str, declared_idents)
@ -331,16 +398,19 @@ pub fn uniq_expr_with(
arena: &Bump, arena: &Bump,
expr_str: &str, expr_str: &str,
declared_idents: &ImMap<Ident, (Symbol, Region)>, declared_idents: &ImMap<Ident, (Symbol, Region)>,
) -> ( ) -> Result<
Located<roc_can::expr::Expr>, (
Output, Located<roc_can::expr::Expr>,
Vec<Problem>, Output,
Subs, Vec<Problem>,
Variable, Subs,
Constraint, Variable,
ModuleId, Constraint,
Interns, ModuleId,
) { Interns,
),
Fail,
> {
let home = repl_home(); let home = repl_home();
let CanExprOut { let CanExprOut {
loc_expr, loc_expr,
@ -350,7 +420,7 @@ pub fn uniq_expr_with(
var, var,
interns, interns,
.. ..
} = can_expr_with(arena, home, expr_str); } = can_expr_with(arena, home, expr_str)?;
// double check // double check
let var_store = VarStore::new(old_var_store.fresh()); let var_store = VarStore::new(old_var_store.fresh());
@ -389,9 +459,9 @@ pub fn uniq_expr_with(
let subs2 = Subs::new(var_store.into()); let subs2 = Subs::new(var_store.into());
( Ok((
loc_expr, output, problems, subs2, var, constraint, home, interns, loc_expr, output, problems, subs2, var, constraint, home, interns,
) ))
} }
pub struct CanExprOut { pub struct CanExprOut {
@ -405,14 +475,8 @@ pub struct CanExprOut {
pub constraint: Constraint, pub constraint: Constraint,
} }
pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut { pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> Result<CanExprOut, Fail> {
let loc_expr = parse_loc_with(&arena, expr_str).unwrap_or_else(|e| { let loc_expr = parse_loc_with(&arena, expr_str)?;
panic!(
"can_expr_with() got a parse error when attempting to canonicalize:\n\n{:?} {:?}",
expr_str, e
)
});
let var_store = VarStore::default(); let var_store = VarStore::default();
let var = var_store.fresh(); let var = var_store.fresh();
let expected = Expected::NoExpectation(Type::Variable(var)); let expected = Expected::NoExpectation(Type::Variable(var));
@ -488,7 +552,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
all_ident_ids, all_ident_ids,
}; };
CanExprOut { Ok(CanExprOut {
loc_expr, loc_expr,
output, output,
problems: env.problems, problems: env.problems,
@ -497,7 +561,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
interns, interns,
var, var,
constraint, constraint,
} })
} }
pub fn mut_map_from_pairs<K, V, I>(pairs: I) -> MutMap<K, V> pub fn mut_map_from_pairs<K, V, I>(pairs: I) -> MutMap<K, V>