Added Boolean Expression parser along with tests

This commit is contained in:
Ishan Jain 2020-01-19 21:45:11 +05:30
parent 2293c442eb
commit 9763c5ca2e
2 changed files with 142 additions and 2 deletions

View File

@ -65,6 +65,9 @@ pub struct LetStatement {
} }
impl LetStatement { impl LetStatement {
pub fn new(name: Identifier, value: Option<Expression>) -> Self {
Self { name, value }
}
// TODO: Implement code to parse let statement // TODO: Implement code to parse let statement
pub fn parse(parser: &mut Parser) -> Option<Self> { pub fn parse(parser: &mut Parser) -> Option<Self> {
let mut stmt = LetStatement { let mut stmt = LetStatement {
@ -142,6 +145,9 @@ pub struct ExpressionStatement {
} }
impl ExpressionStatement { impl ExpressionStatement {
pub fn new(token: Token, expression: Expression) -> Self {
Self { token, expression }
}
fn parse(parser: &mut Parser, current_token: Token) -> Option<Self> { fn parse(parser: &mut Parser, current_token: Token) -> Option<Self> {
let stmt = ExpressionStatement { let stmt = ExpressionStatement {
token: current_token.clone(), token: current_token.clone(),
@ -177,6 +183,7 @@ pub enum Expression {
IntegerLiteral(IntegerLiteral), IntegerLiteral(IntegerLiteral),
PrefixExpression(PrefixExpression), PrefixExpression(PrefixExpression),
InfixExpression(InfixExpression), InfixExpression(InfixExpression),
BooleanExpression(BooleanExpression),
// 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,
} }
@ -227,10 +234,13 @@ impl Expression {
return None; return None;
} }
}; };
Some(Self::IntegerLiteral(IntegerLiteral::new(TokenType::Int, n))) Some(Self::IntegerLiteral(IntegerLiteral::new(TokenType::Int, n)))
} }
pub fn parse_boolean(_parser: &mut Parser, token: Token) -> Option<Self> {
Some(Self::BooleanExpression(BooleanExpression::new(token.name)))
}
pub fn parse_prefix_expression(parser: &mut Parser, ctoken: Token) -> Option<Self> { pub fn parse_prefix_expression(parser: &mut Parser, ctoken: Token) -> Option<Self> {
let next_token = parser.lexer.next()?; let next_token = parser.lexer.next()?;
let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?; let right_expr = Expression::parse(parser, next_token.clone(), ExpressionPriority::Prefix)?;
@ -268,6 +278,7 @@ impl Display for Expression {
Expression::IntegerLiteral(v) => v.value.to_string(), Expression::IntegerLiteral(v) => v.value.to_string(),
Expression::PrefixExpression(v) => v.to_string(), Expression::PrefixExpression(v) => v.to_string(),
Expression::InfixExpression(v) => v.to_string(), Expression::InfixExpression(v) => v.to_string(),
Expression::BooleanExpression(v) => v.to_string(),
Expression::None => "None".into(), Expression::None => "None".into(),
} }
) )
@ -373,6 +384,27 @@ impl Display for InfixExpression {
} }
} }
#[derive(Debug, PartialEq)]
pub struct BooleanExpression {
token: TokenType,
value: bool,
}
impl BooleanExpression {
pub fn new(token: TokenType) -> Self {
BooleanExpression {
token: token,
value: token == TokenType::True,
}
}
}
impl Display for BooleanExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "{}", self.value)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{

View File

@ -14,6 +14,8 @@ use {
type PrefixParseFn = fn(&mut Parser, token: Token) -> Option<Expression>; type PrefixParseFn = fn(&mut Parser, token: Token) -> Option<Expression>;
type InfixParseFn = fn(&mut Parser, Token, Expression) -> Option<Expression>; type InfixParseFn = fn(&mut Parser, Token, Expression) -> Option<Expression>;
//TODO: Add Parser tracing so we can easily figure out the call stack hierarchy
lazy_static! { lazy_static! {
static ref PRECEDENCE_MAP: HashMap<TokenType, ExpressionPriority> = { static ref PRECEDENCE_MAP: HashMap<TokenType, ExpressionPriority> = {
let mut m = HashMap::new(); let mut m = HashMap::new();
@ -49,6 +51,8 @@ impl<'a> Parser<'a> {
parser.register_prefix(TokenType::Int, Expression::parse_integer_literal); parser.register_prefix(TokenType::Int, Expression::parse_integer_literal);
parser.register_prefix(TokenType::Bang, Expression::parse_prefix_expression); parser.register_prefix(TokenType::Bang, Expression::parse_prefix_expression);
parser.register_prefix(TokenType::Minus, Expression::parse_prefix_expression); parser.register_prefix(TokenType::Minus, Expression::parse_prefix_expression);
parser.register_prefix(TokenType::True, Expression::parse_boolean);
parser.register_prefix(TokenType::False, Expression::parse_boolean);
parser.register_infix(TokenType::Plus, Expression::parse_infix_expression); parser.register_infix(TokenType::Plus, Expression::parse_infix_expression);
parser.register_infix(TokenType::Minus, Expression::parse_infix_expression); parser.register_infix(TokenType::Minus, Expression::parse_infix_expression);
@ -293,6 +297,28 @@ mod tests {
)), )),
})], })],
), ),
(
"!true;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::Bang),
expression: 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(
Token::new(TokenType::Bang),
"!",
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
// ( // (
// "!isGreaterThanZero( 2);", // "!isGreaterThanZero( 2);",
@ -399,6 +425,42 @@ mod tests {
)), )),
})], })],
), ),
(
"true == true",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::True),
expression: 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(
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(
Token::new(TokenType::Equals),
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
"==",
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
)),
})],
),
]; ];
for test in infix_tests.iter() { for test in infix_tests.iter() {
let lexer = Lexer::new(test.0); let lexer = Lexer::new(test.0);
@ -411,7 +473,7 @@ mod tests {
} }
#[test] #[test]
fn test_operator_precedence_parsing() { fn operator_precedence_parsing() {
let test_cases = [ let test_cases = [
("-a * b", "((-a) * b)"), ("-a * b", "((-a) * b)"),
("!-a", "(!(-a))"), ("!-a", "(!(-a))"),
@ -432,6 +494,10 @@ mod tests {
"3 + 4 * 5 == 3 * 1 + 4 * 5", "3 + 4 * 5 == 3 * 1 + 4 * 5",
"((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))", "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))",
), ),
("true", "true"),
("false", "false"),
("3 > 5 == false", "((3 > 5) == false)"),
("3 < 5 == true", "((3 < 5) == true)"),
]; ];
for test in test_cases.iter() { for test in test_cases.iter() {
@ -443,4 +509,46 @@ mod tests {
assert_eq!(program.unwrap().to_string(), test.1); assert_eq!(program.unwrap().to_string(), test.1);
} }
} }
#[test]
fn boolean_expression() {
let test_cases = [
(
"true;",
Program {
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::True),
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
))],
},
),
(
"false;",
Program {
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::False),
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
))],
},
),
(
"let foobar = true;",
Program {
statements: vec![Statement::Let(LetStatement::new(
Identifier::new(TokenType::Let, "foobar"),
None, // TODO: fix this when we complete parsing of let statements
))],
},
),
];
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!(program.is_some());
assert_eq!(program.unwrap(), test.1);
}
}
} }