Added Function Literal parser

1. Added function literal parser.
2. Replaced all ToString impls with fmt::Display Impls.
3. Fixed few issues in existing fmt::Display impls.
4. Refactored Expression parsers
5. Added more tests to support new changes
This commit is contained in:
Ishan Jain 2020-01-20 14:45:21 +05:30
parent 44506cf591
commit 8536d0defa
5 changed files with 429 additions and 220 deletions

16
Cargo.lock generated
View File

@ -1,16 +1,32 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # 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]] [[package]]
name = "interpreter" name = "interpreter"
version = "0.1.0" version = "0.1.0"
dependencies = [ 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)", "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]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata] [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" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

View File

@ -2,7 +2,9 @@
name = "interpreter" name = "interpreter"
version = "0.1.0" version = "0.1.0"
authors = ["ishanjain28 <ishanjain28@gmail.com>"] authors = ["ishanjain28 <ishanjain28@gmail.com>"]
edition = "2018"
[dependencies] [dependencies]
lazy_static = "1.4.0" lazy_static = "1.4.0"
itertools = "0.8.2"

View File

@ -1,5 +1,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::{Display, Formatter, Result as FmtResult},
iter::Peekable, iter::Peekable,
str::{self, Chars}, str::{self, Chars},
}; };
@ -59,9 +60,9 @@ pub enum TokenType {
Return, Return,
} }
impl TokenType { impl Display for TokenType {
pub fn to_string(&self) -> &'static str { fn fmt(&self, f: &mut Formatter) -> FmtResult {
match self { f.write_str(match self {
TokenType::Assign => "=", TokenType::Assign => "=",
TokenType::Plus => "+", TokenType::Plus => "+",
TokenType::Asterisk => "*", TokenType::Asterisk => "*",
@ -89,7 +90,7 @@ impl TokenType {
eprintln!("{:?}", self); eprintln!("{:?}", self);
unreachable!() unreachable!()
} }
} })
} }
} }
@ -117,9 +118,9 @@ impl Token {
} }
} }
impl ToString for Token { impl Display for Token {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> FmtResult {
self.name.to_string().into() f.write_fmt(format_args!("{}", self.name))
} }
} }

View File

