use myslip::parse::parsetree::parse_to_ast; use myslip::sexp::{SExp::*, SLeaf::{Nil, Let}, util::scons}; use std::{io, io::Write}; fn main() { match repl() { Ok(()) => println!("bye :)"), Err(e) => println!("Error: {}", e), } } fn prompt_line(stdin: &io::Stdin, stdout: &mut io::Stdout) -> Result<(bool, String), io::Error> { let mut line = String::new(); print!("> "); match stdout.flush() { Ok(_) => (), Err(_) => println!("Enter s-expression:"), }; let code = stdin.read_line(&mut line)?; Ok((code == 0, line)) } fn repl() -> Result<(), io::Error> { let stdin = io::stdin(); let mut stdout = io::stdout(); let mut binds = vec![]; loop { let (eof, input) = prompt_line(&stdin, &mut stdout)?; if eof || input == "exit\n" { break; } let mut expression = match parse_to_ast(&input) { Ok(SCons(a, b)) if *b == Atom(Nil) => *a, Ok(t) => t, Err(e) => { println!("Syntax error: {}", e); continue; }, }; match &expression { SCons(l, _) if **l == Atom(Let) => match scons(expression.clone(), Nil).type_check() { Ok(_) => { binds.push(expression); println!("Bind saved"); continue; }, Err(e) => { println!("Type error: {e}"); continue; } }, _ => (), } for i in 1..=binds.len() { expression = scons(binds[binds.len() - i].clone(), expression); } let ty = match expression .type_check() .map_err(|e| e.to_string()) { Ok(t) => t, Err(e) => { println!("Type error: {}", e); continue; }, }; let result = match expression.multistep() { Ok(t) => t, Err(e) => { println!("Runtime error: {}", e); continue; }, }; println!("{} : {}", result, ty); } Ok(()) }