use myslip::parse::parsetree::parse_to_ast; use myslip::sexp::{SExp, SExp::*, SLeaf::Nil, util::scons}; use myslip::r#type::Type::NilType; 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 = vec![]; loop { let (eof, input) = prompt_line(&stdin, &mut stdout)?; if eof || input == "exit\n" { break; } let orig_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; }, }; if let Some((name, _value)) = orig_expression.clone().check_let() { let mut expr = scons(orig_expression.clone(), scons(Nil, Nil)); for i in 1..=binds.len() { expr = scons(binds[binds.len() - i].clone(), expr); } match expr.type_check() { Ok(NilType) => { binds.push(orig_expression); println!("{name} saved"); continue; }, Err(e) => { println!("Type error: {}", e); continue; }, Ok(_) => (), } } let mut expression = orig_expression.clone(); 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(()) }