Last active
November 29, 2019 16:37
-
-
Save carrotflakes/0f9c35955bb8dec8d8fadbd17058f8ed to your computer and use it in GitHub Desktop.
[WIP] A Lisp implementation in Rust =>https://github.com/carrotflakes/gluten
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::rc::Rc; | |
use std::cell::RefCell; | |
use std::str::Chars; | |
type R<T> = Rc<RefCell<T>>; | |
#[derive(Debug, Clone)] | |
enum V { | |
Symbol(String), | |
Int(i64), | |
Cons(R<V>, R<V>), | |
Nil | |
} | |
fn r(v: V) -> R<V> { | |
Rc::new(RefCell::new(v)) | |
} | |
fn parse(src: &str) -> Result<R<V>, String> { | |
parse_value(&src.chars()).map(|x| x.0) | |
} | |
fn skip_whitespace<'a> (cs: &Chars<'a>) -> Chars<'a> { | |
let mut ncs = cs.clone(); | |
match ncs.next() { | |
Some(c) if c.is_whitespace() => | |
skip_whitespace(&ncs), | |
_ => cs.clone() | |
} | |
} | |
fn parse_value<'a>(cs: &Chars<'a>) -> Result<(R<V>, Chars<'a>), String> { | |
let mut cs = skip_whitespace(cs); | |
match cs.next() { | |
Some('(') => { | |
let mut vec = vec![]; | |
loop { | |
match parse_value(&cs) { | |
Ok((rv, ncs)) => { | |
vec.push(rv); | |
cs = ncs.clone(); | |
}, | |
_ => { | |
break; | |
} | |
} | |
} | |
cs = skip_whitespace(&cs); | |
let mut ret_rv = r(V::Nil); | |
while let Some(c) = cs.next() { | |
if c == ')' { | |
break; | |
} else if c == '.' { | |
cs = skip_whitespace(&cs); | |
if let Ok((rv, ncs)) = parse_value(&cs) { | |
ret_rv = rv; | |
cs = ncs.clone(); | |
cs = skip_whitespace(&cs); | |
if let Some(')') = cs.next() { | |
break; | |
} | |
} | |
} | |
return Err("fail".to_string()); | |
} | |
for rv in vec.into_iter().rev() { | |
ret_rv = r(V::Cons(rv, ret_rv)); | |
} | |
Ok((ret_rv, cs)) | |
}, | |
Some(c) if c.is_alphanumeric() => { | |
let mut vec = vec![c]; | |
let mut ncs = cs.clone(); | |
loop { | |
match ncs.next() { | |
Some(c) if c.is_alphanumeric() => { | |
vec.push(c); | |
cs = ncs.clone(); | |
}, | |
_ => { | |
break; | |
} | |
} | |
} | |
let s = vec.iter().collect(); | |
Ok((r(if &s == "nil" { V::Nil } else {V::Symbol(s)}), cs)) | |
}, | |
_ => Err("fail".to_string()) | |
} | |
} | |
#[derive(Debug)] | |
struct RVC<'a>(&'a V); | |
struct RVCTail<'a>(&'a V); | |
impl <'a> std::fmt::Display for RVC<'a> { | |
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
match self.0 { | |
V::Symbol(ref s) => write!(f, "{}", s), | |
v@V::Cons(_, _) => | |
write!(f, "({})", RVCTail(v)), | |
V::Nil => write!(f, "nil"), | |
v => write!(f, "{:?}!", v) | |
} | |
} | |
} | |
impl <'a> std::fmt::Display for RVCTail<'a> { | |
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
match self.0 { | |
V::Cons(ref car, ref cdr) => | |
match *cdr.borrow() { | |
V::Nil => write!(f, "{}", RVC(&car.borrow())), | |
V::Cons(_, _) => | |
write!(f, "{} {}", RVC(&car.borrow()), RVCTail(&cdr.borrow())), | |
_ => write!(f, "{} . {}", RVC(&car.borrow()), RVC(&cdr.borrow())), | |
} | |
rv => write!(f, "{}", RVC(rv)) | |
} | |
} | |
} | |
// macro_rules! pm_arm { | |
// (nil => $e:expr) => (V::Nil => $e); | |
// // (cons($car:pat, $cdr:pat)) => (V::Cons( | |
// ($p:pat => $e:expr) => ($p => $e); | |
// } | |
// macro_rules! pm { | |
// ($v:expr, $($x:pat => $y:expr),*) => { | |
// match $v { | |
// $( | |
// pm_arm!($x => $y) | |
// ),* | |
// } | |
// }; | |
// } | |
fn eval(rv: R<V>) -> R<V> { | |
match *rv.borrow() { | |
V::Cons(ref car, ref cdr) => | |
match *car.borrow() { | |
V::Symbol(ref s) if &*s == "quote" => | |
match *cdr.borrow() { | |
V::Cons(ref car, ref cdr) => | |
match *cdr.borrow() { | |
V::Nil => car.clone(), | |
_ => r(V::Nil) | |
}, | |
_ => r(V::Nil) | |
}, | |
_ => r(V::Nil) | |
}, | |
_ => r(V::Nil) | |
} | |
} | |
fn main() { | |
println!("Hello, world!"); | |
println!("{:?}", V::Cons(r(V::Int(1)), r(V::Int(2)))); | |
println!("{:?}", parse(" (abc 東京) ")); | |
println!("{}", RVC(&parse(" (abc 東京) ").unwrap().borrow())); | |
println!("{}", RVC(&parse(" ( abc () . 東京 ) ").unwrap().borrow())); | |
println!("{}", RVC(&parse(" ( abc (a) . 東京 ) ").unwrap().borrow())); | |
println!("{}", RVC(&parse(" ( abc (a b) . 東京 ) ").unwrap().borrow())); | |
println!("{}", RVC(&parse(" ( abc ( hello world .nil) . 東京 ) ").unwrap().borrow())); | |
println!("{}", RVC(&eval(parse("(quote a)").unwrap()).borrow())); | |
//println!("{}", pm!(1, 1 => 2, _ => 3)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment