├── .gitignore ├── Cargo.toml ├── lib ├── lib.rs ├── parser │ ├── program.rs │ ├── precedence.rs │ ├── ast.rs │ ├── mod.rs │ └── tests.rs ├── eval │ ├── env.rs │ ├── value.rs │ ├── funcs.rs │ ├── tests.rs │ └── mod.rs ├── lexer │ ├── mod.rs │ └── tests.rs └── token.rs ├── README.md └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | 4 | /programs -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "monkey-rs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["wzid "] 6 | 7 | [lib] 8 | name = "monkey_lib" 9 | path = "lib/lib.rs" 10 | 11 | [[bin]] 12 | name = "monkey-rs" 13 | path = "src/main.rs" 14 | 15 | 16 | [dependencies] 17 | clap = { version = "4.3.3", features = ["derive"] } -------------------------------------------------------------------------------- /lib/lib.rs: -------------------------------------------------------------------------------- 1 | use eval::{Evaluator, value::Value, EvaluatorErr}; 2 | use parser::{ast::Ast, program::Program}; 3 | 4 | #[macro_use] 5 | pub mod token; 6 | 7 | pub mod lexer; 8 | pub mod parser; 9 | pub mod eval; 10 | 11 | #[derive(Default)] 12 | pub struct Monkey { 13 | eval: Evaluator 14 | } 15 | 16 | impl Monkey { 17 | 18 | pub fn eval(&mut self, program: Program) -> Result { 19 | self.eval.eval_self(&Ast::Program(program)) 20 | } 21 | } -------------------------------------------------------------------------------- /lib/parser/program.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use crate::parser::ast::Statement; 4 | 5 | #[derive(Debug, Default)] 6 | pub struct Program { 7 | pub statments: Vec, 8 | } 9 | 10 | impl Display for Program { 11 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 12 | let output = self 13 | .statments 14 | .iter() 15 | .map(|stmt| stmt.to_string()) 16 | .collect::>() 17 | .join("\n"); 18 | write!(f, "{output}") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/parser/precedence.rs: -------------------------------------------------------------------------------- 1 | use crate::token::Token; 2 | 3 | #[derive(Debug, PartialEq, PartialOrd)] 4 | pub enum Precedence { 5 | Lowest, 6 | Equality, // == or != 7 | LessGreater, // < or > 8 | AddSubtract, // + or - 9 | TimesDivideMod, // * or / 10 | Prefix, // -X or !X 11 | Call, // myFunction(X) 12 | } 13 | 14 | impl From<&Token> for Precedence { 15 | fn from(value: &Token) -> Self { 16 | match value { 17 | token![==] | token![!=] => Precedence::Equality, 18 | token![<] | token![>] => Precedence::LessGreater, 19 | token![+] | token![-] => Precedence::AddSubtract, 20 | token![*] | token![/] | token![%] => Precedence::TimesDivideMod, 21 | token!['('] => Precedence::Call, 22 | _ => Precedence::Lowest, 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/eval/env.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, collections::HashMap, rc::Rc}; 2 | 3 | use super::{value::Value, EvaluatorErr}; 4 | 5 | #[derive(Debug, Default, Clone)] 6 | pub struct Environment { 7 | map: HashMap, 8 | outer: Option>>, 9 | } 10 | 11 | impl Environment { 12 | pub fn new_enclosed(outer: Rc>) -> Rc> { 13 | Rc::new(RefCell::new(Environment { 14 | outer: Some(outer), 15 | map: HashMap::new(), 16 | })) 17 | } 18 | 19 | pub fn get(&self, name: &String) -> Result { 20 | match self.map.get(name) { 21 | Some(v) => Ok(v.clone()), 22 | None => match &self.outer { 23 | Some(outer) => outer.borrow().get(name), 24 | None => Err(format!("identifier not found: {name}")), 25 | }, 26 | } 27 | } 28 | 29 | pub fn set(&mut self, name: String, value: Value) -> Value { 30 | self.map.insert(name, value.clone()); 31 | value 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # monkey-rs 🐵 2 | An interpreted, dynamically-typed, general purpose hobby programming language written in Rust. 3 | 4 | Inspired by [this tutorial](https://monkeylang.org). 5 | 6 | ## Features: 7 | 1. Arithmetic and logical operators 8 | 2. Very basic IO 9 | 10 | > I am still thinking about how I want to implement arrays and maps. 11 | > 12 | > I would like to be able to call functions from an array or map object like Python 13 | 14 | ## Use: 15 | Building the language from source requires a working rust toolchain installed. Check out the tutorial [here](https://doc.rust-lang.org/cargo/getting-started/installation.html) to setup Rust and Cargo. 16 | 17 | Right now the only way to use the language is to build the project using Cargo. This requires a working rust toolchain installed. Check out the tutorial [here](https://doc.rust-lang.org/cargo/getting-started/installation.html) to setup Rust and Cargo. 18 | 19 | 1. Clone the source code: 20 | ``` 21 | git clone https://github.com/wzid/monkey-rs.git 22 | ``` 23 | 24 | 2. Run with file or REPL mode 25 | ``` 26 | cargo run 27 | 28 | cargo run 29 | ``` 30 | 31 | ## Language examples: 32 | ```rust 33 | println("Salary calculator"); 34 | 35 | let name = input("Enter your name: "); 36 | 37 | let hours_worked = input("Enter the amount of hours you work each day: "); 38 | 39 | let days_worked = input("Enter the amount of days you work each week: "); 40 | 41 | let hourly_wage = input("Enter your hourly pay: "); 42 | 43 | let calculate_salary = fn(hours, days, wage) { 44 | hours * days * wage * 52 45 | }; 46 | 47 | println(name, "your annual salary is", calculate_salary(hours_worked, days_worked, hourly_wage)); 48 | ``` -------------------------------------------------------------------------------- /lib/eval/value.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt::Display, rc::Rc, cell::RefCell}; 2 | 3 | use crate::parser::ast::Statement; 4 | 5 | use super::{env::Environment, funcs::BuiltInFunctionType}; 6 | 7 | pub trait Truth { 8 | fn truth(&self) -> bool; 9 | } 10 | 11 | #[derive(Debug, Clone)] 12 | pub enum Value { 13 | Integer(i64), 14 | Boolean(bool), 15 | String(String), 16 | Return(Box), 17 | Function { 18 | params: Vec, 19 | body: Box, // Statement::BlockStatement 20 | env: Rc>, 21 | }, 22 | BuiltInFunction { 23 | func: BuiltInFunctionType, 24 | }, 25 | Null, 26 | } 27 | 28 | impl Value { 29 | pub fn is_null(&self) -> bool { 30 | matches!(self, Value::Null) 31 | } 32 | } 33 | 34 | impl Truth for Value { 35 | fn truth(&self) -> bool { 36 | match self { 37 | Value::Integer(i) => i > &0, 38 | Value::Boolean(b) => *b, 39 | _ => false 40 | } 41 | } 42 | } 43 | 44 | impl From for Value { 45 | fn from(value: bool) -> Self { 46 | Value::Boolean(value) 47 | } 48 | } 49 | 50 | impl From for Value { 51 | fn from(value: i64) -> Self { 52 | Value::Integer(value) 53 | } 54 | } 55 | 56 | impl From for Value { 57 | fn from(value: String) -> Self { 58 | Value::String(value) 59 | } 60 | } 61 | 62 | impl Display for Value { 63 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 64 | match self { 65 | Value::Integer(i) => write!(f, "{i}"), 66 | Value::Boolean(b) => write!(f, "{b}"), 67 | Value::String(s) => write!(f, "{s}"), 68 | Value::Null => write!(f, "null"), 69 | Value::Return(v) => write!(f, "{v}"), 70 | Value::Function { params, body, .. } => { 71 | write!(f, "fn({}) {{\n{body}\n}}", params.join(", ")) 72 | }, 73 | Value::BuiltInFunction { .. } => write!(f, "builtin function"), 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::{stdin, stdout, Write}; 2 | 3 | use monkey_lib::{ 4 | lexer, 5 | parser::{self, program::Program}, 6 | Monkey, 7 | }; 8 | 9 | use clap::Parser; 10 | 11 | use std::fs; 12 | 13 | use lexer::Lexer; 14 | 15 | #[derive(Parser)] 16 | #[command(version, about, long_about = None)] 17 | struct Args { 18 | /// The location of the monkey file 19 | file: Option, 20 | } 21 | 22 | fn main() { 23 | let args = Args::parse(); 24 | 25 | let mut monkey = Monkey::default(); 26 | 27 | 28 | if let Some(file) = args.file { 29 | let contents = fs::read_to_string(file).expect("Unable to find or read file"); 30 | 31 | if let Ok(program) = lex_and_parse(contents) { 32 | evaluate(program, &mut monkey); 33 | } 34 | } else { 35 | println!("Monkey v1.0"); 36 | println!("REPL Mode"); 37 | 38 | loop { 39 | let input = get_input(); 40 | 41 | if let Ok(program) = lex_and_parse(input) { 42 | evaluate(program, &mut monkey); 43 | } 44 | } 45 | } 46 | } 47 | 48 | fn get_input() -> String { 49 | print!(">> "); 50 | stdout().flush().unwrap(); 51 | 52 | let mut input = String::new(); 53 | 54 | stdin().read_line(&mut input).expect("Failed to read line"); 55 | 56 | input 57 | } 58 | 59 | fn evaluate(program: Program, monkey: &mut Monkey) { 60 | if let Err(msg) = monkey.eval(program) { 61 | println!("Error: {msg}"); 62 | } 63 | } 64 | 65 | fn lex_and_parse(input: String) -> Result { 66 | let lexer = Lexer::new(input.as_str()); 67 | 68 | let mut parser = parser::Parser::new(lexer); 69 | 70 | let program = parser.parse_program(); 71 | 72 | if !parser.errors.is_empty() { 73 | print_parse_errors(&parser.errors); 74 | return Err(()); 75 | } 76 | 77 | Ok(program) 78 | } 79 | 80 | fn print_parse_errors(errors: &Vec) { 81 | println!("Woops! We ran into some monkey business here!"); 82 | println!(" parser errors: "); 83 | for err in errors { 84 | println!("\t{err}"); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/eval/funcs.rs: -------------------------------------------------------------------------------- 1 | use super::{value::Value, EvaluatorErr}; 2 | 3 | use std::io::{stdin, stdout, Write}; 4 | 5 | pub type BuiltInFunctionType = fn(Vec) -> Result; 6 | 7 | pub fn get_function(name: &str) -> Option { 8 | match name { 9 | "len" => Some(len), 10 | "println" => Some(println), 11 | "input" => Some(input), 12 | _ => None, 13 | } 14 | } 15 | 16 | fn len(args: Vec) -> Result { 17 | if args.len() == 1 { 18 | match args.first().unwrap() { 19 | Value::String(s) => Ok(Value::Integer(s.len() as i64)), 20 | _ => Err(format!("Cannot take length of {}", args.first().unwrap())), 21 | } 22 | } else { 23 | return Err(format!( 24 | "len() takes 1 argument, {} arguments given", 25 | args.len() 26 | )); 27 | } 28 | } 29 | 30 | fn println(args: Vec) -> Result { 31 | let result = args 32 | .iter() 33 | .map(|arg| arg.to_string()) 34 | .collect::>() 35 | .join(" "); 36 | 37 | println!("{result}"); 38 | 39 | Ok(Value::Null) 40 | } 41 | 42 | fn input(args: Vec) -> Result { 43 | if args.len() == 1 { 44 | match args.first().unwrap() { 45 | Value::String(s) => { 46 | print!("{s}"); 47 | stdout().flush().unwrap(); 48 | 49 | let mut input = String::new(); 50 | 51 | stdin().read_line(&mut input).expect("Failed to read line"); 52 | 53 | // Remove trailing new line character and trim whitespace 54 | input = input.trim().to_string(); 55 | 56 | if let Ok(parsed_int) = input.parse::() { 57 | Ok(Value::Integer(parsed_int)) 58 | } else { 59 | Ok(Value::String(input)) 60 | } 61 | } 62 | _ => Err(format!("Cannot take input of {}", args.first().unwrap())), 63 | } 64 | } else { 65 | return Err(format!( 66 | "input() takes 1 argument, {} arguments given", 67 | args.len() 68 | )); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/parser/ast.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use crate::token::Token; 4 | 5 | use super::program::Program; 6 | 7 | #[allow(dead_code)] 8 | pub enum Ast { 9 | Program(Program), 10 | Statement(Statement), 11 | Expression(Box), 12 | } 13 | 14 | #[derive(Debug, Clone, PartialEq)] 15 | pub enum Statement { 16 | LetStatement { ident: Token, value: Expression }, 17 | ReturnStatement(Expression), 18 | ExpressionStatement(Expression), 19 | BlockStatement(Vec), 20 | } 21 | 22 | impl Display for Statement { 23 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 24 | match self { 25 | Statement::LetStatement { ident, value } => { 26 | write!(f, "let {ident} = {value};") 27 | } 28 | Statement::ReturnStatement(value) => write!(f, "return {value};"), 29 | Statement::ExpressionStatement(value) => write!(f, "{value}"), 30 | Statement::BlockStatement(statements) => { 31 | let output = statements 32 | .iter() 33 | .map(|stmt| stmt.to_string()) 34 | .collect::>() 35 | .join("\n"); 36 | write!(f, "{output}") 37 | } 38 | } 39 | } 40 | } 41 | 42 | #[derive(Debug, Clone, PartialEq)] 43 | pub enum Expression { 44 | IntExpression(i64), 45 | IdentifierExpression(String), 46 | PrefixExpression { 47 | op_token: Token, 48 | right: Box, 49 | }, 50 | InfixExpression { 51 | left: Box, 52 | op_token: Token, 53 | right: Box, 54 | }, 55 | BooleanExpression(bool), 56 | StringExpression(String), 57 | IfExpression { 58 | condition: Box, 59 | consequence: Box, 60 | alternative: Option>, 61 | }, 62 | FunctionExpression { 63 | parameters: Vec, 64 | body: Box, 65 | }, 66 | CallExpression { 67 | function: Box, 68 | arguments: Vec, 69 | }, 70 | } 71 | 72 | impl Display for Expression { 73 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 74 | match self { 75 | Expression::IntExpression(value) => write!(f, "{value}"), 76 | Expression::IdentifierExpression(name) => write!(f, "{name}"), 77 | Expression::PrefixExpression { op_token, right } => { 78 | write!(f, "({op_token}{right})") 79 | } 80 | Expression::InfixExpression { 81 | left, 82 | op_token, 83 | right, 84 | } => { 85 | write!(f, "({left} {op_token} {right})") 86 | } 87 | Expression::BooleanExpression(value) => write!(f, "{value}"), 88 | Expression::StringExpression(value) => write!(f, "{value}"), 89 | Expression::IfExpression { 90 | condition, 91 | consequence, 92 | alternative, 93 | } => { 94 | write!(f, "if {condition} {{{consequence}}}")?; 95 | if let Some(alt) = alternative { 96 | write!(f, " else {{{alt}}}")?; 97 | } 98 | Ok(()) 99 | } 100 | Expression::FunctionExpression { parameters, body } => { 101 | let params = parameters 102 | .iter() 103 | .map(|p| p.to_string()) 104 | .collect::>() 105 | .join(", "); 106 | write!(f, "fn ({params}) {{{body}}}") 107 | } 108 | Expression::CallExpression { 109 | function, 110 | arguments, 111 | } => { 112 | let args = arguments 113 | .iter() 114 | .map(|p| p.to_string()) 115 | .collect::>() 116 | .join(", "); 117 | write!(f, "{function}({args})") 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /lib/lexer/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{token, token::Token}; 2 | 3 | #[cfg(test)] 4 | mod tests; 5 | 6 | pub struct Lexer<'a> { 7 | input: &'a str, 8 | pos: usize, 9 | next_pos: usize, 10 | ch: u8, 11 | } 12 | 13 | impl<'a> Lexer<'a> { 14 | pub fn new(input: &'a str) -> Self { 15 | let mut lexer = Lexer { 16 | input, 17 | pos: 0, 18 | next_pos: 0, 19 | ch: 0, 20 | }; 21 | 22 | lexer.read_next_char(); 23 | 24 | lexer 25 | } 26 | 27 | fn read_next_char(&mut self) { 28 | if self.next_pos >= self.input.len() { 29 | self.ch = 0; 30 | } else { 31 | self.ch = self.input.as_bytes()[self.next_pos]; 32 | } 33 | 34 | self.pos = self.next_pos; 35 | self.next_pos += 1; 36 | } 37 | 38 | fn read_while(&mut self, mut predicate: impl FnMut(u8) -> bool) { 39 | while predicate(self.ch) { 40 | self.read_next_char() 41 | } 42 | } 43 | 44 | fn is_next_char(&self, check: u8) -> bool { 45 | self.next_pos < self.input.len() && check == self.input.as_bytes()[self.next_pos] 46 | } 47 | 48 | pub fn next_token(&mut self) -> Token { 49 | self.read_while(|cha| cha.is_ascii_whitespace()); 50 | 51 | let tok = match self.ch { 52 | b'=' => { 53 | // == 54 | if self.is_next_char(b'=') { 55 | // Consume the next char 56 | self.read_next_char(); 57 | token![==] 58 | } else { 59 | token![=] 60 | } 61 | } 62 | b'!' => { 63 | // != 64 | if self.is_next_char(b'=') { 65 | self.read_next_char(); 66 | token![!=] 67 | } else { 68 | token![!] 69 | } 70 | } 71 | b'+' => token![+], 72 | b'-' => token![-], 73 | b'*' => token![*], 74 | b'/' => token![/], 75 | b'%' => token![%], 76 | b'<' => token![<], 77 | b'>' => token![>], 78 | 79 | b';' => token![;], 80 | b',' => token![,], 81 | 82 | b'(' => token!['('], 83 | b')' => token![')'], 84 | b'{' => token!['{'], 85 | b'}' => token!['}'], 86 | 87 | b'\0' => token![EOF], 88 | // This makes sure that the identifier consists of letters and/or underscores 89 | b if is_identifier_or_keyword(b) => return self.identifier_or_keyword(), 90 | 91 | // Since we modify the position in this statement and the statement above we do not 92 | // want to to modify it again after the switch statement with the extra `self.read_char` 93 | b if b.is_ascii_digit() => return self.number(), 94 | b'"' => self.read_string(), 95 | _ => token![ILLEGAL], 96 | }; 97 | 98 | self.read_next_char(); 99 | 100 | tok 101 | } 102 | 103 | fn identifier_or_keyword(&mut self) -> Token { 104 | let start_pos = self.pos; 105 | 106 | self.read_while(is_identifier_or_keyword); 107 | 108 | let identifier = &self.input[start_pos..self.pos]; 109 | 110 | token::lookup_identifier(identifier) 111 | } 112 | 113 | fn number(&mut self) -> Token { 114 | let start_pos = self.pos; 115 | // Loop while the character is a digit 116 | self.read_while(|cha| cha.is_ascii_digit()); 117 | 118 | let int_str = &self.input[start_pos..self.pos]; 119 | 120 | let int = int_str.parse::().unwrap(); 121 | 122 | token![INT(int)] 123 | } 124 | 125 | fn read_string(&mut self) -> Token { 126 | // go to start of string (advance past " character) 127 | self.read_next_char(); 128 | 129 | let start_pos = self.pos; 130 | // Loop while the character is a digit 131 | self.read_while(|cha| cha != b'"'); 132 | 133 | let str = &self.input[start_pos..self.pos]; 134 | 135 | token![STR(str.to_string())] 136 | } 137 | 138 | } 139 | fn is_identifier_or_keyword(check: u8) -> bool { 140 | matches!(check, b'a'..=b'z' | b'A'..=b'Z' | b'_') 141 | } 142 | -------------------------------------------------------------------------------- /lib/token.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use crate::token; 4 | 5 | #[derive(PartialEq, Debug, Clone, Eq, Hash)] 6 | #[repr(u8)] 7 | pub enum Token { 8 | Illegal, 9 | Eof, 10 | 11 | // Identifiers and literals 12 | Ident(String), 13 | Int(i64), 14 | String(String), 15 | 16 | // Operators 17 | Assign, 18 | Plus, 19 | Minus, 20 | Bang, 21 | Asterisk, 22 | Slash, 23 | Percent, 24 | 25 | LessThan, 26 | GreaterThan, 27 | 28 | Equal, 29 | NotEqual, 30 | 31 | // Delimeters 32 | Comma, 33 | Semicolon, 34 | 35 | Lparen, 36 | Rparen, 37 | Lbrace, 38 | Rbrace, 39 | 40 | // Keywords 41 | Func, 42 | Let, 43 | True, 44 | False, 45 | If, 46 | Else, 47 | Return, 48 | } 49 | 50 | impl Display for Token { 51 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 52 | match self { 53 | token![ILLEGAL] => write!(f, "ILLEGAL"), 54 | token![EOF] => write!(f, "EOF"), 55 | Token::Ident(value) => write!(f, "{value}"), 56 | Token::Int(value) => write!(f, "{value}"), 57 | Token::String(value) => write!(f, "{value}"), 58 | token![=] => write!(f, "="), 59 | token![+] => write!(f, "+"), 60 | token![-] => write!(f, "-"), 61 | token![!] => write!(f, "!"), 62 | token![*] => write!(f, "*"), 63 | token![/] => write!(f, "/"), 64 | token![%] => write!(f, "%"), 65 | token![<] => write!(f, "<"), 66 | token![>] => write!(f, ">"), 67 | token![==] => write!(f, "=="), 68 | token![!=] => write!(f, "!="), 69 | token![,] => write!(f, ","), 70 | token![;] => write!(f, ";"), 71 | token!['('] => write!(f, "("), 72 | token![')'] => write!(f, ")"), 73 | token!['{'] => write!(f, "{{"), 74 | token!['}'] => write!(f, "}}"), 75 | token![FN] => write!(f, "fn"), 76 | token![LET] => write!(f, "let"), 77 | token![TRUE] => write!(f, "true"), 78 | token![FALSE] => write!(f, "false"), 79 | token![IF] => write!(f, "if"), 80 | token![ELSE] => write!(f, "else"), 81 | token![RETURN] => write!(f, "return"), 82 | } 83 | } 84 | } 85 | 86 | pub fn lookup_identifier(identifier: &str) -> Token { 87 | match identifier { 88 | "fn" => token![FN], 89 | "let" => token![LET], 90 | "if" => token![IF], 91 | "true" => token![TRUE], 92 | "false" => token![FALSE], 93 | "else" => token![ELSE], 94 | "return" => token![RETURN], 95 | _ => token![IDENT(identifier.to_string())], 96 | } 97 | } 98 | 99 | #[macro_export] 100 | macro_rules! token { 101 | [ILLEGAL] => { $crate::token::Token::Illegal }; 102 | [EOF] => { $crate::token::Token::Eof }; 103 | [IDENT($val:expr)] => { $crate::token::Token::Ident($val.to_string()) }; 104 | [INT($val:expr)] => { $crate::token::Token::Int($val) }; 105 | [STR($val:expr)] => { $crate::token::Token::String($val) }; 106 | [=] => { $crate::token::Token::Assign }; 107 | [+] => { $crate::token::Token::Plus }; 108 | [-] => { $crate::token::Token::Minus }; 109 | [!] => { $crate::token::Token::Bang }; 110 | [*] => { $crate::token::Token::Asterisk }; 111 | [/] => { $crate::token::Token::Slash }; 112 | [%] => { $crate::token::Token::Percent }; 113 | [<] => { $crate::token::Token::LessThan }; 114 | [>] => { $crate::token::Token::GreaterThan }; 115 | [==] => { $crate::token::Token::Equal }; 116 | [!=] => { $crate::token::Token::NotEqual }; 117 | [,] => { $crate::token::Token::Comma }; 118 | [;] => { $crate::token::Token::Semicolon }; 119 | ['('] => { $crate::token::Token::Lparen }; 120 | [')'] => { $crate::token::Token::Rparen }; 121 | ['{'] => { $crate::token::Token::Lbrace }; 122 | ['}'] => { $crate::token::Token::Rbrace }; 123 | [FN] => { $crate::token::Token::Func }; 124 | [LET] => { $crate::token::Token::Let }; 125 | [TRUE] => { $crate::token::Token::True }; 126 | [FALSE] => { $crate::token::Token::False }; 127 | [IF] => { $crate::token::Token::If }; 128 | [ELSE] => { $crate::token::Token::Else }; 129 | [RETURN] => { $crate::token::Token::Return }; 130 | } -------------------------------------------------------------------------------- /lib/lexer/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[test] 4 | fn test_next_token_basic() { 5 | let input = "=+(){},;"; 6 | 7 | let tests = vec![ 8 | token![=], 9 | token![+], 10 | token!['('], 11 | token![')'], 12 | token!['{'], 13 | token!['}'], 14 | token![,], 15 | token![;], 16 | ]; 17 | 18 | let mut lexer = Lexer::new(input); 19 | 20 | for expect in tests { 21 | let tok = lexer.next_token(); 22 | 23 | assert_eq!(expect, tok); 24 | } 25 | } 26 | 27 | #[test] 28 | fn test_next_token_program() { 29 | let input = r#" 30 | let five = 5; 31 | 32 | let ten = 10; 33 | 34 | let add = fn(x, y) { 35 | x + y; 36 | }; 37 | let result = add(five, ten); 38 | "foobar"; 39 | "foo bar"; 40 | "#; 41 | 42 | let tests = vec![ 43 | token![LET], 44 | token![IDENT("five".to_string())], 45 | token![=], 46 | token![INT(5)], 47 | token![;], 48 | token![LET], 49 | token![IDENT("ten".to_string())], 50 | token![=], 51 | token![INT(10)], 52 | token![;], 53 | token![LET], 54 | token![IDENT("add".to_string())], 55 | token![=], 56 | token![FN], 57 | token!['('], 58 | token![IDENT("x".to_string())], 59 | token![,], 60 | token![IDENT("y".to_string())], 61 | token![')'], 62 | token!['{'], 63 | token![IDENT("x".to_string())], 64 | token![+], 65 | token![IDENT("y".to_string())], 66 | token![;], 67 | token!['}'], 68 | token![;], 69 | token![LET], 70 | token![IDENT("result".to_string())], 71 | token![=], 72 | token![IDENT("add".to_string())], 73 | token!['('], 74 | token![IDENT("five".to_string())], 75 | token![,], 76 | token![IDENT("ten".to_string())], 77 | token![')'], 78 | token![;], 79 | token![STR("foobar".to_string())], 80 | token![;], 81 | token![STR("foo bar".to_string())], 82 | ]; 83 | 84 | let mut lexer = Lexer::new(input); 85 | 86 | for expect in tests { 87 | let tok = lexer.next_token(); 88 | 89 | assert_eq!(expect, tok); 90 | } 91 | } 92 | 93 | #[test] 94 | fn test_next_token_reserved() { 95 | let input = r#" 96 | if (5 < 10) { 97 | return true; 98 | } else { 99 | return false; 100 | }"#; 101 | 102 | let tests = vec![ 103 | token![IF], 104 | token!['('], 105 | token![INT(5)], 106 | token![<], 107 | token![INT(10)], 108 | token![')'], 109 | token!['{'], 110 | token![RETURN], 111 | token![TRUE], 112 | token![;], 113 | token!['}'], 114 | token![ELSE], 115 | token!['{'], 116 | token![RETURN], 117 | token![FALSE], 118 | token![;], 119 | token!['}'], 120 | ]; 121 | 122 | let mut lexer = Lexer::new(input); 123 | 124 | for expect in tests { 125 | let tok = lexer.next_token(); 126 | 127 | assert_eq!(expect, tok); 128 | } 129 | } 130 | 131 | #[test] 132 | fn test_next_token_operators() { 133 | let input = r#" 134 | !-/*5 135 | 5 < 10 > 5"#; 136 | 137 | let tests = vec![ 138 | token![!], 139 | token![-], 140 | token![/], 141 | token![*], 142 | token![INT(5)], 143 | token![INT(5)], 144 | token![<], 145 | token![INT(10)], 146 | token![>], 147 | token![INT(5)], 148 | ]; 149 | 150 | let mut lexer = Lexer::new(input); 151 | 152 | for expect in tests { 153 | let tok = lexer.next_token(); 154 | 155 | assert_eq!(expect, tok); 156 | } 157 | } 158 | 159 | #[test] 160 | fn test_next_token_double_char() { 161 | let input = r#" 162 | 10 == 10; 163 | 10 != 9;"#; 164 | 165 | let tests = vec![ 166 | token![INT(10)], 167 | token![==], 168 | token![INT(10)], 169 | token![;], 170 | token![INT(10)], 171 | token![!=], 172 | token![INT(9)], 173 | token![;], 174 | ]; 175 | 176 | let mut lexer = Lexer::new(input); 177 | 178 | for expect in tests { 179 | let tok = lexer.next_token(); 180 | 181 | assert_eq!(expect, tok); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /lib/eval/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | lexer::Lexer, 3 | parser::{ast::Ast, Parser}, 4 | }; 5 | 6 | use super::{value::Value, Evaluator}; 7 | 8 | fn test_eval(input: &str) -> Value { 9 | let lexer = Lexer::new(input); 10 | let mut parser = Parser::new(lexer); 11 | 12 | let program = parser.parse_program(); 13 | assert!(parser.errors.is_empty(), "Parser had errors"); 14 | 15 | let result = Evaluator::eval(&Ast::Program(program)); 16 | match result { 17 | Ok(v) => v, 18 | Err(e) => panic!("Error: {}", e), 19 | } 20 | } 21 | 22 | #[test] 23 | fn test_eval_integer_expression() { 24 | let tests = vec![ 25 | ("5", 5), 26 | ("10", 10), 27 | ("-5", -5), 28 | ("-10", -10), 29 | ("5+5+5+5", 20), 30 | ("5+5+5+5-10", 10), 31 | ("2*2*2*2*2", 32), 32 | ("3 * (3 *3)+10", 37), 33 | ("(5+10*2+15/3)*2+-10", 50), 34 | ]; 35 | 36 | for (input, expected) in tests { 37 | let evaluated = test_eval(input); 38 | test_integer_object(evaluated, expected); 39 | } 40 | } 41 | 42 | fn test_integer_object(value: Value, expected: i64) { 43 | match value { 44 | Value::Integer(i) => assert_eq!(expected, i, "value is not {}. got {}", expected, i), 45 | _ => panic!("value is not an Integer. got {:?}", value), 46 | } 47 | } 48 | 49 | #[test] 50 | fn test_eval_boolean_expression() { 51 | let tests = vec![ 52 | ("true", true), 53 | ("false", false), 54 | ("1 < 2", true), 55 | ("1 > 2", false), 56 | ("1 < 1", false), 57 | ("1 > 1", false), 58 | ("1 == 1", true), 59 | ("1 != 1", false), 60 | ("1 == 2", false), 61 | ("1 != 2", true), 62 | ("false != true", true), 63 | ("false == false", true), 64 | ("true == false", false), 65 | ("(1 > 2) == false", true), 66 | ("(1 < 2) == false", false), 67 | ]; 68 | 69 | for (input, expected) in tests { 70 | let evaluated = test_eval(input); 71 | test_boolean_object(evaluated, expected); 72 | } 73 | } 74 | 75 | fn test_boolean_object(value: Value, expected: bool) { 76 | match value { 77 | Value::Boolean(b) => assert_eq!(expected, b, "value is not {}. got {}", expected, b), 78 | _ => panic!("value is not an Boolean. got {:?}", value), 79 | } 80 | } 81 | 82 | #[test] 83 | fn test_bang_operator() { 84 | let tests = vec![ 85 | ("!true", false), 86 | ("!false", true), 87 | ("!!!true", false), 88 | ("!5", false), 89 | ("!!5", true), 90 | ]; 91 | 92 | for (input, expected) in tests { 93 | let evaluated = test_eval(input); 94 | test_boolean_object(evaluated, expected); 95 | } 96 | } 97 | 98 | #[test] 99 | fn test_if_else_expressions() { 100 | let tests = vec![ 101 | ("if true { 10 }", Some(10)), 102 | ("if false { 10 }", None), 103 | ("if 1 > 2 { 10 }", None), 104 | ("if 1 < 2 { 10 }", Some(10)), 105 | ("if 1 > 2 { 10 } else { 20 }", Some(20)), 106 | ("if 1 < 2 { 10 } else { 20 }", Some(10)), 107 | ]; 108 | 109 | for (input, expected) in tests { 110 | let evaluated = test_eval(input); 111 | 112 | match expected { 113 | Some(i) => test_integer_object(evaluated, i), 114 | None => assert!( 115 | evaluated.is_null(), 116 | "value is not Null. got {:?}", 117 | evaluated 118 | ), 119 | } 120 | } 121 | } 122 | 123 | #[test] 124 | fn test_return_statements() { 125 | let tests = vec![ 126 | ("return 10;", 10), 127 | ("return 10; 9;", 10), 128 | ("return 2*5; 9;", 10), 129 | ("9; return 2*5; 9;", 10), 130 | ("if 10 > 1 { if 10 > 1 { return 10; } return 1; }", 10), 131 | ]; 132 | 133 | for (input, expected) in tests { 134 | let evaluated = test_eval(input); 135 | test_integer_object(evaluated, expected); 136 | } 137 | } 138 | 139 | #[test] 140 | fn test_let_statements() { 141 | let tests = vec![ 142 | ("let a = 5; a;", 5), 143 | ("let a = 5 * 5; a;", 25), 144 | ("let a = 5; let b = a; b;", 5), 145 | ("let a = 5; let b = a; let c = a + b + 5; c;", 15), 146 | ]; 147 | 148 | for (input, expected) in tests { 149 | let evaluated = test_eval(input); 150 | test_integer_object(evaluated, expected); 151 | } 152 | } 153 | 154 | #[test] 155 | fn test_functions() { 156 | let input = "fn(x) { x + 2; };"; 157 | 158 | let evaluated = test_eval(input); 159 | 160 | match evaluated { 161 | Value::Function { 162 | params, 163 | body, 164 | env: _, 165 | } => { 166 | assert_eq!( 167 | params.len(), 168 | 1, 169 | "function has {} parameters. expected {} parameters", 170 | params.len(), 171 | 1 172 | ); 173 | 174 | assert_eq!( 175 | params.first().unwrap(), 176 | "x", 177 | "parameter is not 'x'. got {}", 178 | params.first().unwrap() 179 | ); 180 | 181 | assert_eq!( 182 | body.to_string(), 183 | "(x + 2)", 184 | "body is not '(x + 2)'. got {}", 185 | body.to_string() 186 | ); 187 | } 188 | _ => panic!("evaluated value is not a Value::Function"), 189 | } 190 | } 191 | 192 | #[test] 193 | fn test_function_appliction() { 194 | let tests = vec![ 195 | ("let identity = fn(x) { x; }; identity(5);", 5), 196 | ("let identity = fn(x) { return x; }; identity(5);", 5), 197 | ("let double = fn(x) { x * 2; }; double(5);", 10), 198 | ("let add = fn(x, y) { x + y; }; add(5, 5);", 10), 199 | ("let add = fn(x, y) { x + y; }; add(5 + 5, add(5, 5));", 20), 200 | ("fn(x) { x; }(5)", 5), 201 | ]; 202 | 203 | for (input, expected) in tests { 204 | let evaluated = test_eval(input); 205 | test_integer_object(evaluated, expected); 206 | } 207 | } 208 | 209 | #[test] 210 | fn test_strings() { 211 | let input = r#" 212 | let greet = fn(name, age) { 213 | "Hello, " + name + "! You are " + age + " years old."; 214 | }; 215 | 216 | greet("Cameron", 19); 217 | "#; 218 | 219 | let evaluated = test_eval(input); 220 | 221 | assert_eq!( 222 | evaluated.to_string(), 223 | "Hello, Cameron! You are 19 years old." 224 | ); 225 | } 226 | 227 | #[test] 228 | fn test_built_in_funcs() { 229 | let tests = vec![ 230 | ("len(\"\")", 0), 231 | ("len(\"five\")", 4) 232 | ]; 233 | 234 | for (input, expected) in tests { 235 | let evaluated = test_eval(input); 236 | test_integer_object(evaluated, expected); 237 | } 238 | } -------------------------------------------------------------------------------- /lib/eval/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, rc::Rc}; 2 | 3 | use crate::{ 4 | parser::{ 5 | ast::{Ast, Expression, Statement}, 6 | program::Program, 7 | }, 8 | token::Token, 9 | }; 10 | 11 | use self::value::{Truth, Value}; 12 | use env::Environment; 13 | use funcs::get_function; 14 | 15 | pub mod env; 16 | pub mod funcs; 17 | pub mod value; 18 | 19 | #[cfg(test)] 20 | mod tests; 21 | 22 | pub type EvaluatorErr = String; 23 | 24 | #[derive(Default)] 25 | pub struct Evaluator { 26 | env: Rc>, 27 | } 28 | 29 | impl Evaluator { 30 | pub fn new() -> Self { 31 | Evaluator { 32 | env: Rc::new(RefCell::new(Environment::default())), 33 | } 34 | } 35 | // Main entry point 36 | pub fn eval_with_environment( 37 | ast: &Ast, 38 | env: Rc>, 39 | ) -> Result { 40 | let mut evaluator = Evaluator { env }; 41 | match ast { 42 | Ast::Program(prog) => evaluator.eval_program(prog), 43 | Ast::Statement(stmt) => evaluator.eval_statement(stmt), 44 | Ast::Expression(expr) => evaluator.eval_expression(expr), 45 | } 46 | } 47 | 48 | // Entry point method with a new Environment (no local variables set) 49 | pub fn eval(ast: &Ast) -> Result { 50 | Evaluator::eval_with_environment(ast, Rc::new(RefCell::new(Environment::default()))) 51 | } 52 | 53 | pub fn eval_self(&mut self, ast: &Ast) -> Result { 54 | match ast { 55 | Ast::Program(prog) => self.eval_program(prog), 56 | Ast::Statement(stmt) => self.eval_statement(stmt), 57 | Ast::Expression(expr) => self.eval_expression(expr), 58 | } 59 | } 60 | 61 | fn eval_statement(&mut self, stmt: &Statement) -> Result { 62 | match stmt { 63 | Statement::LetStatement { ident, value } => { 64 | let value = self.eval_expression(value)?; 65 | 66 | // Set the value in the map and return the value 67 | Ok(self.env.borrow_mut().set(ident.to_string(), value)) 68 | } 69 | Statement::BlockStatement(statements) => self.eval_block(statements), 70 | Statement::ReturnStatement(expr) => { 71 | let value = self.eval_expression(expr)?; 72 | Ok(Value::Return(Box::new(value))) 73 | } 74 | Statement::ExpressionStatement(expr) => self.eval_expression(expr), 75 | } 76 | } 77 | 78 | fn eval_expression(&mut self, expr: &Expression) -> Result { 79 | match expr { 80 | Expression::IntExpression(i) => Ok(Value::Integer(*i)), 81 | Expression::BooleanExpression(b) => Ok(Value::Boolean(*b)), 82 | Expression::IdentifierExpression(s) => self.eval_identifier(s), 83 | Expression::PrefixExpression { op_token, right } => { 84 | let right = self.eval_expression(right)?; 85 | self.eval_prefix_expression(op_token, right) 86 | } 87 | Expression::InfixExpression { 88 | left, 89 | op_token, 90 | right, 91 | } => { 92 | let left = self.eval_expression(left)?; 93 | let right = self.eval_expression(right)?; 94 | self.eval_infix_expression(left, op_token, right) 95 | } 96 | Expression::IfExpression { 97 | condition, 98 | consequence, 99 | alternative, 100 | } => { 101 | let condition = self.eval_expression(condition)?; 102 | self.eval_if_expression(condition, consequence, alternative.as_deref()) 103 | } 104 | Expression::FunctionExpression { parameters, body } => Ok(Value::Function { 105 | params: parameters.clone(), 106 | body: body.clone(), 107 | env: Rc::clone(&self.env), 108 | }), 109 | Expression::CallExpression { 110 | function, 111 | arguments, 112 | } => { 113 | let function = self.eval_expression(function)?; 114 | 115 | // Evaluate every argument into a Vec or return an error if it happens 116 | let arguments = arguments 117 | .iter() 118 | .map(|arg| self.eval_expression(arg)) 119 | .collect::, EvaluatorErr>>()?; 120 | 121 | let result = self.apply_function(function, arguments)?; 122 | 123 | Ok(match result { 124 | Value::Return(v) => *v, 125 | _ => result, 126 | }) 127 | } 128 | Expression::StringExpression(s) => Ok(Value::String(s.to_string())), 129 | } 130 | } 131 | 132 | fn eval_program(&mut self, program: &Program) -> Result { 133 | let mut stmt_value = Value::Null; 134 | 135 | for stmt in &program.statments { 136 | stmt_value = self.eval_statement(stmt)?; 137 | 138 | // In evaluating the program we want to return the value of the return statement 139 | if let Value::Return(val) = stmt_value { 140 | return Ok(*val); 141 | } 142 | } 143 | 144 | Ok(stmt_value) 145 | } 146 | 147 | fn eval_block(&mut self, block: &Vec) -> Result { 148 | let mut stmt_value = Value::Null; 149 | 150 | for stmt in block { 151 | stmt_value = self.eval_statement(stmt)?; 152 | 153 | // In evaluating the block statement we only want to return the Value::Return object 154 | if let Value::Return(_) = stmt_value { 155 | return Ok(stmt_value); 156 | } 157 | } 158 | 159 | Ok(stmt_value) 160 | } 161 | 162 | fn eval_prefix_expression( 163 | &self, 164 | operator: &Token, 165 | right: Value, 166 | ) -> Result { 167 | match (operator, &right) { 168 | // Negate the truth value 169 | (token![!], right) => Ok((!right.truth()).into()), 170 | // Only apply the negative operator when its an integer 171 | (token![-], Value::Integer(i)) => Ok(Value::Integer(-i)), 172 | _ => Err(format!("Invalid prefix expression!\n\t({operator}{right})")), 173 | } 174 | } 175 | 176 | fn eval_infix_expression( 177 | &self, 178 | left: Value, 179 | operator: &Token, 180 | right: Value, 181 | ) -> Result { 182 | match (&left, operator, &right) { 183 | (Value::Integer(l), _, Value::Integer(r)) => { 184 | self.eval_integer_infix_expression(*l, operator, *r) 185 | } 186 | (Value::Boolean(l), token![==], Value::Boolean(r)) => Ok((l == r).into()), 187 | (Value::Boolean(l), token![!=], Value::Boolean(r)) => Ok((l != r).into()), 188 | 189 | // String concatenation 190 | (Value::String(l), token![+], Value::String(r)) => Ok((l.to_owned() + r).into()), 191 | (Value::String(l), token![+], Value::Integer(r)) => Ok((format!("{l}{r}")).into()), 192 | (Value::Integer(l), token![+], Value::String(r)) => Ok((format!("{l}{r}")).into()), 193 | _ => Err(format!( 194 | "Invalid infix expression!\n({left} {operator} {right})" 195 | )), 196 | } 197 | } 198 | 199 | fn eval_integer_infix_expression( 200 | &self, 201 | left: i64, 202 | operator: &Token, 203 | right: i64, 204 | ) -> Result { 205 | match operator { 206 | // Returns a Value::Integer 207 | token![+] => Ok((left + right).into()), 208 | token![-] => Ok((left - right).into()), 209 | token![*] => Ok((left * right).into()), 210 | token![/] => Ok((left / right).into()), 211 | token![%] => Ok((left % right).into()), 212 | // Returns a Value::Boolean 213 | token![<] => Ok((left < right).into()), 214 | token![>] => Ok((left > right).into()), 215 | token![==] => Ok((left == right).into()), 216 | token![!=] => Ok((left != right).into()), 217 | _ => return Err(format!("Invalid integer infix operator!\n\t({left} {operator} {right}).\n {operator} is not a valid integer operator")), 218 | } 219 | } 220 | 221 | fn eval_if_expression( 222 | &mut self, 223 | condition: Value, 224 | consequence: &Statement, 225 | alternative: Option<&Statement>, 226 | ) -> Result { 227 | // If the condition is true then we evaluate the first block 228 | if condition.truth() { 229 | return self.eval_statement(consequence); 230 | // if the condition is not true and the alternative is defined then we evalue that 231 | } else if let Some(alt) = alternative { 232 | return self.eval_statement(alt); 233 | } 234 | 235 | // Not an error. this means nothing was done from the if statement 236 | Ok(Value::Null) 237 | } 238 | 239 | fn eval_identifier(&self, name: &String) -> Result { 240 | let env_indent = self.env.borrow().get(name); 241 | 242 | // If could not find the identifier in the current environment then check the built in functions 243 | if let Err(msg) = env_indent { 244 | return match get_function(name) { 245 | Some(func) => Ok(Value::BuiltInFunction { func }), 246 | None => Err(msg), 247 | }; 248 | } 249 | 250 | env_indent 251 | } 252 | 253 | fn apply_function(&self, func: Value, arguments: Vec) -> Result { 254 | match func { 255 | Value::BuiltInFunction { func } => func(arguments), 256 | Value::Function { params, body, env } => { 257 | let func_env = self.setup_function_env(env, params, arguments); 258 | 259 | let result = 260 | Evaluator::eval_with_environment(&Ast::Statement(*body), func_env)?; 261 | 262 | Ok(result) 263 | } 264 | _ => Err(format!( 265 | "apply_function had an error. func is not of type Value::Function or Value::BuiltInFunction. got {func}" 266 | )), 267 | } 268 | } 269 | 270 | fn setup_function_env( 271 | &self, 272 | function_env: Rc>, 273 | params: Vec, 274 | arguments: Vec, 275 | ) -> Rc> { 276 | let function_env = Environment::new_enclosed(function_env); 277 | 278 | for (i, param) in params.iter().enumerate() { 279 | function_env 280 | .borrow_mut() 281 | .set(param.to_string(), arguments[i].clone()); 282 | } 283 | 284 | function_env 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /lib/parser/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ast; 2 | pub mod precedence; 3 | pub mod program; 4 | 5 | #[cfg(test)] 6 | mod tests; 7 | 8 | use crate::lexer::Lexer; 9 | use crate::token::Token; 10 | use program::Program; 11 | 12 | use ast::{Expression, Statement}; 13 | 14 | use precedence::Precedence; 15 | 16 | pub struct Parser<'a> { 17 | lexer: Lexer<'a>, 18 | curr_token: Token, 19 | next_token: Token, 20 | pub errors: Vec, 21 | } 22 | 23 | #[allow(dead_code)] 24 | impl<'a> Parser<'a> { 25 | pub fn new(lexer: Lexer<'a>) -> Self { 26 | let mut p = Parser { 27 | lexer, 28 | curr_token: token![ILLEGAL], 29 | next_token: token![ILLEGAL], 30 | errors: Vec::new(), 31 | }; 32 | 33 | // Read 2 tokens so that curr_token and next_token are both set 34 | p.advance_tokens(); 35 | p.advance_tokens(); 36 | 37 | p 38 | } 39 | 40 | fn advance_tokens(&mut self) { 41 | self.curr_token = self.next_token.clone(); 42 | self.next_token = self.lexer.next_token(); 43 | } 44 | 45 | pub fn parse_program(&mut self) -> Program { 46 | let mut program = Program::default(); 47 | 48 | while self.curr_token != token![EOF] { 49 | let stmt = self.parse_statement(); 50 | 51 | if let Some(statement) = stmt { 52 | program.statments.push(statement); 53 | } 54 | 55 | self.advance_tokens(); 56 | } 57 | 58 | program 59 | } 60 | 61 | fn parse_statement(&mut self) -> Option { 62 | match self.curr_token { 63 | token![LET] => self.parse_let_statement(), 64 | token![RETURN] => self.parse_return_statement(), 65 | _ => self.parse_expression_statement(), 66 | } 67 | } 68 | 69 | fn parse_expression_statement(&mut self) -> Option { 70 | if let Some(expr) = self.parse_expression(Precedence::Lowest) { 71 | if self.is_next_token(Token::Semicolon) { 72 | self.advance_tokens(); 73 | } 74 | 75 | return Some(Statement::ExpressionStatement(expr)); 76 | } 77 | None 78 | } 79 | 80 | fn parse_expression(&mut self, precedence: Precedence) -> Option { 81 | // Get the first expression 82 | let prefix = self.parse_prefix(); 83 | 84 | // Something has messed up with other logic if this code runs 85 | if prefix.is_none() { 86 | self.report_error(format!("no prefix parse function for {}", self.curr_token)); 87 | return None; 88 | } 89 | 90 | // We loop through and update the expression as it grow in size 91 | let mut left = prefix.unwrap(); 92 | 93 | // Loop until we hit a semicolon or a token with a lower precedence 94 | while !self.is_next_token(token![;]) && precedence < Precedence::from(&self.next_token) { 95 | // Get the infix expression 96 | if let Some(infix) = self.parse_infix(&left) { 97 | left = infix; 98 | } else { 99 | return Some(left); 100 | } 101 | } 102 | 103 | Some(left) 104 | } 105 | 106 | fn parse_prefix(&mut self) -> Option { 107 | match &self.curr_token { 108 | Token::Ident(name) => Some(self.parse_identifier(name.clone())), 109 | Token::Int(i) => Some(self.parse_integer(*i)), 110 | Token::String(val) => Some(self.parse_string(val.clone())), 111 | token![TRUE] | token![FALSE] => Some(self.parse_boolean_expression()), 112 | token![!] | token![-] => self.parse_prefix_expression(), 113 | token!['('] => self.parse_grouped_expression(), 114 | token![IF] => self.parse_if_expression(), 115 | token![FN] => self.parse_function_expression(), 116 | _ => None, 117 | } 118 | } 119 | 120 | fn parse_infix(&mut self, left: &Expression) -> Option { 121 | // Advance the tokens only if we have a valid infix operator 122 | match &self.next_token { 123 | token![+] 124 | | token![-] 125 | | token![*] 126 | | token![/] 127 | | token![%] 128 | | token![==] 129 | | token![!=] 130 | | token![<] 131 | | token![>] => { 132 | self.advance_tokens(); 133 | self.parse_infix_expression(left.clone()) 134 | } 135 | token!['('] => { 136 | self.advance_tokens(); 137 | self.parse_call_expression(left.clone()) 138 | } 139 | _ => None, 140 | } 141 | } 142 | 143 | fn is_curr_token(&self, token: Token) -> bool { 144 | self.curr_token == token 145 | } 146 | 147 | fn is_next_token(&self, token: Token) -> bool { 148 | self.next_token == token 149 | } 150 | 151 | fn expect_next_token(&mut self, token: Token) -> bool { 152 | if self.is_next_token(token.clone()) { 153 | return true; 154 | } 155 | 156 | self.report_error(format!( 157 | "expected next token to be {}, got {} instead", 158 | token, self.next_token 159 | )); 160 | false 161 | } 162 | 163 | fn report_error(&mut self, msg: String) { 164 | self.errors.push(msg); 165 | } 166 | 167 | fn advance_if_expected(&mut self, token: Token) -> bool { 168 | if self.expect_next_token(token) { 169 | self.advance_tokens(); 170 | return true; 171 | } 172 | false 173 | } 174 | 175 | fn parse_let_statement(&mut self) -> Option { 176 | // Make sure we have an identifier after the let keyword 177 | let identifier = match &self.next_token { 178 | Token::Ident(_s) => { 179 | self.advance_tokens(); 180 | self.curr_token.clone() 181 | } 182 | _ => return None, 183 | }; 184 | 185 | if !self.advance_if_expected(token![=]) { 186 | return None; 187 | } 188 | 189 | // Advance past the '=' 190 | self.advance_tokens(); 191 | 192 | // Parse the expression 193 | if let Some(value) = self.parse_expression(Precedence::Lowest) { 194 | if self.is_next_token(token![;]) { 195 | self.advance_tokens(); 196 | } 197 | 198 | return Some(Statement::LetStatement { 199 | ident: identifier, 200 | value, 201 | }); 202 | } 203 | None 204 | } 205 | 206 | fn parse_return_statement(&mut self) -> Option { 207 | // Advance past the return keyword 208 | self.advance_tokens(); 209 | 210 | // Parse the expression 211 | if let Some(value) = self.parse_expression(Precedence::Lowest) { 212 | if self.is_next_token(token![;]) { 213 | self.advance_tokens(); 214 | } 215 | return Some(Statement::ReturnStatement(value)); 216 | } 217 | None 218 | } 219 | 220 | fn parse_identifier(&self, name: String) -> Expression { 221 | Expression::IdentifierExpression(name) 222 | } 223 | 224 | fn parse_integer(&self, value: i64) -> Expression { 225 | Expression::IntExpression(value) 226 | } 227 | 228 | fn parse_string(&self, value: String) -> Expression { 229 | Expression::StringExpression(value) 230 | } 231 | 232 | // This function is called when we have an operator and an expression after it 233 | fn parse_prefix_expression(&mut self) -> Option { 234 | let op_token = self.curr_token.clone(); 235 | 236 | self.advance_tokens(); 237 | 238 | if let Some(right) = self.parse_expression(Precedence::Prefix) { 239 | return Some(Expression::PrefixExpression { 240 | op_token, 241 | right: Box::new(right), 242 | }); 243 | } 244 | None 245 | } 246 | 247 | // This function is called when we have a left expression and a right expression and an operator in between them 248 | fn parse_infix_expression(&mut self, left: Expression) -> Option { 249 | let op_token = self.curr_token.clone(); 250 | let curr_precedence = Precedence::from(&op_token); 251 | 252 | self.advance_tokens(); 253 | 254 | if let Some(right) = self.parse_expression(curr_precedence) { 255 | return Some(Expression::InfixExpression { 256 | left: Box::new(left), 257 | op_token, 258 | right: Box::new(right), 259 | }); 260 | } 261 | None 262 | } 263 | 264 | fn parse_boolean_expression(&self) -> Expression { 265 | Expression::BooleanExpression(self.is_curr_token(token![TRUE])) 266 | } 267 | 268 | fn parse_grouped_expression(&mut self) -> Option { 269 | self.advance_tokens(); 270 | 271 | let expr = self.parse_expression(Precedence::Lowest); 272 | 273 | // If it does not end with a ')', then we have an error 274 | if !self.advance_if_expected(token![')']) { 275 | return None; 276 | } 277 | 278 | expr 279 | } 280 | 281 | fn parse_if_expression(&mut self) -> Option { 282 | self.advance_tokens(); 283 | 284 | let condition = self.parse_expression(Precedence::Lowest); 285 | 286 | if !self.advance_if_expected(token!['{']) { 287 | return None; 288 | } 289 | 290 | let consequence = self.parse_block_statement(); 291 | 292 | if self.is_next_token(token![ELSE]) { 293 | // ELSE is now curr_token 294 | self.advance_tokens(); 295 | 296 | // '{' is now curr_token 297 | if !self.advance_if_expected(token!['{']) { 298 | return None; 299 | } 300 | 301 | let alternative = self.parse_block_statement(); 302 | 303 | // // Advance past this if it was what ended the block statement 304 | // if self.is_curr_token(token!['}']) { 305 | // self.advance_tokens(); 306 | // } 307 | 308 | return Some(Expression::IfExpression { 309 | condition: Box::new(condition.unwrap()), 310 | consequence: Box::new(consequence), 311 | alternative: Some(Box::new(alternative)), 312 | }); 313 | } 314 | 315 | Some(Expression::IfExpression { 316 | condition: Box::new(condition.unwrap()), 317 | consequence: Box::new(consequence), 318 | alternative: None, 319 | }) 320 | } 321 | 322 | fn parse_block_statement(&mut self) -> Statement { 323 | self.advance_tokens(); 324 | let mut statements = Vec::new(); 325 | 326 | while !self.is_curr_token(token!['}']) && !self.is_curr_token(token![EOF]) { 327 | if let Some(stmt) = self.parse_statement() { 328 | statements.push(stmt); 329 | } 330 | 331 | self.advance_tokens(); 332 | } 333 | 334 | Statement::BlockStatement(statements) 335 | } 336 | 337 | fn parse_function_expression(&mut self) -> Option { 338 | if !self.advance_if_expected(token!['(']) { 339 | return None; 340 | } 341 | 342 | let parameters = self.parse_function_parameters(); 343 | 344 | if !self.advance_if_expected(token!['{']) { 345 | return None; 346 | } 347 | 348 | let body = self.parse_block_statement(); 349 | 350 | Some(Expression::FunctionExpression { 351 | parameters: parameters.unwrap(), 352 | body: Box::new(body), 353 | }) 354 | } 355 | 356 | fn parse_function_parameters(&mut self) -> Option> { 357 | let mut identifiers = Vec::new(); 358 | 359 | if self.is_next_token(token![')']) { 360 | self.advance_tokens(); 361 | return Some(identifiers); 362 | } 363 | 364 | // Move the first parameter into curr_token 365 | self.advance_tokens(); 366 | 367 | // Add the first parameter to the list 368 | match &self.curr_token { 369 | Token::Ident(name) => { 370 | identifiers.push(name.clone()); 371 | } 372 | _ => self.report_error(format!( 373 | "Failure in parse_function_parameters. expected Token::Ident, got {} instead", 374 | self.curr_token 375 | )), 376 | } 377 | 378 | while self.is_next_token(token![,]) { 379 | self.advance_tokens(); 380 | self.advance_tokens(); 381 | 382 | 383 | match &self.curr_token { 384 | Token::Ident(name) => { 385 | identifiers.push(name.clone()); 386 | } 387 | _ => self.report_error(format!( 388 | "Failure in parse_function_parameters. expected Token::Ident, got {} instead", 389 | self.curr_token 390 | )), 391 | } 392 | } 393 | 394 | if !self.advance_if_expected(token![')']) { 395 | return None; 396 | } 397 | 398 | Some(identifiers) 399 | } 400 | 401 | fn parse_call_expression(&mut self, function: Expression) -> Option { 402 | let arguments = self.parse_call_arguments(); 403 | 404 | Some(Expression::CallExpression { 405 | function: Box::new(function), 406 | arguments: arguments.unwrap_or_default(), 407 | }) 408 | } 409 | 410 | fn parse_call_arguments(&mut self) -> Option> { 411 | let mut arguments = Vec::new(); 412 | 413 | if self.is_next_token(token![')']) { 414 | self.advance_tokens(); 415 | return Some(arguments); 416 | } 417 | 418 | // Move the first argument into curr_token 419 | self.advance_tokens(); 420 | 421 | // Add the first argument to the list 422 | arguments.push(self.parse_expression(Precedence::Lowest).unwrap()); 423 | 424 | while self.is_next_token(token![,]) { 425 | self.advance_tokens(); 426 | self.advance_tokens(); 427 | arguments.push(self.parse_expression(Precedence::Lowest).unwrap()); 428 | } 429 | 430 | if !self.advance_if_expected(token![')']) { 431 | return None; 432 | } 433 | 434 | Some(arguments) 435 | } 436 | } 437 | -------------------------------------------------------------------------------- /lib/parser/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{lexer::Lexer, token::Token}; 2 | 3 | use super::{ 4 | ast::{Expression, Statement}, 5 | program::Program, 6 | Parser, 7 | }; 8 | 9 | fn test_parser_errors(parser: &Parser) { 10 | if parser.errors.is_empty() { 11 | return; 12 | } 13 | 14 | println!("parser has {} errors", parser.errors.len()); 15 | for error in &parser.errors { 16 | println!("parser error: {}", error); 17 | } 18 | panic!("parser has {} errors", parser.errors.len()); 19 | } 20 | 21 | fn setup_and_validate(input: &str, expected_statements: usize) -> Program { 22 | let lexer = Lexer::new(input); 23 | let mut parser = Parser::new(lexer); 24 | 25 | let program = parser.parse_program(); 26 | test_parser_errors(&parser); 27 | 28 | assert_eq!( 29 | program.statments.len(), 30 | expected_statements, 31 | "program.statements does not contain {} statements. got={:?}", 32 | expected_statements, 33 | program.statments 34 | ); 35 | 36 | program 37 | } 38 | 39 | #[test] 40 | fn test_parse_let_statements() { 41 | let tests = vec![ 42 | ("let x = 5;", "x", "5"), 43 | ("let y = true;", "y", "true"), 44 | ("let foobar = y;", "foobar", "y"), 45 | ]; 46 | 47 | for (input, expected_ident, expected_value) in tests { 48 | let program = setup_and_validate(input, 1); 49 | 50 | let stmt = program.statments.first().unwrap(); 51 | 52 | test_let_statement(stmt, expected_ident, expected_value); 53 | } 54 | } 55 | 56 | fn test_let_statement(smt: &Statement, expected_name: &str, expected_value: &str) { 57 | match smt { 58 | Statement::LetStatement { ident, value } => match ident { 59 | Token::Ident(name) => { 60 | assert_eq!(expected_name, name, "ident not '{}'. got={}", expected_name, name ); 61 | assert_eq!(expected_value, value.to_string(), "value not '{}'. got={}", expected_value, value) 62 | }, 63 | _ => panic!("ident not Token::Ident. got={}", ident), 64 | }, 65 | _ => panic!("smt not Statement::LetStatement. got={}", smt), 66 | } 67 | } 68 | 69 | #[test] 70 | fn test_parse_return_statements() { 71 | let tests = vec![ 72 | ("return 5;", "5"), 73 | ("return x;", "x"), 74 | ]; 75 | 76 | for (input, expected_value) in tests { 77 | let program = setup_and_validate(input, 1); 78 | 79 | let stmt = program.statments.first().unwrap(); 80 | 81 | match stmt { 82 | Statement::ReturnStatement(return_value) => { 83 | assert_eq!(expected_value, return_value.to_string(), "return_value not '{}'. got={}", expected_value, return_value) 84 | }, 85 | _ => panic!("stmt not Statement::ReturnStatement. got={}", stmt), 86 | } 87 | } 88 | } 89 | 90 | #[test] 91 | fn test_parse_ident_expression() { 92 | let input = "foobar;"; 93 | 94 | let program = setup_and_validate(input, 1); 95 | 96 | let stmt = program.statments.first().unwrap(); 97 | match stmt { 98 | Statement::ExpressionStatement(expr) => test_identifier(expr, "foobar"), 99 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 100 | } 101 | } 102 | 103 | fn test_identifier(expr: &Expression, value: &str) { 104 | match expr { 105 | Expression::IdentifierExpression(ident) => { 106 | assert_eq!(ident, value, "ident not '{}'. got={}", value, ident) 107 | } 108 | _ => panic!("expr not Expression::IdentifierExpression. got={}", expr), 109 | } 110 | } 111 | 112 | #[test] 113 | fn test_parse_integer_expression() { 114 | let input = "5;"; 115 | 116 | let program = setup_and_validate(input, 1); 117 | 118 | let stmt = program.statments.first().unwrap(); 119 | 120 | match stmt { 121 | Statement::ExpressionStatement(expr) => test_integer_expression(expr, &5), 122 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 123 | } 124 | } 125 | 126 | fn test_integer_expression(expr: &Expression, expect_value: &i64) { 127 | match expr { 128 | Expression::IntExpression(i) => { 129 | assert_eq!(i, expect_value, "value not '{}'. got={}", expect_value, i) 130 | } 131 | _ => panic!("expr not Expression::IntExpression. got={}", expr), 132 | } 133 | } 134 | 135 | #[test] 136 | fn test_parse_prefix_expression() { 137 | let input = "-15;"; 138 | 139 | let program = setup_and_validate(input, 1); 140 | 141 | let stmt = program.statments.first().unwrap(); 142 | 143 | match stmt { 144 | Statement::ExpressionStatement(expr) => match expr { 145 | Expression::PrefixExpression { op_token, right } => { 146 | assert_eq!( 147 | op_token, 148 | &Token::Minus, 149 | "op_token not '-'. got={}", 150 | op_token 151 | ); 152 | 153 | test_integer_expression(right, &15); 154 | } 155 | _ => panic!("expr not Expression::PrefixExpression. got={}", expr), 156 | }, 157 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 158 | } 159 | } 160 | 161 | #[test] 162 | fn test_parse_infix_expression() { 163 | let input = "5 + 4089;"; 164 | 165 | let program = setup_and_validate(input, 1); 166 | 167 | let stmt = program.statments.first().unwrap(); 168 | 169 | match stmt { 170 | Statement::ExpressionStatement(expr) => test_infix_expression(expr, "5", "+", "4089"), 171 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 172 | } 173 | } 174 | 175 | fn test_infix_expression( 176 | expr: &Expression, 177 | expect_left: &str, 178 | expect_op: &str, 179 | expect_right: &str, 180 | ) { 181 | match expr { 182 | Expression::InfixExpression { 183 | left, 184 | op_token, 185 | right, 186 | } => { 187 | assert_eq!( 188 | expect_left, 189 | left.to_string(), 190 | "left not '{}'. got={}", 191 | expect_left, 192 | left 193 | ); 194 | assert_eq!( 195 | op_token.to_string(), 196 | expect_op.to_string(), 197 | "op_token not '{}'. got={}", 198 | expect_op, 199 | op_token 200 | ); 201 | assert_eq!( 202 | expect_right, 203 | right.to_string(), 204 | "right not '{}'. got={}", 205 | expect_right, 206 | right 207 | ); 208 | } 209 | _ => panic!("expr not Expression::InfixExpression. got={}", expr), 210 | } 211 | } 212 | 213 | #[test] 214 | fn test_operator_precedence_parsing() { 215 | let tests = vec![ 216 | ("-a * b", "((-a) * b)"), 217 | ("!-a", "(!(-a))"), 218 | ("a + b + c", "((a + b) + c)"), 219 | ("a * b / c", "((a * b) / c)"), 220 | ("a + b / c", "(a + (b / c))"), 221 | ("a + b * c + d / e - f", "(((a + (b * c)) + (d / e)) - f)"), 222 | ("5 > 4 == 3 < 4", "((5 > 4) == (3 < 4))"), 223 | ( 224 | "3 + 4 * 5 == 3 * 1 + 4 * 5", 225 | "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))", 226 | ), 227 | ("3 > 5 == false", "((3 > 5) == false)"), 228 | ("3 < 5 == true", "((3 < 5) == true)"), 229 | ("(3 < 5) == true", "((3 < 5) == true)"), 230 | ("a * (b / c)", "(a * (b / c))"), 231 | ( 232 | "add(a, b, 1, 2 * 3, 4 + 5, add(6, 7 * 8))", 233 | "add(a, b, 1, (2 * 3), (4 + 5), add(6, (7 * 8)))", 234 | ), 235 | ]; 236 | 237 | for (input, expected) in tests { 238 | let lexer = Lexer::new(input); 239 | let mut parser = Parser::new(lexer); 240 | 241 | let program = parser.parse_program(); 242 | 243 | if !parser.errors.is_empty() { 244 | println!("parser has {} errors", parser.errors.len()); 245 | for error in &parser.errors { 246 | println!("parser error: {}", error); 247 | } 248 | panic!( 249 | "parser has {} errors. testcase: {}", 250 | parser.errors.len(), 251 | input 252 | ); 253 | } 254 | 255 | let actual = program.to_string(); 256 | assert_eq!(actual, expected, "expected={}, got={}", expected, actual); 257 | } 258 | } 259 | 260 | fn test_boolean_expression(expr: &Expression, expect_value: &bool) { 261 | match expr { 262 | Expression::BooleanExpression(b) => { 263 | assert_eq!(b, expect_value, "value not '{}'. got={}", expect_value, b) 264 | } 265 | _ => panic!("expr not Expression::BooleanExpression. got={}", expr), 266 | } 267 | } 268 | 269 | #[test] 270 | fn test_parse_boolean_expression() { 271 | let tests = vec![("true;", true), ("false;", false)]; 272 | 273 | for (input, expected) in tests { 274 | let program = setup_and_validate(input, 1); 275 | 276 | let stmt = program.statments.first().unwrap(); 277 | 278 | match stmt { 279 | Statement::ExpressionStatement(expr) => test_boolean_expression(expr, &expected), 280 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 281 | } 282 | } 283 | } 284 | 285 | #[test] 286 | fn test_parse_infix_boolean_expressions() { 287 | let tests = vec![ 288 | ("true == false;", true, "==", false), 289 | ("true != false;", true, "!=", false), 290 | ("false == false;", false, "==", false), 291 | ]; 292 | 293 | for (input, first, op, second) in tests { 294 | let program = setup_and_validate(input, 1); 295 | 296 | let stmt = program.statments.first().unwrap(); 297 | 298 | match stmt { 299 | Statement::ExpressionStatement(expr) => { 300 | test_infix_expression(expr, &first.to_string(), op, &second.to_string()) 301 | } 302 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 303 | } 304 | } 305 | } 306 | 307 | fn test_block_statements(stmt: &Statement, expect_len: usize, expect: Vec<&str>) { 308 | match stmt { 309 | Statement::BlockStatement(statements) => { 310 | assert_eq!( 311 | statements.len(), 312 | expect_len, 313 | "statements does not contain {} statements. got={:?}", 314 | expect_len, 315 | statements 316 | ); 317 | 318 | for (i, test) in expect.iter().enumerate() { 319 | let stmt = &statements[i]; 320 | assert_eq!(stmt.to_string(), *test, "stmt not '{}'. got={}", test, stmt); 321 | } 322 | } 323 | _ => panic!("stmt not Statement::BlockStatement. got={}", stmt), 324 | } 325 | } 326 | 327 | #[test] 328 | fn test_parse_if_expression() { 329 | let input = "if x < y { x }"; 330 | 331 | let program = setup_and_validate(input, 1); 332 | 333 | let stmt = program.statments.first().unwrap(); 334 | 335 | match stmt { 336 | Statement::ExpressionStatement(expr) => match expr { 337 | Expression::IfExpression { 338 | condition, 339 | consequence, 340 | alternative, 341 | } => { 342 | test_infix_expression(condition, "x", "<", "y"); 343 | 344 | test_block_statements(&consequence, 1, vec!["x"]); 345 | 346 | assert_eq!( 347 | alternative, &None, 348 | "alternative is not None. got={:?}", 349 | alternative 350 | ); 351 | } 352 | _ => panic!("expr not Expression::IfExpression. got={}", expr), 353 | }, 354 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 355 | } 356 | } 357 | 358 | #[test] 359 | fn test_parse_if_else_expression() { 360 | let input = "if x { x } else { y } "; 361 | 362 | let program = setup_and_validate(input, 1); 363 | 364 | let stmt = program.statments.first().unwrap(); 365 | 366 | match stmt { 367 | Statement::ExpressionStatement(expr) => match expr { 368 | Expression::IfExpression { 369 | condition, 370 | consequence, 371 | alternative, 372 | } => { 373 | test_identifier(condition, "x"); 374 | 375 | test_block_statements(&consequence, 1, vec!["x"]); 376 | 377 | match alternative { 378 | Some(alt) => test_block_statements(alt, 1, vec!["y"]), 379 | None => panic!("alternative is None. got={:?}", alternative), 380 | } 381 | } 382 | _ => panic!("expr not Expression::IfExpression. got={}", expr), 383 | }, 384 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 385 | } 386 | } 387 | 388 | #[test] 389 | fn test_parse_function_expression() { 390 | let input = "fn(x, y) { x + y; }"; 391 | 392 | let program = setup_and_validate(input, 1); 393 | 394 | let stmt = program.statments.first().unwrap(); 395 | 396 | match stmt { 397 | Statement::ExpressionStatement(expr) => match expr { 398 | Expression::FunctionExpression { parameters, body } => { 399 | assert_eq!( 400 | parameters.len(), 401 | 2, 402 | "parameters does not contain 2 parameters. got={:?}", 403 | parameters 404 | ); 405 | 406 | assert_eq!(parameters[0].to_string(), "x"); 407 | assert_eq!(parameters[1].to_string(), "y"); 408 | 409 | test_block_statements(body, 1, vec!["(x + y)"]); 410 | } 411 | _ => panic!("expr not Expression::FunctionExpression. got={}", expr), 412 | }, 413 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 414 | } 415 | } 416 | 417 | #[test] 418 | fn test_parse_function_call() { 419 | let input = "add(1, 2 * 3, 4 + 5);"; 420 | 421 | let program = setup_and_validate(input, 1); 422 | 423 | let stmt = program.statments.first().unwrap(); 424 | 425 | match stmt { 426 | Statement::ExpressionStatement(expr) => match expr { 427 | Expression::CallExpression { 428 | function, 429 | arguments, 430 | } => { 431 | test_identifier(function, "add"); 432 | 433 | assert_eq!( 434 | arguments.len(), 435 | 3, 436 | "arguments does not contain 3 arguments. got={:?}", 437 | arguments 438 | ); 439 | 440 | test_integer_expression(&arguments[0], &1); 441 | test_infix_expression(&arguments[1], "2", "*", "3"); 442 | test_infix_expression(&arguments[2], "4", "+", "5"); 443 | } 444 | _ => panic!("expr not Expression::CallExpression. got={}", expr), 445 | }, 446 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 447 | } 448 | } 449 | 450 | #[test] 451 | fn test_parse_string_expression() { 452 | let input = r#" "hello world" "#; 453 | 454 | let program = setup_and_validate(input, 1); 455 | 456 | let stmt = program.statments.first().unwrap(); 457 | 458 | match stmt { 459 | Statement::ExpressionStatement(expr) => match expr { 460 | Expression::StringExpression(s) => { 461 | assert_eq!(s, "hello world", "s not '{}'. got={}", "hello world", s) 462 | } 463 | _ => panic!("expr not Expression::CallExpression. got={}", expr), 464 | }, 465 | _ => panic!("stmt not Statement::ExpressionStatement. got={}", stmt), 466 | } 467 | } 468 | --------------------------------------------------------------------------------