├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── environment.rs ├── interpreter.rs ├── intrinsics.rs ├── main.rs └── reader.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - sudo add-apt-repository --yes ppa:hansjorg/rust 3 | - sudo add-apt-repository --yes ppa:cmrx64/cargo 4 | - sudo apt-get update -qq 5 | install: 6 | - sudo apt-get install -qq rust-nightly cargo 7 | script: 8 | - cargo build 9 | - cargo test -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "rust-lisp" 4 | version = "0.0.1" 5 | authors = ["Sean Gillespie "] 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Sean Gillespie 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-lisp [![Build Status](https://travis-ci.org/swgillespie/rust-lisp.svg?branch=master)](https://travis-ci.org/swgillespie/rust-lisp/) 2 | 3 | Rust is my new favorite language and I've really wanted to use it in a project. 4 | I like languages so I wrote a minimal Lisp-like interpreter. It draws heavy inspiration 5 | from both Common Lisp and Scheme. 6 | 7 | ## Building and running ## 8 | This project builds using Cargo. To build, clone this repository and run 9 | ``` 10 | cargo build 11 | ./target/rust-lisp 12 | ``` 13 | or, simply, 14 | ``` 15 | cargo run 16 | ``` 17 | 18 | ```cargo test``` will run the tests, and ```cargo bench``` will run the benchmarks 19 | 20 | ## Features ## 21 | This lisp interpreter draws its heaviest inspiration from Scheme and most of its feature 22 | come directly from it. 23 | 24 | ### Fundamental Forms ### 25 | This interpreter has ten fundamental forms as of right now: 26 | ``` 27 | if defun defmacro define lambda 28 | quote unquote and or quasiquote 29 | ``` 30 | `defun` will be a macro in the future. Each one of these represents a fundamental 31 | feature of this lisp: 32 | 33 | * `(if condition true_branch false_branch?)` - Evaluates condition and executes the true branch 34 | if condition is truthy, otherwise it executes false branch. 35 | * `(defun parameters body)` - Define a function named with the given 36 | parameter list and body. Places the function into the global namespace. 37 | * `(defmacro parameter_form body_form)` - Defines a macro, not yet implemented. 38 | * `(define symbol form)` - Evaluates form and binds it to symbol in the global namespace. 39 | * `(lambda parameters body)` - Creates an anonymous function with parameter list and body. 40 | * `(quote form)` - Returns the form unevaluated. 41 | * `(unquote form)` - If currently evaluating a `quasiquote` form, escapes the quote and evaluates 42 | `form` as it would normally. Only that form is evaluated. This is not usually called directly - 43 | it is almost always invoked using the `,` reader macro. 44 | * `(and form*)` - Evaluates every form unless one of them is `#f`, after which all other 45 | forms will not be evaluated (short circuit evaluation). 46 | * `(or form*)` - Evaluates every form unless one of them is truthy, after which all other forms 47 | will not be evaluated. 48 | * `(quasiquote form)` - Increments the "quasiquotation" level of the form. This behaves exactly 49 | as the `quote` form, except that `unquote` and `unquote-splicing` allow for the select evaluation 50 | of forms. This is not usually called directly - it is almost always invoked using the \` reader macro. 51 | * `(unquote-splicing form)` - Behaves the same as `unquote`, except that if form evaluates to a list, 52 | it will flatten the list, and otherwise it will produce an improper list. This is not usually called directly - 53 | it is almost always invoked using the `,@` reader macro. 54 | 55 | ### Multiple evaluation ### 56 | This interpreter will evaluate every form that it is given. As an example: 57 | ``` 58 | lisp> (+ 1 2) (+ 3 4) (+ 5 6) 59 | $0 = 3 60 | $1 = 7 61 | $2 = 11 62 | ``` 63 | 64 | In the future these `$x` variables may be bound to the current environment, but 65 | they aren't right now. 66 | 67 | ### Nil vs Empty List ### 68 | This interpreter takes the side of Scheme on the nil vs empty list debate. `nil` 69 | is an ordinary symbol and carries no extra meaning. The empty list is written as 70 | `'()`, as in Scheme, and means the same thing: 71 | 72 | ``` 73 | lisp> (cdr '(1)) 74 | $0 = () 75 | ``` 76 | Attempting to evaluate an unquoted `()` will result in an error. 77 | 78 | ### Improper parameter lists ### 79 | 80 | Improper lists can be used as the parameter form in a lambda, defun, or defmacro. An 81 | improper list binds all remaining parameters to the final parameter. As an example, 82 | 83 | ``` 84 | lisp> (defun test (first second third . rest) rest) 85 | $0 = 86 | ``` 87 | 88 | This defines a function that takes three or more parameters. The first 89 | parameter is always bound to `first`, the second to `second`, and the third 90 | to `third`. If there are more than three parameters, the remaining parameters 91 | are bound as a list to `rest`. For example, 92 | 93 | ``` 94 | lisp> (test 1 2 3 4 5) 95 | $0 = (4 5) 96 | ``` 97 | 98 | When there are exactly as many parameters as there are required parameters, 99 | the rest parameter is the null list. For example, 100 | 101 | ``` 102 | lisp> (test 1 2 3) 103 | $0 = () 104 | ``` 105 | 106 | ## TODO list 107 | 108 | - [x] `lambda` form and closures 109 | - [ ] `defmacro`, `unquote`, `quasiquote`, and macros 110 | - [ ] `eval`, `read`, and `macro-expand` 111 | - [ ] don't trap on stack overflows 112 | - [ ] do something about integer overflows 113 | - [ ] a standard library 114 | - [ ] bytecode interpreter? 115 | - [ ] mark and sweep GC? 116 | - [ ] WRITE MORE TESTS 117 | 118 | Rust is awesome! 119 | -------------------------------------------------------------------------------- /src/environment.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | use std::collections::HashMap; 3 | 4 | use interpreter; 5 | 6 | #[derive(Debug)] 7 | pub struct Environment { 8 | stack: Vec>> 9 | } 10 | 11 | impl Environment { 12 | pub fn new() -> Environment { 13 | Environment { 14 | stack: vec![HashMap::new()] 15 | } 16 | } 17 | 18 | pub fn enter_scope(&mut self) { 19 | self.stack.push(HashMap::new()) 20 | } 21 | 22 | pub fn exit_scope(&mut self) { 23 | self.stack.pop().expect("Popping from empty stack"); 24 | } 25 | 26 | pub fn get(&mut self, key: String) -> Option> { 27 | self.stack[self.stack.len() - 1].get(&key).cloned() // find_copy(&key) 28 | .or(self.stack[0].get(&key).cloned()) // find_copy(&key)) 29 | } 30 | 31 | pub fn put(&mut self, key: String, value: Rc) { 32 | let len = self.stack.len(); 33 | self.stack[len - 1].insert(key, value); 34 | } 35 | 36 | pub fn put_global(&mut self, key: String, value: Rc) { 37 | self.stack[0].insert(key, value); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/interpreter.rs: -------------------------------------------------------------------------------- 1 | #![feature(box_syntax, box_patterns)] 2 | 3 | use std::fmt::{self, Error, Formatter}; 4 | 5 | use std::rc::Rc; 6 | use std::ops::Deref; 7 | use std::collections::HashSet; 8 | 9 | use reader; 10 | use intrinsics; 11 | use environment; 12 | 13 | use reader::Sexp; 14 | 15 | 16 | 17 | // The LispValue enum is the type of all Lisp values at runtime. These are 18 | // the same as the S-expression representation, except that functions can also 19 | // be values. LispValues are always used as a reference counted pointer. 20 | #[derive(Debug, PartialEq)] 21 | pub enum LispValue { 22 | Int(i64), 23 | Float(f64), 24 | Str(String), 25 | Bool(bool), 26 | Symbol(String), 27 | Func(Function), 28 | Cons(Rc, Rc), 29 | Nil 30 | } 31 | 32 | impl fmt::Display for LispValue { 33 | fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { 34 | write!(fmt, "{}", self.pretty_print()) 35 | } 36 | } 37 | 38 | impl LispValue { 39 | // Simple algorithm for pretty-printing an S-expression. 40 | // The algorithm goes like this: 41 | // 1) If self isn't a list, print it and return. 42 | // 2) If self is a list, print an open paren. 43 | // 2a) Print the car of the list. 44 | // 2b) If cdr is a list, recurse to step 2a with cdr as the new list 45 | // 2c) If cdr is nil, print nothing, 46 | // 2d) If cdr is anything else, print a "." followed by a space 47 | // and recursively print the cdr. 48 | // This function returns a string so "printing" isn't done, but it's basically 49 | // the same thing. 50 | pub fn pretty_print(&self) -> String { 51 | match *self { 52 | LispValue::Int(v) => v.to_string(), 53 | LispValue::Float(v) => v.to_string(), 54 | LispValue::Str(ref v) => format!("\"{}\"", v), 55 | LispValue::Symbol(ref v) => format!("{}", v), 56 | LispValue::Cons(ref car, ref cdr) => { 57 | let (s_car, s_cdr) = self.print_cons(&**car, &**cdr); 58 | format!("({} {})", s_car, s_cdr) 59 | }, 60 | LispValue::Nil => "()".to_string(), 61 | LispValue::Bool(v) => if v { 62 | "#t".to_string() 63 | } else { 64 | "#f".to_string() 65 | }, 66 | LispValue::Func(ref c) => format!("{}", c) 67 | } 68 | } 69 | 70 | fn print_cons(&self, car: &LispValue, cdr: &LispValue) -> (String, String) { 71 | let car_str = car.pretty_print(); 72 | let cdr_str = match *cdr { 73 | LispValue::Cons(ref c_car, ref c_cdr) => { 74 | let (s_car, s_cdr) = self.print_cons(&**c_car, &**c_cdr); 75 | if s_cdr.len() == 0 { 76 | format!("{}", s_car) 77 | } else { 78 | format!("{} {}", s_car, s_cdr) 79 | } 80 | } 81 | LispValue::Nil => "".to_string(), 82 | _ => format!(". {}", cdr.pretty_print()) 83 | }; 84 | (car_str, cdr_str) 85 | } 86 | } 87 | 88 | #[derive(Debug)] 89 | pub enum FunctionParameters { 90 | Fixed(Vec), 91 | Variadic(Vec, String) 92 | } 93 | 94 | impl FunctionParameters { 95 | pub fn get_variables(&self) -> Vec { 96 | match *self { 97 | FunctionParameters::Fixed(ref vec) => vec.clone(), 98 | FunctionParameters::Variadic(ref vec, ref rest) => { 99 | let mut temp = vec.clone(); 100 | temp.push(rest.clone()); 101 | temp 102 | } 103 | } 104 | } 105 | } 106 | 107 | type Closure = Vec<(String, Option>)>; 108 | 109 | // Functions can be one of three things - an internal function (defined by defun or 110 | // lambda), an external Rust function exposed to the interpreter, or a macro. 111 | // Macros aren't supported yet. 112 | #[allow(dead_code)] // macros aren't used yet 113 | #[derive(Debug)] 114 | pub enum Function { 115 | InternalFunction(FunctionParameters, Rc, Closure), 116 | ExternalFunction(String, fn(Vec>) -> EvalResult), 117 | Macro(FunctionParameters, Rc), 118 | } 119 | 120 | // Impl of PartialEq for the Function type indicating that functions can never 121 | // be equal to one another. 122 | impl PartialEq for Function { 123 | fn eq(&self, _: &Function) -> bool { 124 | false 125 | } 126 | 127 | fn ne(&self, _: &Function) -> bool { 128 | true 129 | } 130 | } 131 | 132 | impl fmt::Display for Function { 133 | fn fmt (&self, fmt: &mut Formatter) -> Result<(), Error> { 134 | match *self { 135 | Function::InternalFunction(_, _, _) => write!(fmt, ""), 136 | Function::ExternalFunction(_, _) => write!(fmt, ""), 137 | Function::Macro(_, _) => write!(fmt, "") 138 | } 139 | } 140 | } 141 | 142 | pub type EvalResult = Result, String>; 143 | 144 | pub struct Interpreter { 145 | environment: environment::Environment, 146 | } 147 | 148 | impl Interpreter { 149 | pub fn new() -> Interpreter { 150 | let mut interpreter = Interpreter { 151 | environment: environment::Environment::new(), 152 | }; 153 | interpreter.load_intrinsics(); 154 | interpreter 155 | } 156 | 157 | fn load_intrinsics(&mut self) { 158 | self.expose_external_function("+".to_string(), intrinsics::add); 159 | self.expose_external_function("-".to_string(), intrinsics::sub); 160 | self.expose_external_function("*".to_string(), intrinsics::mul); 161 | self.expose_external_function("/".to_string(), intrinsics::div); 162 | self.expose_external_function("car".to_string(), intrinsics::car); 163 | self.expose_external_function("cdr".to_string(), intrinsics::cdr); 164 | self.expose_external_function("cons".to_string(), intrinsics::cons); 165 | self.expose_external_function("=".to_string(), intrinsics::eq); 166 | self.expose_external_function("display".to_string(), intrinsics::display); 167 | self.expose_external_function("pair?".to_string(), intrinsics::pair); 168 | } 169 | 170 | pub fn eval(&mut self, sexp: &reader::Sexp) -> EvalResult { 171 | match *sexp { 172 | Sexp::Int(i) => Ok(Rc::new(LispValue::Int(i))), 173 | Sexp::Float(f) => Ok(Rc::new(LispValue::Float(f))), 174 | Sexp::Str(ref s) => Ok(Rc::new(LispValue::Str(s.clone()))), 175 | Sexp::Symbol(ref s) => self.eval_symbol(s.clone()), 176 | Sexp::Boolean(b) => Ok(Rc::new(LispValue::Bool(b))), 177 | Sexp::Cons(box Sexp::Symbol(ref s), ref right) if self.is_intrinsic(s) => self.eval_intrinsic(s, &**right), 178 | Sexp::Cons(ref left, ref right) => self.eval_function(&**left, &**right), 179 | Sexp::Nil => Err("Unknown form ()".to_string()), 180 | _ => unreachable!() 181 | } 182 | } 183 | 184 | pub fn expose_external_function(&mut self, name: String, func: fn(Vec>) -> EvalResult) { 185 | let wrapped_func = LispValue::Func(Function::ExternalFunction(name.clone(), func)); 186 | self.environment.put(name.clone(), Rc::new(wrapped_func)); 187 | } 188 | 189 | fn is_intrinsic(&self, name: &String) -> bool { 190 | match name.as_str() { 191 | "if" 192 | | "defun" 193 | | "defmacro" 194 | | "lambda" 195 | | "define" 196 | | "quote" 197 | | "unquote" 198 | | "and" 199 | | "or" 200 | | "progn" 201 | | "quasiquote" => true, 202 | _ => false 203 | } 204 | } 205 | 206 | fn eval_intrinsic(&mut self, name: &String, sexp: &reader::Sexp) -> EvalResult { 207 | match name.as_str() { 208 | "quote" => self.eval_quote(sexp), 209 | "unquote" => Err("unquote not valid outside of quasiquote form".to_string()), 210 | "lambda" => self.eval_lambda(sexp), 211 | "if" => self.eval_if(sexp), 212 | "define" => self.eval_define(sexp), 213 | "quasiquote" => self.eval_quasiquote(sexp), 214 | "defun" => self.eval_defun(sexp), 215 | "and" => self.eval_and(sexp), 216 | "or" => self.eval_or(sexp), 217 | "defmacro" => self.eval_defmacro(sexp), 218 | "progn" => self.eval_progn(sexp), 219 | _ => unreachable!() 220 | } 221 | } 222 | 223 | fn eval_progn(&mut self, sexp: &reader::Sexp) -> EvalResult { 224 | let mut last : Option> = None; 225 | let mut cursor = sexp; 226 | loop { 227 | match *cursor { 228 | Sexp::Nil => return Ok(last.unwrap_or(Rc::new(LispValue::Nil))), 229 | Sexp::Cons(ref car, ref cdr) => { 230 | let result = try!(self.eval(&**car)); 231 | last = Some(result.clone()); 232 | cursor = &**cdr; 233 | } 234 | _ => return Err("Improper lists disallowed in progn form".to_string()) 235 | } 236 | } 237 | } 238 | 239 | fn eval_and(&mut self, sexp: &reader::Sexp) -> EvalResult { 240 | match *sexp { 241 | Sexp::Cons(ref car, ref cdr) => match self.eval(&**car) { 242 | Ok(val) => match val.deref() { 243 | &LispValue::Bool(false) => Ok(val.clone()), 244 | _ => self.eval_and(&**cdr) 245 | }, 246 | Err(e) => Err(e) 247 | }, 248 | Sexp::Nil => Ok(Rc::new(LispValue::Bool(true))), 249 | ref e => match self.eval(e) { 250 | Ok(val) => match val.deref() { 251 | &LispValue::Bool(false) => Ok(val.clone()), 252 | _ => Ok(Rc::new(LispValue::Bool(true))) 253 | }, 254 | Err(e) => Err(e) 255 | } 256 | } 257 | } 258 | 259 | fn eval_or(&mut self, sexp: &reader::Sexp) -> EvalResult { 260 | match *sexp { 261 | Sexp::Cons(ref car, ref cdr) => match self.eval(&**car) { 262 | Ok(val) => match val.deref() { 263 | &LispValue::Bool(true) => Ok(val.clone()), 264 | _ => self.eval_or(&**cdr) 265 | }, 266 | Err(e) => Err(e) 267 | }, 268 | Sexp::Nil => Ok(Rc::new(LispValue::Bool(false))), 269 | ref e => match self.eval(e) { 270 | Ok(val) => match val.deref() { 271 | &LispValue::Bool(false) => Ok(val.clone()), 272 | &LispValue::Nil => Ok(Rc::new(LispValue::Bool(false))), 273 | _ => Ok(Rc::new(LispValue::Bool(true))) 274 | }, 275 | Err(e) => Err(e) 276 | } 277 | } 278 | } 279 | 280 | fn eval_quote(&mut self, sexp: &reader::Sexp) -> EvalResult { 281 | fn sexp_to_lvalue(s: &reader::Sexp) -> Rc { 282 | match *s { 283 | Sexp::Int(i) => Rc::new(LispValue::Int(i)), 284 | Sexp::Float(i) => Rc::new(LispValue::Float(i)), 285 | Sexp::Str(ref s) => Rc::new(LispValue::Str(s.clone())), 286 | Sexp::Symbol(ref s) => Rc::new(LispValue::Symbol(s.clone())), 287 | Sexp::Boolean(b) => Rc::new(LispValue::Bool(b)), 288 | Sexp::Cons(ref car, ref cdr) => Rc::new(LispValue::Cons(sexp_to_lvalue(&**car), sexp_to_lvalue(&**cdr))), 289 | Sexp::Nil => Rc::new(LispValue::Nil), 290 | _ => unreachable!() 291 | } 292 | } 293 | Ok(sexp_to_lvalue(sexp)) 294 | } 295 | 296 | fn eval_if(&mut self, sexp: &reader::Sexp) -> EvalResult { 297 | match *sexp { 298 | Sexp::Cons(ref condition, 299 | box Sexp::Cons(ref true_branch, 300 | box Sexp::Cons(ref false_branch, 301 | box Sexp::Nil))) => { 302 | let cond = try!(self.eval(&**condition)); 303 | if let &LispValue::Bool(false) = cond.deref() { 304 | self.eval(&**false_branch) 305 | } else { 306 | self.eval(&**true_branch) 307 | } 308 | } 309 | Sexp::Cons(ref condition, 310 | box Sexp::Cons(ref true_branch, 311 | box Sexp::Nil)) => { 312 | let cond = try!(self.eval(&**condition)); 313 | if let &LispValue::Bool(false) = cond.deref() { 314 | Ok(Rc::new(LispValue::Nil)) 315 | } else { 316 | self.eval(&**true_branch) 317 | } 318 | } 319 | _ => Err("Invalid pattern for if form".to_string()) 320 | } 321 | } 322 | 323 | fn eval_define(&mut self, sexp: &reader::Sexp) -> EvalResult { 324 | match *sexp { 325 | Sexp::Cons(box Sexp::Symbol(ref sym), box Sexp::Cons(ref exp, box Sexp::Nil)) => { 326 | let value = try!(self.eval(&**exp)); 327 | self.environment.put_global(sym.clone(), value.clone()); 328 | Ok(value) 329 | } 330 | Sexp::Cons(box Sexp::Symbol(ref sym), ref exp) => { 331 | let value = try!(self.eval(&**exp)); 332 | self.environment.put_global(sym.clone(), value.clone()); 333 | Ok(value) 334 | } 335 | Sexp::Cons(ref other, _) => Err(format!("Not a symbol: {:?}", other)), 336 | _ => Err(format!("No arguments to define form")) 337 | } 338 | } 339 | 340 | // algorithm for evaluating a quasiquoted S-expression: 341 | // 1) incremenent the quasiquote counter 342 | // 2) if the atom isn't a list, evaluate it as a quoted atom and decrement the quasiquote counter. 343 | // 3) if the atom is a list... 344 | // a) If the car of the list is unquoted, decrement the quasiquote counter. If the quasiquote 345 | // counter is zero, evaluate the car of the list. If the counter is less than zero, error. 346 | // If the counter is greater than zero, evaluate the car of the list as a quoted atom. 347 | // b) If the car of the list is not quoted, evaluate the car of the list as a quoted atom. 348 | // c) Evaluate the cdr of the list (goto step 2) 349 | fn eval_quasiquote(&mut self, sexp: &reader::Sexp) -> EvalResult { 350 | match *sexp { 351 | Sexp::Cons(box Sexp::Cons(box Sexp::Symbol(ref s), ref quoted), ref cdr) if *s == "unquote".to_string() => { 352 | let result = try!(self.eval(&**quoted)); 353 | let rest = try!(self.eval_quasiquote(&**cdr)); 354 | Ok(Rc::new(LispValue::Cons(result, rest))) 355 | }, 356 | Sexp::Cons(box Sexp::Symbol(ref s), ref quoted) if *s == "unquote".to_string() => { 357 | let result = try!(self.eval(&**quoted)); 358 | Ok(result) 359 | }, 360 | Sexp::Cons(box Sexp::Cons(box Sexp::Symbol(ref s), ref quoted), box Sexp::Nil) if *s == "unquote-splicing".to_string() => { 361 | let result = try!(self.eval(&**quoted)); 362 | Ok(result) 363 | } 364 | Sexp::Cons(box Sexp::Cons(box Sexp::Symbol(ref s), _), _) if *s == "unquote-splicing".to_string() => { 365 | Err("Invalid unquote-splicing form".to_string()) 366 | } 367 | Sexp::Cons(box Sexp::Symbol(ref s), _) if *s == "unquote-splicing".to_string() => { 368 | Err("Invalid unquote-splicing form".to_string()) 369 | }, 370 | Sexp::Cons(ref car, ref cdr) => { 371 | let result = try!(self.eval_quote(&**car)); 372 | let rest = try!(self.eval_quasiquote(&**cdr)); 373 | Ok(Rc::new(LispValue::Cons(result, rest))) 374 | } 375 | ref val => self.eval_quote(val) 376 | } 377 | } 378 | 379 | fn eval_defun(&mut self, sexp: &reader::Sexp) -> EvalResult { 380 | match *sexp { 381 | Sexp::Cons(box Sexp::Symbol(ref sym), 382 | box Sexp::Cons(ref parameters, 383 | box Sexp::Cons(ref body, 384 | box Sexp::Nil))) => { 385 | let params = self.eval_list_as_parameter_list(&**parameters); 386 | let free_vars = self.get_free_variables(params.get_variables(), &**body); 387 | let closure = free_vars.into_iter().map(|x| (x.clone(), self.environment.get(x.clone()).clone())).collect(); 388 | let func = Rc::new(LispValue::Func(Function::InternalFunction(params, Rc::new(*body.clone()), closure))); 389 | self.environment.put_global(sym.clone(), func.clone()); 390 | Ok(func) 391 | } 392 | Sexp::Cons(ref other, _) => Err(format!("Not a symbol: {:?}", other)), 393 | _ => Err("No arguments to defun form".to_string()) 394 | } 395 | } 396 | 397 | fn eval_lambda(&mut self, sexp: &reader::Sexp) -> EvalResult { 398 | match *sexp { 399 | Sexp::Cons(ref parameters, 400 | box Sexp::Cons(ref body, 401 | box Sexp::Nil)) => { 402 | let params = self.eval_list_as_parameter_list(&**parameters); 403 | let free_vars = self.get_free_variables(params.get_variables(), &**body); 404 | let closure = free_vars.into_iter().map(|x| (x.clone(), self.environment.get(x.clone()).clone())).collect(); 405 | let func = LispValue::Func(Function::InternalFunction(params, Rc::new(*body.clone()), closure)); 406 | Ok(Rc::new(func)) 407 | } 408 | _ => Err("Incorrect pattern for lambda form".to_string()) 409 | } 410 | } 411 | 412 | fn eval_symbol(&mut self, sym: String) -> EvalResult { 413 | match self.environment.get(sym.clone()) { 414 | Some(value) => Ok(value), 415 | None => Err(format!("Unbound symbol: {}", sym)) 416 | } 417 | } 418 | 419 | fn eval_function(&mut self, car: &reader::Sexp, cdr: &reader::Sexp) -> EvalResult { 420 | let sym_val = try!(self.eval(car)); 421 | match *sym_val { 422 | LispValue::Func(ref f) => match *f { 423 | Function::InternalFunction(ref parameters, ref body, ref closure) => self.eval_internal_function(cdr, parameters, body.clone(), closure), 424 | Function::ExternalFunction(_, func) => self.eval_external_function(cdr, func), 425 | Function::Macro(ref parameters, ref body) => self.eval_macro(cdr, parameters, body.clone()) 426 | }, 427 | _ => Err(format!("Value is not callable: {}", sym_val)) 428 | } 429 | } 430 | 431 | fn eval_internal_function(&mut self, 432 | actual_params: &reader::Sexp, 433 | formal_params: &FunctionParameters, 434 | body: Rc, 435 | closure: &Closure) -> EvalResult { 436 | let params = try!(self.sexp_map(actual_params, |s, t| s.eval(t))); 437 | let actual : &Vec = match *formal_params { 438 | FunctionParameters::Fixed(ref vec) => { 439 | if params.len() != vec.len() { 440 | return Err("Incorrect number of parameters".to_string()); 441 | } 442 | vec 443 | }, 444 | FunctionParameters::Variadic(ref vec, _) => { 445 | if params.len() < vec.len() { 446 | return Err("Incorrect number of parameters".to_string()); 447 | } 448 | vec 449 | } 450 | }; 451 | self.environment.enter_scope(); 452 | for (value, binding) in params.iter().zip(actual.iter()) { 453 | self.environment.put(binding.clone(), value.clone()); 454 | } 455 | if let FunctionParameters::Variadic(_, ref rest) = *formal_params { 456 | let rest_as_vector = params.iter().skip(actual.len()); 457 | let list = self.iter_to_list(rest_as_vector); 458 | self.environment.put(rest.clone(), list); 459 | } 460 | for &(ref binding, ref value) in closure.iter() { 461 | match *value { 462 | Some(ref v) => self.environment.put(binding.clone(), v.clone()), 463 | None => match self.environment.get(binding.clone()) { 464 | Some(ref v) => self.environment.put(binding.clone(), v.clone()), 465 | None => return Err(format!("unbound variable: {}", binding.clone())) 466 | } 467 | } 468 | } 469 | let result = self.eval(body.deref()); 470 | self.environment.exit_scope(); 471 | result 472 | } 473 | 474 | fn iter_to_list<'a, 475 | T: Iterator> 476 | >(&mut self, mut iter: T) -> Rc 477 | { 478 | match iter.next() { 479 | Some(v) => Rc::new(LispValue::Cons(v.clone(), self.iter_to_list(iter))), 480 | None => Rc::new(LispValue::Nil) 481 | } 482 | } 483 | 484 | fn eval_external_function(&mut self, 485 | actual_params: &reader::Sexp, 486 | func: fn(Vec>) -> EvalResult) -> EvalResult { 487 | match self.sexp_map(actual_params, |s, t| s.eval(t)) { 488 | Ok(v) => func(v), 489 | Err(e) => Err(e) 490 | } 491 | } 492 | 493 | fn eval_macro(&mut self, 494 | actual_params: &reader::Sexp, 495 | formal_params: &FunctionParameters, 496 | body: Rc) -> EvalResult { 497 | let params = try!(self.sexp_map(actual_params, |s, t| s.eval_quote(t))); 498 | let actual : &Vec = match *formal_params { 499 | FunctionParameters::Fixed(ref vec) => { 500 | if params.len() != vec.len() { 501 | return Err("Incorrect number of parameters".to_string()); 502 | } 503 | vec 504 | }, 505 | FunctionParameters::Variadic(ref vec, _) => { 506 | if params.len() < vec.len() { 507 | return Err("Incorrect number of parameters".to_string()); 508 | } 509 | vec 510 | } 511 | }; 512 | self.environment.enter_scope(); 513 | for (value, binding) in params.iter().zip(actual.iter()) { 514 | self.environment.put(binding.clone(), value.clone()); 515 | } 516 | if let FunctionParameters::Variadic(_, ref rest) = *formal_params { 517 | let rest_as_vector = params.iter().skip(actual.len()); 518 | let list = self.iter_to_list(rest_as_vector); 519 | self.environment.put(rest.clone(), list); 520 | } 521 | let result = self.eval(body.deref()); 522 | self.environment.exit_scope(); 523 | if let Ok(value) = result { 524 | let sexp = self.value_to_sexp(value); 525 | self.eval(&sexp) 526 | } else { 527 | result 528 | } 529 | } 530 | 531 | fn eval_defmacro(&mut self, sexp: &reader::Sexp) -> EvalResult { 532 | match *sexp { 533 | Sexp::Cons(box Sexp::Symbol(ref sym), 534 | box Sexp::Cons(ref parameters, 535 | box Sexp::Cons(ref body, 536 | box Sexp::Nil))) => { 537 | let params = self.eval_list_as_parameter_list(&**parameters); 538 | let macro_thing = Rc::new(LispValue::Func(Function::Macro(params, Rc::new(*body.clone())))); 539 | self.environment.put_global(sym.clone(), macro_thing.clone()); 540 | Ok(macro_thing) 541 | } 542 | _ => Err("Not a legal defmacro pattern".to_string()) 543 | } 544 | } 545 | 546 | fn sexp_map(&mut self, params: &reader::Sexp, 547 | func: F 548 | ) -> Result>, String> 549 | where F: for<'a> Fn(&'a mut Interpreter, &'a Sexp) -> EvalResult 550 | { 551 | match *params { 552 | Sexp::Cons(ref car, ref cdr) => { 553 | let mut out_vec = vec![]; 554 | match func(self, &**car) { 555 | Ok(v) => out_vec.push(v), 556 | Err(e) => return Err(e) 557 | }; 558 | match self.sexp_map(&**cdr, func) { 559 | Ok(vec) => { 560 | out_vec.extend(vec.into_iter()); 561 | Ok(out_vec) 562 | } 563 | Err(e) => Err(e) 564 | } 565 | } 566 | Sexp::Nil => Ok(vec![]), 567 | _ => Err("Cannot use an improper list as parameters to a function".to_string()) 568 | } 569 | } 570 | 571 | fn value_to_sexp(&self, value: Rc) -> reader::Sexp { 572 | match *value { 573 | LispValue::Int(i) => Sexp::Int(i), 574 | LispValue::Float(i) => Sexp::Float(i), 575 | LispValue::Str(ref s) => Sexp::Str(s.clone()), 576 | LispValue::Bool(b) => Sexp::Boolean(b), 577 | LispValue::Symbol(ref s) => Sexp::Symbol(s.clone()), 578 | LispValue::Cons(ref car, ref cdr) => Sexp::Cons(box self.value_to_sexp(car.clone()), 579 | box self.value_to_sexp(cdr.clone())), 580 | LispValue::Nil => Sexp::Nil, 581 | _ => unreachable!() 582 | } 583 | } 584 | 585 | // The function is similar to eval_list_as_parameters, but it just gets the names 586 | // of all of the symbols in the linked list instead of evaluating them. This 587 | // is also used for evaluating parameters for a function call. 588 | fn eval_list_as_parameter_list(&self, params: &reader::Sexp) -> FunctionParameters { 589 | let mut cursor = params; 590 | let mut out = vec![]; 591 | let mut out_rest = None; 592 | loop { 593 | match *cursor { 594 | Sexp::Cons(box Sexp::Symbol(ref s), box Sexp::Symbol(ref rest)) => { 595 | out.push(s.clone()); 596 | out_rest = Some(rest.clone()); 597 | break; 598 | }, 599 | Sexp::Cons(box Sexp::Symbol(ref s), ref cdr) => { 600 | out.push(s.clone()); 601 | cursor = &**cdr; 602 | }, 603 | Sexp::Nil => break, 604 | _ => unreachable!() 605 | }; 606 | } 607 | if out_rest.is_some() { 608 | FunctionParameters::Variadic(out, out_rest.unwrap()) 609 | } else { 610 | FunctionParameters::Fixed(out) 611 | } 612 | } 613 | 614 | fn get_free_variables(&self, variables: Vec, body: &Sexp) -> Vec { 615 | let parameter_set : HashSet = variables.iter().map(|&ref x| x.clone()).collect(); 616 | let variable_set : HashSet = self.get_variables(body); 617 | variable_set.difference(¶meter_set).map(|&ref x| x.clone()).collect() 618 | } 619 | 620 | fn get_variables(&self, body: &Sexp) -> HashSet { 621 | match *body { 622 | Sexp::Symbol(ref s) if !self.is_intrinsic(s) => { 623 | let mut set = HashSet::new(); 624 | set.insert(s.clone()); 625 | set 626 | }, 627 | Sexp::Cons(ref car, ref cdr) => { 628 | let free_car = self.get_variables(&**car); 629 | let free_cdr = self.get_variables(&**cdr); 630 | free_car.union(&free_cdr).map(|&ref x| x.clone()).collect() 631 | }, 632 | _ => HashSet::new() 633 | } 634 | } 635 | 636 | } 637 | 638 | #[cfg(test)] 639 | mod tests { 640 | extern crate test; 641 | 642 | use super::*; 643 | use self::test::Bencher; 644 | 645 | use super::super::reader; 646 | use std::process::Command; 647 | 648 | fn evaluate(input: &'static str) -> EvalResult { 649 | let mut interpreter = Interpreter::new(); 650 | evaluate_with_context(input, &mut interpreter) 651 | } 652 | 653 | fn evaluate_with_context(input: &'static str, interpreter: &mut Interpreter) -> EvalResult { 654 | let mut reader = reader::SexpReader::new(); 655 | match reader.parse_str(input) { 656 | Ok(e) => match interpreter.eval(&e) { 657 | Ok(val) => Ok(val), 658 | Err(e) => Err(e) 659 | }, 660 | Err(e) => Err(e) 661 | } 662 | } 663 | 664 | #[test] 665 | fn test_addition() { 666 | if let Ok(val) = evaluate("(+ 1 2)") { 667 | match val.deref() { 668 | &LispValue::Int(x) => assert_eq!(x, 3), 669 | e => panic!("Unexpected: {}", e) 670 | } 671 | } else { 672 | panic!("Unexpected error") 673 | } 674 | } 675 | 676 | #[test] 677 | fn test_varargs_addition() { 678 | if let Ok(val) = evaluate("(+ 5 5 5 5 5)") { 679 | match val.deref() { 680 | &LispValue::Int(x) => assert_eq!(x, 25), 681 | e => panic!("Unexpected: {}", e) 682 | } 683 | } else { 684 | panic!("Unexpected error") 685 | } 686 | } 687 | 688 | #[test] 689 | fn test_subtraction() { 690 | if let Ok(val) = evaluate("(- 1 2)") { 691 | match val.deref() { 692 | &LispValue::Int(x) => assert_eq!(x, -1), 693 | e => panic!("Unexpected: {}", e) 694 | } 695 | } else { 696 | panic!("Unexpected error") 697 | } 698 | } 699 | 700 | #[test] 701 | fn test_division() { 702 | if let Ok(val) = evaluate("(/ 8 2 2.5)") { 703 | match val.deref() { 704 | &LispValue::Float(x) => assert_eq!(x, 1.6), 705 | e => panic!("Unexpected: {}", e) 706 | } 707 | } else { 708 | panic!("Unexpected error") 709 | } 710 | } 711 | 712 | #[test] 713 | fn test_varargs_subtraction() { 714 | if let Ok(val) = evaluate("(- 5 1 1 1)") { 715 | match val.deref() { 716 | &LispValue::Int(x) => assert_eq!(x, 2), 717 | e => panic!("Unexpected: {}", e) 718 | } 719 | } else { 720 | panic!("Unexpected error") 721 | } 722 | } 723 | 724 | #[test] 725 | fn test_car() { 726 | if let Ok(val) = evaluate("(car '(1 2))") { 727 | match val.deref() { 728 | &LispValue::Int(x) => assert_eq!(x, 1), 729 | e => panic!("Unexpected: {}", e) 730 | } 731 | } else { 732 | panic!("Unexpected error") 733 | } 734 | } 735 | 736 | #[test] 737 | fn test_cdr() { 738 | if let Ok(val) = evaluate("(cdr '(1 2))") { 739 | match val.deref() { 740 | &LispValue::Cons(ref car, _) => match car.deref() { 741 | &LispValue::Int(a) => assert_eq!(a, 2), 742 | _ => panic!("Unexpected: {}", car) 743 | }, 744 | e => panic!("Unexpected: {}", e) 745 | } 746 | } else { 747 | panic!("Unexpected error") 748 | } 749 | } 750 | 751 | #[test] 752 | fn test_if_true() { 753 | if let Ok(val) = evaluate("(if #t 1 2)") { 754 | match val.deref() { 755 | &LispValue::Int(a) => assert_eq!(a, 1), 756 | e => panic!("Unexpected: {}", e) 757 | } 758 | } else { 759 | panic!("Unexpected error") 760 | } 761 | 762 | } 763 | 764 | #[test] 765 | fn test_if_false() { 766 | if let Ok(val) = evaluate("(if #f 1 2)") { 767 | match val.deref() { 768 | &LispValue::Int(a) => assert_eq!(a, 2), 769 | e => panic!("Unexpected: {}", e) 770 | } 771 | } else { 772 | panic!("Unexpected error") 773 | } 774 | } 775 | 776 | #[test] 777 | fn test_if_true_no_false_branch() { 778 | if let Ok(val) = evaluate("(if #t 1)") { 779 | match val.deref() { 780 | &LispValue::Int(a) => assert_eq!(a, 1), 781 | e => panic!("Unexpected: {}", e) 782 | } 783 | } else { 784 | panic!("Unexpected error") 785 | } 786 | } 787 | 788 | #[test] 789 | fn test_if_false_no_false_branch() { 790 | if let Ok(val) = evaluate("(if #f 1)") { 791 | match val.deref() { 792 | &LispValue::Nil => (), 793 | e => panic!("Unexpected: {}", e) 794 | } 795 | } else { 796 | panic!("Unexpected error") 797 | } 798 | } 799 | 800 | #[test] 801 | fn test_basic_defun() { 802 | let mut interpreter = Interpreter::new(); 803 | if let Ok(_) = evaluate_with_context("(defun square (x) (* x x))", &mut interpreter) { 804 | if let Ok(val) = evaluate_with_context("(square 5)", &mut interpreter) { 805 | match val.deref() { 806 | &LispValue::Int(v) => assert_eq!(v, 25), 807 | e => panic!("Unexpected: {}", e) 808 | } 809 | } else { 810 | panic!("Unexpected error"); 811 | } 812 | } else { 813 | panic!("Unexpected error") 814 | } 815 | } 816 | 817 | #[test] 818 | fn test_recursive_defun() { 819 | let mut interpreter = Interpreter::new(); 820 | if let Ok(_) = evaluate_with_context("(defun fact (n) (if (= n 0) 1 (* n (fact (- n 1)))))", &mut interpreter) { 821 | if let Ok(val) = evaluate_with_context("(fact 5)", &mut interpreter) { 822 | match val.deref() { 823 | &LispValue::Int(v) => assert_eq!(v, 120), 824 | e => panic!("Unexpected: {}", e) 825 | } 826 | } else { 827 | panic!("Unexpected error"); 828 | } 829 | } else { 830 | panic!("Unexpected error") 831 | } 832 | } 833 | 834 | #[test] 835 | fn test_and_short_circuit() { 836 | if let Ok(val) = evaluate("(and #f asdfjsldlf)") { 837 | match val.deref() { 838 | &LispValue::Bool(b) => assert!(!b), 839 | e => panic!("Unexpected: {}", e) 840 | } 841 | } else { 842 | panic!("Unexpected error") 843 | } 844 | } 845 | 846 | #[test] 847 | fn test_or_short_circuit() { 848 | if let Ok(val) = evaluate("(or #t asdfjsldlf)") { 849 | match val.deref() { 850 | &LispValue::Bool(b) => assert!(b), 851 | e => panic!("Unexpected: {}", e) 852 | } 853 | } else { 854 | panic!("Unexpected error") 855 | } 856 | } 857 | 858 | #[test] 859 | fn test_or() { 860 | if let Ok(val) = evaluate("(or #f #f)") { 861 | match val.deref() { 862 | &LispValue::Bool(b) => assert!(!b), 863 | e => panic!("Unexpected: {}", e) 864 | } 865 | } else { 866 | panic!("Unexpected error") 867 | } 868 | } 869 | 870 | #[test] 871 | fn test_and() { 872 | if let Ok(val) = evaluate("(and #t #t)") { 873 | match val.deref() { 874 | &LispValue::Bool(b) => assert!(b), 875 | e => panic!("Unexpected: {}", e) 876 | } 877 | } else { 878 | panic!("Unexpected error") 879 | } 880 | } 881 | 882 | #[test] 883 | fn test_lambda() { 884 | if let Ok(val) = evaluate("((lambda (x) (* x x)) 5)") { 885 | match val.deref() { 886 | &LispValue::Int(b) => assert_eq!(b, 25), 887 | e => panic!("Unexpected: {}", e) 888 | } 889 | } else { 890 | panic!("Unexpected error") 891 | } 892 | } 893 | 894 | #[test] 895 | fn test_atom_quasiquote_unquote() { 896 | if let Ok(val) = evaluate("`,10") { 897 | match val.deref() { 898 | &LispValue::Int(b) => assert_eq!(b, 10), 899 | e => panic!("Unexpected: {}", e) 900 | } 901 | } else { 902 | panic!("Unexpected error") 903 | } 904 | } 905 | 906 | #[test] 907 | fn test_quasiquote_with_no_unquote() { 908 | if let Ok(val) = evaluate("`(1 2 3)") { 909 | match val.deref() { 910 | &LispValue::Cons(ref car, ref cdr) => { 911 | assert_eq!(car.deref(), &LispValue::Int(1)); 912 | match cdr.deref() { 913 | &LispValue::Cons(ref car_2, ref cdr_2) => { 914 | assert_eq!(car_2.deref(), &LispValue::Int(2)); 915 | match cdr_2.deref() { 916 | &LispValue::Cons(ref car_3, ref cdr_3) => { 917 | assert_eq!(car_3.deref(), &LispValue::Int(3)); 918 | assert_eq!(cdr_3.deref(), &LispValue::Nil); 919 | }, 920 | e => panic!("Unexpected: {}", e) 921 | } 922 | }, 923 | e => panic!("Unexpected: {}", e) 924 | } 925 | } 926 | e => panic!("Unexpected: {}", e) 927 | } 928 | } else { 929 | panic!("Unexpected error") 930 | } 931 | } 932 | 933 | #[test] 934 | fn test_quasiquote_with_unquote() { 935 | if let Ok(val) = evaluate("`(1 2 ,(* 2 2))") { 936 | match val.deref() { 937 | &LispValue::Cons(ref car, ref cdr) => { 938 | assert_eq!(car.deref(), &LispValue::Int(1)); 939 | match cdr.deref() { 940 | &LispValue::Cons(ref car_2, ref cdr_2) => { 941 | assert_eq!(car_2.deref(), &LispValue::Int(2)); 942 | match cdr_2.deref() { 943 | &LispValue::Cons(ref car_3, ref cdr_3) => { 944 | assert_eq!(car_3.deref(), &LispValue::Int(4)); 945 | assert_eq!(cdr_3.deref(), &LispValue::Nil); 946 | }, 947 | e => panic!("Unexpected: {}", e) 948 | } 949 | }, 950 | e => panic!("Unexpected: {}", e) 951 | } 952 | } 953 | e => panic!("Unexpected: {}", e) 954 | } 955 | } else { 956 | panic!("Unexpected error") 957 | } 958 | } 959 | 960 | #[test] 961 | fn test_quasiquote_with_unquote_splicing() { 962 | if let Ok(val) = evaluate("`(1 ,@'(2 3))") { 963 | match val.deref() { 964 | &LispValue::Cons(ref car, ref cdr) => { 965 | assert_eq!(car.deref(), &LispValue::Int(1)); 966 | match cdr.deref() { 967 | &LispValue::Cons(ref car_2, ref cdr_2) => { 968 | assert_eq!(car_2.deref(), &LispValue::Int(2)); 969 | match cdr_2.deref() { 970 | &LispValue::Cons(ref car_3, ref cdr_3) => { 971 | assert_eq!(car_3.deref(), &LispValue::Int(3)); 972 | assert_eq!(cdr_3.deref(), &LispValue::Nil); 973 | }, 974 | e => panic!("Unexpected: {}", e) 975 | } 976 | }, 977 | e => panic!("Unexpected: {}", e) 978 | } 979 | } 980 | e => panic!("Unexpected: {}", e) 981 | } 982 | } else { 983 | panic!("Unexpected error") 984 | } 985 | } 986 | 987 | 988 | 989 | #[test] 990 | fn test_higher_order_function() { 991 | let mut interpreter = Interpreter::new(); 992 | if let Ok(_) = evaluate_with_context("(defun apply (f x) (f x))", &mut interpreter) { 993 | if let Ok(val) = evaluate_with_context("(apply (lambda (x) (* x x)) 5)", &mut interpreter) { 994 | match val.deref() { 995 | &LispValue::Int(v) => assert_eq!(v, 25), 996 | e => panic!("Unexpected: {}", e) 997 | } 998 | } else { 999 | panic!("Unexpected error"); 1000 | } 1001 | } else { 1002 | panic!("Unexpected error") 1003 | } 1004 | } 1005 | 1006 | #[test] 1007 | fn test_improper_parameter_list() { 1008 | let mut interpreter = Interpreter::new(); 1009 | if let Ok(_) = evaluate_with_context("(defun test-thing (first . rest) rest)", &mut interpreter) { 1010 | if let Ok(val) = evaluate_with_context("(test-thing 1 2)", &mut interpreter) { 1011 | match val.deref() { 1012 | &LispValue::Cons(ref left, ref right) => match (left.deref(), right.deref()) { 1013 | (&LispValue::Int(a), &LispValue::Nil) => assert_eq!(a, 2), 1014 | e => panic!("Unexpected: {:?}", e) 1015 | }, 1016 | e => panic!("Unexpected: {}", e) 1017 | } 1018 | } else { 1019 | panic!("Unexpected error"); 1020 | } 1021 | } else { 1022 | panic!("Unexpected error") 1023 | } 1024 | } 1025 | 1026 | 1027 | 1028 | #[bench] 1029 | fn bench_fibonacci(b: &mut Bencher) { 1030 | let mut interpreter = Interpreter::new(); 1031 | if let Ok(_) = evaluate_with_context("(defun fib (n) (if (or (= n 0) (= n 1)) 1 (+ (fib (- n 1)) (fib (- n 2)))))", &mut interpreter) { 1032 | b.iter(|| { 1033 | if let Ok(_) = evaluate_with_context("(fib 4)", &mut interpreter) { 1034 | () 1035 | } else { 1036 | panic!("Unexpected error"); 1037 | } 1038 | }) 1039 | } else { 1040 | panic!("Unexpected error") 1041 | } 1042 | } 1043 | 1044 | #[bench] 1045 | fn bench_addition(b: &mut Bencher) { 1046 | b.iter(|| { 1047 | evaluate("(+ 1 2)") 1048 | }) 1049 | } 1050 | 1051 | #[bench] 1052 | fn bench_factorial(b: &mut Bencher) { 1053 | let mut interpreter = Interpreter::new(); 1054 | if let Ok(_) = evaluate_with_context("(defun fact (n) (if (= n 0) 1 (* n (fact (- n 1)))))", &mut interpreter) { 1055 | b.iter(|| { 1056 | if let Ok(_) = evaluate_with_context("(fact 5)", &mut interpreter) { 1057 | () 1058 | } else { 1059 | panic!("Unexpected error"); 1060 | } 1061 | }) 1062 | } else { 1063 | panic!("Unexpected error") 1064 | } 1065 | } 1066 | 1067 | #[bench] 1068 | fn lisp_first_25_squares(b: &mut Bencher) { 1069 | let mut interpreter = Interpreter::new(); 1070 | if let Ok(_) = evaluate_with_context("(defun map (f list) (if (= list '()) '() (cons (f (car list)) (map f (cdr list)))))", &mut interpreter) { 1071 | if let Ok(_) = evaluate_with_context("(defun reduce (f z l) (if (= l '()) z (f (car l) (reduce f z (cdr l)))))", &mut interpreter) { 1072 | b.iter(|| { 1073 | if let Ok(_) = evaluate_with_context("(reduce + 0 (map (lambda (x) (* x x)) '(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25)))", &mut interpreter) { 1074 | () 1075 | } else { 1076 | panic!("Unexpected error"); 1077 | } 1078 | }) 1079 | } 1080 | } else { 1081 | panic!("Unexpected error") 1082 | } 1083 | } 1084 | 1085 | #[bench] 1086 | fn rust_first_25_squares(b: &mut Bencher) { 1087 | b.iter(|| { 1088 | let vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25isize]; 1089 | test::black_box(vec.iter().map(|x| *x * *x).fold(0, |a, b| a + b)); 1090 | }) 1091 | } 1092 | 1093 | #[bench] 1094 | fn python_first_25_squares(b: &mut Bencher) { 1095 | b.iter(|| { 1096 | let mut c = Command::new("python"); 1097 | c.arg("-c").arg("print reduce(lambda x, y: x + y, map(lambda x: x * x, range(1, 25)))"); 1098 | c 1099 | }) 1100 | } 1101 | 1102 | #[bench] 1103 | fn ruby_first_25_squares(b: &mut Bencher) { 1104 | b.iter(|| { 1105 | let mut c = Command::new("ruby"); 1106 | c.arg("'e").arg("puts (1..25).to_a.map { |x| x * x } .reduce(:+)"); 1107 | c 1108 | }) 1109 | } 1110 | } 1111 | -------------------------------------------------------------------------------- /src/intrinsics.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | use std::ops::Deref; 3 | 4 | use interpreter::{LispValue, EvalResult}; 5 | 6 | // add function - exposed as (+) to Lisp 7 | pub fn add(params: Vec>) -> EvalResult { 8 | params.into_iter() 9 | .fold(Ok(LispValue::Int(0)), |a, b| { 10 | match a { 11 | Ok(acc) => match (acc, b.deref()) { 12 | (LispValue::Int(r), &LispValue::Int(a)) => Ok(LispValue::Int(r + a)), 13 | (LispValue::Int(r), &LispValue::Float(a)) => Ok(LispValue::Float((r as f64) + a)), 14 | (LispValue::Float(r), &LispValue::Int(a)) => Ok(LispValue::Float(r + (a as f64))), 15 | (LispValue::Float(r), &LispValue::Float(a)) => Ok(LispValue::Float(r + a)), 16 | (_, ref rb) => Err(format!("Wrong type: {}", rb)) 17 | }, 18 | Err(e) => Err(e) 19 | } 20 | }) 21 | .map(|e| Rc::new(e)) 22 | } 23 | 24 | // subtraction function - exposed as (-) to Lisp 25 | pub fn sub(params: Vec>) -> EvalResult { 26 | if params.len() == 0 { 27 | return Err("Incorrect number of parameters".to_string()); 28 | } 29 | let initial = match params[0].deref() { 30 | &LispValue::Int(r) => LispValue::Int(r), 31 | &LispValue::Float(r) => LispValue::Float(r), 32 | e => return Err(format!("Wrong type: {}", e)) 33 | }; 34 | params.into_iter() 35 | .skip(1) 36 | .fold(Ok(initial), |a, b| { 37 | match a { 38 | Ok(acc) => match (acc, b.deref()) { 39 | (LispValue::Int(r), &LispValue::Int(a)) => Ok(LispValue::Int(r - a)), 40 | (LispValue::Int(r), &LispValue::Float(a)) => Ok(LispValue::Float((r as f64) - a)), 41 | (LispValue::Float(r), &LispValue::Int(a)) => Ok(LispValue::Float(r - (a as f64))), 42 | (LispValue::Float(r), &LispValue::Float(a)) => Ok(LispValue::Float(r - a)), 43 | (_, ref rb) => Err(format!("Wrong type: {}", rb)) 44 | }, 45 | Err(e) => Err(e) 46 | } 47 | }) 48 | .map(|e| Rc::new(e)) 49 | } 50 | 51 | // multiplication function - exposed as (*) to Lisp 52 | pub fn mul(params: Vec>) -> EvalResult { 53 | params.into_iter() 54 | .fold(Ok(LispValue::Int(1)), |a, b| { 55 | match a { 56 | Ok(acc) => match (acc, b.deref()) { 57 | (LispValue::Int(r), &LispValue::Int(a)) => Ok(LispValue::Int(r * a)), 58 | (LispValue::Int(r), &LispValue::Float(a)) => Ok(LispValue::Float((r as f64) * a)), 59 | (LispValue::Float(r), &LispValue::Int(a)) => Ok(LispValue::Float(r * (a as f64))), 60 | (LispValue::Float(r), &LispValue::Float(a)) => Ok(LispValue::Float(r * a)), 61 | (_, ref rb) => Err(format!("Wrong type: {}", rb)) 62 | }, 63 | Err(e) => Err(e) 64 | } 65 | }) 66 | .map(|e| Rc::new(e)) 67 | } 68 | 69 | // division function - exposed as (/) to Lisp 70 | pub fn div(params: Vec>) -> EvalResult { 71 | if params.len() == 0 { 72 | return Err("Incorrect number of parameters".to_string()); 73 | } 74 | let initial = match params[0].deref() { 75 | &LispValue::Int(r) => LispValue::Int(r), 76 | &LispValue::Float(r) => LispValue::Float(r), 77 | e => return Err(format!("Wrong type: {}", e)) 78 | }; 79 | params.into_iter() 80 | .skip(1) 81 | .fold(Ok(initial), |a, b| { 82 | match a { 83 | Ok(acc) => match (acc, b.deref()) { 84 | (LispValue::Int(r), &LispValue::Int(a)) => if a == 0 { Err(format!("Division by zero")) } else { Ok(LispValue::Float(r as f64 / a as f64)) }, 85 | (LispValue::Int(r), &LispValue::Float(a)) => if a == 0.0 { Err(format!("Division by zero")) } else { Ok(LispValue::Float((r as f64) / a)) }, 86 | (LispValue::Float(r), &LispValue::Int(a)) => if a == 0 { Err(format!("Division by zero")) } else { Ok(LispValue::Float(r / (a as f64))) }, 87 | (LispValue::Float(r), &LispValue::Float(a)) => if a == 0.0 { Err(format!("Division by zero")) } else { Ok(LispValue::Float(r / a)) }, 88 | (_, ref rb) => Err(format!("Wrong type: {}", rb)) 89 | }, 90 | Err(e) => Err(e) 91 | } 92 | }) 93 | .map(|e| Rc::new(e)) 94 | } 95 | 96 | // car function - exposed as (car) to Lisp 97 | pub fn car(params: Vec>) -> EvalResult { 98 | if params.len() != 1 { 99 | return Err("Incorrect number of parameters".to_string()) 100 | } 101 | match params[0].deref() { 102 | &LispValue::Cons(ref car, _) => Ok(car.clone()), 103 | &LispValue::Nil => Err("Cannot take the car of an empty list".to_string()), 104 | _ => Err("Cannot take the car of a non-list".to_string()) 105 | } 106 | } 107 | 108 | // cdr function - exposed as (cdr) to Lisp 109 | pub fn cdr(params: Vec>) -> EvalResult { 110 | if params.len() != 1 { 111 | return Err("Incorrect number of parameters".to_string()) 112 | } 113 | match params[0].deref() { 114 | &LispValue::Cons(_, ref cdr) => Ok(cdr.clone()), 115 | &LispValue::Nil => Err("Cannot take the cdr of an empty list".to_string()), 116 | _ => Err("Cannot take the cdr of a non-list".to_string()) 117 | } 118 | } 119 | 120 | pub fn cons(params: Vec>) -> EvalResult { 121 | if params.len() != 2 { 122 | return Err("Incorrect number of parameters".to_string()) 123 | } 124 | Ok(Rc::new(LispValue::Cons(params[0].clone(), params[1].clone()))) 125 | } 126 | 127 | // eq function - exposed as (=) to Lisp. 128 | pub fn eq(params: Vec>) -> EvalResult { 129 | if params.len() == 0 { 130 | return Ok(Rc::new(LispValue::Bool(true))); 131 | } 132 | let first = params[0].clone(); 133 | let res = params.into_iter() 134 | .fold(true, |a, b| { 135 | a && b == first 136 | }); 137 | Ok(Rc::new(LispValue::Bool(res))) 138 | } 139 | 140 | pub fn display(params: Vec>) -> EvalResult { 141 | for ref value in params.iter() { 142 | println!("{}", value); 143 | } 144 | Ok(Rc::new(LispValue::Nil)) 145 | } 146 | 147 | // pair function - exposed as (pair?) to Lisp. 148 | pub fn pair(params: Vec>) -> EvalResult { 149 | if params.len() != 1 { 150 | return Err("Incorrect number of parameters".to_string()) 151 | } 152 | if let &LispValue::Cons(_, _) = params[0].deref() { 153 | Ok(Rc::new(LispValue::Bool(true))) 154 | } else { 155 | Ok(Rc::new(LispValue::Bool(false))) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(if_let)] 2 | #![feature(while_let)] 3 | #![feature(globs)] 4 | #![feature(box_syntax, box_patterns)] 5 | 6 | // This feature is enabled to use `bench` feature, requires nigthly rust 7 | #![feature(test)] 8 | 9 | use std::io; 10 | use std::ops::Deref; 11 | 12 | use std::io::Write; 13 | 14 | use reader::SexpReader; 15 | use interpreter::Interpreter; 16 | 17 | mod reader; 18 | mod interpreter; 19 | mod intrinsics; 20 | mod environment; 21 | 22 | #[allow(dead_code)] 23 | fn main() { 24 | println!("Rust Lisp interpreter, by Sean Gillespie 2014"); 25 | println!("Licensed under the MIT license"); 26 | println!("Control+D to exit"); 27 | let mut stdin = io::stdin(); 28 | let mut interpreter = Interpreter::new(); 29 | loop { 30 | print!("lisp> "); 31 | io::stdout().flush().ok().expect("Could not flush stdout"); // to print prompt before user input 32 | let mut input_line = String::new(); 33 | match stdin.read_line(&mut input_line) { 34 | Ok(bytes_read) => { 35 | if bytes_read > 0 { 36 | process_line(input_line, &mut interpreter); 37 | } else { // EOF or ^D (Ctrl-D) 38 | println!("\nBye!"); 39 | break; 40 | } 41 | } 42 | Err(error) => { 43 | println!("Error occured while reading: {}", error); 44 | println!("Exiting."); 45 | break; 46 | } 47 | } 48 | } 49 | } 50 | 51 | 52 | fn process_line(input: String, interpreter: &mut Interpreter) { 53 | let mut reader = SexpReader::new(); 54 | match reader.parse_str_all(input.as_str()) { 55 | Ok(e) => for (idx, sexp) in e.iter().enumerate() { 56 | match interpreter.eval(sexp) { 57 | Ok(ref val) => match val.deref() { 58 | v => println!("${} = {}", idx, v), 59 | }, 60 | Err(e) => println!("error: {}", e) 61 | } 62 | }, 63 | Err(e) => println!("error: {}", e) 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /src/reader.rs: -------------------------------------------------------------------------------- 1 | // use std::io::{BufReader, BufferedReader, Reader}; 2 | use std::io::{self, Read, BufReader}; 3 | 4 | use std::fmt; 5 | 6 | // This data structure is the output of the reading phase of the interpreter. 7 | // An S-expression is composed of either an integer, a float, a string, a symbol, 8 | // or a list. A list has a pointer to the head (car) of its values, and a pointer 9 | // to the rest of the list (cdr). 10 | #[derive(Debug, Clone)] 11 | pub enum Sexp { 12 | Int(i64), 13 | Float(f64), 14 | Str(String), 15 | Symbol(String), 16 | Boolean(bool), 17 | Cons(Box, Box), 18 | Nil, 19 | NoMatch, 20 | } 21 | 22 | // A ReadResult is the output of the reader. It is either an S-expression upon 23 | // success or a String error message upon failure. 24 | pub type ReadResult = Result; 25 | 26 | pub struct SexpReader { 27 | unget_stack: Vec 28 | } 29 | 30 | impl SexpReader { 31 | pub fn new() -> SexpReader { 32 | SexpReader { 33 | unget_stack: vec![] 34 | } 35 | } 36 | 37 | pub fn parse_all(&mut self, reader: &mut BufReader) -> Result, String> { 38 | let mut out = vec![]; 39 | loop { 40 | match self.parse(reader) { 41 | Ok(Sexp::NoMatch) => break, 42 | Err(v) => return Err(v), 43 | Ok(v) => out.push(v) 44 | } 45 | } 46 | Ok(out) 47 | } 48 | 49 | 50 | // Top-level parse of an S-expression. The empty string is parsed as 51 | // a Nil. 52 | pub fn parse(&mut self, reader: &mut BufReader) -> ReadResult { 53 | match self.get_char(reader, true) { 54 | Some(c) => { 55 | match c { 56 | '\'' => self.parse_quoted_sexp(reader), 57 | ',' => self.parse_unquoted_sexp(reader), 58 | '`' => self.parse_quasiquoted_sexp(reader), 59 | '(' => self.parse_list(reader), 60 | _ => { 61 | self.unget_char(c); 62 | self.parse_atom(reader) 63 | } 64 | } 65 | }, 66 | None => Ok(Sexp::NoMatch) 67 | } 68 | } 69 | 70 | // Wrapper around parse() that allows for the parsing of strings. 71 | // not actually dead code - used in the tests. 72 | #[allow(dead_code)] 73 | pub fn parse_str(&mut self, string: &str) -> ReadResult { 74 | let reader = BufReader::new(string.as_bytes()); 75 | let mut buf_reader = BufReader::new(reader); 76 | self.parse(&mut buf_reader) 77 | } 78 | 79 | pub fn parse_str_all(&mut self, string: &str) -> Result, String> { 80 | let reader = BufReader::new(string.as_bytes()); 81 | let mut buf_reader = BufReader::new(reader); 82 | self.parse_all(&mut buf_reader) 83 | } 84 | 85 | fn parse_quoted_sexp(&mut self, reader: &mut BufReader) -> ReadResult { 86 | let cdr = try!(self.parse(reader)); 87 | let new_sexp = Sexp::Cons(box Sexp::Symbol("quote".to_string()), box cdr); 88 | Ok(new_sexp) 89 | } 90 | 91 | fn parse_unquoted_sexp(&mut self, reader: &mut BufReader) -> ReadResult { 92 | match self.peek_char(reader, true) { 93 | Some('@') => { 94 | let _ = self.get_char(reader, true); 95 | let cdr = try!(self.parse(reader)); 96 | let new_sexp = Sexp::Cons(box Sexp::Symbol("unquote-splicing".to_string()), box cdr); 97 | Ok(new_sexp) 98 | }, 99 | _ => { 100 | let cdr = try!(self.parse(reader)); 101 | let new_sexp = Sexp::Cons(box Sexp::Symbol("unquote".to_string()), box cdr); 102 | Ok(new_sexp) 103 | } 104 | } 105 | } 106 | 107 | fn parse_quasiquoted_sexp(&mut self, reader: &mut BufReader) -> ReadResult { 108 | let cdr = try!(self.parse(reader)); 109 | let new_sexp = Sexp::Cons(box Sexp::Symbol("quasiquote".to_string()), box cdr); 110 | Ok(new_sexp) 111 | } 112 | 113 | fn parse_list(&mut self, reader: &mut BufReader) -> ReadResult { 114 | let car = match self.parse(reader) { 115 | Ok(value) => value, 116 | Err(e) => match self.get_char(reader, true) { 117 | Some(')') => return Ok(Sexp::Nil), 118 | _ => return Err(e) 119 | } 120 | }; 121 | let cdr = match self.get_char(reader, true) { 122 | Some(e) if e == '.' => { 123 | // look ahead one token to see if we are looking at an ellipsis (...) 124 | match self.peek_char(reader, true) { 125 | Some(v) if v != '.' => { 126 | let result = try!(self.parse(reader)); 127 | match self.get_char(reader, true) { 128 | Some(')') => result, 129 | _ => return Err("Expected )".to_string()) 130 | } 131 | } 132 | // if we are, treat it like a symbol 133 | _ => { 134 | self.unget_char(e); 135 | try!(self.parse_list(reader)) 136 | } 137 | } 138 | }, 139 | Some(e) => { 140 | self.unget_char(e); 141 | try!(self.parse_list(reader)) 142 | }, 143 | None => return Err("Unexpected EOF, expected . or atom".to_string()) 144 | }; 145 | 146 | Ok(Sexp::Cons(box car, box cdr)) 147 | } 148 | 149 | fn parse_atom(&mut self, reader: &mut BufReader) -> ReadResult { 150 | match self.peek_char(reader, true) { 151 | Some(c) => match c { 152 | '\"' => self.parse_string_literal(reader), 153 | c if c.is_digit(10) => self.parse_number(reader), 154 | '#' => self.parse_boolean(reader), 155 | _ => self.parse_symbol(reader) 156 | }, 157 | None => Err("Unexpected EOF while scanning atom".to_string()) 158 | } 159 | } 160 | 161 | fn parse_boolean(&mut self, reader: &mut BufReader) -> ReadResult { 162 | let _ = self.get_char(reader, true); 163 | match self.get_char(reader, false) { 164 | Some(e) => match e { 165 | 't' => Ok(Sexp::Boolean(true)), 166 | 'f' => Ok(Sexp::Boolean(false)), 167 | _ => Err(format!("Unknown boolean literal, got {}", e)) 168 | }, 169 | None => Err("Unexpected EOF while scanning boolean literal".to_string()) 170 | } 171 | } 172 | 173 | fn parse_string_literal(&mut self, reader: &mut BufReader) -> ReadResult { 174 | let _ = self.get_char(reader, false); 175 | let mut string = "".to_string(); 176 | loop { 177 | match self.get_char(reader, false) { 178 | Some(e) => match e { 179 | '\"' => break, 180 | '\\' => match self.parse_escape_char(reader) { 181 | Some(v) => string.push(v), 182 | None => return Err(format!("Unexpected escape sequence, got {}", e)) 183 | }, 184 | '\n' => return Err("Unescaped newlines are not allowed in string literals".to_string()), 185 | _ => string.push(e) 186 | }, 187 | None => return Err("Unexpected EOF while scanning string literal".to_string()) 188 | } 189 | } 190 | Ok(Sexp::Str(string)) 191 | } 192 | 193 | fn parse_escape_char(&mut self, reader: &mut BufReader) -> Option { 194 | match self.get_char(reader, false) { 195 | Some(e) => match e { 196 | '\"' => Some('\"'), 197 | '\'' => Some('\''), 198 | '\\' => Some('\\'), 199 | 'n' => Some('\n'), 200 | 'r' => Some('\r'), 201 | 't' => Some('\t'), 202 | _ => None 203 | }, 204 | None => None 205 | } 206 | } 207 | 208 | fn parse_number(&mut self, reader: &mut BufReader) -> ReadResult { 209 | let mut is_double = false; 210 | let mut string = "".to_string(); 211 | loop { 212 | match self.get_char(reader, false) { 213 | Some(e) if e == '.' && is_double => return Err("More than one . in numeric literal".to_string()), 214 | Some(e) if e == '.' => { 215 | is_double = true; 216 | string.push(e); 217 | } 218 | Some(e) if e.is_digit(10) => string.push(e), 219 | Some(e) => { 220 | self.unget_char(e); 221 | break; 222 | } 223 | None => break 224 | } 225 | } 226 | if is_double { 227 | Ok(Sexp::Float( 228 | string.parse::().unwrap() 229 | )) 230 | } else { 231 | Ok(Sexp::Int( 232 | string.parse::().unwrap() 233 | )) 234 | } 235 | } 236 | 237 | fn parse_symbol(&mut self, reader: &mut BufReader) -> ReadResult { 238 | let mut symbol = match self.peek_char(reader, false) { 239 | Some(e) if self.is_valid_for_identifier(e) => { 240 | let ch = self.get_char(reader, false).unwrap(); 241 | let mut s = String::new(); 242 | s.push(ch); 243 | // Workaround to replace convertion from char to string 244 | // String::from_char(1, self.get_char(reader, false).unwrap()) 245 | s 246 | }, 247 | Some(e) => { 248 | return Err(format!("Unexpected character: got {}, expected an atom", e)) 249 | }, 250 | None => return Err("Unexpected EOF".to_string()) 251 | }; 252 | loop { 253 | match self.get_char(reader, false) { 254 | Some(v) if self.is_valid_for_identifier(v) => symbol.push(v), 255 | Some(v) => { 256 | self.unget_char(v); 257 | break; 258 | }, 259 | None => break 260 | } 261 | } 262 | Ok(Sexp::Symbol(symbol)) 263 | } 264 | 265 | fn is_valid_for_identifier(&self, c: char) -> bool { 266 | match c { 267 | '!' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '~' | 268 | '/' | ':' | '<' | '=' | '>' | '?' | '@' | '^' | '_' | 269 | 'a'...'z' | 'A'...'Z' | '0'...'9' => true, 270 | _ => false 271 | } 272 | } 273 | 274 | fn get_char(&mut self, reader: &mut BufReader, skip_whitespace: bool) -> Option { 275 | loop { 276 | match self.unget_stack.pop() { 277 | Some(e) if !e.is_whitespace() || !skip_whitespace => 278 | { 279 | return Some(e) 280 | }, 281 | Some(_) => continue, 282 | None => () 283 | }; 284 | 285 | // Workaround to replace `reader.read_char()` 286 | let mut one_char_buffer = [0]; 287 | let n_bytes_read = reader.read(&mut one_char_buffer); 288 | match n_bytes_read { 289 | Ok(n) if n > 0 => {}, 290 | Ok(n) => return None, 291 | Err(e) => return None 292 | }; 293 | let ch = one_char_buffer[0] as char; 294 | 295 | match ch { 296 | c if !c.is_whitespace() || !skip_whitespace => return Some(c), 297 | _ => (), 298 | }; 299 | } 300 | } 301 | 302 | fn unget_char(&mut self, c: char) { 303 | self.unget_stack.push(c); 304 | } 305 | 306 | fn peek_char(&mut self, reader: &mut BufReader, skip_whitespace: bool) -> Option { 307 | match self.get_char(reader, skip_whitespace) { 308 | Some(c) => { 309 | self.unget_char(c); 310 | Some(c) 311 | }, 312 | None => None 313 | } 314 | } 315 | } 316 | 317 | #[cfg(test)] 318 | mod tests { 319 | use super::*; 320 | 321 | #[test] 322 | fn parses_ints() { 323 | let mut reader = SexpReader::new(); 324 | let result = reader.parse_str("42"); 325 | assert!(result.is_ok()); 326 | let sexp = result.unwrap(); 327 | match sexp { 328 | Sexp::Int(x) => assert_eq!(x, 42), 329 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 330 | }; 331 | } 332 | 333 | #[test] 334 | fn parses_floats() { 335 | let mut reader = SexpReader::new(); 336 | let result = reader.parse_str("9.8"); 337 | assert!(result.is_ok()); 338 | let sexp = result.unwrap(); 339 | match sexp { 340 | Sexp::Float(x) => assert_eq!(x, 9.8), 341 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 342 | }; 343 | } 344 | 345 | #[test] 346 | fn parses_strings() { 347 | let mut reader = SexpReader::new(); 348 | let result = reader.parse_str("\"hello world\""); 349 | assert!(result.is_ok()); 350 | let sexp = result.unwrap(); 351 | match sexp { 352 | Sexp::Str(x) => assert_eq!(x, "hello world".to_string()), 353 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 354 | }; 355 | } 356 | 357 | #[test] 358 | fn parses_symbols() { 359 | let mut reader = SexpReader::new(); 360 | let result = reader.parse_str("hello"); 361 | assert!(result.is_ok()); 362 | let sexp = result.unwrap(); 363 | match sexp { 364 | Sexp::Symbol(x) => assert_eq!(x, "hello".to_string()), 365 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 366 | }; 367 | } 368 | 369 | #[test] 370 | fn parses_lists() { 371 | let mut reader = SexpReader::new(); 372 | let result = reader.parse_str("(1 2 3)"); 373 | assert!(result.is_ok(), "parse failed: {:?}", result); 374 | let sexp = result.unwrap(); 375 | match sexp { 376 | Sexp::Cons(box Sexp::Int(x), box Sexp::Cons(box Sexp::Int(y), box Sexp::Cons(box Sexp::Int(z), box Sexp::Nil))) => { 377 | assert_eq!(x, 1); 378 | assert_eq!(y, 2); 379 | assert_eq!(z, 3); 380 | }, 381 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 382 | }; 383 | } 384 | 385 | #[test] 386 | fn parses_quotes() { 387 | let mut reader = SexpReader::new(); 388 | let result = reader.parse_str("'42"); 389 | assert!(result.is_ok(), "parse failed: {:?}", result); 390 | let sexp = result.unwrap(); 391 | match sexp { 392 | Sexp::Cons(box Sexp::Symbol(s), box Sexp::Int(i)) => { 393 | assert_eq!(s, "quote".to_string()); 394 | assert_eq!(i, 42); 395 | } 396 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 397 | }; 398 | } 399 | 400 | #[test] 401 | fn parses_quoted_lists() { 402 | let mut reader = SexpReader::new(); 403 | let result = reader.parse_str("'(1 2 3)"); 404 | assert!(result.is_ok(), "parse failed: {:?}", result); 405 | let sexp = result.unwrap(); 406 | match sexp { 407 | Sexp::Cons(box Sexp::Symbol(s), box Sexp::Cons(box Sexp::Int(a), box Sexp::Cons(box Sexp::Int(b), box Sexp::Cons(box Sexp::Int(c), box Sexp::Nil)))) => { 408 | assert_eq!(s, "quote".to_string()); 409 | assert_eq!(a, 1); 410 | assert_eq!(b, 2); 411 | assert_eq!(c, 3); 412 | } 413 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 414 | }; 415 | } 416 | 417 | 418 | #[test] 419 | fn parses_improper_lists() { 420 | let mut reader = SexpReader::new(); 421 | let result = reader.parse_str("(1 . 2)"); 422 | assert!(result.is_ok(), "parse failed: {:?}", result); 423 | let sexp = result.unwrap(); 424 | match sexp { 425 | Sexp::Cons(box Sexp::Int(a), box Sexp::Int(b)) => { 426 | assert_eq!(a, 1); 427 | assert_eq!(b, 2); 428 | }, 429 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 430 | } 431 | } 432 | 433 | #[test] 434 | fn parses_ellipsis_as_symbol() { 435 | let mut reader = SexpReader::new(); 436 | let result = reader.parse_str("..."); 437 | assert!(result.is_ok(), "parse failed: {:?}", result); 438 | let sexp = result.unwrap(); 439 | match sexp { 440 | Sexp::Symbol(s) => assert_eq!(s, "...".to_string()), 441 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 442 | } 443 | } 444 | 445 | #[test] 446 | fn parses_boolean_true() { 447 | let mut reader = SexpReader::new(); 448 | let result = reader.parse_str("#t"); 449 | assert!(result.is_ok(), "parse failed: {:?}", result); 450 | let sexp = result.unwrap(); 451 | match sexp { 452 | Sexp::Boolean(v) => assert!(v), 453 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 454 | } 455 | } 456 | 457 | #[test] 458 | fn parses_boolean_false() { 459 | let mut reader = SexpReader::new(); 460 | let result = reader.parse_str("#f"); 461 | assert!(result.is_ok(), "parse failed: {:?}", result); 462 | let sexp = result.unwrap(); 463 | match sexp { 464 | Sexp::Boolean(v) => assert!(!v), 465 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 466 | } 467 | } 468 | 469 | #[test] 470 | fn parses_empty_list() { 471 | let mut reader = SexpReader::new(); 472 | let result = reader.parse_str("()"); 473 | assert!(result.is_ok(), "parse failed: {:?}", result); 474 | let sexp = result.unwrap(); 475 | match sexp { 476 | Sexp::Nil => (), 477 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 478 | } 479 | } 480 | 481 | #[test] 482 | fn parses_quoted_empty_list() { 483 | let mut reader = SexpReader::new(); 484 | let result = reader.parse_str("'()"); 485 | assert!(result.is_ok(), "parse failed: {:?}", result); 486 | let sexp = result.unwrap(); 487 | match sexp { 488 | Sexp::Cons(box Sexp::Symbol(ref quote), box Sexp::Nil) => assert_eq!(*quote, "quote".to_string()), 489 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 490 | } 491 | } 492 | 493 | #[test] 494 | fn parses_quasiquote() { 495 | let mut reader = SexpReader::new(); 496 | let result = reader.parse_str("`5"); 497 | assert!(result.is_ok(), "parse failed: {:?}", result); 498 | let sexp = result.unwrap(); 499 | match sexp { 500 | Sexp::Cons(box Sexp::Symbol(ref quote), box Sexp::Int(5)) => assert_eq!(*quote, "quasiquote".to_string()), 501 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 502 | } 503 | } 504 | 505 | #[test] 506 | fn parses_unquote() { 507 | let mut reader = SexpReader::new(); 508 | let result = reader.parse_str(",5"); 509 | assert!(result.is_ok(), "parse failed: {:?}", result); 510 | let sexp = result.unwrap(); 511 | match sexp { 512 | Sexp::Cons(box Sexp::Symbol(ref quote), box Sexp::Int(5)) => assert_eq!(*quote, "unquote".to_string()), 513 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 514 | } 515 | } 516 | 517 | #[test] 518 | fn parses_unquote_splicing() { 519 | let mut reader = SexpReader::new(); 520 | let result = reader.parse_str(",@5"); 521 | assert!(result.is_ok(), "parse failed: {:?}", result); 522 | let sexp = result.unwrap(); 523 | match sexp { 524 | Sexp::Cons(box Sexp::Symbol(ref quote), box Sexp::Int(5)) => assert_eq!(*quote, "unquote-splicing".to_string()), 525 | _ => panic!("Parsed incorrectly, got {:?}", sexp) 526 | } 527 | } 528 | 529 | #[test] 530 | fn parses_several_expressions() { 531 | let mut reader = SexpReader::new(); 532 | let result = reader.parse_str_all("(hello) (world)"); 533 | let sexp = result.unwrap(); 534 | assert_eq!(sexp.len(), 2); 535 | match sexp[0] { 536 | Sexp::Cons(box Sexp::Symbol(ref s), box Sexp::Nil) => assert_eq!(*s, "hello".to_string()), 537 | ref s => panic!("Parsed incorrectly, got {:?}", s) 538 | }; 539 | match sexp[1] { 540 | Sexp::Cons(box Sexp::Symbol(ref s), box Sexp::Nil) => assert_eq!(*s, "world".to_string()), 541 | ref s => panic!("Parsed incorrectly, got {:?}", s) 542 | } 543 | } 544 | 545 | #[test] 546 | fn parses_several_empty_lists() { 547 | let mut reader = SexpReader::new(); 548 | let result = reader.parse_str_all("()()"); 549 | let sexp = result.unwrap(); 550 | assert_eq!(sexp.len(), 2); 551 | match sexp[0] { 552 | Sexp::Nil => (), 553 | ref s => panic!("Parsed incorrectly, got {:?}", s) 554 | }; 555 | match sexp[1] { 556 | Sexp::Nil => (), 557 | ref s => panic!("Parsed incorrectly, got {:?}", s) 558 | } 559 | } 560 | 561 | #[test] 562 | fn parses_several_improper_lists() { 563 | let mut reader = SexpReader::new(); 564 | let result = reader.parse_str_all("(1 . 2) (3 . 4)"); 565 | let sexp = result.unwrap(); 566 | assert_eq!(sexp.len(), 2); 567 | match sexp[0] { 568 | Sexp::Cons(box Sexp::Int(a), box Sexp::Int(b)) => { 569 | assert_eq!(a, 1); 570 | assert_eq!(b, 2); 571 | }, 572 | ref s => panic!("Parsed incorrectly, got {:?}", s) 573 | }; 574 | match sexp[1] { 575 | Sexp::Cons(box Sexp::Int(a), box Sexp::Int(b)) => { 576 | assert_eq!(a, 3); 577 | assert_eq!(b, 4); 578 | }, 579 | ref s => panic!("Parsed incorrectly, got {:?}", s) 580 | }; 581 | } 582 | 583 | 584 | } 585 | --------------------------------------------------------------------------------