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}