Bug fixes and completed prefix and infix expression parser

1. Changed names of some variants of TokenType.
2. Implemented std::fmt::Display and std::string::ToString for some
   types
3. Added Infix and Prefix expressions parser
4. Added tests to ensure correctness of added parsers
This commit is contained in:
Ishan Jain 2020-01-19 19:57:53 +05:30
parent 203ebb169b
commit 2293c442eb
4 changed files with 452 additions and 98 deletions

View File

@ -1,6 +1,5 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
convert::Into,
iter::Peekable, iter::Peekable,
str::{self, Chars}, str::{self, Chars},
}; };
@ -33,10 +32,10 @@ pub enum TokenType {
// Operators // Operators
Assign, Assign,
Plus, Plus,
Multiply, Asterisk,
Divide, Slash,
Subtract, Minus,
ExclamationMark, Bang,
LessThan, LessThan,
GreaterThan, GreaterThan,
Equals, Equals,
@ -60,17 +59,17 @@ pub enum TokenType {
Return, Return,
} }
impl Into<&'static str> for TokenType { impl TokenType {
fn into(self) -> &'static str { pub fn to_string(&self) -> &'static str {
match self { match self {
TokenType::Assign => "=", TokenType::Assign => "=",
TokenType::Plus => "+", TokenType::Plus => "+",
TokenType::Multiply => "*", TokenType::Asterisk => "*",
TokenType::Divide => "/", TokenType::Slash => "/",
TokenType::Subtract => "-", TokenType::Minus => "-",
TokenType::ExclamationMark => "!", TokenType::Bang => "!",
TokenType::LessThan => "<=", TokenType::LessThan => "<",
TokenType::GreaterThan => ">=", TokenType::GreaterThan => ">",
TokenType::Equals => "==", TokenType::Equals => "==",
TokenType::NotEquals => "!=", TokenType::NotEquals => "!=",
TokenType::Comma => ",", TokenType::Comma => ",",
@ -86,7 +85,10 @@ impl Into<&'static str> for TokenType {
TokenType::True => "true", TokenType::True => "true",
TokenType::False => "false", TokenType::False => "false",
TokenType::Return => "return", TokenType::Return => "return",
_ => unreachable!(), _ => {
eprintln!("{:?}", self);
unreachable!()
}
} }
} }
} }
@ -113,9 +115,11 @@ impl Token {
literal: Some(value.to_string()), literal: Some(value.to_string()),
} }
} }
}
pub fn to_string(&self) -> &'static str { impl ToString for Token {
self.name.into() fn to_string(&self) -> String {
self.name.to_string().into()
} }
} }
@ -207,9 +211,9 @@ impl<'a> Iterator for Lexer<'a> {
} }
} }
Some('+') => Some(Token::new(TokenType::Plus)), Some('+') => Some(Token::new(TokenType::Plus)),
Some('*') => Some(Token::new(TokenType::Multiply)), Some('*') => Some(Token::new(TokenType::Asterisk)),
Some('/') => Some(Token::new(TokenType::Divide)), Some('/') => Some(Token::new(TokenType::Slash)),
Some('-') => Some(Token::new(TokenType::Subtract)), Some('-') => Some(Token::new(TokenType::Minus)),
Some(',') => Some(Token::new(TokenType::Comma)), Some(',') => Some(Token::new(TokenType::Comma)),
Some(';') => Some(Token::new(TokenType::Semicolon)), Some(';') => Some(Token::new(TokenType::Semicolon)),
Some('(') => Some(Token::new(TokenType::LParen)), Some('(') => Some(Token::new(TokenType::LParen)),
@ -225,7 +229,7 @@ impl<'a> Iterator for Lexer<'a> {
self.read_char(); self.read_char();
Some(Token::new(TokenType::NotEquals)) Some(Token::new(TokenType::NotEquals))
} else { } else {
Some(Token::new(TokenType::ExclamationMark)) Some(Token::new(TokenType::Bang))
} }
} }
Some('>') => Some(Token::new(TokenType::GreaterThan)), Some('>') => Some(Token::new(TokenType::GreaterThan)),
@ -363,10 +367,10 @@ mod tests {
Token::with_value(TokenType::Ident, "ten"), Token::with_value(TokenType::Ident, "ten"),
Token::new(TokenType::RParen), Token::new(TokenType::RParen),
Token::new(TokenType::Semicolon), Token::new(TokenType::Semicolon),
Token::new(TokenType::ExclamationMark), Token::new(TokenType::Bang),
Token::new(TokenType::Subtract), Token::new(TokenType::Minus),
Token::new(TokenType::Divide), Token::new(TokenType::Slash),
Token::new(TokenType::Multiply), Token::new(TokenType::Asterisk),
Token::with_value(TokenType::Int, "5"), Token::with_value(TokenType::Int, "5"),
Token::new(TokenType::Semicolon), Token::new(TokenType::Semicolon),
Token::with_value(TokenType::Int, "5"), Token::with_value(TokenType::Int, "5"),

View File

@ -2,9 +2,13 @@
use { use {
crate::{ crate::{
lexer::{Token, TokenType}, lexer::{Token, TokenType},
parser::{Parser, ParserError}, parser::{Error as ParserError, Parser},
},
std::{
cmp::PartialOrd,
convert::From,
fmt::{Display, Error as FmtError, Formatter},
}, },
std::convert::From,
}; };
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -12,23 +16,17 @@ pub struct Program {
pub statements: Vec<Statement>, pub statements: Vec<Statement>,
} }
impl ToString for Program { impl Display for Program {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
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());
out.push('\n');
} }
out write!(f, "{}", out)
} }
} }
pub enum Node {
Statement(Statement),
Expression(Expression),
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Statement { pub enum Statement {
Let(LetStatement), Let(LetStatement),
@ -48,12 +46,12 @@ impl<'a> Statement {
} }
} }
impl ToString for Statement { impl Display for Statement {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self { match self {
Statement::Let(v) => v.to_string(), Statement::Let(v) => write!(f, "{}", v.to_string()),
Statement::Return(v) => v.to_string(), Statement::Return(v) => write!(f, "{}", v.to_string()),
Statement::ExpressionStatement(v) => v.to_string(), Statement::ExpressionStatement(v) => write!(f, "{}", v.to_string()),
} }
} }
} }
@ -76,7 +74,6 @@ impl LetStatement {
let ident = parser.expect_peek(TokenType::Ident)?; let ident = parser.expect_peek(TokenType::Ident)?;
stmt.name.value = ident.literal?; stmt.name.value = ident.literal?;
parser.expect_peek(TokenType::Assign)?; parser.expect_peek(TokenType::Assign)?;
// TODO: Right now, We are just skipping over all the expressions // TODO: Right now, We are just skipping over all the expressions
@ -92,8 +89,8 @@ impl LetStatement {
} }
} }
impl ToString for LetStatement { impl Display for LetStatement {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
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 {
@ -101,7 +98,7 @@ impl ToString for LetStatement {
out.push_str(&a); out.push_str(&a);
} }
out.push(';'); out.push(';');
out write!(f, "{}", out)
} }
} }
@ -119,14 +116,13 @@ impl ReturnStatement {
return Some(stmt); return Some(stmt);
} }
// TODO: REMOVE THIS!
const fn token_literal() -> &'static str { const fn token_literal() -> &'static str {
"return" "return"
} }
} }
impl ToString for ReturnStatement { impl Display for ReturnStatement {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
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 {
@ -135,7 +131,7 @@ impl ToString for ReturnStatement {
out.push_str(&a); out.push_str(&a);
} }
out.push(';'); out.push(';');
out write!(f, "{}", out)
} }
} }
@ -147,7 +143,6 @@ pub struct ExpressionStatement {
impl ExpressionStatement { impl ExpressionStatement {
fn parse(parser: &mut Parser, current_token: Token) -> Option<Self> { fn parse(parser: &mut Parser, current_token: Token) -> Option<Self> {
// let expr = Expression::parse(parser, token.clone(), ExpressionPriority::Lowest)?;
let stmt = ExpressionStatement { let stmt = ExpressionStatement {
token: current_token.clone(), token: current_token.clone(),
expression: Expression::parse(parser, current_token, ExpressionPriority::Lowest)?, expression: Expression::parse(parser, current_token, ExpressionPriority::Lowest)?,
@ -159,14 +154,14 @@ impl ExpressionStatement {
} }
} }
impl ToString for ExpressionStatement { impl Display for ExpressionStatement {
fn to_string(&self) -> String { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
self.expression.to_string() write!(f, "{}", self.expression.to_string())
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Copy, PartialOrd, Clone)]
enum ExpressionPriority { pub enum ExpressionPriority {
Lowest = 0, Lowest = 0,
Equals = 1, Equals = 1,
LessGreater = 2, LessGreater = 2,
@ -176,24 +171,46 @@ enum ExpressionPriority {
Call = 6, Call = 6,
} }
// TODO: Expressions are not going to be a struct so using this here just as a placeholder
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Expression { pub enum Expression {
Identifier(Identifier), Identifier(Identifier),
IntegerLiteral(IntegerLiteral), IntegerLiteral(IntegerLiteral),
PrefixExpression(PrefixExpression),
InfixExpression(InfixExpression),
// 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,
} }
impl Expression { impl Expression {
fn parse(parser: &mut Parser, token: Token, precedence: ExpressionPriority) -> Option<Self> { fn parse(parser: &mut Parser, ctoken: Token, precedence: ExpressionPriority) -> Option<Self> {
let prefix = parser.prefix_parse_fns.get(&token.name)?; match parser.prefix_parse_fns.get(&ctoken.name) {
Some(prefix) => {
prefix(parser, token) let mut left_expr = prefix(parser, ctoken);
while !parser.peek_token_is(TokenType::Semicolon)
&& precedence < parser.peek_precedence()
{
let peek_token = match parser.lexer.peek() {
Some(token) => token.clone(),
None => return left_expr,
};
match parser.infix_parse_fns.get(&peek_token.name) {
Some(infix) => {
let next_token = parser.lexer.next()?;
left_expr = infix(parser, next_token, left_expr.unwrap());
}
None => return left_expr,
};
}
left_expr
}
None => {
parser.no_prefix_parse_fn_error(&ctoken.name);
None
}
}
} }
pub fn parse_identifier(parser: &mut Parser, token: Token) -> Option<Self> { pub fn parse_identifier(_parser: &mut Parser, token: Token) -> Option<Self> {
Some(Self::Identifier(Identifier::new( Some(Self::Identifier(Identifier::new(
token.name, token.name,
&token.literal?, &token.literal?,
@ -214,12 +231,46 @@ impl Expression {
Some(Self::IntegerLiteral(IntegerLiteral::new(TokenType::Int, n))) Some(Self::IntegerLiteral(IntegerLiteral::new(TokenType::Int, n)))
} }
fn to_string(&self) -> String { 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 {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
f,
"{}",
match self { match self {
Expression::Identifier(v) => v.to_string(), Expression::Identifier(v) => v.to_string(),
Expression::IntegerLiteral(v) => v.value.to_string(), Expression::IntegerLiteral(v) => v.value.to_string(),
Expression::PrefixExpression(v) => v.to_string(),
Expression::InfixExpression(v) => v.to_string(),
Expression::None => "None".into(), Expression::None => "None".into(),
} }
)
} }
} }
@ -245,9 +296,11 @@ impl Identifier {
value: v.to_string(), value: v.to_string(),
} }
} }
}
pub fn to_string(&self) -> String { impl Display for Identifier {
self.value.clone() fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "{}", self.value.clone())
} }
} }
@ -266,10 +319,64 @@ impl IntegerLiteral {
} }
} }
#[derive(Debug, PartialEq)]
pub struct PrefixExpression {
token: Token,
operator: String,
right: Box<Expression>,
}
impl PrefixExpression {
pub fn new(token: Token, operator: &str, right: Expression) -> Self {
Self {
token: token,
operator: operator.to_string(),
right: Box::new(right),
}
}
}
impl Display for PrefixExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(f, "({}{})", self.operator, self.right.to_string())
}
}
#[derive(Debug, PartialEq)]
pub struct InfixExpression {
token: Token,
left: Box<Expression>,
operator: String,
right: Box<Expression>,
}
impl InfixExpression {
pub fn new(token: Token, left: Expression, operator: &str, right: Expression) -> Self {
Self {
token: token,
left: Box::new(left),
operator: operator.to_string(),
right: Box::new(right),
}
}
}
impl Display for InfixExpression {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
write!(
f,
"({} {} {})",
self.left.to_string(),
self.operator,
self.right.to_string()
)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
lexer::{Token, TokenType}, lexer::TokenType,
parser::{ parser::{
ast::{Expression, Identifier, LetStatement, ReturnStatement, Statement}, ast::{Expression, Identifier, LetStatement, ReturnStatement, Statement},
Program, Program,
@ -298,7 +405,7 @@ mod tests {
}; };
assert_eq!( assert_eq!(
program.to_string(), program.to_string(),
"let myVar = anotherVar;\nreturn 5;\nreturn;\n" "let myVar = anotherVar;return 5;return;"
); );
} }
} }

