symoxide/mapper_impls/
reprifier.rs

1use crate::mappers::fold::FoldMapperWithContext;
2use crate::mappers::CachedMapper;
3use crate::primitives::{BinaryOpType, Expression, LiteralT, SmallVecExprT, UnaryOpType};
4use crate::utils::ExpressionRawPointer;
5use crate::CachedMapper;
6use hashbrown::HashMap;
7use std::fmt;
8use std::rc::Rc;
9
10// TODO: Use Cached Mapper here?
11
12#[derive(CachedMapper)]
13pub struct Reprifier {
14    truncation_level: u32,
15    cache: HashMap<(ExpressionRawPointer, u32), String>,
16}
17
18impl FoldMapperWithContext for Reprifier {
19    type Context = u32;
20    type Output = String;
21    type CacheKey = (ExpressionRawPointer, u32);
22
23    fn get_cache_key(&self, expr: &Rc<Expression>, context: &Self::Context) -> Self::CacheKey {
24        (ExpressionRawPointer(expr.clone()), *context)
25    }
26
27    fn map_scalar(&mut self, value: &LiteralT, level: &Self::Context) -> Self::Output {
28        if *level < self.truncation_level {
29            format!("{:?}", value)
30        } else {
31            format!("(...)")
32        }
33    }
34    fn map_variable(&mut self, name: String, level: &Self::Context) -> Self::Output {
35        if *level < self.truncation_level {
36            format!("Variable(\"{}\"))", name)
37        } else {
38            format!("(...)")
39        }
40    }
41    fn map_unary_op(&mut self, op: UnaryOpType, x: &Rc<Expression>, level: &Self::Context)
42                    -> Self::Output {
43        if *level < self.truncation_level {
44            let new_level: u32 = level + 1;
45            format!("UnaryOp({}, {}))", op, self.visit(x, &new_level))
46        } else {
47            format!("(...)")
48        }
49    }
50    fn map_binary_op(&mut self, left: &Rc<Expression>, op: BinaryOpType, right: &Rc<Expression>,
51                     level: &Self::Context)
52                     -> Self::Output {
53        if *level < self.truncation_level {
54            let new_level: u32 = level + 1;
55            format!("BinaryOp({}, {}, {}))",
56                    self.visit(left, &new_level),
57                    op,
58                    self.visit(right, &new_level))
59        } else {
60            format!("(...)")
61        }
62    }
63    fn map_call(&mut self, call: &Rc<Expression>, params: &SmallVecExprT, level: &Self::Context)
64                -> Self::Output {
65        if *level < self.truncation_level {
66            let new_level: u32 = level + 1;
67            let mut param_str = format!("");
68            // TODO: Make it functional. Couldn't find a neater way using fold.
69            for (iparam, param) in params.iter().enumerate() {
70                param_str = if iparam == 0 {
71                    format!("{}", param)
72                } else {
73                    format!("{}, {}", param_str, self.visit(param, &new_level))
74                };
75            }
76
77            format!("Call({}, [{}]))", self.visit(call, &new_level), param_str)
78        } else {
79            format!("(...)")
80        }
81    }
82    fn map_subscript(&mut self, agg: &Rc<Expression>, indices: &SmallVecExprT,
83                     level: &Self::Context)
84                     -> Self::Output {
85        if *level < self.truncation_level {
86            let new_level: u32 = level + 1;
87            let mut indices_str = format!("");
88            // TODO: Make it functional. Couldn't find a neater way using fold.
89            for (i_idx, idx) in indices.iter().enumerate() {
90                indices_str = if i_idx == 0 {
91                    format!("{}", idx)
92                } else {
93                    format!("{}, {}", indices_str, self.visit(idx, &new_level))
94                };
95            }
96
97            format!("Subscript({}, [{}]))",
98                    self.visit(agg, &new_level),
99                    indices_str)
100        } else {
101            format!("(...)")
102        }
103    }
104    fn map_if(&mut self, cond: &Rc<Expression>, then: &Rc<Expression>, else_: &Rc<Expression>,
105              level: &Self::Context)
106              -> Self::Output {
107        if *level < self.truncation_level {
108            let new_level: u32 = level + 1;
109            format!("If({}, {}, {}))",
110                    self.visit(cond, &new_level),
111                    self.visit(then, &new_level),
112                    self.visit(else_, &new_level))
113        } else {
114            format!("(...)")
115        }
116    }
117}
118
119impl fmt::Debug for Expression {
120    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121        let mut mapper = Reprifier { truncation_level: 3,
122                                     cache: HashMap::new() };
123        let start_level = 0;
124        write!(f, "{}", mapper.visit(&Rc::new(self.clone()), &start_level))
125    }
126}