1
0
Fork 0
This repository has been archived on 2025-03-30. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
compiler-course/src/compiler/parser/tests.rs

274 lines
5.8 KiB
Rust
Raw Normal View History

use super::*;
2025-01-31 13:03:38 +02:00
use crate::compiler::tokenizer::tokenize;
macro_rules! int_ast {
($x:expr) => {
Box::new(IntLiteral($x))
};
}
macro_rules! id_ast {
($x:expr) => {
Box::new(Identifier($x))
};
}
macro_rules! bin_ast {
($x:expr, $y:expr, $z:expr) => {
Box::new(BinaryOp($x, $y, $z))
};
}
macro_rules! bool_ast {
($x:expr) => {
Box::new(BoolLiteral($x))
};
}
2025-01-29 16:51:33 +02:00
#[test]
#[should_panic]
fn test_empty() {
parse(&vec![]);
}
#[test]
#[should_panic]
fn test_invalid_start() {
2025-01-31 13:03:38 +02:00
parse(&tokenize("1 2 + 3"));
2025-01-29 16:51:33 +02:00
}
#[test]
#[should_panic]
fn test_invalid_middle() {
2025-01-31 13:03:38 +02:00
parse(&tokenize("1 + 2 2 + 3"));
2025-01-29 16:51:33 +02:00
}
#[test]
#[should_panic]
fn test_invalid_end() {
2025-01-31 13:03:38 +02:00
parse(&tokenize("1 + 2 3"));
2025-01-29 16:51:33 +02:00
}
#[test]
fn test_binary_op_basic() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 + 23"));
assert_eq!(result, BinaryOp(int_ast!(1), "+", int_ast!(23)));
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("4 - 56"));
assert_eq!(result, BinaryOp(int_ast!(4), "-", int_ast!(56)));
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 * 2"));
assert_eq!(result, BinaryOp(int_ast!(1), "*", int_ast!(2)));
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 / 2"));
assert_eq!(result, BinaryOp(int_ast!(1), "/", int_ast!(2)));
}
#[test]
fn test_binary_op_all_levels() {
let result = parse(&tokenize("1 * 2 + 3 < 4 == 5 and 6 or 7"));
assert_eq!(
result,
BinaryOp(
bin_ast!(
bin_ast!(
bin_ast!(
bin_ast!(bin_ast!(int_ast!(1), "*", int_ast!(2)), "+", int_ast!(3)),
"<",
int_ast!(4)
),
"==",
int_ast!(5)
),
"and",
int_ast!(6)
),
"or",
int_ast!(7)
)
);
}
#[test]
fn test_binary_op_identifier() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("a + 1"));
assert_eq!(result, BinaryOp(id_ast!("a"), "+", int_ast!(1)));
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 - a"));
assert_eq!(result, BinaryOp(int_ast!(1), "-", id_ast!("a")));
}
#[test]
fn test_binary_op_multiple() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 + 2 - 3"));
assert_eq!(
result,
BinaryOp(bin_ast!(int_ast!(1), "+", int_ast!(2)), "-", int_ast!(3))
);
}
#[test]
fn test_binary_op_precedence() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 + 2 * 3"));
assert_eq!(
result,
BinaryOp(int_ast!(1), "+", bin_ast!(int_ast!(2), "*", int_ast!(3)),)
);
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 - 2 / 3"));
assert_eq!(
result,
BinaryOp(int_ast!(1), "-", bin_ast!(int_ast!(2), "/", int_ast!(3)),)
);
}
#[test]
fn test_parenthesized() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("(1+2)*3"));
assert_eq!(
result,
BinaryOp(bin_ast!(int_ast!(1), "+", int_ast!(2)), "*", int_ast!(3),)
);
2025-01-29 16:51:33 +02:00
}
2025-01-29 16:51:33 +02:00
#[test]
fn test_parenthesized_nested() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("((1 - 2))/3"));
assert_eq!(
result,
BinaryOp(bin_ast!(int_ast!(1), "-", int_ast!(2)), "/", int_ast!(3),)
);
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("((1 + 2)*3) / 4"));
assert_eq!(
result,
BinaryOp(
bin_ast!(bin_ast!(int_ast!(1), "+", int_ast!(2)), "*", int_ast!(3)),
"/",
int_ast!(4)
)
);
}
2025-01-29 16:51:33 +02:00
#[test]
#[should_panic]
fn test_parenthesized_mismatched() {
2025-01-31 13:03:38 +02:00
parse(&tokenize("(1+2*3"));
2025-01-29 16:51:33 +02:00
}
#[test]
fn test_if_then() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("if 1 + 2 then 3"));
assert_eq!(
result,
Conditional(bin_ast!(int_ast!(1), "+", int_ast!(2)), int_ast!(3), None,)
);
}
#[test]
fn test_if_then_else() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("if a then b + c else 1 * 2"));
assert_eq!(
result,
Conditional(
id_ast!("a"),
bin_ast!(id_ast!("b"), "+", id_ast!("c")),
Some(bin_ast!(int_ast!(1), "*", int_ast!(2)))
)
);
}
#[test]
2025-01-29 16:51:33 +02:00
fn test_if_then_else_embedded() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 + if true then 2 else 3"));
assert_eq!(
result,
BinaryOp(
int_ast!(1),
"+",
Box::new(Conditional(bool_ast!(true), int_ast!(2), Some(int_ast!(3))))
)
);
}
#[test]
2025-01-29 16:51:33 +02:00
fn test_if_then_else_nested() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("if true then if false then 1 else 2 else 3"));
assert_eq!(
result,
Conditional(
bool_ast!(true),
Box::new(Conditional(
bool_ast!(false),
int_ast!(1),
Some(int_ast!(2))
)),
Some(int_ast!(3))
)
);
}
2025-01-29 16:51:33 +02:00
#[test]
#[should_panic]
fn test_if_no_then() {
2025-01-31 13:03:38 +02:00
parse(&tokenize("if true"));
2025-01-29 16:51:33 +02:00
}
#[test]
fn test_func_basic() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("f(a, b)"));
assert_eq!(
result,
FunCall("f", vec![Identifier("a"), Identifier("b"),])
);
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("f(a, 1 + 2)"));
assert_eq!(
result,
FunCall(
"f",
vec![Identifier("a"), BinaryOp(int_ast!(1), "+", int_ast!(2),),]
)
);
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("f()"));
assert_eq!(result, FunCall("f", vec![]));
}
#[test]
2025-01-29 16:51:33 +02:00
fn test_func_embedded() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("1 + f(a)"));
assert_eq!(
result,
2025-01-29 16:51:33 +02:00
BinaryOp(
int_ast!(1),
"+",
Box::new(FunCall("f", vec![Identifier("a")]))
)
);
}
#[test]
2025-01-29 16:51:33 +02:00
fn test_func_nested() {
2025-01-31 13:03:38 +02:00
let result = parse(&tokenize("f(a, g(b))"));
assert_eq!(
result,
2025-01-29 16:51:33 +02:00
FunCall(
"f",
vec![Identifier("a"), FunCall("g", vec![Identifier("b")]),]
)
);
}
#[test]
#[should_panic]
fn test_func_missing_comma() {
2025-01-31 13:03:38 +02:00
parse(&tokenize("f(a b)"));
}
#[test]
#[should_panic]
fn test_func_missing_close() {
2025-01-31 13:03:38 +02:00
parse(&tokenize("f(a"));
}