Completed Let/Return Statement parser

1. Completed Expression parsing in Let/Return Statement Parsers
2. Removed most of the TODOs
3. Added more tests
This commit is contained in:
Ishan Jain 2020-01-20 17:38:58 +05:30
parent a1c316a43e
commit 0833ba3448
2 changed files with 155 additions and 125 deletions

View File

@ -1,4 +1,3 @@
// TODO: Maybe implement String method to pretty print all AST nodes
use { use {
crate::{ crate::{
lexer::{Token, TokenType}, lexer::{Token, TokenType},
@ -71,26 +70,26 @@ impl LetStatement {
pub fn new(name: Identifier) -> Self { pub fn new(name: Identifier) -> Self {
Self { name, value: None } Self { name, value: None }
} }
pub fn with_value(name: Identifier, value: Option<Expression>) -> Self { pub fn with_value(name: Identifier, value: Expression) -> Self {
Self { name, value } Self {
name,
value: Some(value),
} }
// 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 {
name: Identifier::new(TokenType::Let, "placeholder_value"),
value: None,
};
let ident = parser.expect_peek(TokenType::Ident)?; let ident = parser.expect_peek(TokenType::Ident)?;
stmt.name.value = ident.literal?;
parser.expect_peek(TokenType::Assign)?; parser.expect_peek(TokenType::Assign)?;
let ntoken = parser.lexer.next()?;
let expr = Expression::parse(parser, ntoken, ExpressionPriority::Lowest);
// TODO: Right now, We are just skipping over all the expressions parser.expect_peek(TokenType::Semicolon);
// That'll come later
// Also, Right now, It hangs forever in case there is no semicolon at the end
while parser.lexer.next() != Some(Token::new(TokenType::Semicolon)) {}
Some(stmt) Some(Self {
name: Identifier::new(TokenType::Let, &ident.literal?),
value: expr,
})
} }
const fn token_literal() -> &'static str { const fn token_literal() -> &'static str {
@ -117,12 +116,17 @@ pub struct ReturnStatement {
} }
impl ReturnStatement { impl ReturnStatement {
pub fn new(expr: Expression) -> Self {
ReturnStatement {
return_value: Some(expr),
}
}
fn parse(parser: &mut Parser) -> Option<Self> { fn parse(parser: &mut Parser) -> Option<Self> {
let stmt = ReturnStatement { let token = parser.lexer.next()?;
return_value: Some(Expression::None), let expr = Expression::parse(parser, token, ExpressionPriority::Lowest);
}; parser.expect_peek(TokenType::Semicolon);
while parser.lexer.next() != Some(Token::new(TokenType::Semicolon)) {} return Some(ReturnStatement { return_value: expr });
return Some(stmt);
} }
const fn token_literal() -> &'static str { const fn token_literal() -> &'static str {
@ -193,8 +197,6 @@ pub enum Expression {
IfExpression(IfExpression), IfExpression(IfExpression),
FunctionExpression(FunctionLiteral), FunctionExpression(FunctionLiteral),
CallExpression(CallExpression), CallExpression(CallExpression),
// TODO: Temporary placeholder value. Should be removed once this section is done
None,
} }
impl Expression { impl Expression {
@ -249,7 +251,6 @@ impl Display for Expression {
Expression::IfExpression(v) => v.to_string(), Expression::IfExpression(v) => v.to_string(),
Expression::FunctionExpression(v) => v.to_string(), Expression::FunctionExpression(v) => v.to_string(),
Expression::CallExpression(v) => v.to_string(), Expression::CallExpression(v) => v.to_string(),
Expression::None => "None".into(),
}; };
f.write_str(&value) f.write_str(&value)

View File

@ -15,7 +15,6 @@ 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 //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();
@ -186,34 +185,74 @@ mod tests {
#[test] #[test]
fn let_statements() { fn let_statements() {
let mut lexer = Lexer::new("let x =5;let y=10; let foobar=538383;"); let test_cases = [(
"let x =5;let y=10; let foobar=538383;",
vec![
Statement::Let(LetStatement::with_value(
Identifier::new(TokenType::Let, "x"),
Expression::IntegerLiteral(IntegerLiteral::new(5)),
)),
Statement::Let(LetStatement::with_value(
Identifier::new(TokenType::Let, "y"),
Expression::IntegerLiteral(IntegerLiteral::new(10)),
)),
Statement::Let(LetStatement::with_value(
Identifier::new(TokenType::Let, "foobar"),
Expression::IntegerLiteral(IntegerLiteral::new(538383)),
)),
],
)];
for test in test_cases.iter() {
let lexer = Lexer::new(test.0);
let mut parser = Parser::new(lexer); let mut parser = Parser::new(lexer);
let program = parser.parse_program(); let program = parser.parse_program();
check_parser_errors(&parser); check_parser_errors(&parser);
assert_eq!(parser.errors.len(), 0); assert_eq!(parser.errors.len(), 0);
assert!(program.is_some()); assert!(program.is_some());
let program = program.unwrap(); assert_eq!(program.unwrap().statements, test.1);
assert_eq!(program.statements.len(), 3);
assert_eq!(
program,
Program {
statements: vec![
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"),))
],
} }
);
lexer = Lexer::new("let x 5; let 10; let 83838383;"); let fail_case = "let x 5; let 10; let 83838383;";
parser = Parser::new(lexer);
let _program = parser.parse_program(); let lexer = Lexer::new(fail_case);
let mut parser = Parser::new(lexer);
let program = parser.parse_program();
check_parser_errors(&parser); check_parser_errors(&parser);
assert_eq!(parser.errors.len(), 3); assert_eq!(parser.errors.len(), 3);
assert!(program.is_some());
} }
#[test] #[test]
fn return_statements() { fn return_statements() {
let test_cases = [(
"return 5; return 10; return add(10);",
vec![
Statement::Return(ReturnStatement::new(Expression::IntegerLiteral(
IntegerLiteral::new(5),
))),
Statement::Return(ReturnStatement::new(Expression::IntegerLiteral(
IntegerLiteral::new(10),
))),
Statement::Return(ReturnStatement::new(Expression::CallExpression(
CallExpression::new(
Expression::Identifier(Identifier::new(TokenType::Ident, "add")),
vec![Expression::IntegerLiteral(IntegerLiteral::new(10))],
),
))),
],
)];
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);
}
let lexer = Lexer::new("return 5; return 10; return add(10);"); let lexer = Lexer::new("return 5; return 10; return add(10);");
let mut parser = Parser::new(lexer); let mut parser = Parser::new(lexer);
let program = parser.parse_program(); let program = parser.parse_program();
@ -322,20 +361,23 @@ mod tests {
)), )),
))], ))],
), ),
// TODO: Add this test when we add function call parser (
// ( "!isGreaterThanZero( 2);",
// "!isGreaterThanZero( 2);", vec![Statement::ExpressionStatement(ExpressionStatement::new(
// vec![Statement::ExpressionStatement(ExpressionStatement { Token::new(TokenType::Bang),
// token: Token::new(TokenType::Bang), Expression::PrefixExpression(PrefixExpression::new(
// expression: Expression::PrefixExpression(PrefixExpression::new( TokenType::Bang,
// Token::new(TokenType::Bang), "!",
// "!", Expression::CallExpression(CallExpression::new(
// Expression::Identifier(Identifier::new( Expression::Identifier(Identifier::new(
// TokenType::Function, TokenType::Ident,
// "", "isGreaterThanZero",
// )), )),
// )), vec![Expression::IntegerLiteral(IntegerLiteral::new(2))],
// }) )),
)),
))],
),
]; ];
for test in prefix_tests.iter() { for test in prefix_tests.iter() {
@ -526,30 +568,24 @@ mod tests {
let test_cases = [ let test_cases = [
( (
"true;", "true;",
Program { vec![Statement::ExpressionStatement(ExpressionStatement::new(
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::True), Token::new(TokenType::True),
Expression::BooleanExpression(BooleanExpression::new(TokenType::True)), Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
))], ))],
},
), ),
( (
"false;", "false;",
Program { vec![Statement::ExpressionStatement(ExpressionStatement::new(
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::False), Token::new(TokenType::False),
Expression::BooleanExpression(BooleanExpression::new(TokenType::False)), Expression::BooleanExpression(BooleanExpression::new(TokenType::False)),
))], ))],
},
), ),
( (
"let foobar = true;", "let foobar = true;",
Program { vec![Statement::Let(LetStatement::with_value(
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 Expression::BooleanExpression(BooleanExpression::new(TokenType::True)),
))], ))],
},
), ),
]; ];
@ -560,15 +596,14 @@ mod tests {
check_parser_errors(&parser); check_parser_errors(&parser);
assert_eq!(parser.errors.len(), 0); assert_eq!(parser.errors.len(), 0);
assert!(program.is_some()); assert!(program.is_some());
assert_eq!(program.unwrap(), test.1); assert_eq!(program.unwrap().statements, test.1);
} }
} }
#[test] #[test]
fn if_expression() { fn if_expression() {
let test_cases = [( let test_cases = [(
"if (x > y) { x };", "if (x > y) { x };",
Program { vec![Statement::ExpressionStatement(ExpressionStatement::new(
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::If), Token::new(TokenType::If),
Expression::IfExpression(IfExpression::new( Expression::IfExpression(IfExpression::new(
Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
@ -586,7 +621,6 @@ mod tests {
None, None,
)), )),
))], ))],
},
)]; )];
for test in test_cases.iter() { for test in test_cases.iter() {
@ -596,15 +630,14 @@ mod tests {
check_parser_errors(&parser); check_parser_errors(&parser);
assert_eq!(parser.errors.len(), 0); assert_eq!(parser.errors.len(), 0);
assert!(program.is_some()); assert!(program.is_some());
assert_eq!(program.unwrap(), test.1); assert_eq!(program.unwrap().statements, test.1);
} }
} }
#[test] #[test]
fn if_else_expression() { fn if_else_expression() {
let test_cases = [( let test_cases = [(
"if (x > y) { x } else { y };", "if (x > y) { x } else { y };",
Program { vec![Statement::ExpressionStatement(ExpressionStatement::new(
statements: vec![Statement::ExpressionStatement(ExpressionStatement::new(
Token::new(TokenType::If), Token::new(TokenType::If),
Expression::IfExpression(IfExpression::new( Expression::IfExpression(IfExpression::new(
Expression::InfixExpression(InfixExpression::new( Expression::InfixExpression(InfixExpression::new(
@ -627,7 +660,6 @@ mod tests {
)])), )])),
)), )),
))], ))],
},
)]; )];
for test in test_cases.iter() { for test in test_cases.iter() {
@ -637,13 +669,12 @@ mod tests {
check_parser_errors(&parser); check_parser_errors(&parser);
assert_eq!(parser.errors.len(), 0); assert_eq!(parser.errors.len(), 0);
assert!(program.is_some()); assert!(program.is_some());
assert_eq!(program.unwrap(), test.1); assert_eq!(program.unwrap().statements, test.1);
} }
} }
#[test] #[test]
fn function_literal_parsing() { fn function_literal_parsing() {
// TODO: Figure out why are there inconsistencies in BlockStatements Token
let test_cases = [ let test_cases = [
( (
"fn(a,b) {x + y;}", "fn(a,b) {x + y;}",
@ -767,7 +798,6 @@ mod tests {
} }
#[test] #[test]
fn call_expression_parsing() { fn call_expression_parsing() {
// TODO: Figure out why are there inconsistencies in BlockStatements Token
let test_cases = [ let test_cases = [
( (
"add(1, 2 * 3, 4 + 5);", "add(1, 2 * 3, 4 + 5);",
@ -930,7 +960,6 @@ mod tests {
} }
#[test] #[test]
fn call_expression_parsing_string() { fn call_expression_parsing_string() {
// TODO: Figure out why are there inconsistencies in BlockStatements Token
let test_cases = [ let test_cases = [
("add(1, 2 * 3, 4 + 5);", "add(1, (2 * 3), (4 + 5))"), ("add(1, 2 * 3, 4 + 5);", "add(1, (2 * 3), (4 + 5))"),
( (