use crate::expr::Expr;
use sexp::{Sexp,Atom};
pub fn uncurry_sexp(e: &Sexp) -> Sexp {
match e {
Sexp::List(orig_list) => {
assert!(orig_list.len() > 1);
let uncurried_children: Vec<Sexp> = orig_list.iter().map(uncurry_sexp).collect();
match uncurried_children[0].to_string().as_str() {
"lam" => {
Sexp::List(uncurried_children)
},
"app" => {
assert_eq!(uncurried_children.len(), 3);
let has_inner_app = if let Sexp::List(innerlist) = &orig_list[1] {
innerlist[0].to_string().as_str() == "app"
} else { false };
let f = uncurried_children[1].clone();
let x = uncurried_children[2].clone();
let mut res = vec![];
if has_inner_app {
match f {
Sexp::List(list) => { res.extend(list) }
_ => panic!("expected list, got {}", f)
}
} else {
res.push(f);
}
res.push(x);
Sexp::List(res)
},
"programs" => {
Sexp::List(uncurried_children)
}
_ => {
panic!("not curried {}",e);
}
}
},
Sexp::Atom(atom) => Sexp::Atom(atom.clone())
}
}
pub fn curry_sexp(e: &Sexp) -> Sexp {
let app:Sexp = Sexp::Atom(Atom::S("app".into()));
match e {
Sexp::List(list) => {
assert!(list.len() > 1);
let list: Vec<Sexp> = list.iter().map(curry_sexp).collect();
match list[0].to_string().as_str() {
"lam" => {
Sexp::List(list)
},
"app" => panic!("already curried: {}",e),
"programs" => {
Sexp::List(list)
}
_ => {
let mut res = Sexp::List(vec![app.clone(), list[0].clone(), list[1].clone()]);
for item in list.iter().skip(2) {
res = Sexp::List(vec![app.clone(), res, item.clone()])
}
res
}
}
},
Sexp::Atom(atom) => Sexp::Atom(atom.clone())
}
}
impl std::str::FromStr for Expr {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.contains("(app ") {
Self::from_curried(s)
} else {
Self::from_uncurried(s)
}
}
}