use std::io::{self, BufRead, Write};
use std::process::ExitCode;
use doge_compiler::{parse_repl, ReplParse};
use doge_interp::Interp;
use doge_runtime::Value;
const BANNER: &str = "much doge. very repl. leave with wow or ctrl-d.";
const PROMPT: &str = "doge> ";
const CONTINUE: &str = "... ";
const REPL_PATH: &str = "<repl>";
pub fn run() -> ExitCode {
println!("{BANNER}");
let mut interp = Interp::new();
let stdin = io::stdin();
let mut buffer = String::new();
let mut continuing = false;
prompt(continuing);
for line in stdin.lock().lines() {
let Ok(line) = line else { break };
if continuing {
if line.trim().is_empty() {
evaluate(&mut interp, &buffer, true);
buffer.clear();
continuing = false;
} else {
buffer.push_str(&line);
buffer.push('\n');
}
} else {
let trimmed = line.trim();
if trimmed.is_empty() {
prompt(false);
continue;
}
if trimmed == "wow" {
break;
}
buffer.clear();
buffer.push_str(&line);
buffer.push('\n');
continuing = !evaluate(&mut interp, &buffer, false);
if !continuing {
buffer.clear();
}
}
prompt(continuing);
}
println!();
ExitCode::SUCCESS
}
fn prompt(continuing: bool) {
let prompt = if continuing { CONTINUE } else { PROMPT };
print!("{prompt}");
let _ = io::stdout().flush();
}
fn evaluate(interp: &mut Interp, source: &str, force: bool) -> bool {
match parse_repl(REPL_PATH, source) {
ReplParse::Complete(script) => {
run_checked(interp, source, &script);
true
}
ReplParse::Incomplete(diag) => {
if force {
eprint!("{}", diag.render());
true
} else {
false
}
}
ReplParse::Error(diag) => {
eprint!("{}", diag.render());
true
}
}
}
fn run_checked(interp: &mut Interp, source: &str, script: &doge_compiler::Script) {
let session = interp.session_scope();
if let Err(diag) = doge_compiler::check_snippet(REPL_PATH, source, script, &session) {
eprint!("{}", diag.render());
return;
}
match interp.eval_snippet(REPL_PATH, script) {
Ok(Some(Value::None)) | Ok(None) => {}
Ok(Some(value)) => println!("{value}"),
Err(err) => {
let (_, line) = interp.error_site();
let src = source
.lines()
.nth((line as usize).saturating_sub(1))
.unwrap_or("");
eprintln!("very error. much broken.\n\n {REPL_PATH}:{line}\n {src}\n {err}");
}
}
}