add operator precedences tests

This commit is contained in:
Victor Timofei 2023-09-10 23:36:10 +03:00
parent d84878c323
commit b9d9f5b87e
Signed by: vtimofei
GPG Key ID: B790DCEBE281403A
1 changed files with 268 additions and 2 deletions

View File

@ -418,8 +418,8 @@ mod tests {
use crate::{
ast::{
Boolean, ExpressionStatement, Identifier, Infix, InfixOperator, IntegerLiteral, Let,
Prefix, PrefixOperator, Program, Return, Statement,
Boolean, DummyExpression, Expression, ExpressionStatement, Identifier, Infix,
InfixOperator, IntegerLiteral, Let, Prefix, PrefixOperator, Program, Return, Statement,
},
lexer::Lexer,
token::{Token, TokenType},
@ -708,6 +708,272 @@ mod tests {
}
}
#[test]
fn operator_precedences() {
struct Test {
input: String,
expression: Rc<dyn Expression>,
}
let tests = vec![
Test {
input: "-a * b".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Asterisk,
left: Rc::new(Prefix {
operator: PrefixOperator::Minus,
right: Rc::new(Identifier {
value: "a".into(),
token_type: TokenType::Ident,
}),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "b".into(),
}),
}),
},
Test {
input: "!-a".into(),
expression: Rc::new(Prefix {
operator: PrefixOperator::Bang,
right: Rc::new(Prefix {
operator: PrefixOperator::Minus,
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "a".into(),
}),
}),
}),
},
Test {
input: "a + b + c".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Plus,
left: Rc::new(Infix {
operator: InfixOperator::Plus,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "a".into(),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "b".into(),
}),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "c".into(),
}),
}),
},
Test {
input: "a + b - c".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Minus,
left: Rc::new(Infix {
operator: InfixOperator::Plus,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "a".into(),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "b".into(),
}),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "c".into(),
}),
}),
},
Test {
input: "a * b * c".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Asterisk,
left: Rc::new(Infix {
operator: InfixOperator::Asterisk,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "a".into(),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "b".into(),
}),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "c".into(),
}),
}),
},
Test {
input: "a * b / c".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Slash,
left: Rc::new(Infix {
operator: InfixOperator::Asterisk,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "a".into(),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "b".into(),
}),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "c".into(),
}),
}),
},
Test {
input: "a + b / c".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Plus,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "a".into(),
}),
right: Rc::new(Infix {
operator: InfixOperator::Slash,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "b".into(),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "c".into(),
}),
}),
}),
},
Test {
input: "a + b * c + d / e - f".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Minus,
left: Rc::new(Infix {
operator: InfixOperator::Plus,
left: Rc::new(Infix {
operator: InfixOperator::Plus,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "a".into(),
}),
right: Rc::new(Infix {
operator: InfixOperator::Asterisk,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "b".into(),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "c".into(),
}),
}),
}),
right: Rc::new(Infix {
operator: InfixOperator::Slash,
left: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "d".into(),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "e".into(),
}),
}),
}),
right: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "f".into(),
}),
}),
},
Test {
input: "5 > 4 == 3 < 4".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Eq,
left: Rc::new(Infix {
operator: InfixOperator::Gt,
left: Rc::new(IntegerLiteral { value: 5 }),
right: Rc::new(IntegerLiteral { value: 4 }),
}),
right: Rc::new(Infix {
operator: InfixOperator::Lt,
left: Rc::new(IntegerLiteral { value: 3 }),
right: Rc::new(IntegerLiteral { value: 4 }),
}),
}),
},
Test {
input: "5 < 4 != 3 > 4".into(),
expression: Rc::new(Infix {
operator: InfixOperator::NotEq,
left: Rc::new(Infix {
operator: InfixOperator::Lt,
left: Rc::new(IntegerLiteral { value: 5 }),
right: Rc::new(IntegerLiteral { value: 4 }),
}),
right: Rc::new(Infix {
operator: InfixOperator::Gt,
left: Rc::new(IntegerLiteral { value: 3 }),
right: Rc::new(IntegerLiteral { value: 4 }),
}),
}),
},
Test {
input: "3 + 4 * 5 == 3 * 1 + 4 * 5".into(),
expression: Rc::new(Infix {
operator: InfixOperator::Eq,
left: Rc::new(Infix {
operator: InfixOperator::Plus,
left: Rc::new(IntegerLiteral { value: 3 }),
right: Rc::new(Infix {
operator: InfixOperator::Asterisk,
left: Rc::new(IntegerLiteral { value: 4 }),
right: Rc::new(IntegerLiteral { value: 5 }),
}),
}),
right: Rc::new(Infix {
operator: InfixOperator::Plus,
left: Rc::new(Infix {
operator: InfixOperator::Asterisk,
left: Rc::new(IntegerLiteral { value: 3 }),
right: Rc::new(IntegerLiteral { value: 1 }),
}),
right: Rc::new(Infix {
operator: InfixOperator::Asterisk,
left: Rc::new(IntegerLiteral { value: 4 }),
right: Rc::new(IntegerLiteral { value: 5 }),
}),
}),
}),
},
];
for test in tests {
let l = Lexer::new(test.input);
let mut parser = Parser::new(l);
let program = parser.parse().unwrap();
check_parser_errors(parser);
assert_eq!(
program,
Program {
statements: vec![Rc::new(ExpressionStatement {
expression: test.expression
})]
}
);
}
}
fn check_parser_errors(parser: Parser) {
if parser.errors().len() == 0 {
return;