├── .gitignore ├── Makefile ├── output.txt ├── input.txt ├── README.md ├── LICENSE └── lisp.rs /.gitignore: -------------------------------------------------------------------------------- 1 | lisp 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: lisp 2 | ./lisp < input.txt | diff - output.txt 3 | 4 | lisp: lisp.rs 5 | rustc lisp.rs 6 | -------------------------------------------------------------------------------- /output.txt: -------------------------------------------------------------------------------- 1 | > a 2 | > (b c) 3 | > (1 2 3) 4 | > fact 5 | > 3628800 6 | > fib 7 | > 233 8 | > gen 9 | > 10 | > 110 11 | > 200 12 | > 500 13 | > -------------------------------------------------------------------------------- /input.txt: -------------------------------------------------------------------------------- 1 | (car '(a b c)) 2 | (cdr '(a b c)) 3 | (cons 1 (cons 2 (cons 3 ()))) 4 | (defun fact (n) (if (eq n 0) 1 (* n (fact (- n 1))))) 5 | (fact 10) 6 | (defun fib (n) (if (eq n 1) 1 (if (eq n 0) 1 (+ (fib(- n 1)) (fib(- n 2)))))) 7 | (fib 12) 8 | (defun gen (n) (lambda (m) (setq n (+ n m)))) 9 | (setq x (gen 100)) 10 | (x 10) 11 | (x 90) 12 | (x 300) 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lisp.rs 2 | Lisp implementation in Rust. This implementation refers to https://github.com/zick/JavaLisp. 3 | 4 | ## How to use 5 | 6 | ``` 7 | $ rustc lisp.rs && ./lisp 8 | > (car '(a b c)) 9 | a 10 | > (cdr '(a b c)) 11 | (b c) 12 | > (cons 1 (cons 2 (cons 3 ()))) 13 | (1 2 3) 14 | > (defun fact (n) (if (eq n 0) 1 (* n (fact (- n 1))))) 15 | fact 16 | > (fact 10) 17 | 3628800 18 | > (defun fib (n) (if (eq n 1) 1 (if (eq n 0) 1 (+ (fib(- n 1)) (fib(- n 2)))))) 19 | fib 20 | > (fib 12) 21 | 233 22 | > (defun gen (n) (lambda (m) (setq n (+ n m)))) 23 | gen 24 | > (setq x (gen 100)) 25 | 26 | > (x 10) 27 | 110 28 | > (x 90) 29 | 200 30 | > (x 300) 31 | 500 32 | ``` 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Kentaro IMAJO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lisp.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | use std::io; 3 | use std::collections::HashMap; 4 | use std::collections::HashSet; 5 | 6 | #[derive(Clone, PartialEq, Eq, Hash)] 7 | struct LRef(i64); 8 | 9 | struct Arena { last: i64, data: HashMap } 10 | 11 | impl Arena { 12 | fn new() -> Arena { Arena { last: 0, data: HashMap::new() } } 13 | 14 | fn get(&self, key: &LRef) -> LObj 15 | { match self.data.get(&key) { Some(val) => val.clone(), _ => LObj::Nil } } 16 | fn set(&mut self, key: LRef, val: LObj) { self.data.insert(key, val); } 17 | 18 | fn make(&mut self, obj: LObj) -> LRef { 19 | self.last += 1; 20 | self.data.insert(LRef(self.last), obj); 21 | LRef(self.last) 22 | } 23 | 24 | fn to_string(&self, key: &LRef) -> String { 25 | match self.get(key) { 26 | LObj::Nil => "nil".to_string(), 27 | LObj::Sym(ref symbol) => symbol.clone(), 28 | LObj::Num(number) => format!("{}", number), 29 | LObj::Subr(_) => "".to_string(), 30 | LObj::Expr(_, _) => "".to_string(), 31 | LObj::Cons(_, _) => format!("({})", self.to_list_string(key)), 32 | } 33 | } 34 | 35 | fn to_list_string(&self, key: &LRef) -> String { 36 | match self.get(key) { 37 | LObj::Cons(ref car, ref cdr) => 38 | format!("{}{}", self.to_string(car), match self.get(cdr) { 39 | LObj::Nil => "".to_string(), 40 | LObj::Cons(_, _) => format!(" {}", self.to_list_string(cdr)), 41 | _ => format!(" . {}", self.to_string(cdr)) 42 | }), 43 | _ => "".to_string(), 44 | } 45 | } 46 | 47 | fn nreverse(&mut self, lst: LRef) -> LRef { 48 | let mut lst = lst; 49 | let mut ret = self.make(LObj::Nil); 50 | while let LObj::Cons(car, cdr) = self.get(&lst) { 51 | self.set(lst.clone(), LObj::Cons(car, ret)); 52 | ret = lst; 53 | lst = cdr; 54 | } 55 | ret 56 | } 57 | 58 | fn pairlis(&mut self, lst1: LRef, lst2: LRef) -> LRef { 59 | let mut lst1 = lst1; 60 | let mut lst2 = lst2; 61 | let mut ret = self.make(LObj::Nil); 62 | while let LObj::Cons(car1, cdr1) = self.get(&lst1) { 63 | if let LObj::Cons(car2, cdr2) = self.get(&lst2) { 64 | let car = self.make(LObj::Cons(car1, car2)); 65 | ret = self.make(LObj::Cons(car, ret)); 66 | lst1 = cdr1; 67 | lst2 = cdr2; 68 | continue; 69 | } 70 | break; 71 | } 72 | self.nreverse(ret) 73 | } 74 | } 75 | 76 | #[derive(Clone, PartialEq)] 77 | enum LObj { 78 | Nil, Sym(String), Num(i64), Subr(SubrFn), Expr(LRef, LRef), Cons(LRef, LRef), 79 | } 80 | 81 | impl LObj { 82 | fn sym(s: &str) -> LObj { LObj::Sym(s.into()) } 83 | fn t() -> LObj { LObj::sym("t") } 84 | 85 | fn car(&self, arena: &Arena) -> LObj 86 | { match self { &LObj::Cons(ref x, _) => arena.get(x), _ => LObj::Nil } } 87 | fn cdr(&self, arena: &Arena) -> LObj 88 | { match self { &LObj::Cons(_, ref x) => arena.get(x), _ => LObj::Nil } } 89 | } 90 | 91 | #[derive(Clone, PartialEq)] 92 | enum SubrFn 93 | { Car, Cdr, Cons, Eq, Atom, Numberp, Symbolp, Add, Mul, Sub, Div, Mod, T } 94 | 95 | impl SubrFn { 96 | fn call(&self, arena: &mut Arena, args: &LRef) -> LObj { 97 | if let LObj::Cons(ref car, ref cdr) = arena.get(args) { 98 | let cdar = arena.get(cdr).car(&arena); 99 | let cdar = arena.make(cdar); 100 | return match *self { 101 | SubrFn::Car => arena.get(car).car(&arena), 102 | SubrFn::Cdr => arena.get(car).cdr(&arena), 103 | SubrFn::Cons => LObj::Cons(car.clone(), cdar), 104 | SubrFn::Eq => match arena.get(car) == arena.get(&cdar) 105 | { true => LObj::t(), _ => LObj::Nil }, 106 | SubrFn::Atom => match arena.get(car) 107 | { LObj::Cons(_, _) => LObj::Nil, _ => LObj::t() }, 108 | SubrFn::Numberp => match arena.get(car) 109 | { LObj::Num(_) => LObj::t(), _ => LObj::Nil }, 110 | SubrFn::Symbolp => match arena.get(car) 111 | { LObj::Sym(_) => LObj::t(), _ => LObj::Nil }, 112 | SubrFn::Add => Self::fold(arena, car, cdr, &|x, y| x + y), 113 | SubrFn::Mul => Self::fold(arena, car, cdr, &|x, y| x * y), 114 | SubrFn::Sub => Self::fold(arena, car, cdr, &|x, y| x - y), 115 | SubrFn::Div => Self::fold(arena, car, cdr, &|x, y| x / y), 116 | SubrFn::Mod => Self::fold(arena, car, cdr, &|x, y| x % y), 117 | SubrFn::T => LObj::t(), 118 | }; 119 | } 120 | LObj::Nil 121 | } 122 | 123 | fn all() -> Vec<(SubrFn, &'static str)> { 124 | vec![(SubrFn::Car, "car"), (SubrFn::Cdr, "cdr"), (SubrFn::Cons, "cons"), 125 | (SubrFn::Eq, "eq"), (SubrFn::Atom, "atom"), 126 | (SubrFn::Numberp, "numberp"), (SubrFn::Symbolp, "symbolp"), 127 | (SubrFn::Add, "+"), (SubrFn::Mul, "*"), (SubrFn::Sub, "-"), 128 | (SubrFn::Div, "/"), (SubrFn::Mod, "mod"), (SubrFn::T, "t")] 129 | } 130 | 131 | fn fold(arena: &mut Arena, car: &LRef, cdr: &LRef, f: &Fn(i64, i64) -> i64) 132 | -> LObj { 133 | if let LObj::Num(x) = arena.get(car) { 134 | if let LObj::Cons(ref cdar, ref cddr) = arena.get(cdr) { 135 | if let LObj::Num(y) = arena.get(cdar) { 136 | let sum = &arena.make(LObj::Num(f(x, y))); 137 | return Self::fold(arena, sum, cddr, f); 138 | } 139 | } else { 140 | return arena.get(car); 141 | } 142 | } 143 | LObj::Nil 144 | } 145 | } 146 | 147 | struct Reader<'a> { next: &'a str } 148 | 149 | impl<'a> Reader<'a> { 150 | fn make_num_or_sym(s: &str) -> LObj 151 | { match s.parse::() { Ok(n) => LObj::Num(n), _ => LObj::sym(s) } } 152 | 153 | fn read_atom(&mut self) -> LObj { 154 | let (atom, next) = match self.next.find( 155 | |c: char| c == '(' || c == ')' || c == '\'' || c.is_whitespace()) 156 | { Some(pos) => self.next.split_at(pos), _ => (self.next, "") }; 157 | self.next = next; 158 | Self::make_num_or_sym(atom) 159 | } 160 | 161 | fn read_list(&mut self, arena: &mut Arena) -> Result { 162 | let mut ret = LObj::Nil; 163 | loop { 164 | self.next = self.next.trim_left(); 165 | if self.next.is_empty() { 166 | return Err("unfinished parenthesis".into()); 167 | } else if self.next.starts_with(")") { 168 | self.next = self.next.split_at(1).1; 169 | let ret = arena.make(ret); 170 | let ret = arena.nreverse(ret); 171 | return Ok(arena.get(&ret)); 172 | } 173 | let car = try!(self.read(arena)); 174 | ret = LObj::Cons(arena.make(car), arena.make(ret)); 175 | } 176 | } 177 | 178 | fn read(&mut self, arena: &mut Arena) -> Result { 179 | self.next = self.next.trim_left(); 180 | if self.next.is_empty() { 181 | return Err("empty input".into()); 182 | } else if self.next.starts_with(")") { 183 | return Err(format!("invalid syntax: {}", self.next)); 184 | } else if self.next.starts_with("(") { 185 | self.next = self.next.split_at(1).1; 186 | return self.read_list(arena); 187 | } else if self.next.starts_with("'") { 188 | self.next = self.next.split_at(1).1; 189 | let cdar = try!(self.read(arena)); 190 | let cdr = LObj::Cons(arena.make(cdar), arena.make(LObj::Nil)); 191 | return Ok(LObj::Cons(arena.make(LObj::sym("quote")), arena.make(cdr))); 192 | } 193 | Ok(self.read_atom()) 194 | } 195 | } 196 | 197 | struct Evaluator { arena: Arena, genv: LRef } 198 | 199 | impl Evaluator { 200 | fn new() -> Evaluator { 201 | let mut evaluator = Evaluator { arena: Arena::new(), genv: LRef(0) }; 202 | let nil = evaluator.arena.make(LObj::Nil); 203 | evaluator.genv = evaluator.arena.make(LObj::Cons(nil.clone(), nil.clone())); 204 | for (subr, name) in SubrFn::all() { 205 | evaluator.add_to_env(LObj::sym(name), LObj::Subr(subr)); 206 | } 207 | evaluator 208 | } 209 | 210 | fn find_var(&self, sym: &LObj, env: LRef) -> Option { 211 | let mut env = env; 212 | while let LObj::Cons(car, cdr) = self.arena.get(&env) { 213 | let mut alist = car; 214 | while let LObj::Cons(kv, next) = self.arena.get(&alist) { 215 | if let LObj::Cons(ref key, ref val) = self.arena.get(&kv) { 216 | if self.arena.get(key) == *sym { 217 | return Some(val.clone()); 218 | } 219 | } 220 | alist = next; 221 | } 222 | env = cdr; 223 | } 224 | None 225 | } 226 | 227 | fn add_to_env(&mut self, sym: LObj, val: LObj) { 228 | if let LObj::Cons(car, cdr) = self.arena.get(&self.genv) { 229 | let sym = self.arena.make(sym); 230 | let val = self.arena.make(val); 231 | let result = self.arena.make(LObj::Cons(sym, val)); 232 | let result = self.arena.make(LObj::Cons(result, car)); 233 | self.arena.set(self.genv.clone(), LObj::Cons(result, cdr)); 234 | } else { 235 | panic!("env must be cons"); 236 | } 237 | } 238 | 239 | fn eval(&mut self, obj: LObj, env: LRef) -> Result { 240 | return match &obj { 241 | &LObj::Nil | &LObj::Num(_) => Ok(obj.clone()), 242 | &LObj::Sym(ref name) => { 243 | let ret = match self.find_var(&obj, env) { 244 | Some(bind) => bind, 245 | _ => return Err(format!("{} has no value", name)), 246 | }; 247 | Ok(self.arena.get(&ret)) 248 | }, 249 | &LObj::Cons(ref f, ref args) => self.apply(f.clone(), args.clone(), env), 250 | _ => Ok(LObj::Nil), 251 | } 252 | } 253 | 254 | fn evlis(&mut self, lst: LRef, env: LRef) -> Result { 255 | let mut lst = lst; 256 | let mut ret = self.arena.make(LObj::Nil); 257 | while let LObj::Cons(car, cdr) = self.arena.get(&lst) { 258 | let car = self.arena.get(&car); 259 | let elm = try!(self.eval(car, env.clone())); 260 | let elm = self.arena.make(elm); 261 | ret = self.arena.make(LObj::Cons(elm, ret)); 262 | lst = cdr; 263 | } 264 | Ok(self.arena.nreverse(ret)) 265 | } 266 | 267 | fn progn(&mut self, body: LRef, env: LRef) -> Result { 268 | let mut body = body; 269 | let mut ret = LObj::Nil; 270 | while let LObj::Cons(car, cdr) = self.arena.get(&body) { 271 | let car = self.arena.get(&car); 272 | ret = try!(self.eval(car, env.clone())); 273 | body = cdr; 274 | } 275 | Ok(ret) 276 | } 277 | 278 | fn apply(&mut self, f: LRef, args: LRef, env: LRef) -> Result { 279 | if let LObj::Sym(name) = self.arena.get(&f) { 280 | match name.as_str() { 281 | "quote" => return Ok(self.arena.get(&args).car(&self.arena)), 282 | "if" => if let LObj::Cons(car, cdr) = self.arena.get(&args) { 283 | let car = self.arena.get(&car); 284 | let ret = match try!(self.eval(car, env.clone())) != LObj::Nil { 285 | true => self.arena.get(&cdr).car(&self.arena), 286 | _ => self.arena.get(&cdr).cdr(&self.arena).car(&self.arena), 287 | }; 288 | return self.eval(ret, env); 289 | } else { 290 | return Ok(LObj::Nil); 291 | }, 292 | "defun" => if let LObj::Cons(car, cdr) = self.arena.get(&args) { 293 | let car = self.arena.get(&car); 294 | self.add_to_env(car.clone(), LObj::Expr(cdr, env)); 295 | return Ok(car); 296 | } else { 297 | return Ok(LObj::Nil); 298 | }, 299 | "setq" => if let LObj::Cons(sym, val) = self.arena.get(&args) { 300 | let val = self.arena.get(&val).car(&self.arena); 301 | let val = try!(self.eval(val, env.clone())); 302 | let sym = self.arena.get(&sym); 303 | match self.find_var(&sym, env.clone()) { 304 | Some(bind) => self.arena.set(bind, val.clone()), 305 | None => self.add_to_env(sym, val.clone()), 306 | }; 307 | return Ok(val); 308 | } else { 309 | return Ok(LObj::Nil); 310 | }, 311 | "lambda" => return Ok(LObj::Expr(args, env)), 312 | _ => {}, 313 | } 314 | } 315 | let f = self.arena.get(&f); 316 | let f = try!(self.eval(f, env.clone())); 317 | let args = try!(self.evlis(args, env.clone())); 318 | return Ok(match f { 319 | LObj::Subr(subr) => subr.call(&mut self.arena, &args), 320 | LObj::Expr(body, env) => match self.arena.get(&body) { 321 | LObj::Cons(car, cdr) => { 322 | let args = self.arena.pairlis(car, args); 323 | let car = self.arena.make(LObj::Cons(args, env)); 324 | try!(self.progn(cdr, car)) 325 | }, 326 | _ => LObj::Nil, 327 | }, 328 | _ => return Err("not function".into()), 329 | }); 330 | } 331 | 332 | fn mark(&mut self, target: LRef, unused: &mut HashSet) { 333 | if !unused.remove(&target) { return; } 334 | match self.arena.get(&target) { 335 | LObj::Expr(a, b) | LObj::Cons(a, b) => { 336 | self.mark(a, unused); 337 | self.mark(b, unused); 338 | }, 339 | _ => {} 340 | } 341 | } 342 | 343 | fn garbage_collect(&mut self) { 344 | let mut unused = HashSet::new(); 345 | for key in self.arena.data.keys() { 346 | unused.insert(key.clone()); 347 | } 348 | let env = self.genv.clone(); 349 | self.mark(env, &mut unused); 350 | for key in unused { 351 | self.arena.data.remove(&key); 352 | } 353 | } 354 | } 355 | 356 | fn process(line: &str, evaluator: &mut Evaluator) -> Result { 357 | let obj = try!(Reader{ next: &line }.read(&mut evaluator.arena)); 358 | let env = evaluator.genv.clone(); 359 | let result = try!(evaluator.eval(obj, env)); 360 | Ok(evaluator.arena.make(result)) 361 | } 362 | 363 | fn main() { 364 | let mut evaluator = Evaluator::new(); 365 | loop { 366 | print!("> "); 367 | if let Err(e) = io::stdout().flush() { panic!(e); } 368 | let mut line = "".to_string(); 369 | if let Err(_) = io::stdin().read_line(&mut line) { break; } 370 | if line.is_empty() { break; } 371 | match process(&line, &mut evaluator) { 372 | Ok(obj) => println!("{}", evaluator.arena.to_string(&obj)), 373 | Err(e) => println!("", e), 374 | }; 375 | evaluator.garbage_collect(); 376 | } 377 | } 378 | --------------------------------------------------------------------------------