1use super::*;
6use serde_derive::Serialize;
7
8#[derive(Debug, Clone, Serialize, PartialEq)]
9#[serde(rename_all = "lowercase")]
10#[serde(tag = "type")]
11pub enum Expr {
12 Unit { name: String },
13 Quote { string: String },
14 Const { value: Numeric },
15 Date { tokens: Vec<DateToken> },
16 BinOp(BinOpExpr),
17 UnaryOp(UnaryOpExpr),
18 Mul { exprs: Vec<Expr> },
19 Of { property: String, expr: Box<Expr> },
20 Call { func: Function, args: Vec<Expr> },
21 Error { message: String },
22}
23
24impl Expr {
25 pub fn new_const(value: Numeric) -> Expr {
26 Expr::Const { value }
27 }
28
29 pub fn new_error(message: String) -> Expr {
30 Expr::Error { message }
31 }
32
33 pub fn new_unit(name: String) -> Expr {
34 Expr::Unit { name }
35 }
36
37 pub fn new_call(func: Function, args: Vec<Expr>) -> Expr {
38 Expr::Call { func, args }
39 }
40
41 pub fn new_mul(mut exprs: Vec<Expr>) -> Expr {
42 if exprs.len() == 1 {
43 exprs.pop().unwrap()
44 } else {
45 Expr::Mul { exprs }
46 }
47 }
48
49 pub fn new_bin(op: BinOpType, numer: Expr, denom: Expr) -> Expr {
50 let left = Box::new(numer);
51 let right = Box::new(denom);
52 Expr::BinOp(BinOpExpr { op, left, right })
53 }
54
55 pub fn new_add(numer: Expr, denom: Expr) -> Expr {
56 Expr::new_bin(BinOpType::Add, numer, denom)
57 }
58
59 pub fn new_sub(numer: Expr, denom: Expr) -> Expr {
60 Expr::new_bin(BinOpType::Sub, numer, denom)
61 }
62
63 pub fn new_frac(numer: Expr, denom: Expr) -> Expr {
64 Expr::new_bin(BinOpType::Frac, numer, denom)
65 }
66
67 pub fn new_pow(numer: Expr, denom: Expr) -> Expr {
68 Expr::new_bin(BinOpType::Pow, numer, denom)
69 }
70
71 pub fn new_equals(numer: Expr, denom: Expr) -> Expr {
72 Expr::new_bin(BinOpType::Equals, numer, denom)
73 }
74
75 pub fn new_of(property: &str, expr: Expr) -> Expr {
76 let property = property.to_owned();
77 let expr = Box::new(expr);
78 Expr::Of { property, expr }
79 }
80
81 pub fn new_unary(op: UnaryOpType, expr: Expr) -> Expr {
82 let expr = Box::new(expr);
83 Expr::UnaryOp(UnaryOpExpr { op, expr })
84 }
85
86 pub fn new_suffix(suffix: Degree, expr: Expr) -> Expr {
87 let op = UnaryOpType::Degree(suffix);
88 Expr::new_unary(op, expr)
89 }
90
91 pub fn new_plus(expr: Expr) -> Expr {
92 Expr::new_unary(UnaryOpType::Positive, expr)
93 }
94
95 pub fn new_negate(expr: Expr) -> Expr {
96 Expr::new_unary(UnaryOpType::Negative, expr)
97 }
98}
99
100#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy)]
101pub enum Precedence {
102 Term,
103 Plus,
104 Pow,
105 Mul,
106 Div,
107 Add,
108 Equals,
109}
110
111impl Precedence {
112 pub fn from(binop_type: BinOpType) -> Precedence {
113 match binop_type {
114 BinOpType::Add => Precedence::Add,
115 BinOpType::Sub => Precedence::Add,
116 BinOpType::Pow => Precedence::Pow,
117 BinOpType::Frac => Precedence::Div,
118 BinOpType::ShiftL => Precedence::Div,
119 BinOpType::ShiftR => Precedence::Div,
120 BinOpType::Mod => Precedence::Div,
121 BinOpType::And => Precedence::Div,
122 BinOpType::Or => Precedence::Div,
123 BinOpType::Xor => Precedence::Div,
124 BinOpType::Equals => Precedence::Equals,
125 }
126 }
127
128 pub fn next(binop_type: BinOpType) -> Precedence {
129 match binop_type {
130 BinOpType::Add => Precedence::Div,
131 BinOpType::Sub => Precedence::Div,
132 BinOpType::Pow => Precedence::Term,
133 BinOpType::Frac => Precedence::Mul,
134 BinOpType::ShiftL => Precedence::Mul,
135 BinOpType::ShiftR => Precedence::Mul,
136 BinOpType::Mod => Precedence::Mul,
137 BinOpType::And => Precedence::Mul,
138 BinOpType::Or => Precedence::Mul,
139 BinOpType::Xor => Precedence::Mul,
140 BinOpType::Equals => Precedence::Add,
141 }
142 }
143}
144
145impl fmt::Display for Expr {
146 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
147 fn recurse(expr: &Expr, fmt: &mut fmt::Formatter<'_>, prec: Precedence) -> fmt::Result {
148 match *expr {
149 Expr::Unit { ref name } => write!(fmt, "{}", name),
150 Expr::Quote { ref string } => write!(fmt, "'{}'", string),
151 Expr::Const { ref value } => {
152 let (_exact, val) = value.to_string(10, Digits::Default);
153 write!(fmt, "{}", val)
154 }
155 Expr::Date { .. } => write!(fmt, "NYI: date expr Display"),
156 Expr::BinOp(ref binop) => {
157 let op_prec = Precedence::from(binop.op);
158 let succ = Precedence::next(binop.op);
159 if prec < op_prec {
160 write!(fmt, "(")?;
161 }
162 recurse(&binop.left, fmt, succ)?;
163 write!(fmt, "{}", binop.op.symbol())?;
164 recurse(&binop.right, fmt, op_prec)?;
165 if prec < op_prec {
166 write!(fmt, ")")?;
167 }
168 Ok(())
169 }
170 Expr::UnaryOp(ref unaryop) => match unaryop.op {
171 UnaryOpType::Positive => {
172 write!(fmt, "+")?;
173 recurse(&unaryop.expr, fmt, Precedence::Plus)
174 }
175 UnaryOpType::Negative => {
176 write!(fmt, "-")?;
177 recurse(&unaryop.expr, fmt, Precedence::Plus)
178 }
179 UnaryOpType::Degree(ref suffix) => {
180 if prec < Precedence::Mul {
181 write!(fmt, "(")?;
182 }
183 recurse(&unaryop.expr, fmt, Precedence::Mul)?;
184 write!(fmt, " {}", suffix)?;
185 if prec < Precedence::Mul {
186 write!(fmt, ")")?;
187 }
188 Ok(())
189 }
190 },
191 Expr::Mul { ref exprs } => {
192 if prec < Precedence::Mul {
193 write!(fmt, "(")?;
194 }
195 if let Some(first) = exprs.first() {
196 recurse(first, fmt, Precedence::Pow)?;
197 }
198 for expr in exprs.iter().skip(1) {
199 write!(fmt, " ")?;
200 recurse(expr, fmt, Precedence::Pow)?;
201 }
202 if prec < Precedence::Mul {
203 write!(fmt, ")")?;
204 }
205 Ok(())
206 }
207 Expr::Call { ref func, ref args } => {
208 write!(fmt, "{}(", func.name())?;
209 if let Some(first) = args.first() {
210 recurse(first, fmt, Precedence::Equals)?;
211 }
212 for arg in args.iter().skip(1) {
213 write!(fmt, ", ")?;
214 recurse(arg, fmt, Precedence::Equals)?;
215 }
216 write!(fmt, ")")
217 }
218 Expr::Of {
219 ref property,
220 ref expr,
221 } => {
222 if prec < Precedence::Add {
223 write!(fmt, "(")?;
224 }
225 write!(fmt, "{} of ", property)?;
226 recurse(expr, fmt, Precedence::Div)?;
227 if prec < Precedence::Add {
228 write!(fmt, ")")?;
229 }
230 Ok(())
231 }
232 Expr::Error { ref message } => write!(fmt, "<error: {}>", message),
233 }
234 }
235
236 recurse(self, fmt, Precedence::Equals)
237 }
238}
239
240impl From<i64> for Expr {
241 fn from(x: i64) -> Self {
242 Expr::new_const(x.into())
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use crate::parsing::text_query::{parse_expr, TokenIterator};
249
250 fn parse_then_pretty(input: &str) -> String {
251 let mut iter = TokenIterator::new(&input).peekable();
252 let expr = parse_expr(&mut iter);
253 expr.to_string()
254 }
255
256 #[test]
257 fn expr_display() {
258 assert_eq!(parse_then_pretty("meter"), "meter");
259 assert_eq!(parse_then_pretty("'hello world'"), "'hello world'");
260 assert_eq!(parse_then_pretty("234234"), "234234");
261 assert_eq!(parse_then_pretty("1 + 2"), "1 + 2");
262 assert_eq!(parse_then_pretty("speed of light"), "speed of light");
263 assert_eq!(parse_then_pretty("1 + 2 * 3"), "1 + 2 3");
264 assert_eq!(parse_then_pretty("(1 + 2) * 3"), "(1 + 2) 3");
265 assert_eq!(parse_then_pretty("a = 2"), "a = 2");
266 }
267}