use std::collections::HashMap; use fancy_regex::Regex; use std::fmt; use std::fs::File; use std::io; use std::io::{BufRead, BufReader}; use std::num::ParseFloatError; use std::rc::Rc; /* Types */ #[derive(Clone)] enum RispExp { Bool(bool), Symbol(String), Number(f64), List(Vec), Func(fn(&[RispExp]) -> Result), Lambda(RispLambda), } #[derive(Clone)] struct RispLambda { params_exp: Rc, body_exp: Rc, } impl fmt::Display for RispExp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let str = match self { RispExp::Bool(a) => a.to_string(), RispExp::Symbol(s) => s.clone(), RispExp::Number(n) => n.to_string(), RispExp::List(list) => { let xs: Vec = list.iter().map(|x| x.to_string()).collect(); format!("({})", xs.join(",")) } RispExp::Func(_) => "Function {}".to_string(), RispExp::Lambda(_) => "Lambda {}".to_string(), }; write!(f, "{}", str) } } #[derive(Debug)] enum RispErr { Reason(String), } #[derive(Clone)] struct RispEnv<'a> { data: HashMap, outer: Option<&'a RispEnv<'a>>, } /* InPort */ // TODO change to symbol(eof) struct InPort { line: String, lines: Vec, cur_line: usize } impl InPort { fn init(filename: String) -> InPort { let file = File::open(filename).unwrap(); let reader = io::BufReader::new(file).lines().map(|s| s.ok().unwrap().to_string()).collect(); InPort { line : String::new(), lines: reader, cur_line: 0 } } pub fn next_token(&mut self) -> String { loop { if self.line.is_empty() { self.line = self.lines.get(self.cur_line).unwrap_or(&"#".to_string()).to_string(); self.cur_line = self.cur_line + 1; } if self.line.is_empty() { return "#".to_string(); } let (token, rest) = InPort::tokenize(self.line.clone()); self.line = rest; if !token.is_empty() { return token; } } } fn tokenize(expr: String) -> (String, String) { let re = Regex::new(r#"\s*(,@|[('`,)]|"(?:[\\].|[^\\"])*"|;.*|[^\s('"`,;)]*)(.*)"#).unwrap(); let result = re.captures(&expr); let captures = result .expect("Error running regex") .expect("No match found"); // println!("{}", captures.get(0).unwrap().as_str().to_string()); ( captures.get(1).unwrap().as_str().to_string(), captures.get(2).unwrap().as_str().to_string(), ) } } // TODO change return type to Symbol fn read(inport: InPort) -> String { fn read_ahead(token: String) { match token { "(" => { let L = Vec::new(); loop { let token = inport.next_token(); if token == ")" { return L; } else { L.append(read_ahead(token)); } } }, _ => { println!("{}", token); } } } let token1 = inport.next_token(); if token1 == "#".to_string() { return "#".to_string(); } } fn parse_atom(token: &str) -> RispExp { match token.as_ref() { "true" => RispExp::Bool(true), "false" => RispExp::Bool(false), _ => { let potential_float: Result = token.parse(); match potential_float { Ok(v) => RispExp::Number(v), Err(_) => RispExp::Symbol(token.to_string().clone()), } } } } /* Env */ macro_rules! ensure_tonicity { ($check_fn:expr) => {{ |args: &[RispExp]| -> Result { let floats = parse_list_of_floats(args)?; let first = floats .first() .ok_or(RispErr::Reason("expected at least one number".to_string()))?; let rest = &floats[1..]; fn f(prev: &f64, xs: &[f64]) -> bool { match xs.first() { Some(x) => $check_fn(prev, x) && f(x, &xs[1..]), None => true, } }; Ok(RispExp::Bool(f(first, rest))) } }}; } fn default_env<'a>() -> RispEnv<'a> { let mut data: HashMap = HashMap::new(); data.insert( "+".to_string(), RispExp::Func(|args: &[RispExp]| -> Result { let sum = parse_list_of_floats(args)? .iter() .fold(0.0, |sum, a| sum + a); Ok(RispExp::Number(sum)) }), ); data.insert( "-".to_string(), RispExp::Func(|args: &[RispExp]| -> Result { let floats = parse_list_of_floats(args)?; let first = *floats .first() .ok_or(RispErr::Reason("expected at least one number".to_string()))?; let sum_of_rest = floats[1..].iter().fold(0.0, |sum, a| sum + a); Ok(RispExp::Number(first - sum_of_rest)) }), ); data.insert( "=".to_string(), RispExp::Func(ensure_tonicity!(|a, b| a == b)), ); data.insert( ">".to_string(), RispExp::Func(ensure_tonicity!(|a, b| a > b)), ); data.insert( ">=".to_string(), RispExp::Func(ensure_tonicity!(|a, b| a >= b)), ); data.insert( "<".to_string(), RispExp::Func(ensure_tonicity!(|a, b| a < b)), ); data.insert( "<=".to_string(), RispExp::Func(ensure_tonicity!(|a, b| a <= b)), ); RispEnv { data, outer: None } } fn parse_list_of_floats(args: &[RispExp]) -> Result, RispErr> { args.iter().map(|x| parse_single_float(x)).collect() } fn parse_single_float(exp: &RispExp) -> Result { match exp { RispExp::Number(num) => Ok(*num), _ => Err(RispErr::Reason("expected a number".to_string())), } } /* Eval */ fn eval_if_args(arg_forms: &[RispExp], env: &mut RispEnv) -> Result { let test_form = arg_forms .first() .ok_or(RispErr::Reason("expected test form".to_string()))?; let test_eval = eval(test_form, env)?; match test_eval { RispExp::Bool(b) => { let form_idx = if b { 1 } else { 2 }; let res_form = arg_forms .get(form_idx) .ok_or(RispErr::Reason(format!("expected form idx={}", form_idx)))?; let res_eval = eval(res_form, env); res_eval } _ => Err(RispErr::Reason(format!( "unexpected test form='{}'", test_form.to_string() ))), } } fn eval_def_args(arg_forms: &[RispExp], env: &mut RispEnv) -> Result { let first_form = arg_forms .first() .ok_or(RispErr::Reason("expected first form".to_string()))?; let first_str = match first_form { RispExp::Symbol(s) => Ok(s.clone()), _ => Err(RispErr::Reason( "expected first form to be a symbol".to_string(), )), }?; let second_form = arg_forms .get(1) .ok_or(RispErr::Reason("expected second form".to_string()))?; if arg_forms.len() > 2 { return Err(RispErr::Reason("def can only have two forms ".to_string())); } let second_eval = eval(second_form, env)?; env.data.insert(first_str, second_eval); Ok(first_form.clone()) } fn eval_lambda_args(arg_forms: &[RispExp]) -> Result { let params_exp = arg_forms .first() .ok_or(RispErr::Reason("expected args form".to_string()))?; let body_exp = arg_forms .get(1) .ok_or(RispErr::Reason("expected second form".to_string()))?; if arg_forms.len() > 2 { return Err(RispErr::Reason( "fn definition can only have two forms ".to_string(), )); } Ok(RispExp::Lambda(RispLambda { body_exp: Rc::new(body_exp.clone()), params_exp: Rc::new(params_exp.clone()), })) } fn eval_built_in_form( exp: &RispExp, arg_forms: &[RispExp], env: &mut RispEnv, ) -> Option> { match exp { RispExp::Symbol(s) => match s.as_ref() { "if" => Some(eval_if_args(arg_forms, env)), "def" => Some(eval_def_args(arg_forms, env)), "fn" => Some(eval_lambda_args(arg_forms)), _ => None, }, _ => None, } } fn env_get(k: &str, env: &RispEnv) -> Option { match env.data.get(k) { Some(exp) => Some(exp.clone()), None => match &env.outer { Some(outer_env) => env_get(k, &outer_env), None => None, }, } } fn parse_list_of_symbol_strings(form: Rc) -> Result, RispErr> { let list = match form.as_ref() { RispExp::List(s) => Ok(s.clone()), _ => Err(RispErr::Reason( "expected args form to be a list".to_string(), )), }?; list.iter() .map(|x| match x { RispExp::Symbol(s) => Ok(s.clone()), _ => Err(RispErr::Reason( "expected symbols in the argument list".to_string(), )), }) .collect() } fn env_for_lambda<'a>( params: Rc, arg_forms: &[RispExp], outer_env: &'a mut RispEnv, ) -> Result, RispErr> { let ks = parse_list_of_symbol_strings(params)?; if ks.len() != arg_forms.len() { return Err(RispErr::Reason(format!( "expected {} arguments, got {}", ks.len(), arg_forms.len() ))); } let vs = eval_forms(arg_forms, outer_env)?; let mut data: HashMap = HashMap::new(); for (k, v) in ks.iter().zip(vs.iter()) { data.insert(k.clone(), v.clone()); } Ok(RispEnv { data, outer: Some(outer_env), }) } fn eval_forms(arg_forms: &[RispExp], env: &mut RispEnv) -> Result, RispErr> { arg_forms.iter().map(|x| eval(x, env)).collect() } fn eval(exp: &RispExp, env: &mut RispEnv) -> Result { match exp { RispExp::Symbol(k) => { env_get(k, env).ok_or(RispErr::Reason(format!("unexpected symbol k='{}'", k))) } RispExp::Bool(_a) => Ok(exp.clone()), RispExp::Number(_a) => Ok(exp.clone()), RispExp::List(list) => { let first_form = list .first() .ok_or(RispErr::Reason("expected a non-empty list".to_string()))?; let arg_forms = &list[1..]; match eval_built_in_form(first_form, arg_forms, env) { Some(res) => res, None => { let first_eval = eval(first_form, env)?; match first_eval { RispExp::Func(f) => f(&eval_forms(arg_forms, env)?), RispExp::Lambda(lambda) => { let new_env = &mut env_for_lambda(lambda.params_exp, arg_forms, env)?; eval(&lambda.body_exp, new_env) } _ => Err(RispErr::Reason("first form must be a function".to_string())), } } } } RispExp::Func(_) => Err(RispErr::Reason("unexpected form".to_string())), RispExp::Lambda(_) => Err(RispErr::Reason("unexpected form".to_string())), } } fn main() { let env = &mut default_env(); let mut reader = InPort::init("new.lisp".to_string()); let mut token = String::new(); read(reader); // read from file // let file = File::open("new.lisp").unwrap(); // let lines = io::BufReader::new(file).lines(); // let mut cur_line = String::new(); // let mut token = String::new(); // for line in lines { // let (token, cur_line) = tokenize(line.ok().unwrap().as_str().to_string()); // println!("token {:?}", token); // println!("line {:?}", cur_line); // } /* loop { println!("risp >"); let expr = slurp_expr(); match parse_eval(expr, env) { Ok(res) => println!("// 🔥 => {}", res), Err(e) => match e { RispErr::Reason(msg) => println!("// 🙀 => {}", msg), }, } } */ }