diff --git a/Cargo.lock b/Cargo.lock index 6d50657..222f446 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,16 +1,32 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "interpreter" version = "0.1.0" dependencies = [ + "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" diff --git a/Cargo.toml b/Cargo.toml index 60ef0aa..629c937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,9 @@ name = "interpreter" version = "0.1.0" authors = ["ishanjain28 "] +edition = "2018" [dependencies] lazy_static = "1.4.0" +itertools = "0.8.2" diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index 3ac96f7..49b3327 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -1,5 +1,6 @@ use std::{ collections::HashMap, + fmt::{Display, Formatter, Result as FmtResult}, iter::Peekable, str::{self, Chars}, }; @@ -59,9 +60,9 @@ pub enum TokenType { Return, } -impl TokenType { - pub fn to_string(&self) -> &'static str { - match self { +impl Display for TokenType { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_str(match self { TokenType::Assign => "=", TokenType::Plus => "+", TokenType::Asterisk => "*", @@ -89,7 +90,7 @@ impl TokenType { eprintln!("{:?}", self); unreachable!() } - } + }) } } @@ -117,9 +118,9 @@ impl Token { } } -impl ToString for Token { - fn to_string(&self) -> String { - self.name.to_string().into() +impl Display for Token { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_fmt(format_args!("{}", self.name)) } } diff --git a/src/parser/ast/mod.rs b/src/parser/ast/mod.rs index a5181a0..323c685 100644 --- a/src/parser/ast/mod.rs +++ b/src/parser/ast/mod.rs @@ -4,10 +4,11 @@ use { lexer::{Token, TokenType}, parser::{Error as ParserError, Parser}, }, + itertools::Itertools, std::{ cmp::PartialOrd, convert::From, - fmt::{Display, Error as FmtError, Formatter}, + fmt::{Display, Formatter, Result as FmtResult}, }, }; @@ -17,13 +18,13 @@ pub struct Program { } impl Display for Program { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + fn fmt(&self, f: &mut Formatter) -> FmtResult { let mut out = String::new(); for statement in &self.statements { out.push_str(&statement.to_string()); } - write!(f, "{}", out) + f.write_str(&out) } } @@ -47,13 +48,13 @@ impl<'a> Statement { } } -impl ToString for Statement { - fn to_string(&self) -> String { +impl Display for Statement { + fn fmt(&self, f: &mut Formatter) -> FmtResult { match self { - Statement::Let(v) => v.to_string(), - Statement::Return(v) => v.to_string(), - Statement::ExpressionStatement(v) => v.to_string(), - Statement::BlockStatement(v) => v.to_string(), + Statement::Let(v) => f.write_str(&v.to_string()), + Statement::Return(v) => f.write_str(&v.to_string()), + Statement::ExpressionStatement(v) => f.write_str(&v.to_string()), + Statement::BlockStatement(v) => f.write_str(&v.to_string()), } } } @@ -61,13 +62,16 @@ impl ToString for Statement { #[derive(Debug, PartialEq)] pub struct LetStatement { // name field is to store the identifier of the binding - pub name: Identifier, + name: Identifier, // value is to store the expression that'll produce value - pub value: Option, + value: Option, } impl LetStatement { - pub fn new(name: Identifier, value: Option) -> Self { + pub fn new(name: Identifier) -> Self { + Self { name, value: None } + } + pub fn with_value(name: Identifier, value: Option) -> Self { Self { name, value } } // TODO: Implement code to parse let statement @@ -95,7 +99,7 @@ impl LetStatement { } impl Display for LetStatement { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + fn fmt(&self, f: &mut Formatter) -> FmtResult { let mut out = format!("{} {} = ", Self::token_literal(), self.name.value); if let Some(v) = &self.value { @@ -103,7 +107,7 @@ impl Display for LetStatement { out.push_str(&a); } out.push(';'); - write!(f, "{}", out) + f.write_str(&out) } } @@ -127,7 +131,7 @@ impl ReturnStatement { } impl Display for ReturnStatement { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + fn fmt(&self, f: &mut Formatter) -> FmtResult { let mut out = String::from(Self::token_literal()); if let Some(v) = &self.return_value { @@ -136,14 +140,14 @@ impl Display for ReturnStatement { out.push_str(&a); } out.push(';'); - write!(f, "{}", out) + f.write_str(&out) } } #[derive(Debug, PartialEq)] pub struct ExpressionStatement { - pub token: Token, - pub expression: Expression, + token: Token, + expression: Expression, } impl ExpressionStatement { @@ -162,9 +166,9 @@ impl ExpressionStatement { } } -impl ToString for ExpressionStatement { - fn to_string(&self) -> String { - String::from(self.expression.to_string()) +impl Display for ExpressionStatement { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_str(&self.expression.to_string()) } } @@ -187,6 +191,7 @@ pub enum Expression { InfixExpression(InfixExpression), BooleanExpression(BooleanExpression), IfExpression(IfExpression), + FunctionExpression(FunctionLiteral), // TODO: Temporary placeholder value. Should be removed once this section is done None, } @@ -220,26 +225,6 @@ impl Expression { } } - pub fn parse_identifier(_parser: &mut Parser, token: Token) -> Option { - Some(Self::Identifier(Identifier::new( - token.name, - &token.literal?, - ))) - } - - pub fn parse_integer_literal(parser: &mut Parser, token: Token) -> Option { - let n = match token.literal?.parse::() { - Ok(v) => v, - Err(e) => { - parser.errors.push(ParserError { - reason: e.to_string(), - }); - return None; - } - }; - Some(Self::IntegerLiteral(IntegerLiteral::new(TokenType::Int, n))) - } - pub fn parse_boolean(_parser: &mut Parser, token: Token) -> Option { Some(Self::BooleanExpression(BooleanExpression::new(token.name))) } @@ -295,49 +280,22 @@ impl Expression { ))) } } - - pub fn parse_prefix_expression(parser: &mut Parser, ctoken: Token) -> Option { - let next_token = parser.lexer.next()?; - let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?; - Some(Expression::PrefixExpression(PrefixExpression { - token: ctoken.clone(), - operator: ctoken.to_string().into(), - right: Box::new(right_expr), - })) - } - - pub fn parse_infix_expression( - parser: &mut Parser, - token: Token, - left_expr: Self, - ) -> Option { - let cprecedence = parser.current_precedence(&token.name); - let next_token = parser.lexer.next()?; - let right_expr = Expression::parse(parser, next_token, cprecedence)?; - Some(Expression::InfixExpression(InfixExpression::new( - token.clone(), - left_expr, - &token.to_string(), - right_expr, - ))) - } } impl Display for Expression { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - write!( - f, - "{}", - match self { - Expression::Identifier(v) => v.to_string(), - Expression::IntegerLiteral(v) => v.value.to_string(), - Expression::PrefixExpression(v) => v.to_string(), - Expression::InfixExpression(v) => v.to_string(), - Expression::BooleanExpression(v) => v.to_string(), - Expression::IfExpression(v) => v.to_string(), - Expression::None => "None".into(), - } - ) + fn fmt(&self, f: &mut Formatter) -> FmtResult { + let value = match self { + Expression::Identifier(v) => v.to_string(), + Expression::IntegerLiteral(v) => v.value.to_string(), + Expression::PrefixExpression(v) => v.to_string(), + Expression::InfixExpression(v) => v.to_string(), + Expression::BooleanExpression(v) => v.to_string(), + Expression::IfExpression(v) => v.to_string(), + Expression::FunctionExpression(v) => v.to_string(), + Expression::None => "None".into(), + }; + + f.write_str(&value) } } @@ -352,8 +310,8 @@ impl From<&Expression> for String { // but an identifier *can* produce value when used on rhs, e.g. let x = y; Here `y` is producing a value #[derive(Debug, PartialEq)] pub struct Identifier { - pub token: TokenType, - pub value: String, + token: TokenType, + value: String, } impl Identifier { @@ -363,11 +321,17 @@ impl Identifier { value: v.to_string(), } } + pub fn parse(_parser: &mut Parser, token: Token) -> Option { + Some(Expression::Identifier(Identifier::new( + token.name, + &token.literal?, + ))) + } } impl Display for Identifier { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - write!(f, "{}", self.value.clone()) + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_str(&self.value) } } @@ -384,6 +348,21 @@ impl IntegerLiteral { value: v, } } + pub fn parse(parser: &mut Parser, token: Token) -> Option { + let n = match token.literal?.parse::() { + Ok(v) => v, + Err(e) => { + parser.errors.push(ParserError { + reason: e.to_string(), + }); + return None; + } + }; + Some(Expression::IntegerLiteral(IntegerLiteral::new( + TokenType::Int, + n, + ))) + } } #[derive(Debug, PartialEq)] @@ -401,11 +380,25 @@ impl PrefixExpression { right: Box::new(right), } } + + pub fn parse(parser: &mut Parser, ctoken: Token) -> Option { + let next_token = parser.lexer.next()?; + let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?; + Some(Expression::PrefixExpression(PrefixExpression { + token: ctoken.clone(), + operator: ctoken.to_string().into(), + right: Box::new(right_expr), + })) + } } impl Display for PrefixExpression { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - write!(f, "({}{})", self.operator, self.right.to_string()) + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_fmt(format_args!( + "({}{})", + self.operator, + self.right.to_string() + )) } } @@ -426,17 +419,27 @@ impl InfixExpression { right: Box::new(right), } } + pub fn parse(parser: &mut Parser, token: Token, left_expr: Expression) -> Option { + let cprecedence = parser.current_precedence(&token.name); + let next_token = parser.lexer.next()?; + let right_expr = Expression::parse(parser, next_token, cprecedence)?; + Some(Expression::InfixExpression(InfixExpression::new( + token.clone(), + left_expr, + &token.to_string(), + right_expr, + ))) + } } impl Display for InfixExpression { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - write!( - f, + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_fmt(format_args!( "({} {} {})", self.left.to_string(), self.operator, - self.right.to_string() - ) + self.right.to_string(), + )) } } @@ -456,8 +459,8 @@ impl BooleanExpression { } impl Display for BooleanExpression { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - write!(f, "{}", self.value) + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_str(&self.value.to_string()) } } @@ -485,8 +488,8 @@ impl IfExpression { } } -impl ToString for IfExpression { - fn to_string(&self) -> String { +impl Display for IfExpression { + fn fmt(&self, f: &mut Formatter) -> FmtResult { let mut out = format!( "if {} {{ {} }} ", self.condition.to_string(), @@ -495,7 +498,7 @@ impl ToString for IfExpression { if let Some(alternative) = &self.alternative { out += &format!("else {{ {} }}", alternative.to_string()); } - out + f.write_str(&out) } } @@ -534,14 +537,89 @@ impl BlockStatement { } } -impl ToString for BlockStatement { - fn to_string(&self) -> String { +impl Display for BlockStatement { + fn fmt(&self, f: &mut Formatter) -> FmtResult { let mut out = String::new(); for stmt in &self.statements { out.push_str(&stmt.to_string()); } - out + f.write_str(&out) + } +} + +#[derive(Debug, PartialEq)] +pub struct FunctionLiteral { + token: Token, + parameters: Vec, + body: BlockStatement, +} + +impl FunctionLiteral { + pub fn new(token: Token, parameters: Vec, body: BlockStatement) -> Self { + Self { + token, + parameters, + body, + } + } + pub fn parse(parser: &mut Parser, ctoken: Token) -> Option { + if parser.expect_peek(TokenType::LParen).is_none() { + return None; + } + let ntoken = parser.lexer.peek()?.clone(); + let parameters = FunctionLiteral::parse_function_parameters(parser, ntoken)?; + + if parser.expect_peek(TokenType::LBrace).is_none() { + return None; + } + + let ntoken = parser.lexer.peek()?.clone(); + + let body = BlockStatement::parse(parser, ntoken)?; + + Some(Expression::FunctionExpression(Self { + token: ctoken, + parameters, + body, + })) + } + + fn parse_function_parameters(parser: &mut Parser, ctoken: Token) -> Option> { + let mut out = vec![]; + + if parser.peek_token_is(TokenType::RParen) { + parser.lexer.next(); + Some(out) + } else { + let ntoken = parser.lexer.next()?; + let ident = Identifier::new(ntoken.name, &ntoken.literal?); + out.push(ident); + + while parser.peek_token_is(TokenType::Comma) { + parser.lexer.next(); + let token = parser.lexer.next()?; + let ident = Identifier::new(token.name, &token.literal?); + out.push(ident); + } + + if parser.expect_peek(TokenType::RParen).is_none() { + return None; + } + + Some(out) + } + } +} +impl Display for FunctionLiteral { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_fmt(format_args!( + "{} {}({}) {}", + self.token.name.to_string(), + self.token.literal.as_ref().unwrap(), + self.parameters.iter().map(|x| x.to_string()).join(","), + "" + )) } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index b061e8c..6ca8f12 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -2,7 +2,7 @@ pub mod ast; use { crate::{ lexer::{Lexer, Token, TokenType}, - parser::ast::{Expression, ExpressionPriority, Program, Statement}, + parser::ast::*, }, std::{ collections::HashMap, @@ -47,23 +47,24 @@ impl<'a> Parser<'a> { infix_parse_fns: HashMap::new(), }; - parser.register_prefix(TokenType::Ident, Expression::parse_identifier); - parser.register_prefix(TokenType::Int, Expression::parse_integer_literal); - parser.register_prefix(TokenType::Bang, Expression::parse_prefix_expression); - parser.register_prefix(TokenType::Minus, Expression::parse_prefix_expression); + parser.register_prefix(TokenType::Ident, Identifier::parse); + parser.register_prefix(TokenType::Int, IntegerLiteral::parse); + parser.register_prefix(TokenType::Bang, PrefixExpression::parse); + parser.register_prefix(TokenType::Minus, PrefixExpression::parse); parser.register_prefix(TokenType::True, Expression::parse_boolean); parser.register_prefix(TokenType::False, Expression::parse_boolean); parser.register_prefix(TokenType::LParen, Expression::parse_grouped_expression); parser.register_prefix(TokenType::If, Expression::parse_if_expression); + parser.register_prefix(TokenType::Function, FunctionLiteral::parse); - parser.register_infix(TokenType::Plus, Expression::parse_infix_expression); - parser.register_infix(TokenType::Minus, Expression::parse_infix_expression); - parser.register_infix(TokenType::Slash, Expression::parse_infix_expression); - parser.register_infix(TokenType::Asterisk, Expression::parse_infix_expression); - parser.register_infix(TokenType::Equals, Expression::parse_infix_expression); - parser.register_infix(TokenType::NotEquals, Expression::parse_infix_expression); - parser.register_infix(TokenType::LessThan, Expression::parse_infix_expression); - parser.register_infix(TokenType::GreaterThan, Expression::parse_infix_expression); + parser.register_infix(TokenType::Plus, InfixExpression::parse); + parser.register_infix(TokenType::Minus, InfixExpression::parse); + parser.register_infix(TokenType::Slash, InfixExpression::parse); + parser.register_infix(TokenType::Asterisk, InfixExpression::parse); + parser.register_infix(TokenType::Equals, InfixExpression::parse); + parser.register_infix(TokenType::NotEquals, InfixExpression::parse); + parser.register_infix(TokenType::LessThan, InfixExpression::parse); + parser.register_infix(TokenType::GreaterThan, InfixExpression::parse); parser } @@ -153,8 +154,8 @@ pub struct Error { } impl Display for Error { - fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { - write!(fmt, "{}", self.reason) + fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + f.write_str(&self.reason) } } @@ -192,18 +193,9 @@ mod tests { program, Program { statements: vec![ - Statement::Let(LetStatement { - name: Identifier::new(TokenType::Let, "x"), - value: None - }), - Statement::Let(LetStatement { - name: Identifier::new(TokenType::Let, "y"), - value: None - }), - Statement::Let(LetStatement { - name: Identifier::new(TokenType::Let, "foobar"), - value: None - }) + Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "x"),)), + Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "y"),)), + Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "foobar"),)) ], } ); @@ -242,10 +234,10 @@ mod tests { assert_eq!(program.statements.len(), 1); assert_eq!( program.statements, - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Ident, "foobar"), - expression: Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")), - })] + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Ident, "foobar"), + Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")), + ))] ); } @@ -260,10 +252,10 @@ mod tests { assert_eq!( program.unwrap().statements, - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Int, "5"), - expression: Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)) - })] + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Int, "5"), + Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)) + ))] ); } @@ -272,58 +264,58 @@ mod tests { let prefix_tests = [ ( "!5", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::new(TokenType::Bang), - expression: Expression::PrefixExpression(PrefixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Bang), + Expression::PrefixExpression(PrefixExpression::new( Token::new(TokenType::Bang), "!", Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), )), - })], + ))], ), ( "-15;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::new(TokenType::Minus), - expression: Expression::PrefixExpression(PrefixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Minus), + Expression::PrefixExpression(PrefixExpression::new( Token::new(TokenType::Minus), "-", Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)), )), - })], + ))], ), ( "!foobar;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::new(TokenType::Bang), - expression: Expression::PrefixExpression(PrefixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Bang), + Expression::PrefixExpression(PrefixExpression::new( Token::new(TokenType::Bang), "!", Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")), )), - })], + ))], ), ( "!true;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::new(TokenType::Bang), - expression: Expression::PrefixExpression(PrefixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Bang), + Expression::PrefixExpression(PrefixExpression::new( Token::new(TokenType::Bang), "!", Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), )), - })], + ))], ), ( "!false;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::new(TokenType::Bang), - expression: Expression::PrefixExpression(PrefixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Bang), + Expression::PrefixExpression(PrefixExpression::new( Token::new(TokenType::Bang), "!", Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), )), - })], + ))], ), // TODO: Add this test when we add function call parser // ( @@ -357,69 +349,69 @@ mod tests { let infix_tests = [ ( "5 + 10;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Int, "5"), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Int, "5"), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::Plus), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), "+", Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)), )), - })], + ))], ), ( "5 - 10;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Int, "5"), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Int, "5"), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::Minus), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), "-", Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)), )), - })], + ))], ), ( "5 * 15;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Int, "5"), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Int, "5"), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::Asterisk), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), "*", Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)), )), - })], + ))], ), ( "15 / 3;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Int, "15"), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Int, "15"), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::Slash), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)), "/", Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 3)), )), - })], + ))], ), ( "5 > 15;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Int, "5"), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Int, "5"), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::GreaterThan), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), ">", Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)), )), - })], + ))], ), ( "a + b + c;", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Ident, "a"), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Ident, "a"), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::Plus), Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::Plus), @@ -430,43 +422,43 @@ mod tests { "+", Expression::Identifier(Identifier::new(TokenType::Ident, "c")), )), - })], + ))], ), ( "true == true", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::new(TokenType::True), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::True), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::Equals), Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), "==", Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), )), - })], + ))], ), ( "true != false", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::new(TokenType::True), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::True), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::NotEquals), Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), "!=", Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), )), - })], + ))], ), ( "false == false", - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::new(TokenType::False), - expression: Expression::InfixExpression(InfixExpression::new( + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::False), + Expression::InfixExpression(InfixExpression::new( Token::new(TokenType::Equals), Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), "==", Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), )), - })], + ))], ), ]; for test in infix_tests.iter() { @@ -548,7 +540,7 @@ mod tests { ( "let foobar = true;", Program { - statements: vec![Statement::Let(LetStatement::new( + statements: vec![Statement::Let(LetStatement::with_value( Identifier::new(TokenType::Let, "foobar"), None, // TODO: fix this when we complete parsing of let statements ))], @@ -583,13 +575,10 @@ mod tests { )), BlockStatement::new( Token::with_value(TokenType::Ident, "x"), - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Ident, "x"), - expression: Expression::Identifier(Identifier::new( - TokenType::Ident, - "x", - )), - })], + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Ident, "x"), + Expression::Identifier(Identifier::new(TokenType::Ident, "x")), + ))], ), None, )), @@ -624,23 +613,20 @@ mod tests { )), BlockStatement::new( Token::with_value(TokenType::Ident, "x"), - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Ident, "x"), - expression: Expression::Identifier(Identifier::new( - TokenType::Ident, - "x", - )), - })], + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Ident, "x"), + Expression::Identifier(Identifier::new(TokenType::Ident, "x")), + ))], ), Some(BlockStatement::new( + // TODO: Not sure if this is the right token to have here. + // Since, It's a block statement parser, I believe it *should* have the first token it encounters in the block + // Else is dealt with before the block starts so, maybe this is not the right token to have here. Will revisit later Token::new(TokenType::Else), - vec![Statement::ExpressionStatement(ExpressionStatement { - token: Token::with_value(TokenType::Ident, "y"), - expression: Expression::Identifier(Identifier::new( - TokenType::Ident, - "y", - )), - })], + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Ident, "y"), + Expression::Identifier(Identifier::new(TokenType::Ident, "y")), + ))], )), )), ))], @@ -657,4 +643,130 @@ mod tests { assert_eq!(program.unwrap(), test.1); } } + + #[test] + fn function_literal_expression() { + let test_cases = [ + ( + "fn(a,b) {x + y;}", + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Function), + Expression::FunctionExpression(FunctionLiteral::new( + Token::new(TokenType::Function), + vec![ + Identifier::new(TokenType::Ident, "a"), + Identifier::new(TokenType::Ident, "b"), + ], + BlockStatement::new( + Token::with_value(TokenType::Ident, "x"), + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::with_value(TokenType::Ident, "x"), + Expression::InfixExpression(InfixExpression::new( + Token::new(TokenType::Plus), + Expression::Identifier(Identifier::new(TokenType::Ident, "x")), + "+", + Expression::Identifier(Identifier::new(TokenType::Ident, "y")), + )), + ))], + ), + )), + ))], + ), + ( + "fn() {}", + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Function), + Expression::FunctionExpression(FunctionLiteral::new( + Token::new(TokenType::Function), + vec![], + BlockStatement::new(Token::new(TokenType::RBrace), vec![]), + )), + ))], + ), + ( + "fn(x,ya,z) {}", + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Function), + Expression::FunctionExpression(FunctionLiteral::new( + Token::new(TokenType::Function), + vec![ + Identifier::new(TokenType::Ident, "x"), + Identifier::new(TokenType::Ident, "ya"), + Identifier::new(TokenType::Ident, "z"), + ], + BlockStatement::new(Token::new(TokenType::RBrace), vec![]), + )), + ))], + ), + ( + "fn(a) {}", + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Function), + Expression::FunctionExpression(FunctionLiteral::new( + Token::new(TokenType::Function), + vec![Identifier::new(TokenType::Ident, "a")], + BlockStatement::new(Token::new(TokenType::RBrace), vec![]), + )), + ))], + ), + ( + "fn(a,b,abc) {(x + y) * (a -b);}", + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::Function), + Expression::FunctionExpression(FunctionLiteral::new( + Token::new(TokenType::Function), + vec![ + Identifier::new(TokenType::Ident, "a"), + Identifier::new(TokenType::Ident, "b"), + Identifier::new(TokenType::Ident, "abc"), + ], + BlockStatement::new( + Token::new(TokenType::LParen), + vec![Statement::ExpressionStatement(ExpressionStatement::new( + Token::new(TokenType::LParen), + Expression::InfixExpression(InfixExpression::new( + Token::new(TokenType::Asterisk), + Expression::InfixExpression(InfixExpression::new( + Token::new(TokenType::Plus), + Expression::Identifier(Identifier::new( + TokenType::Ident, + "x", + )), + "+", + Expression::Identifier(Identifier::new( + TokenType::Ident, + "y", + )), + )), + "*", + Expression::InfixExpression(InfixExpression::new( + Token::new(TokenType::Minus), + Expression::Identifier(Identifier::new( + TokenType::Ident, + "a", + )), + "-", + Expression::Identifier(Identifier::new( + TokenType::Ident, + "b", + )), + )), + )), + ))], + ), + )), + ))], + ), + ]; + + for test in test_cases.iter() { + let lexer = Lexer::new(test.0); + let mut parser = Parser::new(lexer); + let program = parser.parse_program(); + check_parser_errors(&parser); + assert_eq!(parser.errors.len(), 0); + assert!(program.is_some()); + assert_eq!(program.unwrap().statements, test.1); + } + } }