@ -4,10 +4,11 @@ use {
lexer::{Token, TokenType}, lexer::{Token, TokenType},
parser::{Error as ParserError, Parser}, parser::{Error as ParserError, Parser},
}, },
itertools::Itertools,
std::{ std::{
cmp::PartialOrd, cmp::PartialOrd,
convert::From, 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 { impl Display for Program {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> FmtResult {
let mut out = String::new(); let mut out = String::new();
for statement in &self.statements { for statement in &self.statements {
out.push_str(&statement.to_string()); out.push_str(&statement.to_string());
} }
write!(f, "{}", out) f.write_str(&out)
} }
} }
@ -47,13 +48,13 @@ impl<'a> Statement {
} }
} }
impl ToString for Statement { impl Display for Statement {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> FmtResult {
match self { match self {
Statement::Let(v) => v.to_string(), Statement::Let(v) => f.write_str(&v.to_string()),
Statement::Return(v) => v.to_string(), Statement::Return(v) => f.write_str(&v.to_string()),
Statement::ExpressionStatement(v) => v.to_string(), Statement::ExpressionStatement(v) => f.write_str(&v.to_string()),
Statement::BlockStatement(v) => v.to_string(), Statement::BlockStatement(v) => f.write_str(&v.to_string()),
} }
} }
} }
@ -61,13 +62,16 @@ impl ToString for Statement {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct LetStatement { pub struct LetStatement {
// name field is to store the identifier of the binding // 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 // value is to store the expression that'll produce value
pub value: Option<Expression>, value: Option<Expression>,
} }
impl LetStatement { impl LetStatement {
pub fn new(name: Identifier, value: Option<Expression>) -> Self { pub fn new(name: Identifier) -> Self {
Self { name, value: None }
}
pub fn with_value(name: Identifier, value: Option<Expression>) -> Self {
Self { name, value } Self { name, value }
} }
// TODO: Implement code to parse let statement // TODO: Implement code to parse let statement
@ -95,7 +99,7 @@ impl LetStatement {
} }
impl Display for 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); let mut out = format!("{} {} = ", Self::token_literal(), self.name.value);
if let Some(v) = &self.value { if let Some(v) = &self.value {
@ -103,7 +107,7 @@ impl Display for LetStatement {
out.push_str(&a); out.push_str(&a);
} }
out.push(';'); out.push(';');
write!(f, "{}", out) f.write_str(&out)
} }
} }
@ -127,7 +131,7 @@ impl ReturnStatement {
} }
impl Display for 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()); let mut out = String::from(Self::token_literal());
if let Some(v) = &self.return_value { if let Some(v) = &self.return_value {
@ -136,14 +140,14 @@ impl Display for ReturnStatement {
out.push_str(&a); out.push_str(&a);
} }
out.push(';'); out.push(';');
write!(f, "{}", out) f.write_str(&out)
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct ExpressionStatement { pub struct ExpressionStatement {
pub token: Token, token: Token,
pub expression: Expression, expression: Expression,
} }
impl ExpressionStatement { impl ExpressionStatement {
@ -162,9 +166,9 @@ impl ExpressionStatement {
} }
} }
impl ToString for ExpressionStatement { impl Display for ExpressionStatement {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> FmtResult {
String::from(self.expression.to_string()) f.write_str(&self.expression.to_string())
} }
} }
@ -187,6 +191,7 @@ pub enum Expression {
InfixExpression(InfixExpression), InfixExpression(InfixExpression),
BooleanExpression(BooleanExpression), BooleanExpression(BooleanExpression),
IfExpression(IfExpression), IfExpression(IfExpression),
FunctionExpression(FunctionLiteral),
// TODO: Temporary placeholder value. Should be removed once this section is done // TODO: Temporary placeholder value. Should be removed once this section is done
None, None,
} }
@ -220,26 +225,6 @@ impl Expression {
} }
} }
pub fn parse_identifier(_parser: &mut Parser, token: Token) -> Option<Self> {
Some(Self::Identifier(Identifier::new(
token.name,
&token.literal?,
)))
}
pub fn parse_integer_literal(parser: &mut Parser, token: Token) -> Option<Self> {
let n = match token.literal?.parse::<i64>() {
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<Self> { pub fn parse_boolean(_parser: &mut Parser, token: Token) -> Option<Self> {
Some(Self::BooleanExpression(BooleanExpression::new(token.name))) Some(Self::BooleanExpression(BooleanExpression::new(token.name)))
} }
@ -295,49 +280,22 @@ impl Expression {
))) )))
} }
} }
pub fn parse_prefix_expression(parser: &mut Parser, ctoken: Token) -> Option<Self> {
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<Self> {
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 { impl Display for Expression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!( let value = match self {
f, Expression::Identifier(v) => v.to_string(),
"{}", Expression::IntegerLiteral(v) => v.value.to_string(),
match self { Expression::PrefixExpression(v) => v.to_string(),
Expression::Identifier(v) => v.to_string(), Expression::InfixExpression(v) => v.to_string(),
Expression::IntegerLiteral(v) => v.value.to_string(), Expression::BooleanExpression(v) => v.to_string(),
Expression::PrefixExpression(v) => v.to_string(), Expression::IfExpression(v) => v.to_string(),
Expression::InfixExpression(v) => v.to_string(), Expression::FunctionExpression(v) => v.to_string(),
Expression::BooleanExpression(v) => v.to_string(), Expression::None => "None".into(),
Expression::IfExpression(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 // but an identifier *can* produce value when used on rhs, e.g. let x = y; Here `y` is producing a value
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Identifier { pub struct Identifier {
pub token: TokenType, token: TokenType,
pub value: String, value: String,
} }
impl Identifier { impl Identifier {
@ -363,11 +321,17 @@ impl Identifier {
value: v.to_string(), value: v.to_string(),
} }
} }
pub fn parse(_parser: &mut Parser, token: Token) -> Option<Expression> {
Some(Expression::Identifier(Identifier::new(
token.name,
&token.literal?,
)))
}
} }
impl Display for Identifier { impl Display for Identifier {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{}", self.value.clone()) f.write_str(&self.value)
} }
} }
@ -384,6 +348,21 @@ impl IntegerLiteral {
value: v, value: v,
} }
} }
pub fn parse(parser: &mut Parser, token: Token) -> Option<Expression> {
let n = match token.literal?.parse::<i64>() {
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)] #[derive(Debug, PartialEq)]
@ -401,11 +380,25 @@ impl PrefixExpression {
right: Box::new(right), right: Box::new(right),
} }
} }
pub fn parse(parser: &mut Parser, ctoken: Token) -> Option<Expression> {
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 { impl Display for PrefixExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "({}{})", self.operator, self.right.to_string()) f.write_fmt(format_args!(
"({}{})",
self.operator,
self.right.to_string()
))
} }
} }
@ -426,17 +419,27 @@ impl InfixExpression {
right: Box::new(right), right: Box::new(right),
} }
} }
pub fn parse(parser: &mut Parser, token: Token, left_expr: Expression) -> Option<Expression> {
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 { impl Display for InfixExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!( f.write_fmt(format_args!(
f,
"({} {} {})", "({} {} {})",
self.left.to_string(), self.left.to_string(),
self.operator, self.operator,
self.right.to_string() self.right.to_string(),
) ))
} }
} }
@ -456,8 +459,8 @@ impl BooleanExpression {
} }
impl Display for BooleanExpression { impl Display for BooleanExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{}", self.value) f.write_str(&self.value.to_string())
} }
} }
@ -485,8 +488,8 @@ impl IfExpression {
} }
} }
impl ToString for IfExpression { impl Display for IfExpression {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> FmtResult {
let mut out = format!( let mut out = format!(
"if {} {{ {} }} ", "if {} {{ {} }} ",
self.condition.to_string(), self.condition.to_string(),
@ -495,7 +498,7 @@ impl ToString for IfExpression {
if let Some(alternative) = &self.alternative { if let Some(alternative) = &self.alternative {
out += &format!("else {{ {} }}", alternative.to_string()); out += &format!("else {{ {} }}", alternative.to_string());
} }
out f.write_str(&out)
} }
} }
@ -534,14 +537,89 @@ impl BlockStatement {
} }
} }
impl ToString for BlockStatement { impl Display for BlockStatement {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> FmtResult {
let mut out = String::new(); let mut out = String::new();
for stmt in &self.statements { for stmt in &self.statements {
out.push_str(&stmt.to_string()); out.push_str(&stmt.to_string());
} }
out f.write_str(&out)
}
}
#[derive(Debug, PartialEq)]
pub struct FunctionLiteral {
token: Token,
parameters: Vec<Identifier>,
body: BlockStatement,
}
impl FunctionLiteral {
pub fn new(token: Token, parameters: Vec<Identifier>, body: BlockStatement) -> Self {
Self {
token,
parameters,
body,
}
}
pub fn parse(parser: &mut Parser, ctoken: Token) -> Option<Expression> {
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<Vec<Identifier>> {
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(","),
""
))
} }
} }

