sqlx_ledger_cel_parser/
ast.rs

1use std::sync::Arc;
2
3#[derive(Debug, Eq, PartialEq, Clone)]
4pub enum LogicOp {
5    And,
6    Or,
7}
8
9#[derive(Debug, Eq, PartialEq, Clone, Copy)]
10pub enum RelationOp {
11    LessThan,
12    LessThanEq,
13    GreaterThan,
14    GreaterThanEq,
15    Equals,
16    NotEquals,
17    In,
18}
19
20#[derive(Debug, Eq, PartialEq, Clone, Copy)]
21pub enum ArithmeticOp {
22    Add,
23    Subtract,
24    Divide,
25    Multiply,
26    Modulus,
27}
28
29#[derive(Debug, Eq, PartialEq, Clone)]
30pub enum UnaryOp {
31    Not,
32    DoubleNot,
33    Minus,
34    DoubleMinus,
35}
36
37#[derive(Debug, Eq, PartialEq, Clone)]
38pub enum LeftRightOp {
39    Logic(LogicOp),
40    Relation(RelationOp),
41    Arithmetic(ArithmeticOp),
42}
43
44#[derive(Debug, PartialEq, Clone)]
45pub enum Expression {
46    Ternary(Box<Expression>, Box<Expression>, Box<Expression>),
47    Relation(RelationOp, Box<Expression>, Box<Expression>),
48    Arithmetic(ArithmeticOp, Box<Expression>, Box<Expression>),
49    Unary(UnaryOp, Box<Expression>),
50
51    Member(Box<Expression>, Box<Member>),
52
53    List(Vec<Expression>),
54    Map(Vec<(Expression, Expression)>),
55    Struct(Vec<Arc<String>>, Vec<(Arc<String>, Expression)>),
56
57    Literal(Literal),
58    Ident(Arc<String>),
59}
60
61impl Expression {
62    pub(crate) fn from_op(op: LeftRightOp, left: Box<Expression>, right: Box<Expression>) -> Self {
63        use LeftRightOp::*;
64        match op {
65            Logic(LogicOp::Or) => Expression::Ternary(
66                left,
67                Box::new(Expression::Literal(Literal::Bool(true))),
68                right,
69            ),
70            Logic(LogicOp::And) => Expression::Ternary(
71                left,
72                right,
73                Box::new(Expression::Literal(Literal::Bool(false))),
74            ),
75            Relation(op) => Expression::Relation(op, left, right),
76            Arithmetic(op) => Expression::Arithmetic(op, left, right),
77        }
78    }
79}
80
81#[derive(Debug, PartialEq, Clone)]
82pub enum Member {
83    Attribute(Arc<String>),
84    FunctionCall(Vec<Expression>),
85    Index(Box<Expression>),
86}
87
88#[derive(Debug, PartialEq, Eq, Clone)]
89pub enum Literal {
90    Int(i64),
91    UInt(u64),
92    Double(Arc<String>),
93    String(Arc<String>),
94    Bytes(Arc<Vec<u8>>),
95    Bool(bool),
96    Null,
97}
98
99#[cfg(test)]
100mod tests {
101    use crate::parser::ExpressionParser;
102    use crate::{ArithmeticOp::*, Expression, Expression::*, Literal::*, Member::*};
103
104    fn parse(input: &str) -> Expression {
105        ExpressionParser::new()
106            .parse(input)
107            .unwrap_or_else(|e| panic!("{}", e))
108    }
109
110    fn assert_parse_eq(input: &str, expected: Expression) {
111        assert_eq!(parse(input), expected);
112    }
113
114    #[test]
115    fn op_precedence() {
116        assert_parse_eq(
117            "1 + 2 * 3",
118            Arithmetic(
119                Add,
120                Literal(Int(1)).into(),
121                Arithmetic(Multiply, Literal(Int(2)).into(), Literal(Int(3)).into()).into(),
122            ),
123        );
124        assert_parse_eq(
125            "1 * 2 + 3",
126            Arithmetic(
127                Add,
128                Arithmetic(Multiply, Literal(Int(1)).into(), Literal(Int(2)).into()).into(),
129                Literal(Int(3)).into(),
130            ),
131        );
132        assert_parse_eq(
133            "1 * (2 + 3)",
134            Arithmetic(
135                Multiply,
136                Literal(Int(1)).into(),
137                Arithmetic(Add, Literal(Int(2)).into(), Literal(Int(3)).into()).into(),
138            ),
139        )
140    }
141
142    #[test]
143    fn simple_int() {
144        assert_parse_eq("1", Literal(Int(1)))
145    }
146
147    #[test]
148    fn simple_float() {
149        assert_parse_eq("1.0", Literal(Double("1.0".to_string().into())))
150    }
151
152    #[test]
153    fn lookup() {
154        assert_parse_eq(
155            "hello.world",
156            Member(
157                Ident("hello".to_string().into()).into(),
158                Attribute("world".to_string().into()).into(),
159            ),
160        )
161    }
162
163    #[test]
164    fn nested_attributes() {
165        assert_parse_eq(
166            "a.b[1]",
167            Member(
168                Member(
169                    Ident("a".to_string().into()).into(),
170                    Attribute("b".to_string().into()).into(),
171                )
172                .into(),
173                Index(Literal(Int(1)).into()).into(),
174            ),
175        )
176    }
177}