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 Has(Box<Expression>),
53
54 List(Vec<Expression>),
55 Map(Vec<(Expression, Expression)>),
56 Struct(Vec<Arc<String>>, Vec<(Arc<String>, Expression)>),
57
58 Literal(Literal),
59 Ident(Arc<String>),
60}
61
62impl Expression {
63 pub(crate) fn from_op(op: LeftRightOp, left: Box<Expression>, right: Box<Expression>) -> Self {
64 use LeftRightOp::*;
65 match op {
66 Logic(LogicOp::Or) => Expression::Ternary(
67 left,
68 Box::new(Expression::Literal(Literal::Bool(true))),
69 right,
70 ),
71 Logic(LogicOp::And) => Expression::Ternary(
72 left,
73 right,
74 Box::new(Expression::Literal(Literal::Bool(false))),
75 ),
76 Relation(op) => Expression::Relation(op, left, right),
77 Arithmetic(op) => Expression::Arithmetic(op, left, right),
78 }
79 }
80}
81
82#[derive(Debug, PartialEq, Clone)]
83pub enum Member {
84 Attribute(Arc<String>),
85 FunctionCall(Vec<Expression>),
86 Index(Box<Expression>),
87}
88
89#[derive(Debug, PartialEq, Eq, Clone)]
90pub enum Literal {
91 Int(i64),
92 UInt(u64),
93 Double(Arc<String>),
94 String(Arc<String>),
95 Bytes(Arc<Vec<u8>>),
96 Bool(bool),
97 Null,
98}
99
100#[cfg(test)]
101mod tests {
102 use crate::parser::ExpressionParser;
103 use crate::{ArithmeticOp::*, Expression, Expression::*, Literal::*, Member::*};
104
105 fn parse(input: &str) -> Expression {
106 ExpressionParser::new()
107 .parse(input)
108 .unwrap_or_else(|e| panic!("{}", e))
109 }
110
111 fn assert_parse_eq(input: &str, expected: Expression) {
112 assert_eq!(parse(input), expected);
113 }
114
115 #[test]
116 fn op_precedence() {
117 assert_parse_eq(
118 "1 + 2 * 3",
119 Arithmetic(
120 Add,
121 Literal(Int(1)).into(),
122 Arithmetic(Multiply, Literal(Int(2)).into(), Literal(Int(3)).into()).into(),
123 ),
124 );
125 assert_parse_eq(
126 "1 * 2 + 3",
127 Arithmetic(
128 Add,
129 Arithmetic(Multiply, Literal(Int(1)).into(), Literal(Int(2)).into()).into(),
130 Literal(Int(3)).into(),
131 ),
132 );
133 assert_parse_eq(
134 "1 * (2 + 3)",
135 Arithmetic(
136 Multiply,
137 Literal(Int(1)).into(),
138 Arithmetic(Add, Literal(Int(2)).into(), Literal(Int(3)).into()).into(),
139 ),
140 )
141 }
142
143 #[test]
144 fn simple_int() {
145 assert_parse_eq("1", Literal(Int(1)))
146 }
147
148 #[test]
149 fn simple_float() {
150 assert_parse_eq("1.0", Literal(Double("1.0".to_string().into())))
151 }
152
153 #[test]
154 fn lookup() {
155 assert_parse_eq(
156 "hello.world",
157 Member(
158 Ident("hello".to_string().into()).into(),
159 Attribute("world".to_string().into()).into(),
160 ),
161 )
162 }
163
164 #[test]
165 fn nested_attributes() {
166 assert_parse_eq(
167 "a.b[1]",
168 Member(
169 Member(
170 Ident("a".to_string().into()).into(),
171 Attribute("b".to_string().into()).into(),
172 )
173 .into(),
174 Index(Literal(Int(1)).into()).into(),
175 ),
176 )
177 }
178
179 #[test]
180 fn has_macro() {
181 assert_parse_eq(
182 "has(a.b)",
183 Has(Member(
184 Ident("a".to_string().into()).into(),
185 Attribute("b".to_string().into()).into(),
186 )
187 .into()),
188 );
189 assert_parse_eq(
190 "has(params.field)",
191 Has(Member(
192 Ident("params".to_string().into()).into(),
193 Attribute("field".to_string().into()).into(),
194 )
195 .into()),
196 );
197 assert_parse_eq(
199 "has(a.b.c.d)",
200 Has(Member(
201 Member(
202 Member(
203 Ident("a".to_string().into()).into(),
204 Attribute("b".to_string().into()).into(),
205 )
206 .into(),
207 Attribute("c".to_string().into()).into(),
208 )
209 .into(),
210 Attribute("d".to_string().into()).into(),
211 )
212 .into()),
213 );
214 }
215}