View File

@ -2,7 +2,7 @@ pub mod ast;
use { use {
crate::{ crate::{
lexer::{Lexer, Token, TokenType}, lexer::{Lexer, Token, TokenType},
parser::ast::{Expression, ExpressionPriority, Program, Statement}, parser::ast::*,
}, },
std::{ std::{
collections::HashMap, collections::HashMap,
@ -47,23 +47,24 @@ impl<'a> Parser<'a> {
infix_parse_fns: HashMap::new(), infix_parse_fns: HashMap::new(),
}; };
parser.register_prefix(TokenType::Ident, Expression::parse_identifier); parser.register_prefix(TokenType::Ident, Identifier::parse);
parser.register_prefix(TokenType::Int, Expression::parse_integer_literal); parser.register_prefix(TokenType::Int, IntegerLiteral::parse);
parser.register_prefix(TokenType::Bang, Expression::parse_prefix_expression); parser.register_prefix(TokenType::Bang, PrefixExpression::parse);
parser.register_prefix(TokenType::Minus, Expression::parse_prefix_expression); parser.register_prefix(TokenType::Minus, PrefixExpression::parse);
parser.register_prefix(TokenType::True, Expression::parse_boolean); parser.register_prefix(TokenType::True, Expression::parse_boolean);
parser.register_prefix(TokenType::False, Expression::parse_boolean); parser.register_prefix(TokenType::False, Expression::parse_boolean);
parser.register_prefix(TokenType::LParen, Expression::parse_grouped_expression); parser.register_prefix(TokenType::LParen, Expression::parse_grouped_expression);
parser.register_prefix(TokenType::If, Expression::parse_if_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::Plus, InfixExpression::parse);
parser.register_infix(TokenType::Minus, Expression::parse_infix_expression); parser.register_infix(TokenType::Minus, InfixExpression::parse);
parser.register_infix(TokenType::Slash, Expression::parse_infix_expression); parser.register_infix(TokenType::Slash, InfixExpression::parse);
parser.register_infix(TokenType::Asterisk, Expression::parse_infix_expression); parser.register_infix(TokenType::Asterisk, InfixExpression::parse);
parser.register_infix(TokenType::Equals, Expression::parse_infix_expression); parser.register_infix(TokenType::Equals, InfixExpression::parse);
parser.register_infix(TokenType::NotEquals, Expression::parse_infix_expression); parser.register_infix(TokenType::NotEquals, InfixExpression::parse);
parser.register_infix(TokenType::LessThan, Expression::parse_infix_expression); parser.register_infix(TokenType::LessThan, InfixExpression::parse);
parser.register_infix(TokenType::GreaterThan, Expression::parse_infix_expression); parser.register_infix(TokenType::GreaterThan, InfixExpression::parse);
parser parser
} }
@ -153,8 +154,8 @@ pub struct Error {
} }
impl Display for Error { impl Display for Error {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(fmt, "{}", self.reason) f.write_str(&self.reason)
} }
} }
@ -192,18 +193,9 @@ mod tests {
program, program,
Program { Program {
statements: vec![ statements: vec![
Statement::Let(LetStatement { Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "x"),)),
name: Identifier::new(TokenType::Let, "x"), Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "y"),)),
value: None Statement::Let(LetStatement::new(Identifier::new(TokenType::Let, "foobar"),))
}),
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "y"),
value: None
}),
Statement::Let(LetStatement {
name: Identifier::new(TokenType::Let, "foobar"),
value: None
})
], ],
} }
); );
@ -242,10 +234,10 @@ mod tests {
assert_eq!(program.statements.len(), 1); assert_eq!(program.statements.len(), 1);
assert_eq!( assert_eq!(
program.statements, program.statements,
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Ident, "foobar"), Token::with_value(TokenType::Ident, "foobar"),
expression: Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")), Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
})] ))]
); );
} }
@ -260,10 +252,10 @@ mod tests {
assert_eq!( assert_eq!(
program.unwrap().statements, program.unwrap().statements,
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Int, "5"), Token::with_value(TokenType::Int, "5"),
expression: Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)) Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5))
})] ))]
); );
} }
@ -272,58 +264,58 @@ mod tests {
let prefix_tests = [ let prefix_tests = [
( (
"!5", "!5",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::new(TokenType::Bang), Token::new(TokenType::Bang),
expression: Expression::PrefixExpression(PrefixExpression::new( Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Bang), Token::new(TokenType::Bang),
"!", "!",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
)), )),
})], ))],
), ),
( (
"-15;", "-15;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::new(TokenType::Minus), Token::new(TokenType::Minus),
expression: Expression::PrefixExpression(PrefixExpression::new( Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Minus), Token::new(TokenType::Minus),
"-", "-",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
)), )),
})], ))],
), ),
( (
"!foobar;", "!foobar;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::new(TokenType::Bang), Token::new(TokenType::Bang),
expression: Expression::PrefixExpression(PrefixExpression::new( Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Bang), Token::new(TokenType::Bang),
"!", "!",
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")), Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
)), )),
})], ))],
), ),
( (
"!true;", "!true;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::new(TokenType::Bang), Token::new(TokenType::Bang),
expression: Expression::PrefixExpression(PrefixExpression::new( Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Bang), Token::new(TokenType::Bang),
"!", "!",
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
)), )),
})], ))],
), ),
( (
"!false;", "!false;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::new(TokenType::Bang), Token::new(TokenType::Bang),
expression: Expression::PrefixExpression(PrefixExpression::new( Expression::PrefixExpression(PrefixExpression::new(
Token::new(TokenType::Bang), Token::new(TokenType::Bang),
"!", "!",
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
)), )),
})], ))],
), ),
// TODO: Add this test when we add function call parser // TODO: Add this test when we add function call parser
// ( // (
@ -357,69 +349,69 @@ mod tests {
let infix_tests = [ let infix_tests = [
( (
"5 + 10;", "5 + 10;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Int, "5"), Token::with_value(TokenType::Int, "5"),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Plus), Token::new(TokenType::Plus),
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
"+", "+",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
)), )),
})], ))],
), ),
( (
"5 - 10;", "5 - 10;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Int, "5"), Token::with_value(TokenType::Int, "5"),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Minus), Token::new(TokenType::Minus),
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
"-", "-",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 10)),
)), )),
})], ))],
), ),
( (
"5 * 15;", "5 * 15;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Int, "5"), Token::with_value(TokenType::Int, "5"),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Asterisk), Token::new(TokenType::Asterisk),
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
"*", "*",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
)), )),
})], ))],
), ),
( (
"15 / 3;", "15 / 3;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Int, "15"), Token::with_value(TokenType::Int, "15"),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Slash), Token::new(TokenType::Slash),
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
"/", "/",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 3)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 3)),
)), )),
})], ))],
), ),
( (
"5 > 15;", "5 > 15;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Int, "5"), Token::with_value(TokenType::Int, "5"),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::GreaterThan), Token::new(TokenType::GreaterThan),
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)),
">", ">",
Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)), Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 15)),
)), )),
})], ))],
), ),
( (
"a + b + c;", "a + b + c;",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Ident, "a"), Token::with_value(TokenType::Ident, "a"),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Plus), Token::new(TokenType::Plus),
Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Plus), Token::new(TokenType::Plus),
@ -430,43 +422,43 @@ mod tests {
"+", "+",
Expression::Identifier(Identifier::new(TokenType::Ident, "c")), Expression::Identifier(Identifier::new(TokenType::Ident, "c")),
)), )),
})], ))],
), ),
( (
"true == true", "true == true",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::new(TokenType::True), Token::new(TokenType::True),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Equals), Token::new(TokenType::Equals),
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
"==", "==",
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
)), )),
})], ))],
), ),
( (
"true != false", "true != false",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::new(TokenType::True), Token::new(TokenType::True),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::NotEquals), Token::new(TokenType::NotEquals),
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
"!=", "!=",
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
)), )),
})], ))],
), ),
( (
"false == false", "false == false",
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::new(TokenType::False), Token::new(TokenType::False),
expression: Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Equals), Token::new(TokenType::Equals),
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
"==", "==",
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
)), )),
})], ))],
), ),
]; ];
for test in infix_tests.iter() { for test in infix_tests.iter() {
@ -548,7 +540,7 @@ mod tests {
( (
"let foobar = true;", "let foobar = true;",
Program { Program {
statements: vec![Statement::Let(LetStatement::new( statements: vec![Statement::Let(LetStatement::with_value(
Identifier::new(TokenType::Let, "foobar"), Identifier::new(TokenType::Let, "foobar"),
None, // TODO: fix this when we complete parsing of let statements None, // TODO: fix this when we complete parsing of let statements
))], ))],
@ -583,13 +575,10 @@ mod tests {
)), )),
BlockStatement::new( BlockStatement::new(
Token::with_value(TokenType::Ident, "x"), Token::with_value(TokenType::Ident, "x"),
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Ident, "x"), Token::with_value(TokenType::Ident, "x"),
expression: Expression::Identifier(Identifier::new( Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
TokenType::Ident, ))],
"x",
)),
})],
), ),
None, None,
)), )),
@ -624,23 +613,20 @@ mod tests {
)), )),
BlockStatement::new( BlockStatement::new(
Token::with_value(TokenType::Ident, "x"), Token::with_value(TokenType::Ident, "x"),
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Ident, "x"), Token::with_value(TokenType::Ident, "x"),
expression: Expression::Identifier(Identifier::new( Expression::Identifier(Identifier::new(TokenType::Ident, "x")),
TokenType::Ident, ))],
"x",
)),
})],
), ),
Some(BlockStatement::new( 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), Token::new(TokenType::Else),
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement::new(
token: Token::with_value(TokenType::Ident, "y"), Token::with_value(TokenType::Ident, "y"),
expression: Expression::Identifier(Identifier::new( Expression::Identifier(Identifier::new(TokenType::Ident, "y")),
TokenType::Ident, ))],
"y",
)),
})],
)), )),
)), )),
))], ))],
@ -657,4 +643,130 @@ mod tests {
assert_eq!(program.unwrap(), test.1); 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);
}
}
} }