add operator precedences tests
This commit is contained in:
parent
d84878c323
commit
b9d9f5b87e
270
src/parser.rs
270
src/parser.rs
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue