use bumpalo::Bump;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use zen_parser::ast::Node;
use zen_parser::lexer::Lexer;
use zen_parser::parser::StandardParser;
struct StandardTest {
src: &'static str,
result: &'static Node<'static>,
}
const D0: Decimal = dec!(0);
const D1: Decimal = dec!(1);
const D2: Decimal = dec!(2);
const D2P5: Decimal = dec!(2.5);
const D3: Decimal = dec!(3);
const D4: Decimal = dec!(4);
const D9: Decimal = dec!(9);
const D10: Decimal = dec!(10);
const D25: Decimal = dec!(25);
const D10_000_000: Decimal = dec!(10_000_000);
#[test]
fn standard_test() {
let tests: Vec<StandardTest> = Vec::from([
StandardTest {
src: ")10..25(",
result: &Node::Interval {
left_bracket: ")",
left: &Node::Number(D10),
right: &Node::Number(D25),
right_bracket: "(",
},
},
StandardTest {
src: "a",
result: &Node::Identifier("a"),
},
StandardTest {
src: "'str'",
result: &Node::String("str"),
},
StandardTest {
src: "3",
result: &Node::Number(D3),
},
StandardTest {
src: "10_000_000",
result: &Node::Number(D10_000_000),
},
StandardTest {
src: "2.5",
result: &Node::Number(D2P5),
},
StandardTest {
src: "true",
result: &Node::Bool(true),
},
StandardTest {
src: "false",
result: &Node::Bool(false),
},
StandardTest {
src: "null",
result: &Node::Null,
},
StandardTest {
src: "-3",
result: &Node::Unary {
operator: "-",
node: &Node::Number(D3),
},
},
StandardTest {
src: "1 - 2",
result: &Node::Binary {
left: &Node::Number(D1),
operator: "-",
right: &Node::Number(D2),
},
},
StandardTest {
src: "(1 - 2) * 3",
result: &Node::Binary {
left: &Node::Binary {
left: &Node::Number(D1),
operator: "-",
right: &Node::Number(D2),
},
operator: "*",
right: &Node::Number(D3),
},
},
StandardTest {
src: "a or b or c",
result: &Node::Binary {
operator: "or",
left: &Node::Binary {
left: &Node::Identifier("a"),
right: &Node::Identifier("b"),
operator: "or",
},
right: &Node::Identifier("c"),
},
},
StandardTest {
src: "a or b and c",
result: &Node::Binary {
operator: "or",
left: &Node::Identifier("a"),
right: &Node::Binary {
left: &Node::Identifier("b"),
right: &Node::Identifier("c"),
operator: "and",
},
},
},
StandardTest {
src: "(a or b) and c",
result: &Node::Binary {
operator: "and",
left: &Node::Binary {
left: &Node::Identifier("a"),
right: &Node::Identifier("b"),
operator: "or",
},
right: &Node::Identifier("c"),
},
},
StandardTest {
src: "2^4 - 1",
result: &Node::Binary {
left: &Node::Binary {
operator: "^",
left: &Node::Number(D2),
right: &Node::Number(D4),
},
operator: "-",
right: &Node::Number(D1),
},
},
StandardTest {
src: "foo.and",
result: &Node::Member {
node: &Node::Identifier("foo"),
property: &Node::String("and"),
},
},
StandardTest {
src: "foo.all",
result: &Node::Member {
node: &Node::Identifier("foo"),
property: &Node::String("all"),
},
},
StandardTest {
src: "foo[3]",
result: &Node::Member {
node: &Node::Identifier("foo"),
property: &Node::Number(D3),
},
},
StandardTest {
src: "true ? true : false",
result: &Node::Conditional {
condition: &Node::Bool(true),
on_true: &Node::Bool(true),
on_false: &Node::Bool(false),
},
},
StandardTest {
src: "a ? [b] : c",
result: &Node::Conditional {
condition: &Node::Identifier("a"),
on_true: &Node::Array(&[&Node::Identifier("b")]),
on_false: &Node::Identifier("c"),
},
},
StandardTest {
src: "'a' == 'b'",
result: &Node::Binary {
left: &Node::String("a"),
right: &Node::String("b"),
operator: "==",
},
},
StandardTest {
src: "+0 != -1",
result: &Node::Binary {
left: &Node::Unary {
operator: "+",
node: &Node::Number(D0),
},
right: &Node::Unary {
operator: "-",
node: &Node::Number(D1),
},
operator: "!=",
},
},
StandardTest {
src: "[a, b, c]",
result: &Node::Array(&[
&Node::Identifier("a"),
&Node::Identifier("b"),
&Node::Identifier("c"),
]),
},
StandardTest {
src: "[9].foo",
result: &Node::Member {
node: &Node::Array(&[&Node::Number(D9)]),
property: &Node::String("foo"),
},
},
StandardTest {
src: "x not in (1..9]",
result: &Node::Binary {
left: &Node::Identifier("x"),
operator: "not in",
right: &Node::Interval {
left_bracket: "(",
left: &Node::Number(D1),
right: &Node::Number(D9),
right_bracket: "]",
},
},
},
StandardTest {
src: "not in_var",
result: &Node::Unary {
operator: "not",
node: &Node::Identifier("in_var"),
},
},
StandardTest {
src: "array[1:2]",
result: &Node::Slice {
node: &Node::Identifier("array"),
from: Some(&Node::Number(D1)),
to: Some(&Node::Number(D2)),
},
},
StandardTest {
src: "array[:2]",
result: &Node::Slice {
node: &Node::Identifier("array"),
from: None,
to: Some(&Node::Number(D2)),
},
},
StandardTest {
src: "array[1:]",
result: &Node::Slice {
node: &Node::Identifier("array"),
from: Some(&Node::Number(D1)),
to: None,
},
},
StandardTest {
src: "array[:]",
result: &Node::Slice {
node: &Node::Identifier("array"),
from: None,
to: None,
},
},
StandardTest {
src: "[]",
result: &Node::Array(&[]),
},
StandardTest {
src: "0 in []",
result: &Node::Binary {
left: &Node::Number(D0),
operator: "in",
right: &Node::Array(&[]),
},
},
]);
let lexer = Lexer::new();
let mut bump = Bump::new();
for StandardTest { src, result } in tests {
let t_res = lexer.tokenize(src).unwrap();
let tokens = t_res.borrow();
let unary_parser = StandardParser::try_new(tokens.as_ref(), &bump).unwrap();
let ast = unary_parser.parse();
assert_eq!(ast.unwrap(), result);
bump.reset();
}
}
#[test]
fn failure_tests() {
let tests: Vec<&str> = Vec::from(["a + b ++"]);
let lexer = Lexer::new();
let mut bump = Bump::new();
for test in tests {
let t_res = lexer.tokenize(test).unwrap();
let tokens = t_res.borrow();
let unary_parser = StandardParser::try_new(tokens.as_ref(), &bump).unwrap();
let ast = unary_parser.parse();
assert!(ast.is_err());
bump.reset();
}
}