View File

@ -2,7 +2,7 @@ pub mod ast;
use { use {
crate::{ crate::{
lexer::{Lexer, Token, TokenType}, lexer::{Lexer, Token, TokenType},
parser::ast::{Expression, Program, Statement}, parser::ast::{Expression, ExpressionPriority, Program, Statement},
}, },
std::{ std::{
collections::HashMap, collections::HashMap,
@ -12,11 +12,26 @@ use {
}; };
type PrefixParseFn = fn(&mut Parser, token: Token) -> Option<Expression>; type PrefixParseFn = fn(&mut Parser, token: Token) -> Option<Expression>;
type InfixParseFn = fn(Expression) -> Option<Expression>; type InfixParseFn = fn(&mut Parser, Token, Expression) -> Option<Expression>;
lazy_static! {
static ref PRECEDENCE_MAP: HashMap<TokenType, ExpressionPriority> = {
let mut m = HashMap::new();
m.insert(TokenType::Equals, ExpressionPriority::Equals);
m.insert(TokenType::NotEquals, ExpressionPriority::Equals);
m.insert(TokenType::LessThan, ExpressionPriority::LessGreater);
m.insert(TokenType::GreaterThan, ExpressionPriority::LessGreater);
m.insert(TokenType::Plus, ExpressionPriority::Sum);
m.insert(TokenType::Minus, ExpressionPriority::Sum);
m.insert(TokenType::Slash, ExpressionPriority::Product);
m.insert(TokenType::Asterisk, ExpressionPriority::Product);
m
};
}
pub struct Parser<'a> { pub struct Parser<'a> {
lexer: Peekable<Lexer<'a>>, lexer: Peekable<Lexer<'a>>,
errors: Vec<ParserError>, errors: Vec<Error>,
prefix_parse_fns: HashMap<TokenType, PrefixParseFn>, prefix_parse_fns: HashMap<TokenType, PrefixParseFn>,
infix_parse_fns: HashMap<TokenType, InfixParseFn>, infix_parse_fns: HashMap<TokenType, InfixParseFn>,
} }
@ -32,23 +47,35 @@ impl<'a> Parser<'a> {
parser.register_prefix(TokenType::Ident, Expression::parse_identifier); parser.register_prefix(TokenType::Ident, Expression::parse_identifier);
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::Minus, Expression::parse_prefix_expression);
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 parser
} }
pub fn parse_program(&mut self) -> Program { pub fn parse_program(&mut self) -> Option<Program> {
let mut program = Program { statements: vec![] }; let mut program = Program { statements: vec![] };
while let Some(token) = self.lexer.next() { while let Some(token) = self.lexer.next() {
if token.name == TokenType::EOF { if token.name == TokenType::EOF {
break; break;
} }
match Statement::parse(self, token) {
Some(v) => program.statements.push(v), match Statement::parse(self, token.clone()) {
None => {} // This will happen in case of a parsing error or something Some(x) => program.statements.push(x),
} None => eprintln!("error in generating statement: {:?}", token),
};
} }
program Some(program)
} }
fn peek_token_is(&mut self, token: TokenType) -> bool { fn peek_token_is(&mut self, token: TokenType) -> bool {
@ -58,11 +85,6 @@ impl<'a> Parser<'a> {
} }
} }
// TODO: Remove this. We most likely don't need it anywhere
// fn current_token_is(&self, token: TokenType) -> bool {
// false
// }
fn expect_peek(&mut self, token: TokenType) -> Option<Token> { fn expect_peek(&mut self, token: TokenType) -> Option<Token> {
if self.peek_token_is(token) { if self.peek_token_is(token) {
self.lexer.next() self.lexer.next()
@ -79,9 +101,12 @@ impl<'a> Parser<'a> {
fn peek_error(&mut self, et: TokenType, gt: Option<TokenType>) { fn peek_error(&mut self, et: TokenType, gt: Option<TokenType>) {
let msg = match gt { let msg = match gt {
Some(v) => format!("expected next token to be {:?}, Got {:?} instead", et, v), Some(v) => format!("expected next token to be {:?}, Got {:?} instead", et, v),
None => format!("expected next token to be {:?}, Got None instead", et), None => format!(
"expected next token to be {}, Got None instead",
et.to_string()
),
}; };
self.errors.push(ParserError { reason: msg }); self.errors.push(Error { reason: msg });
} }
fn register_prefix(&mut self, token: TokenType, f: PrefixParseFn) { fn register_prefix(&mut self, token: TokenType, f: PrefixParseFn) {
@ -91,13 +116,37 @@ impl<'a> Parser<'a> {
fn register_infix(&mut self, token: TokenType, f: InfixParseFn) { fn register_infix(&mut self, token: TokenType, f: InfixParseFn) {
self.infix_parse_fns.insert(token, f); self.infix_parse_fns.insert(token, f);
} }
fn no_prefix_parse_fn_error(&mut self, token: &TokenType) {
self.errors.push(Error {
reason: format!("no prefix parse function for {} found", token.to_string()),
});
} }
pub struct ParserError { fn peek_precedence(&mut self) -> ExpressionPriority {
match self.lexer.peek() {
Some(token) => match PRECEDENCE_MAP.get(&token.name) {
Some(p) => *p,
None => ExpressionPriority::Lowest,
},
None => ExpressionPriority::Lowest,
}
}
fn current_precedence(&mut self, token: &TokenType) -> ExpressionPriority {
match PRECEDENCE_MAP.get(&token) {
Some(p) => *p,
None => ExpressionPriority::Lowest,
}
}
}
#[derive(PartialEq, Debug)]
pub struct Error {
reason: String, reason: String,
} }
impl Display for ParserError { impl Display for Error {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
write!(fmt, "{}", self.reason) write!(fmt, "{}", self.reason)
} }
@ -107,13 +156,7 @@ impl Display for ParserError {
mod tests { mod tests {
use crate::{ use crate::{
lexer::{Lexer, Token, TokenType}, lexer::{Lexer, Token, TokenType},
parser::{ parser::{ast::*, Parser},
ast::{
Expression, ExpressionStatement, Identifier, IntegerLiteral, LetStatement, Program,
Statement,
},
Parser,
},
}; };
fn check_parser_errors(p: &Parser) { fn check_parser_errors(p: &Parser) {
@ -135,6 +178,8 @@ mod tests {
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!(program.is_some());
let program = program.unwrap();
assert_eq!(program.statements.len(), 3); assert_eq!(program.statements.len(), 3);
assert_eq!( assert_eq!(
program, program,
@ -170,9 +215,12 @@ mod tests {
let program = parser.parse_program(); let program = parser.parse_program();
check_parser_errors(&parser); check_parser_errors(&parser);
assert!(program.is_some());
let program = program.unwrap();
assert_eq!(program.statements.len(), 3); assert_eq!(program.statements.len(), 3);
assert_eq!(parser.errors.len(), 0); assert_eq!(parser.errors.len(), 0);
} }
#[test] #[test]
fn identifier_expression() { fn identifier_expression() {
let lexer = Lexer::new("foobar;"); let lexer = Lexer::new("foobar;");
@ -180,6 +228,8 @@ mod tests {
let program = parser.parse_program(); let program = parser.parse_program();
check_parser_errors(&parser); check_parser_errors(&parser);
assert!(program.is_some());
let program = program.unwrap();
assert_eq!(program.statements.len(), 1); assert_eq!(program.statements.len(), 1);
assert_eq!( assert_eq!(
program.statements, program.statements,
@ -196,13 +246,201 @@ mod tests {
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!(program.is_some());
assert_eq!( assert_eq!(
program.statements, program.unwrap().statements,
vec![Statement::ExpressionStatement(ExpressionStatement { vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Int, "5"), token: Token::with_value(TokenType::Int, "5"),
expression: Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5)) expression: Expression::IntegerLiteral(IntegerLiteral::new(TokenType::Int, 5))
})] })]
); );
} }
#[test]
fn prefix_expressions() {
let prefix_tests = [
(
"!5",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::new(TokenType::Bang),
expression: 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(
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(
Token::new(TokenType::Bang),
"!",
Expression::Identifier(Identifier::new(TokenType::Ident, "foobar")),
)),
})],
),
// TODO: Add this test when we add function call parser
// (
// "!isGreaterThanZero( 2);",
// vec![Statement::ExpressionStatement(ExpressionStatement {
// token: Token::new(TokenType::Bang),
// expression: Expression::PrefixExpression(PrefixExpression::new(
// Token::new(TokenType::Bang),
// "!",
// Expression::Identifier(Identifier::new(
// TokenType::Function,
// "",
// )),
// )),
// })
];
for test in prefix_tests.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().statements, test.1);
}
}
#[test]
fn parsing_infix_expressions() {
let infix_tests = [
(
"5 + 10;",
vec![Statement::ExpressionStatement(ExpressionStatement {
token: Token::with_value(TokenType::Int, "5"),
expression: 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(
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(
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(
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(
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(
Token::new(TokenType::Plus),
Expression::InfixExpression(InfixExpression::new(
Token::new(TokenType::Plus),
Expression::Identifier(Identifier::new(TokenType::Ident, "a")),
"+",
Expression::Identifier(Identifier::new(TokenType::Ident, "b")),
)),
"+",
Expression::Identifier(Identifier::new(TokenType::Ident, "c")),
)),
})],
),
];
for test in infix_tests.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().statements, test.1);
}
}
#[test]
fn test_operator_precedence_parsing() {
let test_cases = [
("-a * b", "((-a) * b)"),
("!-a", "(!(-a))"),
("a + b + c", "((a + b) + c)"),
("a + b - c", "((a + b) - c)"),
("a * b * c", "((a * b) * c)"),
("a * b / c", "((a * b) / c)"),
("a + b / c", "(a + (b / c))"),
("a + b * c + d / e - f", "(((a + (b * c)) + (d / e)) - f)"),
("3 + 4; -5 * 5", "(3 + 4)((-5) * 5)"),
("5 > 4 == 3 < 4", "((5 > 4) == (3 < 4))"),
("5 < 4 != 3 > 4", "((5 < 4) != (3 > 4))"),
(
"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)))",
),
];
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().to_string(), test.1);
}
}
} }

View File

@ -26,6 +26,11 @@ fn start<R: BufRead, W: Write>(mut ip: R, mut out: W) {
let mut parser = Parser::new(tokens); let mut parser = Parser::new(tokens);
let stmts = parser.parse_program(); let program = parser.parse_program();
match program {
Some(stmts) => println!("{}", stmts),
None => (),
}
} }
} }