1use std::fmt;
7
8pub mod visitor;
9
10pub use visitor::Visitor;
11
12#[derive(Debug, Clone, PartialEq)]
17pub enum Expr {
18 Literal(Literal),
20
21 Null,
23
24 Identifier(String),
26
27 FieldAccess {
29 receiver: Box<Expr>,
31 field: String,
33 },
34
35 BinaryOp {
37 op: BinaryOperator,
39 left: Box<Expr>,
41 right: Box<Expr>,
43 },
44
45 UnaryOp {
47 op: UnaryOperator,
49 operand: Box<Expr>,
51 },
52
53 FunctionCall {
55 name: String,
57 args: Vec<Expr>,
59 },
60
61 Lambda {
63 param: String,
65 body: Box<Expr>,
67 },
68
69 Let {
71 name: String,
73 value: Box<Expr>,
75 body: Box<Expr>,
77 },
78
79 If {
81 condition: Box<Expr>,
83 then_branch: Box<Expr>,
85 else_branch: Box<Expr>,
87 },
88
89 Array(Vec<Expr>),
91
92 Object(Vec<(String, Expr)>),
94
95 Pipe {
97 value: Box<Expr>,
99 functions: Vec<Expr>,
101 },
102
103 Alternative {
105 primary: Box<Expr>,
107 alternative: Box<Expr>,
109 },
110
111 Guard {
113 condition: Box<Expr>,
115 body: Box<Expr>,
117 },
118
119 Date(String), DateTime(String), Duration(String), TemporalKeyword(TemporalKeyword),
130
131 String(String),
133}
134
135#[derive(Debug, Clone, PartialEq)]
137pub enum Literal {
138 Integer(i64),
140
141 Float(f64),
143
144 Boolean(bool),
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub enum BinaryOperator {
151 Add,
154 Sub,
156 Mul,
158 Div,
160 Mod,
162 Pow,
164
165 Eq,
168 Neq,
170 Lt,
172 Lte,
174 Gt,
176 Gte,
178
179 And,
182 Or,
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq)]
188pub enum UnaryOperator {
189 Not,
191 Neg,
193 Plus,
195}
196
197#[derive(Debug, Clone, Copy, PartialEq, Eq)]
199pub enum TemporalKeyword {
200 Now,
202 Today,
204 Tomorrow,
206 Yesterday,
208
209 StartOfDay,
212 EndOfDay,
214 StartOfWeek,
216 EndOfWeek,
218 StartOfMonth,
220 EndOfMonth,
222 StartOfQuarter,
224 EndOfQuarter,
226 StartOfYear,
228 EndOfYear,
230
231 BeginningOfTime,
234 EndOfTime,
236}
237
238impl fmt::Display for BinaryOperator {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 match self {
241 Self::Add => write!(f, "+"),
242 Self::Sub => write!(f, "-"),
243 Self::Mul => write!(f, "*"),
244 Self::Div => write!(f, "/"),
245 Self::Mod => write!(f, "%"),
246 Self::Pow => write!(f, "^"),
247 Self::Eq => write!(f, "=="),
248 Self::Neq => write!(f, "!="),
249 Self::Lt => write!(f, "<"),
250 Self::Lte => write!(f, "<="),
251 Self::Gt => write!(f, ">"),
252 Self::Gte => write!(f, ">="),
253 Self::And => write!(f, "&&"),
254 Self::Or => write!(f, "||"),
255 }
256 }
257}
258
259impl fmt::Display for UnaryOperator {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 match self {
262 Self::Not => write!(f, "!"),
263 Self::Neg => write!(f, "-"),
264 Self::Plus => write!(f, "+"),
265 }
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn test_literal_integer() {
275 let expr = Expr::Literal(Literal::Integer(42));
276 assert_eq!(expr, Expr::Literal(Literal::Integer(42)));
277 }
278
279 #[test]
280 fn test_literal_float() {
281 let expr = Expr::Literal(Literal::Float(3.15));
282 assert_eq!(expr, Expr::Literal(Literal::Float(3.15)));
283 }
284
285 #[test]
286 fn test_literal_boolean() {
287 let expr = Expr::Literal(Literal::Boolean(true));
288 assert_eq!(expr, Expr::Literal(Literal::Boolean(true)));
289 }
290
291 #[test]
292 fn test_identifier() {
293 let expr = Expr::Identifier("age".to_string());
294 assert_eq!(expr, Expr::Identifier("age".to_string()));
295 }
296
297 #[test]
298 fn test_string_literal() {
299 let expr = Expr::String("hello".to_string());
300 assert_eq!(expr, Expr::String("hello".to_string()));
301 }
302
303 #[test]
304 fn test_field_access() {
305 let expr = Expr::FieldAccess {
306 receiver: Box::new(Expr::Identifier("user".to_string())),
307 field: "age".to_string(),
308 };
309 matches!(expr, Expr::FieldAccess { .. });
310 }
311
312 #[test]
313 fn test_binary_op() {
314 let expr = Expr::BinaryOp {
315 op: BinaryOperator::Add,
316 left: Box::new(Expr::Literal(Literal::Integer(1))),
317 right: Box::new(Expr::Literal(Literal::Integer(2))),
318 };
319 matches!(expr, Expr::BinaryOp { .. });
320 }
321
322 #[test]
323 fn test_unary_op() {
324 let expr = Expr::UnaryOp {
325 op: UnaryOperator::Not,
326 operand: Box::new(Expr::Literal(Literal::Boolean(true))),
327 };
328 matches!(expr, Expr::UnaryOp { .. });
329 }
330
331 #[test]
332 fn test_function_call() {
333 let expr = Expr::FunctionCall {
334 name: "length".to_string(),
335 args: vec![Expr::Identifier("name".to_string())],
336 };
337 matches!(expr, Expr::FunctionCall { .. });
338 }
339
340 #[test]
341 fn test_lambda() {
342 let expr = Expr::Lambda {
343 param: "x".to_string(),
344 body: Box::new(Expr::BinaryOp {
345 op: BinaryOperator::Mul,
346 left: Box::new(Expr::Identifier("x".to_string())),
347 right: Box::new(Expr::Literal(Literal::Integer(2))),
348 }),
349 };
350 matches!(expr, Expr::Lambda { .. });
351 }
352
353 #[test]
354 fn test_let_expr() {
355 let expr = Expr::Let {
356 name: "x".to_string(),
357 value: Box::new(Expr::Literal(Literal::Integer(1))),
358 body: Box::new(Expr::Identifier("x".to_string())),
359 };
360 matches!(expr, Expr::Let { .. });
361 }
362
363 #[test]
364 fn test_if_expr() {
365 let expr = Expr::If {
366 condition: Box::new(Expr::Literal(Literal::Boolean(true))),
367 then_branch: Box::new(Expr::Literal(Literal::Integer(1))),
368 else_branch: Box::new(Expr::Literal(Literal::Integer(2))),
369 };
370 matches!(expr, Expr::If { .. });
371 }
372
373 #[test]
374 fn test_array() {
375 let expr = Expr::Array(vec![
376 Expr::Literal(Literal::Integer(1)),
377 Expr::Literal(Literal::Integer(2)),
378 ]);
379 matches!(expr, Expr::Array(_));
380 }
381
382 #[test]
383 fn test_object() {
384 let expr = Expr::Object(vec![(
385 "key".to_string(),
386 Expr::Literal(Literal::Integer(1)),
387 )]);
388 matches!(expr, Expr::Object(_));
389 }
390
391 #[test]
392 fn test_null() {
393 let expr = Expr::Null;
394 assert_eq!(expr, Expr::Null);
395 }
396
397 #[test]
398 fn test_date_literal() {
399 let expr = Expr::Date("2024-01-15".to_string());
400 assert_eq!(expr, Expr::Date("2024-01-15".to_string()));
401 }
402
403 #[test]
404 fn test_datetime_literal() {
405 let expr = Expr::DateTime("2024-01-15T10:30:00Z".to_string());
406 assert_eq!(expr, Expr::DateTime("2024-01-15T10:30:00Z".to_string()));
407 }
408
409 #[test]
410 fn test_duration_literal() {
411 let expr = Expr::Duration("P1D".to_string());
412 assert_eq!(expr, Expr::Duration("P1D".to_string()));
413 }
414
415 #[test]
416 fn test_temporal_keyword() {
417 let expr = Expr::TemporalKeyword(TemporalKeyword::Now);
418 assert_eq!(expr, Expr::TemporalKeyword(TemporalKeyword::Now));
419 }
420
421 #[test]
422 fn test_binary_operator_display() {
423 assert_eq!(BinaryOperator::Add.to_string(), "+");
424 assert_eq!(BinaryOperator::Eq.to_string(), "==");
425 assert_eq!(BinaryOperator::And.to_string(), "&&");
426 }
427
428 #[test]
429 fn test_unary_operator_display() {
430 assert_eq!(UnaryOperator::Not.to_string(), "!");
431 assert_eq!(UnaryOperator::Neg.to_string(), "-");
432 }
433
434 #[test]
435 fn test_pipe() {
436 let expr = Expr::Pipe {
437 value: Box::new(Expr::Identifier("x".to_string())),
438 functions: vec![Expr::FunctionCall {
439 name: "double".to_string(),
440 args: vec![],
441 }],
442 };
443 matches!(expr, Expr::Pipe { .. });
444 }
445
446 #[test]
447 fn test_guard() {
448 let expr = Expr::Guard {
449 condition: Box::new(Expr::BinaryOp {
450 op: BinaryOperator::Gt,
451 left: Box::new(Expr::Identifier("x".to_string())),
452 right: Box::new(Expr::Literal(Literal::Integer(0))),
453 }),
454 body: Box::new(Expr::Identifier("x".to_string())),
455 };
456 matches!(expr, Expr::Guard { .. });
457 }
458
459 #[test]
460 fn test_alternative() {
461 let expr = Expr::Alternative {
462 primary: Box::new(Expr::Identifier("maybe".to_string())),
463 alternative: Box::new(Expr::Literal(Literal::Integer(0))),
464 };
465 matches!(expr, Expr::Alternative { .. });
466 }
467}