├── core ├── src │ ├── common │ │ ├── mod.rs │ │ ├── util.rs │ │ └── combinator.rs │ ├── lib.rs │ ├── parser │ │ ├── types.rs │ │ ├── ast.rs │ │ └── mod.rs │ ├── evaluator │ │ ├── types.rs │ │ ├── built_ins.rs │ │ ├── value.rs │ │ └── mod.rs │ └── lexer │ │ ├── types.rs │ │ └── mod.rs └── Cargo.toml ├── src ├── lib.rs ├── main.rs ├── repl.rs └── run.rs ├── .travis.yml ├── Cargo.toml ├── .gitignore ├── examples ├── hash.mk └── map-reduce.mk ├── LICENSE └── README.md /core/src/common/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod combinator; 2 | pub mod util; 3 | -------------------------------------------------------------------------------- /core/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod common; 2 | pub mod evaluator; 3 | #[macro_use] 4 | pub mod lexer; 5 | pub mod parser; 6 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate core; 2 | extern crate ansi_term; 3 | extern crate rustyline; 4 | 5 | pub mod repl; 6 | pub mod run; 7 | -------------------------------------------------------------------------------- /core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "core" 3 | version = "0.1.0" 4 | authors = ["Hyunjae Jun "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | matrix: 7 | allow_failures: 8 | - rust: nightly 9 | script: 10 | - cargo build --verbose --all 11 | - cargo test --verbose --all 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monkey" 3 | version = "0.1.0" 4 | authors = ["Hyunjae Jun "] 5 | 6 | [workspace] 7 | 8 | [dependencies] 9 | core = { path = "core" } 10 | ansi_term = "0.9" 11 | getopts = "0.2" 12 | rustyline = "1.0" 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /examples/hash.mk: -------------------------------------------------------------------------------- 1 | let people = [{"name": "Alice", "age": 24}, {"name": "Anna", "age": 28}]; 2 | 3 | print(people[0]["name"]); 4 | print(people[1]["age"]); 5 | print(people[0]["age"] + people[1]["age"]); 6 | 7 | let getName = fn(person) { person["name"]; }; 8 | 9 | print(getName(people[0])); 10 | print(getName(people[1])); 11 | 12 | let map = fn(f, arr) { 13 | if (len(arr) == 0) { 14 | [] 15 | } else { 16 | let h = head(arr); 17 | cons(f(h), map(f, tail(arr))); 18 | } 19 | }; 20 | 21 | print(map(getName, people)); 22 | -------------------------------------------------------------------------------- /examples/map-reduce.mk: -------------------------------------------------------------------------------- 1 | let map = fn(f, arr) { 2 | if (len(arr) == 0) { 3 | [] 4 | } else { 5 | let h = head(arr); 6 | cons(f(h), map(f, tail(arr))); 7 | } 8 | }; 9 | 10 | let reduce = fn(f, init, arr) { 11 | if (len(arr) == 0) { 12 | init 13 | } else { 14 | let newInit = f(init, head(arr)); 15 | reduce(f, newInit, tail(arr)); 16 | } 17 | }; 18 | 19 | let double = fn(x) { 20 | 2 * x 21 | }; 22 | 23 | let add = fn(x, y) { 24 | x + y 25 | }; 26 | 27 | let mapped = map(double, [1, 2, 3, 4]); 28 | 29 | print(mapped); 30 | 31 | let sum = fn(arr) { 32 | reduce(add, 0, arr); 33 | }; 34 | 35 | let summed = sum([1, 2, 3, 4, 5]); 36 | 37 | print(summed); 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hyunje Jun 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 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate getopts; 2 | extern crate monkey; 3 | 4 | use getopts::Options; 5 | use monkey::repl; 6 | use monkey::run; 7 | use std::env; 8 | 9 | fn print_usage(program: &str, opts: Options) { 10 | let brief = format!("Usage: {} [OPTIONS] COMMAND [PARAMS] 11 | 12 | Commands: 13 | repl\t\tlaunch repl 14 | run INPUT\t\tlaunch a script file", 15 | program); 16 | print!("{}", opts.usage(&brief)); 17 | } 18 | 19 | fn main() { 20 | let args: Vec = env::args().collect(); 21 | let program = args[0].clone(); 22 | 23 | let mut opts = Options::new(); 24 | opts.optflag("h", "help", "print this help menu"); 25 | let matches = opts.parse(&args[1..]).unwrap(); 26 | 27 | if matches.opt_present("h") || matches.free.is_empty() { 28 | print_usage(&program, opts); 29 | return; 30 | } 31 | 32 | let command = matches.free[0].as_str(); 33 | match command { 34 | "repl" => repl::main(), 35 | "run" => { 36 | match matches.free.get(1) { 37 | Some(file_path) => run::main(file_path), 38 | None => print_usage(&program, opts), 39 | } 40 | } 41 | _ => print_usage(&program, opts), 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/parser/types.rs: -------------------------------------------------------------------------------- 1 | use common::combinator; 2 | use std::result; 3 | use lexer::types::*; 4 | 5 | pub type Result = result::Result; 6 | 7 | #[derive(Debug)] 8 | pub struct ParseError { 9 | pub message: String, 10 | pub token: Option, 11 | } 12 | 13 | pub struct Parser { 14 | input: Vec, 15 | cursor: usize, 16 | saved_cursor: usize, 17 | } 18 | 19 | impl Parser { 20 | pub fn new(input: Vec) -> Parser { 21 | Parser { 22 | input: input, 23 | cursor: 0, 24 | saved_cursor: 0, 25 | } 26 | } 27 | } 28 | 29 | impl combinator::Parser for Parser { 30 | fn consume(&mut self) -> Option { 31 | match self.input.get(self.cursor) { 32 | Some(token) => { 33 | self.cursor += 1; 34 | Some(token.clone()) 35 | } 36 | None => None, 37 | } 38 | } 39 | 40 | fn preview(&self) -> Option<&Token> { 41 | self.input.get(self.cursor) 42 | } 43 | 44 | fn current_pos(&self) -> (i32, i32) { 45 | self.preview().unwrap().pos() 46 | } 47 | 48 | fn error>(&self, message: S) -> ParseError { 49 | ParseError { 50 | message: message.into(), 51 | token: if self.cursor > 0 { 52 | self.input.get(self.cursor - 1).map(|token| token.clone()) 53 | } else { 54 | None 55 | }, 56 | } 57 | } 58 | 59 | fn save(&mut self) { 60 | self.saved_cursor = self.cursor; 61 | } 62 | 63 | fn load(&mut self) { 64 | self.cursor = self.saved_cursor; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /core/src/evaluator/types.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::collections::HashMap; 3 | use std::iter::FromIterator; 4 | use std::rc::Rc; 5 | use std::result; 6 | use parser::ast::*; 7 | use evaluator::value::Value; 8 | 9 | pub type Result = result::Result, EvalError>; 10 | 11 | pub fn ret(x: T) -> Result { 12 | Ok(Rc::new(x)) 13 | } 14 | 15 | #[derive(PartialEq, Debug)] 16 | pub struct EvalError(pub String, pub (i32, i32)); 17 | 18 | pub fn throw(message: String, pos: (i32, i32)) -> Result { 19 | Err(EvalError(message, pos)) 20 | } 21 | 22 | #[derive(PartialEq, Eq, Debug)] 23 | pub struct Env { 24 | var_map: HashMap>, 25 | parent: Option>>, 26 | } 27 | 28 | impl Env { 29 | pub fn new() -> Env { 30 | Env { 31 | var_map: HashMap::default(), 32 | parent: None, 33 | } 34 | } 35 | 36 | pub fn from)>>(iter: T) -> Env { 37 | Env { 38 | var_map: HashMap::from_iter(iter), 39 | parent: None, 40 | } 41 | } 42 | 43 | pub fn wrap(items: Vec<(Ident, Rc)>, parent: Rc>) -> Env { 44 | Env { 45 | var_map: HashMap::from_iter(items), 46 | parent: Some(parent.clone()), 47 | } 48 | } 49 | 50 | pub fn insert_var(&mut self, id: Ident, val: Rc) { 51 | self.var_map.insert(id, val); 52 | } 53 | 54 | pub fn get_var(&self, id: &Ident) -> Option> { 55 | match self.var_map.get(id) { 56 | Some(x) => Some(x.clone()), 57 | None => { 58 | match self.parent { 59 | Some(ref p) => p.borrow().get_var(id), 60 | None => None, 61 | } 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # monkey-rs [![Build Status](https://travis-ci.org/noraesae/monkey-rs.svg?branch=master)](https://travis-ci.org/noraesae/monkey-rs) 2 | 3 | A compiler for the Monkey programming language written in Rust 4 | 5 | ![The Monkey Programming Language](https://cloud.githubusercontent.com/assets/1013641/22617482/9c60c27c-eb09-11e6-9dfa-b04c7fe498ea.png) 6 | 7 | *The official Monkey logo* 8 | 9 | ## What's Monkey? 10 | 11 | Monkey is a programming language designed for learning about interpreter 12 | implementation, used in a book, [Writing An Interpreter In Go](https://interpreterbook.com/#the-monkey-programming-language). 13 | 14 | ## Again, why? 15 | 16 | Some people may already know that I've written [a Monkey interpreter in Haskell](https://github.com/noraesae/monkey-hs). 17 | Why do I rewrite a similar thing in another language? Does it really mean 18 | anything? 19 | 20 | Well, I've recently started learning Rust, and thought rewriting what I've 21 | already made would be a nice start to learn a new language. Also, the transition 22 | may not be so difficult as Rust adopted many language concepts from Haskell, 23 | such as pattern match, error handling, and trait (known as type class in 24 | Haskell). 25 | 26 | Let me see if I can do it well :v: 27 | 28 | ## Screenshot 29 | 30 | #### Compiler error messages 31 | 32 | 33 | 34 | 35 | #### REPL 36 | 37 | 38 | 39 | ## Instruction 40 | 41 | Build, test and install: 42 | 43 | ``` 44 | cargo build --all 45 | cargo test --all 46 | cargo install 47 | ``` 48 | 49 | Run REPL and scripts: 50 | 51 | ``` 52 | monkey repl 53 | monkey run examples/map-reduce.mk 54 | ``` 55 | 56 | ## License 57 | 58 | [MIT](LICENSE) 59 | -------------------------------------------------------------------------------- /core/src/common/util.rs: -------------------------------------------------------------------------------- 1 | pub fn is_letter(c: &char) -> bool { 2 | *c == '_' || c.is_alphabetic() 3 | } 4 | 5 | pub fn is_digit(c: &char) -> bool { 6 | c.is_digit(10) 7 | } 8 | 9 | pub fn is_letter_or_digit(c: &char) -> bool { 10 | is_letter(c) || is_digit(c) 11 | } 12 | 13 | pub fn escape(x: &String) -> String { 14 | x.trim_matches('"') 15 | .replace("\\n", "\n") 16 | .replace("\\t", "\t") 17 | .replace("\\\\", "\\") 18 | .replace("\\\"", "\"") 19 | } 20 | 21 | pub fn unescape(x: &String) -> String { 22 | format!("\"{}\"", 23 | x.replace("\"", "\\\"") 24 | .replace("\\", "\\\\") 25 | .replace("\t", "\\t") 26 | .replace("\n", "\\n")) 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | 33 | #[test] 34 | fn is_letter_test() { 35 | assert_eq!(is_letter(&'a'), true); 36 | assert_eq!(is_letter(&'c'), true); 37 | assert_eq!(is_letter(&'k'), true); 38 | assert_eq!(is_letter(&'l'), true); 39 | assert_eq!(is_letter(&'_'), true); 40 | assert_eq!(is_letter(&'1'), false); 41 | assert_eq!(is_letter(&'3'), false); 42 | assert_eq!(is_letter(&' '), false); 43 | assert_eq!(is_letter(&'}'), false); 44 | } 45 | 46 | #[test] 47 | fn is_digit_test() { 48 | assert_eq!(is_digit(&'a'), false); 49 | assert_eq!(is_digit(&'c'), false); 50 | assert_eq!(is_digit(&'k'), false); 51 | assert_eq!(is_digit(&'l'), false); 52 | assert_eq!(is_digit(&'_'), false); 53 | assert_eq!(is_digit(&'1'), true); 54 | assert_eq!(is_digit(&'3'), true); 55 | assert_eq!(is_digit(&' '), false); 56 | assert_eq!(is_digit(&'}'), false); 57 | } 58 | 59 | #[test] 60 | fn is_letter_or_digit_test() { 61 | assert_eq!(is_letter_or_digit(&'a'), true); 62 | assert_eq!(is_letter_or_digit(&'c'), true); 63 | assert_eq!(is_letter_or_digit(&'k'), true); 64 | assert_eq!(is_letter_or_digit(&'l'), true); 65 | assert_eq!(is_letter_or_digit(&'_'), true); 66 | assert_eq!(is_letter_or_digit(&'1'), true); 67 | assert_eq!(is_letter_or_digit(&'3'), true); 68 | assert_eq!(is_letter_or_digit(&' '), false); 69 | assert_eq!(is_letter_or_digit(&'}'), false); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/repl.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::rc::Rc; 3 | use core::evaluator; 4 | use core::evaluator::built_ins; 5 | use core::evaluator::types::*; 6 | use core::lexer; 7 | use core::lexer::types::*; 8 | use core::parser; 9 | use core::parser::types::*; 10 | use rustyline::Editor; 11 | use rustyline::error::ReadlineError; 12 | use std::result; 13 | 14 | pub fn main() { 15 | println!("The Monkey programming language REPL"); 16 | 17 | let mut editor: Editor<()> = Editor::new(); 18 | 19 | let env = Rc::new(RefCell::new(built_ins::init())); 20 | 21 | loop { 22 | match editor.readline("> ") { 23 | Ok(input) => { 24 | match handle_input(env.clone(), input) { 25 | Ok(output) => println!("{}", output), 26 | Err(ReplError::DoNothing) => continue, 27 | Err(ReplError::Exit) => break, 28 | Err(ReplError::LexError(err)) => { 29 | println!("Lexical error: {} at {:?}", err.message, err.pos) 30 | } 31 | Err(ReplError::ParseError(err)) => { 32 | match err.token { 33 | Some(t) => println!("Parse error: {} at {:?}", err.message, t.pos()), 34 | None => println!("Parse error: {}", err.message), 35 | } 36 | } 37 | Err(ReplError::EvalError(err)) => { 38 | println!("Runtime error: {} at {:?}", err.0, err.1) 39 | } 40 | } 41 | } 42 | Err(ReadlineError::Interrupted) => continue, 43 | Err(ReadlineError::Eof) => break, 44 | Err(err) => println!("{:?}", err), 45 | } 46 | } 47 | println!("bye!"); 48 | } 49 | 50 | type Result = result::Result; 51 | 52 | enum ReplError { 53 | Exit, 54 | DoNothing, 55 | LexError(LexError), 56 | ParseError(ParseError), 57 | EvalError(EvalError), 58 | } 59 | 60 | fn handle_input(env: Rc>, input: String) -> Result { 61 | if input.len() == 0 { 62 | return Err(ReplError::DoNothing); 63 | } else if input == "exit" { 64 | return Err(ReplError::Exit); 65 | } 66 | 67 | let tokens = try!(lexer::tokenize(input.chars()).map_err(|err| ReplError::LexError(err))); 68 | let ast = try!(parser::parse(tokens).map_err(|err| ReplError::ParseError(err))); 69 | let value = try!(evaluator::eval(env, &ast).map_err(|err| ReplError::EvalError(err))); 70 | 71 | Ok(format!("{}", value)) 72 | } 73 | -------------------------------------------------------------------------------- /core/src/evaluator/built_ins.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | use evaluator::types::*; 3 | use evaluator::value::*; 4 | use parser::ast::Ident; 5 | use lexer::types::Token; 6 | 7 | fn built_in(name: &str, num_params: usize, func: BuiltInFn) -> (Ident, Rc) { 8 | (Ident(String::from(name), Token::Ident(0, 0, String::from(name))), 9 | Rc::new(Value::BuiltInFn { 10 | name: String::from(name), 11 | num_params, 12 | func, 13 | })) 14 | } 15 | 16 | fn built_in_len(args: Vec<((i32, i32), Rc)>) -> Result { 17 | let &(pos, ref x) = args.get(0).unwrap(); 18 | match x.as_ref() { 19 | &Value::String(ref s) => ret(Value::Int(s.len() as i64)), 20 | &Value::Array(ref arr) => ret(Value::Int(arr.len() as i64)), 21 | _ => throw(format!("{} is not a string or an array", x), pos), 22 | } 23 | } 24 | 25 | fn built_in_head(args: Vec<((i32, i32), Rc)>) -> Result { 26 | let &(pos, ref x) = args.get(0).unwrap(); 27 | match x.as_ref() { 28 | &Value::Array(ref arr) => { 29 | match arr.get(0) { 30 | Some(v) => Ok(v.clone()), 31 | None => throw(String::from("invalid arguments: empty array"), pos), 32 | } 33 | } 34 | _ => throw(format!("{} is not an array", x), pos), 35 | } 36 | } 37 | 38 | fn built_in_tail(args: Vec<((i32, i32), Rc)>) -> Result { 39 | let &(pos, ref x) = args.get(0).unwrap(); 40 | match x.as_ref() { 41 | &Value::Array(ref arr) => { 42 | if arr.is_empty() { 43 | throw(String::from("invalid arguments: empty array"), pos) 44 | } else { 45 | ret(Value::Array(arr[1..].to_vec())) 46 | } 47 | } 48 | _ => throw(format!("{} is not an array", x), pos), 49 | } 50 | } 51 | 52 | fn built_in_cons(args: Vec<((i32, i32), Rc)>) -> Result { 53 | let &(_, ref x) = args.get(0).unwrap(); 54 | let &(pos_xs, ref xs) = args.get(1).unwrap(); 55 | match xs.as_ref() { 56 | &Value::Array(ref arr) => { 57 | let mut res = vec![x.clone()]; 58 | res.extend(arr.iter().cloned()); 59 | ret(Value::Array(res)) 60 | } 61 | _ => throw(format!("{} is not an array", xs), pos_xs), 62 | } 63 | } 64 | 65 | fn built_in_print(args: Vec<((i32, i32), Rc)>) -> Result { 66 | let &(_, ref x) = args.get(0).unwrap(); 67 | match x.as_ref() { 68 | &Value::String(ref s) => println!("{}", s), 69 | v => println!("{}", v), 70 | } 71 | ret(Value::Null) 72 | } 73 | 74 | pub fn init() -> Env { 75 | let built_ins = vec![built_in("len", 1, built_in_len), 76 | built_in("head", 1, built_in_head), 77 | built_in("tail", 1, built_in_tail), 78 | built_in("cons", 2, built_in_cons), 79 | built_in("print", 1, built_in_print)]; 80 | 81 | Env::from(built_ins) 82 | } 83 | -------------------------------------------------------------------------------- /src/run.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::fs::File; 3 | use std::io::prelude::*; 4 | use std::io; 5 | use std::process; 6 | use std::rc::Rc; 7 | use std::result; 8 | use ansi_term::Colour::RGB; 9 | use core::evaluator; 10 | use core::evaluator::built_ins; 11 | use core::evaluator::types::*; 12 | use core::lexer; 13 | use core::lexer::types::*; 14 | use core::parser; 15 | use core::parser::types::*; 16 | 17 | fn read_file(file_path: &String) -> result::Result { 18 | let mut file = File::open(file_path)?; 19 | let mut contents = String::new(); 20 | file.read_to_string(&mut contents)?; 21 | Ok(contents) 22 | } 23 | 24 | fn print_pos(file_path: &String, pos: (i32, i32)) { 25 | println!("{}:{}:{}", file_path, pos.0, pos.1); 26 | } 27 | 28 | fn print_code_around(content: &String, pos: (i32, i32)) { 29 | println!(""); 30 | for (i, line) in content.lines().enumerate() { 31 | let row = pos.0 as usize - 1; 32 | if i < row - 2 { 33 | continue; 34 | } else if i > row + 2 { 35 | break; 36 | } else if i == row { 37 | println!(" {}", RGB(255, 255, 255).paint(line)); 38 | println!(" {}{}", 39 | " ".repeat(pos.1 as usize - 1), 40 | RGB(255, 65, 54).paint("^--")); 41 | } else { 42 | println!(" {}", RGB(143, 143, 143).paint(line)); 43 | } 44 | } 45 | println!(""); 46 | } 47 | 48 | pub fn main(file_path: &String) { 49 | match read_file(file_path) { 50 | Ok(input) => { 51 | match run(&input) { 52 | Ok(_) => {} 53 | Err(RunError::LexError(err)) => { 54 | print_pos(file_path, err.pos); 55 | print_code_around(&input, err.pos); 56 | println!("Lexical error: {}", err.message); 57 | process::exit(1); 58 | } 59 | Err(RunError::ParseError(err)) => { 60 | match err.token { 61 | Some(t) => { 62 | print_pos(file_path, t.pos()); 63 | print_code_around(&input, t.pos()); 64 | } 65 | None => { 66 | println!("{}", file_path); 67 | } 68 | } 69 | println!("Parse error: {}", err.message); 70 | process::exit(1); 71 | } 72 | Err(RunError::EvalError(err)) => { 73 | print_pos(file_path, err.1); 74 | print_code_around(&input, err.1); 75 | println!("Runtime error: {}", err.0); 76 | process::exit(1); 77 | } 78 | } 79 | } 80 | Err(err) => { 81 | println!("error occurred loading {}", file_path); 82 | println!("{:?}", err); 83 | process::exit(1); 84 | } 85 | } 86 | } 87 | 88 | type Result = result::Result; 89 | 90 | enum RunError { 91 | LexError(LexError), 92 | ParseError(ParseError), 93 | EvalError(EvalError), 94 | } 95 | 96 | fn run(input: &String) -> Result<()> { 97 | let tokens = try!(lexer::tokenize(input.chars()).map_err(|err| RunError::LexError(err))); 98 | let ast = try!(parser::parse(tokens).map_err(|err| RunError::ParseError(err))); 99 | 100 | let env = Rc::new(RefCell::new(built_ins::init())); 101 | let _ = try!(evaluator::eval(env, &ast).map_err(|err| RunError::EvalError(err))); 102 | Ok(()) 103 | } 104 | -------------------------------------------------------------------------------- /core/src/lexer/types.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::result; 3 | use common::combinator::*; 4 | 5 | pub type Result = result::Result; 6 | 7 | macro_rules! token_defs { 8 | ($enum_name:ident => { 9 | $($name:ident,)* 10 | }) => { 11 | #[derive(PartialEq, Eq, Clone, Debug)] 12 | pub enum $enum_name { 13 | $( 14 | $name(i32, i32, String), 15 | )* 16 | } 17 | 18 | impl $enum_name { 19 | pub fn pos(&self) -> (i32, i32) { 20 | match *self { 21 | $( 22 | $enum_name::$name(row, col, _) => (row, col), 23 | )* 24 | } 25 | } 26 | 27 | pub fn literal(&self) -> &String { 28 | match *self { 29 | $( 30 | $enum_name::$name(_, _, ref lit) => lit, 31 | )* 32 | } 33 | } 34 | } 35 | } 36 | } 37 | 38 | macro_rules! token { 39 | ($token:ident, $row:expr, $col:expr, $literal:expr) => { 40 | Token::$token($row, $col, $literal.to_string()) 41 | } 42 | } 43 | 44 | token_defs!(Token => { 45 | Illegal, 46 | 47 | // identifier and literals 48 | Ident, 49 | IntLiteral, 50 | BoolLiteral, 51 | StringLiteral, 52 | 53 | // statements 54 | Assign, 55 | If, 56 | Else, 57 | 58 | // operators 59 | Plus, 60 | Minus, 61 | Divide, 62 | Multiply, 63 | Eq, 64 | NotEq, 65 | GreaterThan, 66 | LessThan, 67 | Not, 68 | 69 | // reserved words 70 | Function, 71 | Let, 72 | Return, 73 | 74 | // punctuations 75 | Comma, 76 | Colon, 77 | SemiColon, 78 | LParen, 79 | RParen, 80 | LBrace, 81 | RBrace, 82 | LBracket, 83 | RBracket, 84 | }); 85 | 86 | impl fmt::Display for Token { 87 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 88 | write!(f, "{}", self.literal()) 89 | } 90 | } 91 | 92 | #[derive(Debug)] 93 | pub struct LexError { 94 | pub message: String, 95 | pub pos: (i32, i32), 96 | token: char, 97 | } 98 | 99 | pub struct Lexer { 100 | input: Vec, 101 | cursor: usize, 102 | row: i32, 103 | col: i32, 104 | last_char_info: (i32, i32, char), 105 | saved_cursor: usize, 106 | saved_row: i32, 107 | saved_col: i32, 108 | } 109 | 110 | impl Lexer { 111 | pub fn new(input: I) -> Lexer 112 | where I: Iterator 113 | { 114 | Lexer { 115 | input: input.collect(), 116 | cursor: 0, 117 | row: 1, 118 | col: 1, 119 | last_char_info: (1, 0, '^'), 120 | saved_cursor: 0, 121 | saved_row: 1, 122 | saved_col: 1, 123 | } 124 | } 125 | } 126 | 127 | impl Parser for Lexer { 128 | fn consume(&mut self) -> Option { 129 | match self.input.get(self.cursor) { 130 | Some(x) => { 131 | self.cursor += 1; 132 | 133 | self.last_char_info.0 = self.row; 134 | self.last_char_info.1 = self.col; 135 | 136 | if *x == '\n' { 137 | self.row += 1; 138 | self.col = 1; 139 | } else { 140 | self.col += 1; 141 | } 142 | 143 | let c = x.clone(); 144 | self.last_char_info.2 = c; 145 | Some(c) 146 | } 147 | None => None, 148 | } 149 | } 150 | 151 | fn preview(&self) -> Option<&char> { 152 | self.input.get(self.cursor) 153 | } 154 | 155 | fn current_pos(&self) -> (i32, i32) { 156 | (self.row, self.col) 157 | } 158 | 159 | fn error>(&self, message: S) -> LexError { 160 | LexError { 161 | message: message.into(), 162 | pos: (self.last_char_info.0, self.last_char_info.1), 163 | token: self.last_char_info.2, 164 | } 165 | } 166 | 167 | fn save(&mut self) { 168 | self.saved_cursor = self.cursor; 169 | self.saved_row = self.row; 170 | self.saved_col = self.col; 171 | } 172 | 173 | fn load(&mut self) { 174 | self.cursor = self.saved_cursor; 175 | self.row = self.saved_row; 176 | self.col = self.saved_col; 177 | } 178 | } 179 | 180 | #[cfg(test)] 181 | mod tests { 182 | use super::*; 183 | 184 | #[test] 185 | fn pos() { 186 | let mut l = Lexer::new(String::from("123\n 4\n5\n").chars()); 187 | assert_eq!(l.current_pos(), (1, 1)); 188 | l.consume(); 189 | assert_eq!(l.current_pos(), (1, 2)); 190 | l.consume(); 191 | assert_eq!(l.current_pos(), (1, 3)); 192 | l.consume(); 193 | assert_eq!(l.current_pos(), (1, 4)); 194 | l.consume(); 195 | assert_eq!(l.current_pos(), (2, 1)); 196 | l.consume(); 197 | assert_eq!(l.current_pos(), (2, 2)); 198 | l.consume(); 199 | assert_eq!(l.current_pos(), (2, 3)); 200 | l.consume(); 201 | assert_eq!(l.current_pos(), (3, 1)); 202 | l.consume(); 203 | assert_eq!(l.current_pos(), (3, 2)); 204 | l.consume(); 205 | assert_eq!(l.current_pos(), (4, 1)); 206 | l.consume(); 207 | assert_eq!(l.current_pos(), (4, 1)); 208 | l.consume(); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /core/src/parser/ast.rs: -------------------------------------------------------------------------------- 1 | use lexer::types::*; 2 | use std::hash::{Hash, Hasher}; 3 | 4 | pub trait Positioned { 5 | fn pos(&self) -> (i32, i32); 6 | } 7 | 8 | #[derive(PartialEq, Eq, Debug)] 9 | pub struct Program(pub BlockStmt); 10 | 11 | pub type BlockStmt = Vec; 12 | 13 | #[derive(PartialEq, Eq, Clone, Debug)] 14 | pub enum Stmt { 15 | Let(Ident, Expr), 16 | Return(Expr), 17 | Expr(Expr), 18 | } 19 | 20 | #[derive(PartialEq, Eq, Clone, Debug)] 21 | pub enum Expr { 22 | Ident(Ident), 23 | Lit(Literal), 24 | Prefix(PrefixOp, Box), 25 | Infix(InfixOp, Box, Box), 26 | If { 27 | cond: Box, 28 | con: BlockStmt, 29 | alt: Option, 30 | pos: (i32, i32), 31 | }, 32 | Fn { 33 | params: Vec, 34 | body: BlockStmt, 35 | pos: (i32, i32), 36 | }, 37 | Call { func: Box, args: Vec }, 38 | Array(Vec, (i32, i32)), 39 | Hash(Vec<(Literal, Expr)>, (i32, i32)), 40 | Index { target: Box, index: Box }, 41 | } 42 | 43 | impl Positioned for Expr { 44 | fn pos(&self) -> (i32, i32) { 45 | match self { 46 | &Expr::Ident(ref i) => i.pos(), 47 | &Expr::Lit(ref l) => l.pos(), 48 | &Expr::Prefix(ref p, _) => p.pos(), 49 | &Expr::Infix(ref i, ..) => i.pos(), 50 | &Expr::If { pos, .. } => pos, 51 | &Expr::Fn { pos, .. } => pos, 52 | &Expr::Call { ref func, .. } => func.pos(), 53 | &Expr::Array(_, pos) => pos, 54 | &Expr::Hash(_, pos) => pos, 55 | &Expr::Index { ref target, .. } => target.pos(), 56 | } 57 | } 58 | } 59 | 60 | #[derive(Eq, Clone, Debug)] 61 | pub struct Ident(pub String, pub Token); 62 | 63 | impl PartialEq for Ident { 64 | fn eq(&self, other: &Self) -> bool { 65 | self.0 == other.0 66 | } 67 | } 68 | 69 | impl Hash for Ident { 70 | fn hash(&self, state: &mut H) { 71 | self.0.hash(state); 72 | } 73 | } 74 | 75 | impl Positioned for Ident { 76 | fn pos(&self) -> (i32, i32) { 77 | self.1.pos() 78 | } 79 | } 80 | 81 | #[derive(Eq, Clone, Debug)] 82 | pub enum Literal { 83 | Int(i64, Token), 84 | Bool(bool, Token), 85 | String(String, Token), 86 | } 87 | 88 | impl PartialEq for Literal { 89 | fn eq(&self, other: &Self) -> bool { 90 | match (self, other) { 91 | (&Literal::Int(ref i1, _), &Literal::Int(ref i2, _)) => i1 == i2, 92 | (&Literal::Bool(ref b1, _), &Literal::Bool(ref b2, _)) => b1 == b2, 93 | (&Literal::String(ref s1, _), &Literal::String(ref s2, _)) => s1 == s2, 94 | _ => false, 95 | } 96 | } 97 | } 98 | 99 | impl Positioned for Literal { 100 | fn pos(&self) -> (i32, i32) { 101 | match self { 102 | &Literal::Int(_, ref t) => t.pos(), 103 | &Literal::Bool(_, ref t) => t.pos(), 104 | &Literal::String(_, ref t) => t.pos(), 105 | } 106 | } 107 | } 108 | 109 | #[derive(Eq, Clone, Debug)] 110 | pub enum PrefixOp { 111 | Plus(Token), 112 | Minus(Token), 113 | Not(Token), 114 | } 115 | 116 | impl PartialEq for PrefixOp { 117 | fn eq(&self, other: &Self) -> bool { 118 | match (self, other) { 119 | (&PrefixOp::Plus(_), &PrefixOp::Plus(_)) => true, 120 | (&PrefixOp::Minus(_), &PrefixOp::Minus(_)) => true, 121 | (&PrefixOp::Not(_), &PrefixOp::Not(_)) => true, 122 | _ => false, 123 | } 124 | } 125 | } 126 | 127 | impl Positioned for PrefixOp { 128 | fn pos(&self) -> (i32, i32) { 129 | match self { 130 | &PrefixOp::Plus(ref t) => t.pos(), 131 | &PrefixOp::Minus(ref t) => t.pos(), 132 | &PrefixOp::Not(ref t) => t.pos(), 133 | } 134 | } 135 | } 136 | 137 | #[derive(Eq, Clone, Debug)] 138 | pub enum InfixOp { 139 | Plus(Token), 140 | Minus(Token), 141 | Divide(Token), 142 | Multiply(Token), 143 | Eq(Token), 144 | NotEq(Token), 145 | GreaterThan(Token), 146 | LessThan(Token), 147 | } 148 | 149 | impl PartialEq for InfixOp { 150 | fn eq(&self, other: &Self) -> bool { 151 | match (self, other) { 152 | (&InfixOp::Plus(_), &InfixOp::Plus(_)) => true, 153 | (&InfixOp::Minus(_), &InfixOp::Minus(_)) => true, 154 | (&InfixOp::Divide(_), &InfixOp::Divide(_)) => true, 155 | (&InfixOp::Multiply(_), &InfixOp::Multiply(_)) => true, 156 | (&InfixOp::Eq(_), &InfixOp::Eq(_)) => true, 157 | (&InfixOp::NotEq(_), &InfixOp::NotEq(_)) => true, 158 | (&InfixOp::GreaterThan(_), &InfixOp::GreaterThan(_)) => true, 159 | (&InfixOp::LessThan(_), &InfixOp::LessThan(_)) => true, 160 | _ => false, 161 | } 162 | } 163 | } 164 | 165 | impl Positioned for InfixOp { 166 | fn pos(&self) -> (i32, i32) { 167 | match self { 168 | &InfixOp::Plus(ref t) => t.pos(), 169 | &InfixOp::Minus(ref t) => t.pos(), 170 | &InfixOp::Divide(ref t) => t.pos(), 171 | &InfixOp::Multiply(ref t) => t.pos(), 172 | &InfixOp::Eq(ref t) => t.pos(), 173 | &InfixOp::NotEq(ref t) => t.pos(), 174 | &InfixOp::GreaterThan(ref t) => t.pos(), 175 | &InfixOp::LessThan(ref t) => t.pos(), 176 | } 177 | } 178 | } 179 | 180 | #[derive(PartialEq, Eq, PartialOrd, Ord)] 181 | pub enum Prec { 182 | Lowest, 183 | Equals, 184 | LessGreater, 185 | Sum, 186 | Product, 187 | Call, 188 | Index, 189 | } 190 | -------------------------------------------------------------------------------- /core/src/evaluator/value.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt; 3 | use std::cell::RefCell; 4 | use std::rc::Rc; 5 | use common::util::unescape; 6 | use parser::ast::*; 7 | use evaluator::types::*; 8 | 9 | #[derive(Eq, Debug)] 10 | pub enum Value { 11 | Int(i64), 12 | Bool(bool), 13 | String(String), 14 | Array(Vec>), 15 | Hash(HashMap>), 16 | Fn { 17 | params: Vec, 18 | body: BlockStmt, 19 | env: Rc>, 20 | }, 21 | BuiltInFn { 22 | name: String, 23 | num_params: usize, 24 | func: BuiltInFn, 25 | }, 26 | Return(Rc), 27 | Null, 28 | } 29 | 30 | impl fmt::Display for Value { 31 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 32 | match self { 33 | &Value::Int(i) => write!(f, "{}", i), 34 | &Value::Bool(b) => write!(f, "{}", b), 35 | &Value::String(ref s) => write!(f, "{}", unescape(s)), 36 | &Value::Array(ref a) => { 37 | let mapped: Vec = a.iter().map(|v| format!("{}", v)).collect(); 38 | write!(f, "[{}]", mapped.join(", ")) 39 | }, 40 | &Value::Hash(ref m) => { 41 | let mut mapped: Vec = m.iter().map(|(h, v)| format!("{}: {}", h, v)).collect(); 42 | mapped.sort(); 43 | write!(f, "{{{}}}", mapped.join(", ")) 44 | }, 45 | &Value::Fn { .. } => write!(f, "[function]"), 46 | &Value::BuiltInFn { ref name, .. } => write!(f, "[built-in function: {}]", name), 47 | &Value::Return(ref o) => o.fmt(f), 48 | &Value::Null => write!(f, "null"), 49 | } 50 | } 51 | } 52 | 53 | impl PartialEq for Value { 54 | fn eq(&self, other: &Self) -> bool { 55 | match (self, other) { 56 | (&Value::Int(i1), &Value::Int(i2)) => i1 == i2, 57 | (&Value::Bool(b1), &Value::Bool(b2)) => b1 == b2, 58 | (&Value::String(ref s1), &Value::String(ref s2)) => s1 == s2, 59 | (&Value::Array(ref v1), &Value::Array(ref v2)) => v1 == v2, 60 | (&Value::Hash(ref h1), &Value::Hash(ref h2)) => h1 == h2, 61 | (&Value::Fn { 62 | params: ref p1, 63 | body: ref b1, 64 | env: ref e1, 65 | }, 66 | &Value::Fn { 67 | params: ref p2, 68 | body: ref b2, 69 | env: ref e2, 70 | }) => p1 == p2 && b1 == b2 && e1 == e2, 71 | (&Value::BuiltInFn { 72 | name: ref n1, 73 | num_params: ref p1, 74 | .. 75 | }, 76 | &Value::BuiltInFn { 77 | name: ref n2, 78 | num_params: ref p2, 79 | .. 80 | }) => n1 == n2 && p1 == p2, 81 | (&Value::Return(ref o1), &Value::Return(ref o2)) => o1 == o2, 82 | (&Value::Null, &Value::Null) => true, 83 | _ => false, 84 | } 85 | } 86 | } 87 | 88 | #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 89 | pub enum Hashable { 90 | Int(i64), 91 | Bool(bool), 92 | String(String), 93 | } 94 | 95 | impl Hashable { 96 | pub fn from_lit(lit: &Literal) -> Self { 97 | match lit { 98 | &Literal::Int(i, _) => Hashable::Int(i), 99 | &Literal::Bool(b, _) => Hashable::Bool(b), 100 | &Literal::String(ref s, _) => Hashable::String(s.clone()), 101 | } 102 | } 103 | } 104 | 105 | impl fmt::Display for Hashable { 106 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 107 | write!(f, "{}", match self { 108 | &Hashable::Int(i) => Value::Int(i), 109 | &Hashable::Bool(b) => Value::Bool(b), 110 | &Hashable::String(ref s) => Value::String(s.clone()), 111 | }) 112 | } 113 | } 114 | 115 | pub type BuiltInFn = fn(Vec<((i32, i32), Rc)>) -> Result; 116 | 117 | #[cfg(test)] 118 | mod tests { 119 | use super::*; 120 | use std::iter::FromIterator; 121 | 122 | fn dummy(_: Vec<((i32, i32), Rc)>) -> Result { 123 | unreachable!() 124 | } 125 | 126 | #[test] 127 | fn value_display() { 128 | assert_eq!(format!("{}", Value::Int(35)), "35"); 129 | assert_eq!(format!("{}", Value::Bool(true)), "true"); 130 | assert_eq!(format!("{}", Value::String(String::from("hello\nworld"))), 131 | "\"hello\\nworld\""); 132 | assert_eq!(format!("{}", Value::Array(vec![])), "[]"); 133 | assert_eq!(format!("{}", 134 | Value::Array(vec![Rc::new(Value::Int(1)), Rc::new(Value::Int(2)), Rc::new(Value::Int(3))])), 135 | "[1, 2, 3]"); 136 | assert_eq!(format!("{}", Value::Hash(HashMap::new())), "{}"); 137 | assert_eq!(format!("{}", 138 | Value::Hash(HashMap::from_iter(vec![(Hashable::Int(1), 139 | Rc::new(Value::String(String::from("one")))), 140 | (Hashable::Int(2), 141 | Rc::new(Value::String(String::from("two")))), 142 | (Hashable::Int(3), 143 | Rc::new(Value::String(String::from("three"))))] 144 | ))), 145 | "{1: \"one\", 2: \"two\", 3: \"three\"}"); 146 | assert_eq!(format!("{}", 147 | Value::Fn { 148 | params: vec![], 149 | body: vec![], 150 | env: Rc::new(RefCell::new(Env::new())), 151 | }), 152 | "[function]"); 153 | assert_eq!(format!("{}", 154 | Value::BuiltInFn { 155 | name: String::from("hi"), 156 | num_params: 0, 157 | func: dummy, 158 | }), 159 | "[built-in function: hi]"); 160 | assert_eq!(format!("{}", Value::Return(Rc::from(Value::Int(35)))), "35"); 161 | assert_eq!(format!("{}", Value::Null), "null"); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /core/src/common/combinator.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Eq; 2 | use std::fmt::Display; 3 | use std::iter::FromIterator; 4 | 5 | pub trait Parser: Sized { 6 | fn preview(&self) -> Option<&T>; 7 | fn consume(&mut self) -> Option; 8 | fn current_pos(&self) -> (i32, i32); 9 | fn error>(&self, message: S) -> E; 10 | 11 | fn save(&mut self); 12 | fn load(&mut self); 13 | 14 | fn next(&mut self) -> Result { 15 | self.consume().ok_or(self.error("unexpected eof")) 16 | } 17 | 18 | fn predicate(&mut self, pred: F) -> Result 19 | where F: Fn(&T) -> bool 20 | { 21 | let x = try!(self.next()); 22 | if pred(&x) { 23 | Ok(x) 24 | } else { 25 | Err(self.error(format!("unexpected token {}", x))) 26 | } 27 | } 28 | 29 | fn atom(&mut self, expected: T) -> Result { 30 | let x = try!(self.next()); 31 | if x == expected { 32 | Ok(x) 33 | } else { 34 | Err(self.error(format!("unexpected token {}, expected {}", x, expected))) 35 | } 36 | } 37 | 38 | fn string(&mut self, s: S) -> Result 39 | where S: IntoIterator, 40 | O: FromIterator 41 | { 42 | let mut res: Vec = Vec::new(); 43 | for c in s { 44 | match self.atom(c) { 45 | Ok(x) => res.push(x), 46 | Err(err) => return Err(err), 47 | } 48 | } 49 | Ok(O::from_iter(res)) 50 | } 51 | 52 | fn try(&mut self, parser: F) -> Result 53 | where F: Fn(&mut Self) -> Result 54 | { 55 | self.save(); 56 | parser(self).map_err(|x| { 57 | self.load(); 58 | x 59 | }) 60 | } 61 | 62 | fn choose(&mut self, parsers: &[&Fn(&mut Self) -> Result]) -> Result { 63 | for parser in parsers { 64 | match self.try(parser) { 65 | Ok(x) => return Ok(x), 66 | Err(_) => continue, 67 | } 68 | } 69 | 70 | Err(self.error(match self.preview() { 71 | Some(x) => format!("unexpected token {}", x), 72 | None => String::from("unexpected eof"), 73 | })) 74 | } 75 | 76 | fn many(&mut self, parser: F) -> Result 77 | where F: Fn(&mut Self) -> Result, 78 | O: FromIterator 79 | { 80 | let mut res: Vec = Vec::new(); 81 | loop { 82 | match self.try(&parser) { 83 | Ok(x) => res.push(x), 84 | Err(_) => break, 85 | } 86 | } 87 | Ok(O::from_iter(res)) 88 | } 89 | 90 | fn many1(&mut self, parser: F) -> Result 91 | where F: Fn(&mut Self) -> Result, 92 | O: FromIterator 93 | { 94 | let mut res: Vec = Vec::new(); 95 | res.push(try!(parser(self))); 96 | loop { 97 | match self.try(&parser) { 98 | Ok(x) => res.push(x), 99 | Err(_) => break, 100 | } 101 | } 102 | Ok(O::from_iter(res)) 103 | } 104 | 105 | fn optional(&mut self, parser: F) 106 | where F: Fn(&mut Self) -> Result 107 | { 108 | let _ = self.try(parser); 109 | } 110 | } 111 | 112 | #[cfg(test)] 113 | mod tests { 114 | use super::*; 115 | 116 | struct TP { 117 | input: Vec, 118 | cursor: usize, 119 | saved_cursor: usize, 120 | } 121 | 122 | impl TP { 123 | fn new(input: &[i32]) -> TP { 124 | TP { 125 | input: input.to_vec(), 126 | cursor: 0, 127 | saved_cursor: 0, 128 | } 129 | } 130 | } 131 | 132 | impl Parser for TP { 133 | fn consume(&mut self) -> Option { 134 | match self.input.get(self.cursor) { 135 | Some(x) => { 136 | self.cursor += 1; 137 | Some(x.clone()) 138 | } 139 | None => None, 140 | } 141 | } 142 | 143 | fn preview(&self) -> Option<&i32> { 144 | self.input.get(self.cursor) 145 | } 146 | 147 | fn current_pos(&self) -> (i32, i32) { 148 | (0, 0) 149 | } 150 | 151 | fn error>(&self, message: S) -> String { 152 | message.into() 153 | } 154 | 155 | fn save(&mut self) { 156 | self.saved_cursor = self.cursor; 157 | } 158 | 159 | fn load(&mut self) { 160 | self.cursor = self.saved_cursor; 161 | } 162 | } 163 | 164 | type TPR = Result, String>; 165 | 166 | fn err(m: &str) -> Result { 167 | Err(String::from(m)) 168 | } 169 | 170 | #[test] 171 | fn next_success() { 172 | let mut p = TP::new(&[1, 2, 3]); 173 | assert_eq!(p.next(), Ok(1)); 174 | assert_eq!(p.next(), Ok(2)); 175 | assert_eq!(p.next(), Ok(3)); 176 | } 177 | 178 | #[test] 179 | fn next_fail_empty() { 180 | let mut p = TP::new(&[]); 181 | assert_eq!(p.next(), err("unexpected eof")); 182 | } 183 | 184 | #[test] 185 | fn predicate_success() { 186 | let mut p = TP::new(&[2, 4, 6]); 187 | assert_eq!(p.predicate(|x| x % 2 == 0), Ok(2)); 188 | assert_eq!(p.predicate(|x| x % 2 == 0), Ok(4)); 189 | assert_eq!(p.predicate(|x| x % 2 == 0), Ok(6)); 190 | } 191 | 192 | #[test] 193 | fn predicate_fail_empty() { 194 | let mut p = TP::new(&[]); 195 | assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected eof")); 196 | } 197 | 198 | #[test] 199 | fn predicate_fail_not_satisfy() { 200 | let mut p = TP::new(&[3, 5, 7]); 201 | assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected token 3")); 202 | } 203 | 204 | #[test] 205 | fn atom_success() { 206 | let mut p = TP::new(&[2, 4, 6]); 207 | assert_eq!(p.atom(2), Ok(2)); 208 | assert_eq!(p.atom(4), Ok(4)); 209 | assert_eq!(p.atom(6), Ok(6)); 210 | } 211 | 212 | #[test] 213 | fn atom_fail_empty() { 214 | let mut p = TP::new(&[]); 215 | assert_eq!(p.atom(2), err("unexpected eof")); 216 | } 217 | 218 | #[test] 219 | fn atom_fail_not_expected() { 220 | let mut p = TP::new(&[3, 5, 7]); 221 | assert_eq!(p.atom(3), Ok(3)); 222 | assert_eq!(p.atom(4), err("unexpected token 5, expected 4")); 223 | } 224 | 225 | #[test] 226 | fn string_success() { 227 | let mut p = TP::new(&[2, 4, 6]); 228 | assert_eq!(p.string(vec![2, 4, 6]), Ok(vec![2, 4, 6])); 229 | } 230 | 231 | #[test] 232 | fn string_fail_empty() { 233 | let mut p = TP::new(&[]); 234 | assert_eq!(p.string(vec![2, 4, 6]) as TPR, err("unexpected eof")); 235 | } 236 | 237 | #[test] 238 | fn string_fail_not_expected() { 239 | let mut p = TP::new(&[2, 5, 6]); 240 | assert_eq!(p.string(vec![2, 4, 6]) as TPR, 241 | err("unexpected token 5, expected 4")); 242 | } 243 | 244 | #[test] 245 | fn try_success() { 246 | let mut p = TP::new(&[2, 4, 6]); 247 | assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6])); 248 | } 249 | 250 | #[test] 251 | fn try_fail_recover() { 252 | let mut p = TP::new(&[2, 4, 6]); 253 | assert_eq!(p.try(|p| p.string(vec![2, 4, 7])) as TPR, 254 | err("unexpected token 6, expected 7")); 255 | assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6])); 256 | } 257 | 258 | #[test] 259 | fn choose_success() { 260 | let mut p = TP::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 261 | assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]), 262 | &|p| p.string(vec![4, 5, 6, 7]), 263 | &|p| p.string(vec![4, 5, 6])]), 264 | Ok(vec![1, 2, 3])); 265 | } 266 | 267 | #[test] 268 | fn choose_success_with_recover() { 269 | let mut p = TP::new(&[4, 5, 6, 7, 8, 9, 10]); 270 | assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]), 271 | &|p| p.string(vec![4, 5, 6, 8]), 272 | &|p| p.string(vec![4, 5, 6])]), 273 | Ok(vec![4, 5, 6])); 274 | } 275 | 276 | #[test] 277 | fn choose_fail_no_match() { 278 | let mut p = TP::new(&[5, 6, 7, 8, 9, 10]); 279 | assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]), 280 | &|p| p.string(vec![4, 5, 6, 8]), 281 | &|p| p.string(vec![4, 5, 6])]) as TPR, 282 | err("unexpected token 5")); 283 | } 284 | 285 | #[test] 286 | fn choose_fail_empty() { 287 | let mut p = TP::new(&[]); 288 | assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]), 289 | &|p| p.string(vec![4, 5, 6, 8]), 290 | &|p| p.string(vec![4, 5, 6])]) as TPR, 291 | err("unexpected eof")); 292 | } 293 | 294 | #[test] 295 | fn many_success() { 296 | let lt5 = |p: &mut TP| -> Result { p.predicate(|x| *x < 5) }; 297 | 298 | assert_eq!(TP::new(&[1, 2, 3, 4]).many(<5), Ok(vec![1, 2, 3, 4])); 299 | assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many(<5), 300 | Ok(vec![1, 2, 3, 4])); 301 | assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many(<5), Ok(vec![4])); 302 | assert_eq!(TP::new(&[5, 6, 7, 8]).many(<5), Ok(vec![])); 303 | } 304 | 305 | #[test] 306 | fn many1_success() { 307 | let lt5 = |p: &mut TP| -> Result { p.predicate(|x| *x < 5) }; 308 | 309 | assert_eq!(TP::new(&[1, 2, 3, 4]).many1(<5), Ok(vec![1, 2, 3, 4])); 310 | assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many1(<5), 311 | Ok(vec![1, 2, 3, 4])); 312 | assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many1(<5), Ok(vec![4])); 313 | } 314 | 315 | #[test] 316 | fn many1_fail() { 317 | let lt5 = |p: &mut TP| -> Result { p.predicate(|x| *x < 5) }; 318 | 319 | assert_eq!(TP::new(&[5, 6, 7, 8]).many1(<5) as TPR, 320 | err("unexpected token 5")); 321 | } 322 | 323 | #[test] 324 | fn optional_success() { 325 | let mut p = TP::new(&[1, 2, 3, 4, 5]); 326 | p.optional(|p| p.atom(1)); 327 | assert_eq!(p.string(vec![2, 3, 4]), Ok(vec![2, 3, 4])); 328 | } 329 | 330 | #[test] 331 | fn optional_success_without_matching() { 332 | let mut p = TP::new(&[1, 2, 3, 4, 5]); 333 | p.optional(|p| p.atom(2)); 334 | assert_eq!(p.string(vec![1, 2, 3]), Ok(vec![1, 2, 3])); 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /core/src/lexer/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub mod types; 3 | 4 | use self::types::*; 5 | use common::combinator::Parser; 6 | use common::util::*; 7 | use std::iter::FromIterator; 8 | 9 | pub fn tokenize>(input: T) -> Result> { 10 | let mut l = Lexer::new(input); 11 | 12 | let mut result = Vec::default(); 13 | 14 | loop { 15 | let _ = skip_whitespaces(&mut l); 16 | match l.preview() { 17 | None => break, 18 | _ => { 19 | result.push(try!(lex_token(&mut l))); 20 | } 21 | } 22 | } 23 | 24 | Ok(result) 25 | } 26 | 27 | fn skip_whitespaces(l: &mut Lexer) -> Result> { 28 | l.many(|l| l.predicate(|x| [' ', '\t', '\n', '\r'].contains(x))) 29 | } 30 | 31 | fn lex_token(l: &mut Lexer) -> Result { 32 | l.choose(&[&lex_operator, 33 | &lex_punctuation, 34 | &lex_string, 35 | &lex_reserved_or_ident, 36 | &lex_integer, 37 | &lex_illegal]) 38 | } 39 | 40 | macro_rules! parse_map { 41 | ($pat:expr, $tok:ident) => { 42 | &|l| { 43 | let pos = l.current_pos(); 44 | let lit: String = try!(l.string($pat.chars())); 45 | Ok(token!($tok, pos.0, pos.1, lit)) 46 | } 47 | } 48 | } 49 | 50 | fn lex_operator(l: &mut Lexer) -> Result { 51 | l.choose(&[parse_map!("==", Eq), 52 | parse_map!("=", Assign), 53 | parse_map!("+", Plus), 54 | parse_map!("-", Minus), 55 | parse_map!("*", Multiply), 56 | parse_map!("/", Divide), 57 | parse_map!("!=", NotEq), 58 | parse_map!("!", Not), 59 | parse_map!(">", GreaterThan), 60 | parse_map!("<", LessThan)]) 61 | } 62 | 63 | fn lex_punctuation(l: &mut Lexer) -> Result { 64 | l.choose(&[parse_map!(":", Colon), 65 | parse_map!(";", SemiColon), 66 | parse_map!(",", Comma), 67 | parse_map!("(", LParen), 68 | parse_map!(")", RParen), 69 | parse_map!("{", LBrace), 70 | parse_map!("}", RBrace), 71 | parse_map!("[", LBracket), 72 | parse_map!("]", RBracket)]) 73 | } 74 | 75 | fn lex_string(l: &mut Lexer) -> Result { 76 | let pos = l.current_pos(); 77 | let mut result = Vec::default(); 78 | 79 | result.push(try!(l.atom('"'))); 80 | loop { 81 | let c = try!(l.next()); 82 | result.push(c); 83 | match c { 84 | '\\' => result.push(try!(l.next())), 85 | '"' => break, 86 | _ => continue, 87 | } 88 | } 89 | 90 | Ok(token!(StringLiteral, pos.0, pos.1, String::from_iter(result))) 91 | } 92 | 93 | fn lex_reserved_or_ident(l: &mut Lexer) -> Result { 94 | let pos = l.current_pos(); 95 | let fst = try!(l.predicate(is_letter)).to_string(); 96 | let rest: String = try!(l.many(|l| l.predicate(is_letter_or_digit))); 97 | let name = fst + &rest; 98 | 99 | Ok(match name.as_ref() { 100 | "let" => token!(Let, pos.0, pos.1, name), 101 | "fn" => token!(Function, pos.0, pos.1, name), 102 | "if" => token!(If, pos.0, pos.1, name), 103 | "else" => token!(Else, pos.0, pos.1, name), 104 | "return" => token!(Return, pos.0, pos.1, name), 105 | "true" => token!(BoolLiteral, pos.0, pos.1, name), 106 | "false" => token!(BoolLiteral, pos.0, pos.1, name), 107 | _ => token!(Ident, pos.0, pos.1, name), 108 | }) 109 | } 110 | 111 | fn lex_integer(l: &mut Lexer) -> Result { 112 | let pos = l.current_pos(); 113 | let lit: String = try!(l.many1(|l| l.predicate(is_digit))); 114 | Ok(token!(IntLiteral, pos.0, pos.1, lit)) 115 | } 116 | 117 | fn lex_illegal(l: &mut Lexer) -> Result { 118 | let pos = l.current_pos(); 119 | Ok(token!(Illegal, pos.0, pos.1, try!(l.next()))) 120 | } 121 | 122 | #[cfg(test)] 123 | mod tests { 124 | use super::*; 125 | 126 | fn lex(input: &str) -> Vec { 127 | tokenize(String::from(input).chars()).unwrap() 128 | } 129 | 130 | #[test] 131 | fn special_chars() { 132 | assert_eq!(&lex("=+(){},;"), 133 | &vec![token!(Assign, 1, 1, '='), 134 | token!(Plus, 1, 2, '+'), 135 | token!(LParen, 1, 3, '('), 136 | token!(RParen, 1, 4, ')'), 137 | token!(LBrace, 1, 5, '{'), 138 | token!(RBrace, 1, 6, '}'), 139 | token!(Comma, 1, 7, ','), 140 | token!(SemiColon, 1, 8, ';')]); 141 | } 142 | 143 | #[test] 144 | fn complex_code() { 145 | assert_eq!(&lex(" 146 | let five = 5; 147 | let ten = 10; 148 | let add = fn(x, y) { 149 | x + y; 150 | }; 151 | let result = add(five, ten); 152 | "), 153 | &vec![token!(Let, 2, 1, "let"), 154 | token!(Ident, 2, 5, "five"), 155 | token!(Assign, 2, 10, "="), 156 | token!(IntLiteral, 2, 12, "5"), 157 | token!(SemiColon, 2, 13, ";"), 158 | token!(Let, 3, 1, "let"), 159 | token!(Ident, 3, 5, "ten"), 160 | token!(Assign, 3, 9, "="), 161 | token!(IntLiteral, 3, 11, "10"), 162 | token!(SemiColon, 3, 13, ";"), 163 | token!(Let, 4, 1, "let"), 164 | token!(Ident, 4, 5, "add"), 165 | token!(Assign, 4, 9, "="), 166 | token!(Function, 4, 11, "fn"), 167 | token!(LParen, 4, 13, "("), 168 | token!(Ident, 4, 14, "x"), 169 | token!(Comma, 4, 15, ","), 170 | token!(Ident, 4, 17, "y"), 171 | token!(RParen, 4, 18, ")"), 172 | token!(LBrace, 4, 20, "{"), 173 | token!(Ident, 5, 5, "x"), 174 | token!(Plus, 5, 7, "+"), 175 | token!(Ident, 5, 9, "y"), 176 | token!(SemiColon, 5, 10, ";"), 177 | token!(RBrace, 6, 1, "}"), 178 | token!(SemiColon, 6, 2, ";"), 179 | token!(Let, 7, 1, "let"), 180 | token!(Ident, 7, 5, "result"), 181 | token!(Assign, 7, 12, "="), 182 | token!(Ident, 7, 14, "add"), 183 | token!(LParen, 7, 17, "("), 184 | token!(Ident, 7, 18, "five"), 185 | token!(Comma, 7, 22, ","), 186 | token!(Ident, 7, 24, "ten"), 187 | token!(RParen, 7, 27, ")"), 188 | token!(SemiColon, 7, 28, ";")]); 189 | } 190 | 191 | #[test] 192 | fn complex_code2() { 193 | assert_eq!(&lex(" 194 | if (a == 10) { 195 | return a; 196 | } else if (a != 20) { 197 | return !a; 198 | } else if (a > 20) { 199 | return -30 / 40 * 50; 200 | } else if (a < 30) { 201 | return true; 202 | } 203 | return false; 204 | "), 205 | &vec![token!(If, 2, 1, "if"), 206 | token!(LParen, 2, 4, "("), 207 | token!(Ident, 2, 5, "a"), 208 | token!(Eq, 2, 7, "=="), 209 | token!(IntLiteral, 2, 10, "10"), 210 | token!(RParen, 2, 12, ")"), 211 | token!(LBrace, 2, 14, "{"), 212 | token!(Return, 3, 3, "return"), 213 | token!(Ident, 3, 10, "a"), 214 | token!(SemiColon, 3, 11, ";"), 215 | token!(RBrace, 4, 1, "}"), 216 | token!(Else, 4, 3, "else"), 217 | token!(If, 4, 8, "if"), 218 | token!(LParen, 4, 11, "("), 219 | token!(Ident, 4, 12, "a"), 220 | token!(NotEq, 4, 14, "!="), 221 | token!(IntLiteral, 4, 17, "20"), 222 | token!(RParen, 4, 19, ")"), 223 | token!(LBrace, 4, 21, "{"), 224 | token!(Return, 5, 3, "return"), 225 | token!(Not, 5, 10, "!"), 226 | token!(Ident, 5, 11, "a"), 227 | token!(SemiColon, 5, 12, ";"), 228 | token!(RBrace, 6, 1, "}"), 229 | token!(Else, 6, 3, "else"), 230 | token!(If, 6, 8, "if"), 231 | token!(LParen, 6, 11, "("), 232 | token!(Ident, 6, 12, "a"), 233 | token!(GreaterThan, 6, 14, ">"), 234 | token!(IntLiteral, 6, 16, "20"), 235 | token!(RParen, 6, 18, ")"), 236 | token!(LBrace, 6, 20, "{"), 237 | token!(Return, 7, 3, "return"), 238 | token!(Minus, 7, 10, "-"), 239 | token!(IntLiteral, 7, 11, "30"), 240 | token!(Divide, 7, 14, "/"), 241 | token!(IntLiteral, 7, 16, "40"), 242 | token!(Multiply, 7, 19, "*"), 243 | token!(IntLiteral, 7, 21, "50"), 244 | token!(SemiColon, 7, 23, ";"), 245 | token!(RBrace, 8, 1, "}"), 246 | token!(Else, 8, 3, "else"), 247 | token!(If, 8, 8, "if"), 248 | token!(LParen, 8, 11, "("), 249 | token!(Ident, 8, 12, "a"), 250 | token!(LessThan, 8, 14, "<"), 251 | token!(IntLiteral, 8, 16, "30"), 252 | token!(RParen, 8, 18, ")"), 253 | token!(LBrace, 8, 20, "{"), 254 | token!(Return, 9, 3, "return"), 255 | token!(BoolLiteral, 9, 10, "true"), 256 | token!(SemiColon, 9, 14, ";"), 257 | token!(RBrace, 10, 1, "}"), 258 | token!(Return, 11, 1, "return"), 259 | token!(BoolLiteral, 11, 8, "false"), 260 | token!(SemiColon, 11, 13, ";")]); 261 | } 262 | 263 | #[test] 264 | fn id_with_numbers() { 265 | assert_eq!(&lex("hello2 hel301oo120"), 266 | &vec![token!(Ident, 1, 1, "hello2"), 267 | token!(Ident, 1, 8, "hel301oo120")]); 268 | } 269 | 270 | #[test] 271 | fn string_literals() { 272 | assert_eq!(&lex("\"foobar\""), 273 | &vec![token!(StringLiteral, 1, 1, "\"foobar\"")]); 274 | assert_eq!(&lex("\"foo bar\""), 275 | &vec![token!(StringLiteral, 1, 1, "\"foo bar\"")]); 276 | assert_eq!(&lex("\"foo\\nbar\""), 277 | &vec![token!(StringLiteral, 1, 1, "\"foo\\nbar\"")]); 278 | assert_eq!(&lex("\"foo\\tbar\""), 279 | &vec![token!(StringLiteral, 1, 1, "\"foo\\tbar\"")]); 280 | assert_eq!(&lex("\"foo\\\"bar\""), 281 | &vec![token!(StringLiteral, 1, 1, "\"foo\\\"bar\"")]); 282 | } 283 | 284 | #[test] 285 | fn array_tokens() { 286 | assert_eq!(&lex("[1, 2];"), 287 | &vec![token!(LBracket, 1, 1, "["), 288 | token!(IntLiteral, 1, 2, "1"), 289 | token!(Comma, 1, 3, ","), 290 | token!(IntLiteral, 1, 5, "2"), 291 | token!(RBracket, 1, 6, "]"), 292 | token!(SemiColon, 1, 7, ";")]); 293 | } 294 | 295 | #[test] 296 | fn hash_tokens() { 297 | assert_eq!(&lex("{\"hello\": \"world\"}"), 298 | &vec![token!(LBrace, 1, 1, "{"), 299 | token!(StringLiteral, 1, 2, "\"hello\""), 300 | token!(Colon, 1, 9, ":"), 301 | token!(StringLiteral, 1, 11, "\"world\""), 302 | token!(RBrace, 1, 18, "}")]); 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /core/src/evaluator/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod built_ins; 2 | pub mod value; 3 | pub mod types; 4 | 5 | use std::cell::RefCell; 6 | use std::collections::HashMap; 7 | use std::iter::FromIterator; 8 | use std::rc::Rc; 9 | use std::result; 10 | use self::value::*; 11 | use self::types::*; 12 | use parser::ast::*; 13 | 14 | macro_rules! unwrap_return { 15 | ($val:expr) => {{ 16 | let val = $val; 17 | match val.as_ref() { 18 | &Value::Return(ref v) => return Ok(v.clone()), 19 | _ => {}, 20 | } 21 | val 22 | }} 23 | } 24 | 25 | pub fn eval(env: Rc>, program: &Program) -> Result { 26 | let res = try!(eval_block_stmt(env, &program.0)); 27 | Ok(unwrap_return!(res)) 28 | } 29 | 30 | fn eval_block_stmt(env: Rc>, block: &BlockStmt) -> Result { 31 | let mut res = Rc::new(Value::Null); 32 | 33 | for stmt in block { 34 | res = try!(eval_stmt(env.clone(), stmt)); 35 | match res.as_ref() { 36 | &Value::Return(..) => break, 37 | _ => continue, 38 | } 39 | } 40 | 41 | return Ok(res); 42 | } 43 | 44 | fn eval_stmt(env: Rc>, stmt: &Stmt) -> Result { 45 | match stmt { 46 | &Stmt::Expr(ref expr) => eval_expr(env, expr), 47 | &Stmt::Return(ref expr) => { 48 | let val = try!(eval_expr(env, expr)); 49 | ret(Value::Return(val)) 50 | } 51 | &Stmt::Let(ref ident, ref expr) => eval_let_stmt(env, ident, expr), 52 | } 53 | } 54 | 55 | fn eval_let_stmt(env: Rc>, ident: &Ident, expr: &Expr) -> Result { 56 | let val = try!(eval_expr(env.clone(), &expr)); 57 | env.borrow_mut().insert_var(ident.clone(), val.clone()); 58 | Ok(val) 59 | } 60 | 61 | fn eval_expr(env: Rc>, expr: &Expr) -> Result { 62 | match expr { 63 | &Expr::Ident(ref i) => eval_ident(env, i), 64 | &Expr::Lit(ref l) => eval_literal(l), 65 | &Expr::Prefix(ref p, ref expr) => eval_prefix(env, p, expr), 66 | &Expr::Infix(ref i, ref left, ref right) => eval_infix(env, i, left, right), 67 | &Expr::If { 68 | ref cond, 69 | ref con, 70 | ref alt, 71 | .. 72 | } => eval_if(env, cond, con, alt), 73 | &Expr::Fn { 74 | ref params, 75 | ref body, 76 | .. 77 | } => eval_fn(env, params, body), 78 | &Expr::Call { ref func, ref args } => eval_call(env, func, args), 79 | &Expr::Array(ref arr, ..) => eval_array(env, arr), 80 | &Expr::Hash(ref hash, ..) => eval_hash(env, hash), 81 | &Expr::Index { 82 | ref target, 83 | ref index, 84 | } => eval_index(env, target, index), 85 | } 86 | } 87 | 88 | fn eval_ident(env: Rc>, ident: &Ident) -> Result { 89 | match env.borrow().get_var(&ident) { 90 | Some(val) => Ok(val), 91 | None => throw(format!("identifier not found: {}", ident.0), ident.pos()), 92 | } 93 | } 94 | 95 | fn eval_literal(lit: &Literal) -> Result { 96 | match lit { 97 | &Literal::Bool(b, ..) => ret(Value::Bool(b)), 98 | &Literal::Int(i, ..) => ret(Value::Int(i)), 99 | &Literal::String(ref s, ..) => ret(Value::String(s.clone())), 100 | } 101 | } 102 | 103 | macro_rules! force_eval { 104 | ($env:expr, $expr:expr, $type:ident, $not_found_name:expr) => {{ 105 | let pos = $expr.pos(); 106 | let result = try!(eval_expr($env, $expr)); 107 | match result.as_ref() { 108 | &Value::$type(ref v) => v.clone(), 109 | _ => return throw(format!("{} is not {}", &result, $not_found_name), pos), 110 | } 111 | }} 112 | } 113 | 114 | fn eval_prefix(env: Rc>, prefix: &PrefixOp, expr: &Expr) -> Result { 115 | match prefix { 116 | &PrefixOp::Not(..) => eval_prefix_not(env, expr), 117 | &PrefixOp::Plus(..) => eval_prefix_plus(env, expr), 118 | &PrefixOp::Minus(..) => eval_prefix_minus(env, expr), 119 | } 120 | } 121 | 122 | fn eval_prefix_not(env: Rc>, expr: &Expr) -> Result { 123 | let val = force_eval!(env, expr, Bool, "a bool"); 124 | ret(Value::Bool(!val)) 125 | } 126 | 127 | fn eval_prefix_plus(env: Rc>, expr: &Expr) -> Result { 128 | let val = force_eval!(env, expr, Int, "an integer"); 129 | ret(Value::Int(val)) 130 | } 131 | 132 | fn eval_prefix_minus(env: Rc>, expr: &Expr) -> Result { 133 | let val = force_eval!(env, expr, Int, "an integer"); 134 | ret(Value::Int(-val)) 135 | } 136 | 137 | fn eval_infix(env: Rc>, infix: &InfixOp, left: &Expr, right: &Expr) -> Result { 138 | match infix { 139 | &InfixOp::Plus(..) => eval_infix_plus(env, left, right), 140 | &InfixOp::Minus(..) => eval_infix_minus(env, left, right), 141 | &InfixOp::Divide(..) => eval_infix_divide(env, left, right), 142 | &InfixOp::Multiply(..) => eval_infix_multiply(env, left, right), 143 | &InfixOp::Eq(..) => eval_infix_eq(env, left, right), 144 | &InfixOp::NotEq(..) => eval_infix_not_eq(env, left, right), 145 | &InfixOp::GreaterThan(..) => eval_infix_greater_than(env, left, right), 146 | &InfixOp::LessThan(..) => eval_infix_less_than(env, left, right), 147 | } 148 | } 149 | 150 | fn eval_infix_plus(env: Rc>, left: &Expr, right: &Expr) -> Result { 151 | let l_pos = left.pos(); 152 | let l_val = try!(eval_expr(env.clone(), left)); 153 | match l_val.as_ref() { 154 | &Value::Int(i) => { 155 | let r_val = force_eval!(env, right, Int, "an integer"); 156 | ret(Value::Int(i + r_val)) 157 | } 158 | &Value::String(ref s) => { 159 | let r_val = force_eval!(env, right, String, "a string"); 160 | ret(Value::String(s.clone() + &r_val)) 161 | } 162 | _ => throw(format!("{} is not an integer or string", &l_val), l_pos), 163 | } 164 | } 165 | 166 | fn eval_infix_minus(env: Rc>, left: &Expr, right: &Expr) -> Result { 167 | let l_val = force_eval!(env.clone(), left, Int, "an integer"); 168 | let r_val = force_eval!(env, right, Int, "an integer"); 169 | ret(Value::Int(l_val - r_val)) 170 | } 171 | 172 | fn eval_infix_divide(env: Rc>, left: &Expr, right: &Expr) -> Result { 173 | let l_val = force_eval!(env.clone(), left, Int, "an integer"); 174 | let r_val = force_eval!(env, right, Int, "an integer"); 175 | ret(Value::Int(l_val / r_val)) 176 | } 177 | 178 | fn eval_infix_multiply(env: Rc>, left: &Expr, right: &Expr) -> Result { 179 | let l_val = force_eval!(env.clone(), left, Int, "an integer"); 180 | let r_val = force_eval!(env, right, Int, "an integer"); 181 | ret(Value::Int(l_val * r_val)) 182 | } 183 | 184 | fn eval_infix_eq(env: Rc>, left: &Expr, right: &Expr) -> Result { 185 | let l_val = try!(eval_expr(env.clone(), left)); 186 | let r_val = try!(eval_expr(env, right)); 187 | ret(Value::Bool(l_val == r_val)) 188 | } 189 | 190 | fn eval_infix_not_eq(env: Rc>, left: &Expr, right: &Expr) -> Result { 191 | let l_val = try!(eval_expr(env.clone(), left)); 192 | let r_val = try!(eval_expr(env, right)); 193 | ret(Value::Bool(l_val != r_val)) 194 | } 195 | 196 | fn eval_infix_greater_than(env: Rc>, left: &Expr, right: &Expr) -> Result { 197 | let l_val = force_eval!(env.clone(), left, Int, "an integer"); 198 | let r_val = force_eval!(env, right, Int, "an integer"); 199 | ret(Value::Bool(l_val > r_val)) 200 | } 201 | 202 | fn eval_infix_less_than(env: Rc>, left: &Expr, right: &Expr) -> Result { 203 | let l_val = force_eval!(env.clone(), left, Int, "an integer"); 204 | let r_val = force_eval!(env, right, Int, "an integer"); 205 | ret(Value::Bool(l_val < r_val)) 206 | } 207 | 208 | fn eval_if(env: Rc>, 209 | cond: &Expr, 210 | con: &BlockStmt, 211 | alt: &Option) 212 | -> Result { 213 | let cond_val = force_eval!(env.clone(), cond, Bool, "a bool"); 214 | 215 | if cond_val { 216 | eval_block_stmt(env, con) 217 | } else if let &Some(ref some_alt) = alt { 218 | eval_block_stmt(env, some_alt) 219 | } else { 220 | ret(Value::Null) 221 | } 222 | } 223 | 224 | fn eval_fn(env: Rc>, params: &Vec, body: &BlockStmt) -> Result { 225 | ret(Value::Fn { 226 | params: params.clone(), 227 | body: body.clone(), 228 | env, 229 | }) 230 | } 231 | 232 | fn eval_call(env: Rc>, func: &Expr, args: &Vec) -> Result { 233 | let pos = func.pos(); 234 | let f = try!(eval_expr(env.clone(), func)); 235 | match *f.clone() { 236 | Value::Fn { 237 | ref params, 238 | ref body, 239 | env: ref fn_env, 240 | } => { 241 | if args.len() != params.len() { 242 | throw(format!("wrong number of arguments: {} expected, {} provided", 243 | params.len(), 244 | args.len()), 245 | pos) 246 | } else { 247 | let mut vars = vec![]; 248 | for (idx, ident) in params.iter().enumerate() { 249 | vars.push((ident.clone(), try!(eval_expr(env.clone(), &args[idx])))); 250 | } 251 | let call_env = Rc::new(RefCell::new(Env::wrap(vars, fn_env.clone()))); 252 | Ok(unwrap_return!(try!(eval_block_stmt(call_env, body)))) 253 | } 254 | } 255 | Value::BuiltInFn { num_params, func, .. } => { 256 | if args.len() != num_params { 257 | throw(format!("wrong number of arguments: {} expected, {} provided", 258 | num_params, 259 | args.len()), 260 | pos) 261 | } else { 262 | let mut vars = vec![]; 263 | for expr in args { 264 | let pos = expr.pos(); 265 | vars.push((pos, try!(eval_expr(env.clone(), expr)))); 266 | } 267 | func(vars) 268 | } 269 | } 270 | ref v => throw(format!("{} is not a function", v), pos), 271 | } 272 | } 273 | 274 | fn eval_array(env: Rc>, arr: &Vec) -> Result { 275 | let mut res = vec![]; 276 | for expr in arr { 277 | res.push(try!(eval_expr(env.clone(), expr))); 278 | } 279 | ret(Value::Array(res)) 280 | } 281 | 282 | fn eval_hash(env: Rc>, hash: &Vec<(Literal, Expr)>) -> Result { 283 | let mut res = vec![]; 284 | for &(ref lit, ref expr) in hash { 285 | res.push((Hashable::from_lit(lit), try!(eval_expr(env.clone(), expr)))); 286 | } 287 | ret(Value::Hash(HashMap::from_iter(res))) 288 | } 289 | 290 | fn eval_hashable(env: Rc>, expr: &Expr) -> result::Result { 291 | let val = try!(eval_expr(env, expr)); 292 | match val.as_ref() { 293 | &Value::Int(i) => Ok(Hashable::Int(i)), 294 | &Value::Bool(b) => Ok(Hashable::Bool(b)), 295 | &Value::String(ref s) => Ok(Hashable::String(s.clone())), 296 | ref v => Err(EvalError(format!("{} is not hashable", v), expr.pos())), 297 | } 298 | } 299 | 300 | fn eval_index(env: Rc>, target: &Expr, index: &Expr) -> Result { 301 | let t = try!(eval_expr(env.clone(), target)); 302 | match t.as_ref() { 303 | &Value::Array(ref arr) => { 304 | let idx = force_eval!(env, index, Int, "an integer"); 305 | match arr.get(idx as usize) { 306 | Some(v) => Ok(v.clone()), 307 | None => ret(Value::Null), 308 | } 309 | } 310 | &Value::Hash(ref hash) => { 311 | let h = try!(eval_hashable(env, index)); 312 | match hash.get(&h) { 313 | Some(v) => Ok(v.clone()), 314 | None => ret(Value::Null), 315 | } 316 | } 317 | ref v => throw(format!("unexpected index target: {}", v), target.pos()), 318 | } 319 | } 320 | 321 | #[cfg(test)] 322 | mod tests { 323 | use super::*; 324 | use lexer; 325 | use parser; 326 | 327 | fn eval_to(code: &str, expected: Value) { 328 | let tokens = lexer::tokenize(String::from(code).chars()).unwrap(); 329 | let program = parser::parse(tokens).unwrap(); 330 | let env = Rc::new(RefCell::new(built_ins::init())); 331 | let actual = eval(env.clone(), &program).unwrap(); 332 | assert_eq!(actual, Rc::new(expected)); 333 | } 334 | 335 | fn fail_with(code: &str, error: &str, pos: (i32, i32)) { 336 | let tokens = lexer::tokenize(String::from(code).chars()).unwrap(); 337 | let program = parser::parse(tokens).unwrap(); 338 | let env = Rc::new(RefCell::new(built_ins::init())); 339 | let actual_error = eval(env.clone(), &program); 340 | assert_eq!(actual_error, Err(EvalError(String::from(error), pos))); 341 | } 342 | 343 | #[test] 344 | fn empty_program() { 345 | eval_to("", Value::Null); 346 | } 347 | 348 | #[test] 349 | fn simple_int() { 350 | eval_to("5", Value::Int(5)); 351 | eval_to("10", Value::Int(10)); 352 | eval_to("let a = 20; a", Value::Int(20)); 353 | } 354 | 355 | #[test] 356 | fn simple_bool() { 357 | eval_to("true", Value::Bool(true)); 358 | eval_to("false", Value::Bool(false)); 359 | eval_to("let a = true; a", Value::Bool(true)); 360 | } 361 | 362 | #[test] 363 | fn prefix_op() { 364 | // !, the bang operator 365 | eval_to("!true", Value::Bool(false)); 366 | eval_to("!false", Value::Bool(true)); 367 | eval_to("!!true", Value::Bool(true)); 368 | eval_to("!!false", Value::Bool(false)); 369 | fail_with("!5", "5 is not a bool", (1, 2)); 370 | fail_with("!1", "1 is not a bool", (1, 2)); 371 | fail_with("!0", "0 is not a bool", (1, 2)); 372 | fail_with("!!5", "5 is not a bool", (1, 3)); 373 | fail_with("!!0", "0 is not a bool", (1, 3)); 374 | // the prefix + 375 | eval_to("+1", Value::Int(1)); 376 | eval_to("+5", Value::Int(5)); 377 | eval_to("+20", Value::Int(20)); 378 | fail_with("+true", "true is not an integer", (1, 2)); 379 | fail_with("+false", "false is not an integer", (1, 2)); 380 | // the prefix - 381 | eval_to("-1", Value::Int((-1))); 382 | eval_to("-5", Value::Int((-5))); 383 | eval_to("-20", Value::Int((-20))); 384 | fail_with("-true", "true is not an integer", (1, 2)); 385 | fail_with("-false", "false is not an integer", (1, 2)); 386 | } 387 | 388 | #[test] 389 | fn infix_op() { 390 | // algebra 391 | eval_to("5 + 5 + 5 + 5 - 10", Value::Int(10)); 392 | eval_to("2 * 2 * 2 * 2 * 2", Value::Int(32)); 393 | eval_to("-50 + 100 + -50", Value::Int(0)); 394 | eval_to("5 * 2 + 10", Value::Int(20)); 395 | eval_to("5 + 2 * 10", Value::Int(25)); 396 | eval_to("20 + 2 * -10", Value::Int(0)); 397 | eval_to("50 / 2 * 2 + 10", Value::Int(60)); 398 | eval_to("2 * (5 + 10)", Value::Int(30)); 399 | eval_to("3 * 3 * 3 + 10", Value::Int(37)); 400 | eval_to("3 * (3 * 3) + 10", Value::Int(37)); 401 | eval_to("(5 + 10 * 2 + 15 / 3) * 2 + -10", Value::Int(50)); 402 | // logical algebra 403 | eval_to("1 < 2", Value::Bool(true)); 404 | eval_to("1 > 2", Value::Bool(false)); 405 | eval_to("1 < 1", Value::Bool(false)); 406 | eval_to("1 > 1", Value::Bool(false)); 407 | eval_to("1 == 1", Value::Bool(true)); 408 | eval_to("1 != 1", Value::Bool(false)); 409 | eval_to("1 == 2", Value::Bool(false)); 410 | eval_to("1 != 2", Value::Bool(true)); 411 | // combination 412 | eval_to("(1 < 2) == true", Value::Bool(true)); 413 | eval_to("(1 < 2) == false", Value::Bool(false)); 414 | eval_to("(1 > 2) == true", Value::Bool(false)); 415 | eval_to("(1 > 2) == false", Value::Bool(true)); 416 | } 417 | 418 | #[test] 419 | fn conditional_expr() { 420 | eval_to("if (true) { 10 }", Value::Int(10)); 421 | eval_to("if (false) { 10 }", Value::Null); 422 | fail_with("if (1) { 10 }", "1 is not a bool", (1, 5)); 423 | eval_to("if (1 < 2) { 10 }", Value::Int(10)); 424 | eval_to("if (1 > 2) { 10 }", Value::Null); 425 | eval_to("if (1 < 2) { 10 } else { 20 }", Value::Int(10)); 426 | eval_to("if (1 > 2) { 10 } else { 20 }", Value::Int(20)); 427 | } 428 | 429 | static RETURN1: &str = " 430 | if (10 > 1) { 431 | if (10 > 1) { 432 | return 10; 433 | } 434 | return 1; 435 | } 436 | "; 437 | 438 | #[test] 439 | fn return_stmt() { 440 | eval_to("return 10", Value::Int(10)); 441 | eval_to("return 10; 9", Value::Int(10)); 442 | eval_to("return 2 * 5; 9", Value::Int(10)); 443 | eval_to("9; return 2 * 5; 9", Value::Int(10)); 444 | eval_to(RETURN1, Value::Int(10)); 445 | } 446 | 447 | #[test] 448 | fn bindings() { 449 | eval_to("let a = 5; a;", Value::Int(5)); 450 | eval_to("let a = 5 * 5; a;", Value::Int(25)); 451 | eval_to("let a = 5; let b = a; b;", Value::Int(5)); 452 | eval_to("let a = 5; let b = a; let c = a + b + 5; c;", 453 | Value::Int(15)); 454 | fail_with("foobar", "identifier not found: foobar", (1, 1)) 455 | } 456 | 457 | static FN1: &str = " 458 | let add = fn(a, b, c, d) { return a + b + c + d; }; 459 | add(1, 2, 3, 4); 460 | "; 461 | 462 | static FN2: &str = " 463 | let addThree = fn(x) { return x + 3 }; 464 | addThree(3); 465 | "; 466 | 467 | static FN3: &str = " 468 | let max = fn(x, y) { if (x > y) { x } else { y } }; 469 | max(5, 10) 470 | "; 471 | 472 | static FN4: &str = " 473 | let factorial = fn(n) { 474 | if (n == 0) { 475 | 1 476 | } else { 477 | n * factorial(n - 1) 478 | } 479 | } 480 | factorial(5) 481 | "; 482 | 483 | static FN5: &str = " 484 | let addThree = fn(x) { return x + 3 }; 485 | let callTwoTimes = fn(x, f) { f(f(x)) } 486 | callTwoTimes(3, addThree); 487 | "; 488 | 489 | static FN6: &str = " 490 | let callTwoTimes = fn(x, f) { f(f(x)) } 491 | callTwoTimes(3, fn(x) { x + 1 }); 492 | "; 493 | 494 | static FN7: &str = " 495 | let newAdder = fn(x) { fn(n) { x + n } }; 496 | let addTwo = newAdder(2); 497 | addTwo(2); 498 | "; 499 | 500 | #[test] 501 | fn fn_decl_and_eval() { 502 | eval_to("let identity = fn(x) { x; }; identity(5);", Value::Int(5)); 503 | eval_to("let identity = fn(x) { return x; }; identity(5);", 504 | Value::Int(5)); 505 | eval_to("let double = fn(x) { x * 2; }; double(5);", Value::Int(10)); 506 | eval_to("let add = fn(x, y) { x + y; }; add(5, 5);", Value::Int(10)); 507 | eval_to("let add = fn(x, y) { x + y; }; add(5 + 5, add(5, 5));", 508 | Value::Int(20)); 509 | eval_to("fn(x) { x; }(5)", Value::Int(5)); 510 | fail_with("5();", "5 is not a function", (1, 1)); 511 | fail_with("false();", "false is not a function", (1, 1)); 512 | fail_with("let add = fn(x, y) { x + y; }; add(1);", 513 | "wrong number of arguments: 2 expected, 1 provided", 514 | (1, 32)); 515 | eval_to(FN1, Value::Int(10)); 516 | eval_to(FN2, Value::Int(6)); 517 | eval_to(FN3, Value::Int(10)); 518 | eval_to(FN4, Value::Int(120)); 519 | eval_to(FN5, Value::Int(9)); 520 | eval_to(FN6, Value::Int(5)); 521 | eval_to(FN7, Value::Int(4)); 522 | // special cases 523 | eval_to("let a = 10; let x = fn () { a; }; x();", Value::Int(10)); 524 | eval_to("let x = fn () { a; }; let a = 10; x();", Value::Int(10)); 525 | } 526 | 527 | #[test] 528 | fn string() { 529 | eval_to("\"foobar\"", Value::String(String::from("foobar"))); 530 | eval_to("\"foo bar\"", Value::String(String::from("foo bar"))); 531 | eval_to("\"foo\\nbar\"", Value::String(String::from("foo\nbar"))); 532 | eval_to("\"foo\\tbar\"", Value::String(String::from("foo\tbar"))); 533 | eval_to("\"foo\\\"bar\"", Value::String(String::from("foo\"bar"))); 534 | eval_to("\"foo\" + \"bar\"", Value::String(String::from("foobar"))); 535 | eval_to("\"foo\" + \" \" + \"bar\"", 536 | Value::String(String::from("foo bar"))); 537 | fail_with("\"foo\" - \"bar\"", "\"foo\" is not an integer", (1, 1)); 538 | } 539 | 540 | #[test] 541 | fn array() { 542 | eval_to("[1, 2, 3, 4]", 543 | Value::Array(vec![Rc::new(Value::Int(1)), 544 | Rc::new(Value::Int(2)), 545 | Rc::new(Value::Int(3)), 546 | Rc::new(Value::Int(4))])); 547 | eval_to("let double = fn(x) { x * 2 }; [1, double(2), 3 * 3, 4 - 3]", 548 | Value::Array(vec![Rc::new(Value::Int(1)), 549 | Rc::new(Value::Int(4)), 550 | Rc::new(Value::Int(9)), 551 | Rc::new(Value::Int(1))])); 552 | eval_to("[1, 2, 3][0]", Value::Int(1)); 553 | eval_to("[1, 2, 3][1]", Value::Int(2)); 554 | eval_to("[1, 2, 3][2]", Value::Int(3)); 555 | eval_to("let i = 0; [1][i];", Value::Int(1)); 556 | eval_to("[1, 2, 3][1 + 1];", Value::Int(3)); 557 | eval_to("let myArray = [1, 2, 3]; myArray[2];", Value::Int(3)); 558 | eval_to("let myArray = [1, 2, 3]; myArray[0] + myArray[1] + myArray[2];", 559 | Value::Int(6)); 560 | eval_to("let myArray = [1, 2, 3]; let i = myArray[0]; myArray[i];", 561 | Value::Int(2)); 562 | eval_to("[1, 2, 3][3]", Value::Null); 563 | eval_to("[1, 2, 3][-1]", Value::Null); 564 | } 565 | 566 | #[test] 567 | fn built_in_fn() { 568 | // len 569 | eval_to("len(\"hello world!\")", Value::Int(12)); 570 | eval_to("len(\"\")", Value::Int(0)); 571 | eval_to("len(\"Hey Bob, how ya doin?\")", Value::Int(21)); 572 | fail_with("len(3)", "3 is not a string or an array", (1, 5)); 573 | fail_with("len(\"hello\", \"world\")", 574 | "wrong number of arguments: 1 expected, 2 provided", 575 | (1, 1)); 576 | eval_to("len([])", Value::Int(0)); 577 | eval_to("len([1, 2, 3, 4])", Value::Int(4)); 578 | // head 579 | eval_to("head([1])", Value::Int(1)); 580 | eval_to("head([1, 2, 3, 4])", Value::Int(1)); 581 | fail_with("head([])", "invalid arguments: empty array", (1, 6)); 582 | // tail 583 | eval_to("tail([1])", Value::Array(vec![])); 584 | eval_to("tail([1, 2, 3, 4])", 585 | Value::Array(vec![Rc::new(Value::Int(2)), 586 | Rc::new(Value::Int(3)), 587 | Rc::new(Value::Int(4))])); 588 | fail_with("tail([])", "invalid arguments: empty array", (1, 6)); 589 | // cons 590 | eval_to("cons(1, [])", Value::Array(vec![Rc::new(Value::Int(1))])); 591 | eval_to("cons(1, [2, 3, 4])", 592 | Value::Array(vec![Rc::new(Value::Int(1)), 593 | Rc::new(Value::Int(2)), 594 | Rc::new(Value::Int(3)), 595 | Rc::new(Value::Int(4))])); 596 | } 597 | 598 | static MAP_DECL: &str = " 599 | let map = fn(f, arr) { 600 | if (len(arr) == 0) { 601 | [] 602 | } else { 603 | let h = head(arr); 604 | cons(f(h), map(f, tail(arr))); 605 | } 606 | }; 607 | "; 608 | 609 | static REDUCE_DECL: &str = " 610 | let reduce = fn(f, init, arr) { 611 | if (len(arr) == 0) { 612 | init 613 | } else { 614 | let newInit = f(init, head(arr)); 615 | reduce(f, newInit, tail(arr)); 616 | } 617 | }; 618 | "; 619 | 620 | #[test] 621 | fn map_reduce() { 622 | eval_to(&(MAP_DECL.to_string() + 623 | "let double = fn(x) { x * 2 }; map(double, [1, 2, 3, 4])"), 624 | Value::Array(vec![Rc::new(Value::Int(2)), 625 | Rc::new(Value::Int(4)), 626 | Rc::new(Value::Int(6)), 627 | Rc::new(Value::Int(8))])); 628 | eval_to(&(REDUCE_DECL.to_string() + 629 | "let add = fn(x, y) { x + y }; reduce(add, 0, [1, 2, 3, 4, 5])"), 630 | Value::Int(15)); 631 | } 632 | 633 | static HASH1: &str = " 634 | let double = fn(x) { 635 | x * 2; 636 | }; 637 | let arr = [1, 2, 3, 4]; 638 | let h = { 639 | \"one\": 10 - 9, 640 | \"two\": 8 / 4, 641 | 3: arr[2], 642 | 4: double(2), 643 | true: if (10 > 8) { true } else { false }, 644 | false: \"hello\" == \"world\" 645 | }; 646 | "; 647 | 648 | #[test] 649 | fn hash() { 650 | eval_to(&(HASH1.to_string() + "h[\"one\"]"), Value::Int(1)); 651 | eval_to(&(HASH1.to_string() + "let s = \"two\"; h[s]"), 652 | Value::Int(2)); 653 | eval_to(&(HASH1.to_string() + "h[3]"), Value::Int(3)); 654 | eval_to(&(HASH1.to_string() + "h[2 + 2]"), Value::Int(4)); 655 | eval_to(&(HASH1.to_string() + "h[true]"), Value::Bool(true)); 656 | eval_to(&(HASH1.to_string() + "h[5 < 1]"), Value::Bool(false)); 657 | eval_to(&(HASH1.to_string() + "h[100]"), Value::Null); 658 | fail_with(&(HASH1.to_string() + "h[[]]"), 659 | "[] is not hashable", 660 | (14, 3)); 661 | fail_with("3[true];", "unexpected index target: 3", (1, 1)); 662 | } 663 | } 664 | -------------------------------------------------------------------------------- /core/src/parser/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ast; 2 | pub mod types; 3 | 4 | use self::ast::*; 5 | use self::types::*; 6 | use common::combinator::Parser as P; 7 | use common::util::escape; 8 | use lexer::types::Token; 9 | 10 | pub fn parse(input: Vec) -> Result { 11 | let mut p = Parser::new(input); 12 | parse_program(&mut p) 13 | } 14 | 15 | macro_rules! is { 16 | ($pat:ident) => { 17 | |x| { 18 | match *x { 19 | Token::$pat(..) => true, 20 | _ => false, 21 | } 22 | } 23 | } 24 | } 25 | 26 | macro_rules! drop { 27 | ($e:expr) => {{ 28 | let _ = try!($e); 29 | }} 30 | } 31 | 32 | fn parse_program(p: &mut Parser) -> Result { 33 | let stmts = try!(p.many(parse_stmt)); 34 | 35 | match p.consume() { 36 | Some(token) => Err(p.error(format!("unexpected token {}", token))), 37 | None => Ok(Program(stmts)), 38 | } 39 | } 40 | 41 | fn parse_stmt(p: &mut Parser) -> Result { 42 | p.choose(&[&parse_let_stmt, 43 | &parse_return_stmt, 44 | &parse_expr_stmt]) 45 | } 46 | 47 | fn parse_let_stmt(p: &mut Parser) -> Result { 48 | drop!(p.predicate(is!(Let))); 49 | let ident = try!(parse_ident(p)); 50 | drop!(p.predicate(is!(Assign))); 51 | let expr = try!(parse_expr(p)); 52 | p.optional(|p| p.predicate(is!(SemiColon))); 53 | Ok(Stmt::Let(ident, expr)) 54 | } 55 | 56 | fn parse_ident(p: &mut Parser) -> Result { 57 | let id = try!(p.predicate(is!(Ident))); 58 | Ok(Ident(id.literal().clone(), id)) 59 | } 60 | 61 | fn parse_return_stmt(p: &mut Parser) -> Result { 62 | drop!(p.predicate(is!(Return))); 63 | let expr = try!(parse_expr(p)); 64 | p.optional(|p| p.predicate(is!(SemiColon))); 65 | Ok(Stmt::Return(expr)) 66 | } 67 | 68 | fn parse_expr_stmt(p: &mut Parser) -> Result { 69 | let expr = try!(parse_expr(p)); 70 | p.optional(|p| p.predicate(is!(SemiColon))); 71 | Ok(Stmt::Expr(expr)) 72 | } 73 | 74 | fn parse_block_stmt(p: &mut Parser) -> Result { 75 | drop!(p.predicate(is!(LBrace))); 76 | let ss = try!(p.many(parse_stmt)); 77 | drop!(p.predicate(is!(RBrace))); 78 | Ok(ss) 79 | } 80 | 81 | fn parse_expr(p: &mut Parser) -> Result { 82 | parse_pratt_expr(p, Prec::Lowest) 83 | } 84 | 85 | fn infix_op(token: &Token) -> (Prec, Option) { 86 | match token { 87 | &Token::Eq(..) => (Prec::Equals, Some(InfixOp::Eq(token.clone()))), 88 | &Token::NotEq(..) => (Prec::Equals, Some(InfixOp::NotEq(token.clone()))), 89 | &Token::LessThan(..) => (Prec::LessGreater, Some(InfixOp::LessThan(token.clone()))), 90 | &Token::GreaterThan(..) => (Prec::LessGreater, Some(InfixOp::GreaterThan(token.clone()))), 91 | &Token::Plus(..) => (Prec::Sum, Some(InfixOp::Plus(token.clone()))), 92 | &Token::Minus(..) => (Prec::Sum, Some(InfixOp::Minus(token.clone()))), 93 | &Token::Multiply(..) => (Prec::Product, Some(InfixOp::Multiply(token.clone()))), 94 | &Token::Divide(..) => (Prec::Product, Some(InfixOp::Divide(token.clone()))), 95 | &Token::LParen(..) => (Prec::Call, None), 96 | &Token::LBracket(..) => (Prec::Index, None), 97 | _ => (Prec::Lowest, None), 98 | } 99 | } 100 | 101 | fn parse_pratt_expr(p: &mut Parser, prec: Prec) -> Result { 102 | let mut left = try!(parse_atom_expr(p)); 103 | while let Some((peek_prec, _)) = p.preview().map(infix_op) { 104 | if prec >= peek_prec { 105 | break; 106 | } 107 | match peek_prec { 108 | Prec::Call => { 109 | left = try!(parse_call_expr(p, left)); 110 | } 111 | Prec::Index => { 112 | left = try!(parse_index_expr(p, left)); 113 | } 114 | _ => { 115 | left = try!(parse_infix_expr(p, left)); 116 | } 117 | } 118 | } 119 | Ok(left) 120 | } 121 | 122 | fn parse_call_expr(p: &mut Parser, func: Expr) -> Result { 123 | drop!(p.predicate(is!(LParen))); 124 | let args = try!(parse_comma_separated(p, &parse_expr)); 125 | drop!(p.predicate(is!(RParen))); 126 | Ok(Expr::Call { func: Box::new(func), args }) 127 | } 128 | 129 | fn parse_comma_separated(p: &mut Parser, parser: &F) -> Result> 130 | where F: Fn(&mut Parser) -> Result, 131 | { 132 | match p.try(parser) { 133 | Ok(x) => { 134 | let mut result = vec![x]; 135 | let xs: Vec = try!(p.many(|p| { 136 | drop!(p.predicate(is!(Comma))); 137 | parser(p) 138 | })); 139 | result.extend(xs); 140 | Ok(result) 141 | }, 142 | Err(_) => Ok(vec![]), 143 | } 144 | } 145 | 146 | fn parse_index_expr(p: &mut Parser, target: Expr) -> Result { 147 | drop!(p.predicate(is!(LBracket))); 148 | let index = try!(parse_expr(p)); 149 | drop!(p.predicate(is!(RBracket))); 150 | Ok(Expr::Index { target: Box::new(target), index: Box::new(index) }) 151 | } 152 | 153 | fn parse_infix_expr(p: &mut Parser, left: Expr) -> Result { 154 | let (prec, op) = try!(p.next().map(|x| infix_op(&x))); 155 | let op = op.unwrap(); 156 | let right = try!(parse_pratt_expr(p, prec)); 157 | Ok(Expr::Infix(op, Box::new(left), Box::new(right))) 158 | } 159 | 160 | fn parse_atom_expr(p: &mut Parser) -> Result { 161 | p.choose(&[&parse_lit_expr, 162 | &parse_ident_expr, 163 | &parse_prefix_expr, 164 | &parse_paren_expr, 165 | &parse_array_expr, 166 | &parse_hash_expr, 167 | &parse_if_expr, 168 | &parse_fn_expr]) 169 | } 170 | 171 | fn parse_lit_expr(p: &mut Parser) -> Result { 172 | let lit = try!(parse_literal(p)); 173 | Ok(Expr::Lit(lit)) 174 | } 175 | 176 | fn parse_literal(p: &mut Parser) -> Result { 177 | p.choose(&[&parse_int_literal, 178 | &parse_bool_literal, 179 | &parse_string_literal]) 180 | } 181 | 182 | fn parse_int_literal(p: &mut Parser) -> Result { 183 | let token = try!(p.predicate(is!(IntLiteral))); 184 | Ok(Literal::Int(token.literal().parse().unwrap(), token)) 185 | } 186 | 187 | fn parse_bool_literal(p: &mut Parser) -> Result { 188 | let token = try!(p.predicate(is!(BoolLiteral))); 189 | Ok(Literal::Bool(token.literal().parse().unwrap(), token)) 190 | } 191 | 192 | fn parse_string_literal(p: &mut Parser) -> Result { 193 | let token = try!(p.predicate(is!(StringLiteral))); 194 | Ok(Literal::String(escape(token.literal()), token)) 195 | } 196 | 197 | fn parse_ident_expr(p: &mut Parser) -> Result { 198 | let ident = try!(parse_ident(p)); 199 | Ok(Expr::Ident(ident)) 200 | } 201 | 202 | fn parse_prefix_expr(p: &mut Parser) -> Result { 203 | let token = try!(p.choose(&[&|p| p.predicate(is!(Plus)), 204 | &|p| p.predicate(is!(Minus)), 205 | &|p| p.predicate(is!(Not))])); 206 | let prefix_op = match &token { 207 | &Token::Plus(..) => PrefixOp::Plus(token), 208 | &Token::Minus(..) => PrefixOp::Minus(token), 209 | &Token::Not(..) => PrefixOp::Not(token), 210 | _ => unreachable!(), 211 | }; 212 | 213 | let expr = try!(parse_atom_expr(p)); 214 | 215 | Ok(Expr::Prefix(prefix_op, Box::new(expr))) 216 | } 217 | 218 | fn parse_paren_expr(p: &mut Parser) -> Result { 219 | drop!(p.predicate(is!(LParen))); 220 | let expr = try!(parse_expr(p)); 221 | drop!(p.predicate(is!(RParen))); 222 | Ok(expr) 223 | } 224 | 225 | fn parse_array_expr(p: &mut Parser) -> Result { 226 | let l = try!(p.predicate(is!(LBracket))); 227 | let exprs = try!(parse_comma_separated(p, &parse_expr)); 228 | drop!(p.predicate(is!(RBracket))); 229 | Ok(Expr::Array(exprs, l.pos())) 230 | } 231 | 232 | fn parse_hash_expr(p: &mut Parser) -> Result { 233 | let l = try!(p.predicate(is!(LBrace))); 234 | let pairs = try!(parse_comma_separated(p, &|p| { 235 | let lit = try!(parse_literal(p)); 236 | drop!(p.predicate(is!(Colon))); 237 | let expr = try!(parse_expr(p)); 238 | Ok((lit, expr)) 239 | })); 240 | drop!(p.predicate(is!(RBrace))); 241 | Ok(Expr::Hash(pairs, l.pos())) 242 | } 243 | 244 | fn parse_if_expr(p: &mut Parser) -> Result { 245 | let i = try!(p.predicate(is!(If))); 246 | drop!(p.predicate(is!(LParen))); 247 | let cond = try!(parse_expr(p)); 248 | drop!(p.predicate(is!(RParen))); 249 | let con = try!(parse_block_stmt(p)); 250 | let alt = match p.try(|p| p.predicate(is!(Else))) { 251 | Ok(_) => Some(try!(parse_block_stmt(p))), 252 | Err(_) => None, 253 | }; 254 | Ok(Expr::If { 255 | cond: Box::new(cond), 256 | con, 257 | alt, 258 | pos: i.pos(), 259 | }) 260 | } 261 | 262 | fn parse_fn_expr(p: &mut Parser) -> Result { 263 | let f = try!(p.predicate(is!(Function))); 264 | drop!(p.predicate(is!(LParen))); 265 | let params = try!(parse_comma_separated(p, &parse_ident)); 266 | drop!(p.predicate(is!(RParen))); 267 | let body = try!(parse_block_stmt(p)); 268 | Ok(Expr::Fn { params, body, pos: f.pos() }) 269 | } 270 | 271 | #[cfg(test)] 272 | mod tests { 273 | use super::*; 274 | use lexer; 275 | 276 | fn s(x: &str) -> String { 277 | String::from(x) 278 | } 279 | 280 | fn program_eq(code: &str, stmts: Vec) { 281 | let tokens = lexer::tokenize(s(code).chars()).unwrap(); 282 | assert_eq!(parse(tokens).unwrap(), Program(stmts)); 283 | } 284 | 285 | fn code_result_eq(code1: &str, code2: &str) { 286 | let tokens1 = lexer::tokenize(s(code1).chars()).unwrap(); 287 | let tokens2 = lexer::tokenize(s(code2).chars()).unwrap(); 288 | assert_eq!(parse(tokens1).unwrap(), parse(tokens2).unwrap()); 289 | } 290 | 291 | #[test] 292 | fn empty() { 293 | program_eq("", vec![]); 294 | } 295 | 296 | static CODE_LET_STMTS: &str = " 297 | let x = 5; 298 | let y = 10; 299 | let foobar = 838383; 300 | let boo = true; 301 | "; 302 | 303 | #[test] 304 | fn let_stmt() { 305 | program_eq(CODE_LET_STMTS, 306 | vec![Stmt::Let(Ident(s("x"), token!(Ident, 2, 5, "x")), 307 | Expr::Lit(Literal::Int(5, token!(IntLiteral, 2, 9, "5")))), 308 | Stmt::Let(Ident(s("y"), token!(Ident, 3, 5, "y")), 309 | Expr::Lit(Literal::Int(10, token!(IntLiteral, 3, 9, "10")))), 310 | Stmt::Let(Ident(s("foobar"), token!(Ident, 4, 5, "foobar")), 311 | Expr::Lit(Literal::Int(838383, 312 | token!(IntLiteral, 4, 14, "838383")))), 313 | Stmt::Let(Ident(s("boo"), token!(Ident, 5, 5, "boo")), 314 | Expr::Lit(Literal::Bool(true, 315 | token!(BoolLiteral, 5, 11, "true"))))]); 316 | } 317 | 318 | static CODE_RETURN_STMTS: &str = " 319 | return 5; 320 | return 10; 321 | return 838383; 322 | return true; 323 | "; 324 | 325 | #[test] 326 | fn return_stmt() { 327 | program_eq(CODE_RETURN_STMTS, 328 | vec![Stmt::Return(Expr::Lit(Literal::Int(5, token!(IntLiteral, 2, 8, "5")))), 329 | Stmt::Return(Expr::Lit(Literal::Int(10, token!(IntLiteral, 3, 8, "10")))), 330 | Stmt::Return(Expr::Lit(Literal::Int(838383, 331 | token!(IntLiteral, 4, 8, "838383")))), 332 | Stmt::Return(Expr::Lit(Literal::Bool(true, 333 | token!(BoolLiteral, 5, 8, "true"))))]); 334 | } 335 | 336 | static CODE_MIXED_STMTS: &str = " 337 | let x = 5; 338 | return 10; 339 | 15; 340 | let y = 20; 341 | return false; 342 | "; 343 | 344 | #[test] 345 | fn mixed_stmt() { 346 | program_eq(CODE_MIXED_STMTS, 347 | vec![Stmt::Let(Ident(s("x"), token!(Ident, 2, 5, "x")), 348 | Expr::Lit(Literal::Int(5, token!(IntLiteral, 2, 9, "5")))), 349 | Stmt::Return(Expr::Lit(Literal::Int(10, token!(IntLiteral, 3, 8, "10")))), 350 | Stmt::Expr(Expr::Lit(Literal::Int(15, token!(IntLiteral, 4, 1, "15")))), 351 | Stmt::Let(Ident(s("y"), token!(Ident, 5, 5, "y")), 352 | Expr::Lit(Literal::Int(20, token!(IntLiteral, 5, 9, "20")))), 353 | Stmt::Return(Expr::Lit(Literal::Bool(false, 354 | token!(BoolLiteral, 355 | 6, 356 | 8, 357 | "false"))))]); 358 | } 359 | 360 | static CODE_FN1: &str = " 361 | fn() { 362 | return foobar + barfoo; 363 | } 364 | "; 365 | 366 | #[test] 367 | fn fn1() { 368 | program_eq(CODE_FN1, 369 | vec![Stmt::Expr(Expr::Fn { 370 | params: vec![], 371 | body: vec![ 372 | Stmt::Return(Expr::Infix( 373 | InfixOp::Plus(token!(Plus, 3, 17, "+")), 374 | Box::new(Expr::Ident(Ident(s("foobar"), token!(Ident, 3, 10, "foobar")))), 375 | Box::new(Expr::Ident(Ident(s("barfoo"), token!(Ident, 3, 19, "barfoo")))) 376 | )) 377 | ], 378 | pos: (2, 1), 379 | })]); 380 | } 381 | 382 | static CODE_FN2: &str = " 383 | fn(x, y) { 384 | return x + y; 385 | } 386 | "; 387 | 388 | #[test] 389 | fn fn2() { 390 | program_eq(CODE_FN2, 391 | vec![Stmt::Expr(Expr::Fn { 392 | params: vec![Ident(s("x"), token!(Ident, 2, 4, "x")), 393 | Ident(s("y"), token!(Ident, 2, 7, "y"))], 394 | body: vec![ 395 | Stmt::Return(Expr::Infix( 396 | InfixOp::Plus(token!(Plus, 3, 12, "+")), 397 | Box::new(Expr::Ident(Ident(s("x"), token!(Ident, 3, 10, "x")))), 398 | Box::new(Expr::Ident(Ident(s("y"), token!(Ident, 3, 14, "y")))) 399 | )) 400 | ], 401 | pos: (2, 1), 402 | })]); 403 | } 404 | 405 | static CODE_FN3: &str = " 406 | fn() { 407 | return fn (x, y, z, zz) { return x > y; }; 408 | } 409 | "; 410 | 411 | #[test] 412 | fn fn3() { 413 | program_eq(CODE_FN3, 414 | vec![Stmt::Expr(Expr::Fn { 415 | params: vec![], 416 | body: vec![ 417 | Stmt::Return(Expr::Fn { 418 | params: vec![Ident(s("x"), token!(Ident, 3, 14, "x")), 419 | Ident(s("y"), token!(Ident, 3, 17, "y")), 420 | Ident(s("z"), token!(Ident, 3, 20, "z")), 421 | Ident(s("zz"), token!(Ident, 3, 23, "zz"))], 422 | body: vec![ 423 | Stmt::Return(Expr::Infix( 424 | InfixOp::GreaterThan(token!(GreaterThan, 3, 38, ">")), 425 | Box::new(Expr::Ident(Ident(s("x"), token!(Ident, 3, 36, "x")))), 426 | Box::new(Expr::Ident(Ident(s("y"), token!(Ident, 3, 40, "y")))) 427 | )) 428 | ], 429 | pos: (3, 10), 430 | }) 431 | ], 432 | pos: (2, 1), 433 | })]); 434 | } 435 | 436 | static CODE_CALL: &str = " 437 | add(2, 3); 438 | add(a, b, 1, 2 * 3, other(4 + 5), add(6, 7 * 8)); 439 | fn(a, b) { return a + b; }(1, 2); 440 | "; 441 | 442 | #[test] 443 | fn call() { 444 | program_eq(CODE_CALL, 445 | vec![ 446 | Stmt::Expr(Expr::Call { func: Box::new(Expr::Ident(Ident(s("add"), token!(Ident, 2, 1, "add")))), 447 | args: vec![Expr::Lit(Literal::Int(2, token!(Ident, 2, 5, "2"))), 448 | Expr::Lit(Literal::Int(3, token!(Ident, 2, 8, "3"))) 449 | ] 450 | }), 451 | Stmt::Expr(Expr::Call { func: Box::new(Expr::Ident(Ident(s("add"), token!(Ident, 3, 1, "add")))), 452 | args: vec![Expr::Ident(Ident(s("a"), token!(Ident, 3, 5, "a"))), 453 | Expr::Ident(Ident(s("b"), token!(Ident, 3, 8, "b"))), 454 | Expr::Lit(Literal::Int(1, token!(Ident, 3, 11, "1"))), 455 | Expr::Infix(InfixOp::Multiply(token!(Multiply, 3, 16, "*")), 456 | Box::new(Expr::Lit(Literal::Int(2, token!(Ident, 3, 14, "2")))), 457 | Box::new(Expr::Lit(Literal::Int(3, token!(Ident, 3, 18, "3"))))), 458 | Expr::Call { func: Box::new(Expr::Ident(Ident(s("other"), token!(Ident, 3, 21, "other")))), 459 | args: vec![Expr::Infix(InfixOp::Plus(token!(Plus, 3, 29, "+")), 460 | Box::new(Expr::Lit(Literal::Int(4, token!(IntLiteral, 3, 27, "4")))), 461 | Box::new(Expr::Lit(Literal::Int(5, token!(IntLiteral, 3, 31, "5")))))] 462 | }, 463 | Expr::Call { func: Box::new(Expr::Ident(Ident(s("add"), token!(Ident, 3, 35, "add")))), 464 | args: vec![Expr::Lit(Literal::Int(6, token!(IntLiteral, 3, 39, "6"))), 465 | Expr::Infix(InfixOp::Multiply(token!(Multiply, 3, 44, "*")), 466 | Box::new(Expr::Lit(Literal::Int(7, token!(IntLiteral, 3, 42, "7")))), 467 | Box::new(Expr::Lit(Literal::Int(8, token!(IntLiteral, 3, 46, "8")))))] 468 | } 469 | ] 470 | }), 471 | Stmt::Expr(Expr::Call { func: Box::new(Expr::Fn { params: vec![Ident(s("a"), token!(Ident, 4, 4, "a")), 472 | Ident(s("b"), token!(Ident, 4, 7, "b"))], 473 | body: vec![ 474 | Stmt::Return(Expr::Infix( 475 | InfixOp::Plus(token!(Plus, 4, 21, "+")), 476 | Box::new(Expr::Ident(Ident(s("a"), token!(Ident, 4, 19, "a")))), 477 | Box::new(Expr::Ident(Ident(s("b"), token!(Ident, 4, 23, "b")))) 478 | )) 479 | ], 480 | pos: (4, 1), 481 | }), 482 | args: vec![ 483 | Expr::Lit(Literal::Int(1, token!(IntLiteral, 4, 28, "1"))), 484 | Expr::Lit(Literal::Int(2, token!(IntLiteral, 4, 31, "2"))) 485 | ] 486 | }) 487 | ]); 488 | } 489 | 490 | #[test] 491 | fn identifier() { 492 | program_eq("foobar;", vec![Stmt::Expr(Expr::Ident(Ident(s("foobar"), token!(Ident, 1, 1, "foobar"))))]); 493 | program_eq("foobar", vec![Stmt::Expr(Expr::Ident(Ident(s("foobar"), token!(Ident, 1, 1, "foobar"))))]); 494 | } 495 | 496 | #[test] 497 | fn prefix_expr() { 498 | program_eq("-foobar;", vec![Stmt::Expr(Expr::Prefix(PrefixOp::Minus(token!(Minus, 1, 1, "-")), 499 | Box::new(Expr::Ident(Ident(s("foobar"), token!(Ident, 1, 2, "foobar")))) 500 | ))]); 501 | program_eq("+10", vec![Stmt::Expr(Expr::Prefix(PrefixOp::Plus(token!(Plus, 1, 1, "+")), 502 | Box::new(Expr::Lit(Literal::Int(10, token!(IntLiteral, 1, 2, "10")))) 503 | ))]); 504 | program_eq("!true", vec![Stmt::Expr(Expr::Prefix(PrefixOp::Not(token!(Not, 1, 1, "!")), 505 | Box::new(Expr::Lit(Literal::Bool(true, token!(BoolLiteral, 1, 2, "true")))) 506 | ))]); 507 | } 508 | 509 | #[test] 510 | fn prefix_expr2() { 511 | program_eq("-(foobar);", vec![Stmt::Expr(Expr::Prefix(PrefixOp::Minus(token!(Minus, 1, 1, "-")), 512 | Box::new(Expr::Ident(Ident(s("foobar"), token!(Ident, 1, 3, "foobar")))) 513 | ))]); 514 | program_eq("(+(10))", vec![Stmt::Expr(Expr::Prefix(PrefixOp::Plus(token!(Plus, 1, 2, "+")), 515 | Box::new(Expr::Lit(Literal::Int(10, token!(IntLiteral, 1, 4, "10")))) 516 | ))]); 517 | program_eq("(((!true)))", vec![Stmt::Expr(Expr::Prefix(PrefixOp::Not(token!(Not, 1, 4, "!")), 518 | Box::new(Expr::Lit(Literal::Bool(true, token!(BoolLiteral, 1, 5, "true")))) 519 | ))]); 520 | } 521 | 522 | #[test] 523 | fn infix_expr() { 524 | program_eq("10 + 20", vec![Stmt::Expr(Expr::Infix(InfixOp::Plus(token!(Plus, 1, 4, "+")), 525 | Box::new(Expr::Lit(Literal::Int(10, token!(IntLiteral, 1, 1, "10")))), 526 | Box::new(Expr::Lit(Literal::Int(20, token!(IntLiteral, 1, 6, "20"))))))]); 527 | program_eq("10 * 20", vec![Stmt::Expr(Expr::Infix(InfixOp::Multiply(token!(Multiply, 1, 4, "*")), 528 | Box::new(Expr::Lit(Literal::Int(10, token!(IntLiteral, 1, 1, "10")))), 529 | Box::new(Expr::Lit(Literal::Int(20, token!(IntLiteral, 1, 6, "20"))))))]); 530 | code_result_eq("10 + 5 / -20 - (x + x)", "10 + (5 / (-20)) - (x + x)"); 531 | program_eq("10 + 5 / -20 - (x + x)", vec![ 532 | Stmt::Expr( 533 | Expr::Infix( 534 | InfixOp::Minus(token!(Minus, 1, 14, "-")), 535 | Box::new( 536 | Expr::Infix( 537 | InfixOp::Plus(token!(Plus, 1, 4, "+")), 538 | Box::new(Expr::Lit(Literal::Int(10, token!(IntLiteral, 1, 1, "10")))), 539 | Box::new( 540 | Expr::Infix( 541 | InfixOp::Divide(token!(Divide, 1, 8, "/")), 542 | Box::new(Expr::Lit(Literal::Int(5, token!(IntLiteral, 1, 1, "5")))), 543 | Box::new( 544 | Expr::Prefix( 545 | PrefixOp::Minus(token!(Minus, 1, 10, "-")), 546 | Box::new(Expr::Lit(Literal::Int(20, token!(IntLiteral, 1, 11, "20")))) 547 | ) 548 | ) 549 | ) 550 | ) 551 | ) 552 | ), 553 | Box::new( 554 | Expr::Infix( 555 | InfixOp::Plus(token!(Plus, 1, 19, "+")), 556 | Box::new(Expr::Ident(Ident(s("x"), token!(Ident, 1, 17, "x")))), 557 | Box::new(Expr::Ident(Ident(s("x"), token!(Ident, 1, 21, "x")))) 558 | ) 559 | ) 560 | ) 561 | ) 562 | ]); 563 | } 564 | 565 | #[test] 566 | fn op_precedence() { 567 | code_result_eq("!-a", "(!(-a))"); 568 | code_result_eq("a + b + c", "((a + b) + c)"); 569 | code_result_eq("a + b - c", "((a + b) - c)"); 570 | code_result_eq("a * b * c", "((a * b) * c)"); 571 | code_result_eq("a * b / c", "((a * b) / c)"); 572 | code_result_eq("a + b / c", "(a + (b / c))"); 573 | code_result_eq("a + b * c + d / e - f", "(((a + (b * c)) + (d / e)) - f)"); 574 | code_result_eq("3 + 4; -5 * 5", "(3 + 4);((-5) * 5)"); 575 | code_result_eq("5 > 4 == 3 < 4", "((5 > 4) == (3 < 4))"); 576 | code_result_eq("5 < 4 != 3 > 4", "((5 < 4) != (3 > 4))"); 577 | code_result_eq("3 + 4 * 5 == 3 * 1 + 4 * 5", "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))"); 578 | } 579 | 580 | #[test] 581 | fn if_expr() { 582 | program_eq("if (x < y) { x }", 583 | vec![ 584 | Stmt::Expr( 585 | Expr::If { 586 | cond: Box::new( 587 | Expr::Infix( 588 | InfixOp::LessThan(token!(LessThan, 1, 7, "<")), 589 | Box::new(Expr::Ident(Ident(s("x"), token!(Ident, 1, 5, "x")))), 590 | Box::new(Expr::Ident(Ident(s("y"), token!(Ident, 1, 9, "y")))) 591 | ) 592 | ), 593 | con: vec![Stmt::Expr( 594 | Expr::Ident(Ident(s("x"), token!(Ident, 1, 14, "x"))) 595 | )], 596 | alt: None, 597 | pos: (1, 1), 598 | } 599 | ) 600 | ]); 601 | program_eq("if (x < y) { x } else { y }", 602 | vec![ 603 | Stmt::Expr( 604 | Expr::If { 605 | cond: Box::new( 606 | Expr::Infix( 607 | InfixOp::LessThan(token!(LessThan, 1, 7, "<")), 608 | Box::new(Expr::Ident(Ident(s("x"), token!(Ident, 1, 5, "x")))), 609 | Box::new(Expr::Ident(Ident(s("y"), token!(Ident, 1, 9, "y")))) 610 | ) 611 | ), 612 | con: vec![Stmt::Expr( 613 | Expr::Ident(Ident(s("x"), token!(Ident, 1, 14, "x"))) 614 | )], 615 | alt: Some( 616 | vec![Stmt::Expr( 617 | Expr::Ident(Ident(s("y"), token!(Ident, 1, 25, "y"))) 618 | )] 619 | ), 620 | pos: (1, 1), 621 | } 622 | ) 623 | ]); 624 | } 625 | 626 | #[test] 627 | fn string() { 628 | program_eq("\"foobar\"", vec![Stmt::Expr(Expr::Lit(Literal::String(s("foobar"), token!(StringLiteral, 1, 1, "\"foobar\""))))]); 629 | program_eq("\"foo bar\"", vec![Stmt::Expr(Expr::Lit(Literal::String(s("foo bar"), token!(StringLiteral, 1, 1, "\"foo bar\""))))]); 630 | program_eq("\"foo\\nbar\"", vec![Stmt::Expr(Expr::Lit(Literal::String(s("foo\nbar"), token!(StringLiteral, 1, 1, "\"foo\\nbar\""))))]); 631 | program_eq("\"foo\\tbar\"", vec![Stmt::Expr(Expr::Lit(Literal::String(s("foo\tbar"), token!(StringLiteral, 1, 1, "\"foo\\tbar\""))))]); 632 | program_eq("\"foo\\\"bar\"", vec![Stmt::Expr(Expr::Lit(Literal::String(s("foo\"bar"), token!(StringLiteral, 1, 1, "\"foo\\\"bar\""))))]); 633 | } 634 | 635 | #[test] 636 | fn array() { 637 | program_eq("[1, 2 * 2, 3 + 3]", 638 | vec![Stmt::Expr(Expr::Array(vec![ 639 | Expr::Lit(Literal::Int(1, token!(IntLiteral, 1, 2, "1"))), 640 | Expr::Infix( 641 | InfixOp::Multiply(token!(Multiply, 1, 7, "*")), 642 | Box::new(Expr::Lit(Literal::Int(2, token!(IntLiteral, 1, 5, "2")))), 643 | Box::new(Expr::Lit(Literal::Int(2, token!(IntLiteral, 1, 9, "2")))) 644 | ), 645 | Expr::Infix( 646 | InfixOp::Plus(token!(Plus, 1, 14, "+")), 647 | Box::new(Expr::Lit(Literal::Int(3, token!(IntLiteral, 1, 12, "3")))), 648 | Box::new(Expr::Lit(Literal::Int(3, token!(IntLiteral, 1, 16, "3")))) 649 | ), 650 | ], (1, 1)))]); 651 | program_eq("myArray[1 + 1]", 652 | vec![Stmt::Expr( 653 | Expr::Index { 654 | target: Box::new(Expr::Ident(Ident(s("myArray"), token!(Ident, 1, 1, "myArray")))), 655 | index: Box::new( 656 | Expr::Infix( 657 | InfixOp::Plus(token!(Plus, 1, 11, "+")), 658 | Box::new(Expr::Lit(Literal::Int(1, token!(IntLiteral, 1, 9, "1")))), 659 | Box::new(Expr::Lit(Literal::Int(1, token!(IntLiteral, 1, 13, "1")))) 660 | ) 661 | ) 662 | } 663 | )]); 664 | code_result_eq(" a * [1, 2, 3, 4][b * c] * d", 665 | "((a * ([1, 2, 3, 4][b * c])) * d)"); 666 | code_result_eq("add( a * b[2], b[1], 2 * [1, 2][1])", 667 | "add((a * (b[2])), (b[1]), (2 * ([1, 2][1])))"); 668 | } 669 | 670 | #[test] 671 | fn hash() { 672 | program_eq("{}", vec![Stmt::Expr(Expr::Hash(vec![], (1, 1)))]); 673 | program_eq("{\"one\": 1, \"two\": 2, \"three\": 3}", 674 | vec![Stmt::Expr(Expr::Hash(vec![ 675 | (Literal::String(s("one"), token!(StringLiteral, 1, 2, "\"one\"")), 676 | Expr::Lit(Literal::Int(1, token!(IntLiteral, 1, 9, "1"))) 677 | ), 678 | (Literal::String(s("two"), token!(StringLiteral, 1, 12, "\"two\"")), 679 | Expr::Lit(Literal::Int(2, token!(IntLiteral, 1, 19, "2"))) 680 | ), 681 | (Literal::String(s("three"), token!(StringLiteral, 1, 22, "\"three\"")), 682 | Expr::Lit(Literal::Int(3, token!(IntLiteral, 1, 31, "3"))) 683 | ) 684 | ], (1, 1)))]); 685 | program_eq("{4: 1, 5: 2, 6: 3}", 686 | vec![Stmt::Expr(Expr::Hash(vec![ 687 | (Literal::Int(4, token!(IntLiteral, 1, 2, "4")), 688 | Expr::Lit(Literal::Int(1, token!(IntLiteral, 1, 5, "1"))) 689 | ), 690 | (Literal::Int(5, token!(IntLiteral, 1, 8, "5")), 691 | Expr::Lit(Literal::Int(2, token!(IntLiteral, 1, 11, "2"))) 692 | ), 693 | (Literal::Int(6, token!(IntLiteral, 1, 14, "6")), 694 | Expr::Lit(Literal::Int(3, token!(IntLiteral, 1, 17, "3"))) 695 | ) 696 | ], (1, 1)))]); 697 | program_eq("{true: 1, false: 2}", 698 | vec![Stmt::Expr(Expr::Hash(vec![ 699 | (Literal::Bool(true, token!(BoolLiteral, 1, 2, "true")), 700 | Expr::Lit(Literal::Int(1, token!(IntLiteral, 1, 8, "1"))) 701 | ), 702 | (Literal::Bool(false, token!(BoolLiteral, 1, 11, "false")), 703 | Expr::Lit(Literal::Int(2, token!(IntLiteral, 1, 18, "2"))) 704 | ) 705 | ], (1, 1)))]); 706 | program_eq("{\"one\": 0 + 1, \"two\": 10 - 8, \"three\": 15/5}", 707 | vec![Stmt::Expr(Expr::Hash(vec![ 708 | (Literal::String(s("one"), token!(StringLiteral, 1, 2, "\"one\"")), 709 | Expr::Infix( 710 | InfixOp::Plus(token!(Plus, 1, 11, "+")), 711 | Box::new(Expr::Lit(Literal::Int(0, token!(IntLiteral, 1, 9, "0")))), 712 | Box::new(Expr::Lit(Literal::Int(1, token!(IntLiteral, 1, 13, "1")))) 713 | )), 714 | (Literal::String(s("two"), token!(StringLiteral, 1, 16, "\"two\"")), 715 | Expr::Infix( 716 | InfixOp::Minus(token!(Minus, 1, 26, "-")), 717 | Box::new(Expr::Lit(Literal::Int(10, token!(IntLiteral, 1, 24, "10")))), 718 | Box::new(Expr::Lit(Literal::Int(8, token!(IntLiteral, 1, 28, "8")))) 719 | )), 720 | (Literal::String(s("three"), token!(StringLiteral, 1, 31, "\"three\"")), 721 | Expr::Infix( 722 | InfixOp::Divide(token!(Divide, 1, 42, "/")), 723 | Box::new(Expr::Lit(Literal::Int(15, token!(IntLiteral, 1, 40, "15")))), 724 | Box::new(Expr::Lit(Literal::Int(5, token!(IntLiteral, 1, 44, "5")))) 725 | )) 726 | ], (1, 1)))]); 727 | } 728 | } 729 | --------------------------------------------------------------------------------