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::{
103 parse_expression, ArithmeticOp::*, Expression, Expression::*, Literal::*, Member::*,
104 };
105
106 fn parse(input: &str) -> Expression {
107 parse_expression(input.to_string()).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
178 #[test]
179 fn has_macro() {
180 assert_parse_eq(
181 "has(a.b)",
182 Has(Member(
183 Ident("a".to_string().into()).into(),
184 Attribute("b".to_string().into()).into(),
185 )
186 .into()),
187 );
188 assert_parse_eq(
189 "has(params.field)",
190 Has(Member(
191 Ident("params".to_string().into()).into(),
192 Attribute("field".to_string().into()).into(),
193 )
194 .into()),
195 );
196 assert_parse_eq(
198 "has(a.b.c.d)",
199 Has(Member(
200 Member(
201 Member(
202 Ident("a".to_string().into()).into(),
203 Attribute("b".to_string().into()).into(),
204 )
205 .into(),
206 Attribute("c".to_string().into()).into(),
207 )
208 .into(),
209 Attribute("d".to_string().into()).into(),
210 )
211 .into()),
212 );
213 }
214}