use super::*;
use crate::builder::*;
use pretty_assertions::assert_eq;
#[test]
fn test_parse_int_literals() {
assert_parses_expr_to!("123", Expr::Literal(Literal::Int(123)));
assert_parses_expr_to!("0", Expr::Literal(Literal::Int(0)));
assert_parses_expr_to!("0x7B", Expr::Literal(Literal::Int(123)));
assert_parses_expr_to!("0XfF", Expr::Literal(Literal::Int(255)));
assert_parses_expr_to!("9223372036854775807", Expr::Literal(Literal::Int(i64::MAX)));
assert_parses_expr_to!("0x0", Expr::Literal(Literal::Int(0)));
assert_parse_fails!("0x", "Pest parsing error");
assert_parse_fails!("123a", "Pest parsing error"); }
#[test]
fn test_parse_uint_literals() {
assert_parses_expr_to!("123u", Expr::Literal(Literal::Uint(123)));
assert_parses_expr_to!("0U", Expr::Literal(Literal::Uint(0)));
assert_parses_expr_to!("0x7Bu", Expr::Literal(Literal::Uint(123)));
assert_parses_expr_to!("0XFFU", Expr::Literal(Literal::Uint(255)));
assert_parses_expr_to!(
"18446744073709551615u",
Expr::Literal(Literal::Uint(u64::MAX))
);
assert_parses_expr_to!("0x0U", Expr::Literal(Literal::Uint(0)));
assert_parse_fails!("123L", "Pest parsing error"); assert_parse_fails!("123 u", "Pest parsing error"); }
#[test]
fn test_parse_float_literals() {
assert_parses_expr_to!("123.45", Expr::Literal(Literal::Float(123.45)));
assert_parses_expr_to!("0.0", Expr::Literal(Literal::Float(0.0)));
assert_parses_expr_to!(".5", Expr::Literal(Literal::Float(0.5)));
assert_parse_fails!("1."); assert_parses_expr_to!("1.0e3", Expr::Literal(Literal::Float(1000.0)));
assert_parses_expr_to!("1.2E-3", Expr::Literal(Literal::Float(0.0012)));
assert_parses_expr_to!("1e+4", Expr::Literal(Literal::Float(10000.0)));
assert_parses_expr_to!("5E1", Expr::Literal(Literal::Float(50.0)));
assert_parses_expr_to!("0e0", Expr::Literal(Literal::Float(0.0)));
assert_parses_expr_to!("1e1", Expr::Literal(Literal::Float(10.0))); }
#[test]
fn test_parse_string_literals() {
assert_parses_expr_to!(
r#""hello""#,
Expr::Literal(Literal::String("hello".to_string()))
);
assert_parses_expr_to!(r#"''"#, Expr::Literal(Literal::String("".to_string())));
assert_parses_expr_to!(r#"" ""#, Expr::Literal(Literal::String(" ".to_string())));
assert_parses_expr_to!(
r#"'world'"#,
Expr::Literal(Literal::String("world".to_string()))
);
assert_parses_expr_to!(
r#""esc\"aped""#,
Expr::Literal(Literal::String("esc\"aped".to_string()))
);
assert_parses_expr_to!(
r"'esc\'aped'",
Expr::Literal(Literal::String("esc'aped".to_string()))
);
assert_parses_expr_to!(
r#""a\\b""#,
Expr::Literal(Literal::String("a\\b".to_string()))
);
assert_parses_expr_to!(
r#""\n\r\t\a\b\f\v""#,
Expr::Literal(Literal::String("\n\r\t\u{7}\u{8}\u{C}\u{B}".to_string()))
);
assert_parses_expr_to!(
r#""\? \`""#,
Expr::Literal(Literal::String("? `".to_string()))
);
assert_parses_expr_to!(r#""\x4A""#, Expr::Literal(Literal::String("J".to_string())));
assert_parses_expr_to!(r#""\112""#, Expr::Literal(Literal::String("J".to_string())));
assert_parses_expr_to!(
r#""\377""#,
Expr::Literal(Literal::String("\u{FF}".to_string()))
);
assert_parses_expr_to!(
r#""\u004A""#,
Expr::Literal(Literal::String("J".to_string()))
);
assert_parses_expr_to!(
r#""\uABCD""#,
Expr::Literal(Literal::String("\u{ABCD}".to_string()))
);
assert_parses_expr_to!(
r#""\U0001F600""#,
Expr::Literal(Literal::String("😀".to_string()))
);
assert_parses_expr_to!(
r#"r"hello""#,
Expr::Literal(Literal::String("hello".to_string()))
);
assert_parses_expr_to!(
r#"R'world'"#,
Expr::Literal(Literal::String("world".to_string()))
);
assert_parses_expr_to!(
r#"r"a\\b\n""#,
Expr::Literal(Literal::String("a\\b\n".to_string()))
);
assert_parse_fails!(r#""unterminated"#, "Pest parsing error"); assert_parse_fails!(r"'unterminated", "Pest parsing error"); }
#[test]
fn test_parse_bytes_literals() {
assert_parses_expr_to!(r#"b"abc""#, Expr::Literal(Literal::Bytes(vec![97, 98, 99])));
assert_parses_expr_to!(
r#"B'xyz'"#,
Expr::Literal(Literal::Bytes(vec![120, 121, 122]))
);
assert_parses_expr_to!(r#"b"ÿ""#, Expr::Literal(Literal::Bytes(vec![195, 191]))); assert_parses_expr_to!(r#"b"\x61""#, Expr::Literal(Literal::Bytes(vec![0x61]))); assert_parses_expr_to!(r#"b"\141""#, Expr::Literal(Literal::Bytes(vec![0o141]))); assert_parses_expr_to!(r#"b"\xff""#, Expr::Literal(Literal::Bytes(vec![0xff]))); assert_parses_expr_to!(r#"b"\377""#, Expr::Literal(Literal::Bytes(vec![0xff]))); assert_parses_expr_to!(
r#"b"\\ \" \? \a""#,
Expr::Literal(Literal::Bytes(b"\\ \" ? \x07".to_vec()))
);
assert_parses_expr_to!(r#"b"\000""#, Expr::Literal(Literal::Bytes(vec![0])));
assert_parse_fails!(r#"b"\u0061""#, "Invalid escape sequence"); assert_parse_fails!(r#"b"\U00000061""#, "Invalid escape sequence"); assert_parse_fails!(r#"b"\400""#, "Invalid escape sequence"); assert_parse_fails!(r#"b"\xa""#, "Pest parsing error"); assert_parse_fails!(r#"b"\xZZ""#, "Pest parsing error"); assert_parse_fails!(r#"b"\181""#, "Pest parsing error"); }
#[test]
fn test_parse_bool_literals() {
assert_parses_expr_to!("true", Expr::Literal(Literal::Bool(true)));
assert_parses_expr_to!("false", Expr::Literal(Literal::Bool(false)));
}
#[test]
fn test_parse_null_literal() {
assert_parses_expr_to!("null", Expr::Literal(Literal::Null));
}
#[test]
fn test_parse_literal_failures_general() {
}
#[test]
fn test_parse_identifiers() {
assert_parses_expr_to!("myVar", Expr::Identifier("myVar".to_string()));
assert_parses_expr_to!("_a_b_c", Expr::Identifier("_a_b_c".to_string()));
assert_parses_expr_to!("x", Expr::Identifier("x".to_string()));
}
#[test]
fn test_parse_simple_binary_ops() {
assert_parses_expr_to!(
"1 + 2",
Expr::BinaryOp {
op: BinaryOperator::Add,
left: Box::new(Expr::Literal(Literal::Int(1))),
right: Box::new(Expr::Literal(Literal::Int(2))),
}
);
assert_parses_expr_to!(
"a * b",
Expr::BinaryOp {
op: BinaryOperator::Mul,
left: Box::new(Expr::Identifier("a".to_string())),
right: Box::new(Expr::Identifier("b".to_string())),
}
);
assert_parses_expr_to!(
"10 / 5",
Expr::BinaryOp {
op: BinaryOperator::Div,
left: Box::new(Expr::Literal(Literal::Int(10))),
right: Box::new(Expr::Literal(Literal::Int(5))),
}
);
assert_parses_expr_to!(
"x && y",
Expr::BinaryOp {
op: BinaryOperator::And,
left: Box::new(Expr::Identifier("x".to_string())),
right: Box::new(Expr::Identifier("y".to_string())),
}
);
assert_parses_expr_to!(
"c < 10u",
Expr::BinaryOp {
op: BinaryOperator::Lt,
left: Box::new(Expr::Identifier("c".to_string())),
right: Box::new(Expr::Literal(Literal::Uint(10))),
}
);
assert_parses_expr_to!(
"1 in [1, 2]",
Expr::BinaryOp {
op: BinaryOperator::In,
left: Box::new(Expr::Literal(Literal::Int(1))),
right: Box::new(Expr::List {
elements: vec![
Expr::Literal(Literal::Int(1)),
Expr::Literal(Literal::Int(2)),
]
}),
}
);
assert_parses_expr_to!("[]", Expr::List { elements: vec![] });
assert_parses_expr_to!(
"[1,]",
Expr::List {
elements: vec![Expr::Literal(Literal::Int(1))]
}
);
}
#[test]
fn test_parse_precedence() {
assert_parses_expr_to!(
"1 + 2 * 3",
Expr::BinaryOp {
op: BinaryOperator::Add,
left: Box::new(Expr::Literal(Literal::Int(1))),
right: Box::new(Expr::BinaryOp {
op: BinaryOperator::Mul,
left: Box::new(Expr::Literal(Literal::Int(2))),
right: Box::new(Expr::Literal(Literal::Int(3))),
}),
}
);
assert_parses_expr_to!(
"a || b && c",
Expr::BinaryOp {
op: BinaryOperator::Or,
left: Box::new(Expr::Identifier("a".to_string())),
right: Box::new(Expr::BinaryOp {
op: BinaryOperator::And,
left: Box::new(Expr::Identifier("b".to_string())),
right: Box::new(Expr::Identifier("c".to_string())),
}),
}
);
}
#[test]
fn test_parse_associativity() {
assert_parses_expr_to!(
"1 - 2 + 3",
Expr::BinaryOp {
op: BinaryOperator::Add,
left: Box::new(Expr::BinaryOp {
op: BinaryOperator::Sub,
left: Box::new(Expr::Literal(Literal::Int(1))),
right: Box::new(Expr::Literal(Literal::Int(2))),
}),
right: Box::new(Expr::Literal(Literal::Int(3))),
}
);
assert_parses_expr_to!(
"a || b || c",
Expr::BinaryOp {
op: BinaryOperator::Or,
left: Box::new(Expr::BinaryOp {
op: BinaryOperator::Or,
left: Box::new(Expr::Identifier("a".to_string())),
right: Box::new(Expr::Identifier("b".to_string())),
}),
right: Box::new(Expr::Identifier("c".to_string())),
}
);
}
#[test]
fn test_parse_parentheses() {
assert_parses_expr_to!(
"(1 + 2) * 3",
Expr::BinaryOp {
op: BinaryOperator::Mul,
left: Box::new(Expr::BinaryOp {
op: BinaryOperator::Add,
left: Box::new(Expr::Literal(Literal::Int(1))),
right: Box::new(Expr::Literal(Literal::Int(2))),
}),
right: Box::new(Expr::Literal(Literal::Int(3))),
}
);
assert_parses_expr_to!(
"1 + (2 * 3)",
Expr::BinaryOp {
op: BinaryOperator::Add,
left: Box::new(Expr::Literal(Literal::Int(1))),
right: Box::new(Expr::BinaryOp {
op: BinaryOperator::Mul,
left: Box::new(Expr::Literal(Literal::Int(2))),
right: Box::new(Expr::Literal(Literal::Int(3))),
}),
}
);
}
#[test]
fn test_parse_unary_ops() {
assert_parses_expr_to!(
"-5",
Expr::UnaryOp {
op: UnaryOperator::Neg,
operand: Box::new(Expr::Literal(Literal::Int(5))),
}
);
assert_parses_expr_to!(
"-2.3e+1",
Expr::UnaryOp {
op: UnaryOperator::Neg,
operand: Box::new(Expr::Literal(Literal::Float(23.0))),
}
);
assert_parses_expr_to!(
"-0x55555555",
Expr::UnaryOp {
op: UnaryOperator::Neg,
operand: Box::new(Expr::Literal(Literal::Int(1431655765))),
}
);
assert_parses_expr_to!(
"!true",
Expr::UnaryOp {
op: UnaryOperator::Not,
operand: Box::new(Expr::Literal(Literal::Bool(true))),
}
);
assert_parses_expr_to!(
"--a",
Expr::UnaryOp {
op: UnaryOperator::Neg,
operand: Box::new(Expr::UnaryOp {
op: UnaryOperator::Neg,
operand: Box::new(Expr::Identifier("a".to_string()))
}),
}
);
assert_parses_expr_to!(
"!-a",
Expr::UnaryOp {
op: UnaryOperator::Not,
operand: Box::new(Expr::UnaryOp {
op: UnaryOperator::Neg,
operand: Box::new(Expr::Identifier("a".to_string()))
}),
}
);
assert_parses_expr_to!(
"-a + b",
Expr::BinaryOp {
op: BinaryOperator::Add,
left: Box::new(Expr::UnaryOp {
op: UnaryOperator::Neg,
operand: Box::new(Expr::Identifier("a".to_string())),
}),
right: Box::new(Expr::Identifier("b".to_string())),
}
);
assert_parses_expr_to!(
"!a && b",
Expr::BinaryOp {
op: BinaryOperator::And,
left: Box::new(Expr::UnaryOp {
op: UnaryOperator::Not,
operand: Box::new(Expr::Identifier("a".to_string())),
}),
right: Box::new(Expr::Identifier("b".to_string())),
}
);
}
#[test]
fn test_complex_ast_construction_with_builders() {
let expected = conditional(
and(
gt(field_access(ident("user"), "age"), 18),
has(field_access(ident("request"), "id")),
),
add(
call(ident("size"), vec![ident("list_a")]),
1, ),
0, );
assert_parses_expr_to!(
"user.age > 18 && has(request.id) ? size(list_a) + 1 : 0",
expected
);
}
#[test]
fn test_builder_with_complex_list_and_map() {
let target = list(vec![lit(1), lit("two")]);
let expected = comprehension(ComprehensionOp::Exists, target, "x", eq(ident("x"), 2));
assert_parses_expr_to!("[1, 'two'].exists(x, x == 2)", expected);
}
#[test]
fn test_parse_failures() {
assert_parse_fails!("1 +"); assert_parse_fails!("(1 + 2"); assert_parse_fails!("1 ? 2"); assert_parse_fails!("a ? b :"); assert_parse_fails!("a ? : c"); assert_parse_fails!("!"); assert_parse_fails!("a ++ b"); }