1mod expr1 {
2 use std::fmt::Display;
3
4 use recursion::*;
5 use recursion_visualize::visualize::*;
6 #[derive(Debug, PartialEq, Eq)]
7 pub enum Expr {
8 Add(Box<Expr>, Box<Expr>),
9 Sub(Box<Expr>, Box<Expr>),
10 Mul(Box<Expr>, Box<Expr>),
11 LiteralInt(i64),
12 }
13 impl Display for Expr {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 match self {
16 Expr::Add(a, b) => write!(f, "{} + {}", a, b),
17 Expr::Sub(a, b) => write!(f, "{} - {}", a, b),
18 Expr::Mul(a, b) => write!(f, "{} * {}", a, b),
19 Expr::LiteralInt(x) => write!(f, "{}", x),
20 }
21 }
22 }
23
24 pub fn add(a: Expr, b: Expr) -> Expr {
25 Expr::Add(Box::new(a), Box::new(b))
26 }
27 pub fn subtract(a: Expr, b: Expr) -> Expr {
28 Expr::Sub(Box::new(a), Box::new(b))
29 }
30 pub fn multiply(a: Expr, b: Expr) -> Expr {
31 Expr::Mul(Box::new(a), Box::new(b))
32 }
33 pub fn literal(n: i64) -> Expr {
34 Expr::LiteralInt(n)
35 }
36 pub enum ExprFrame<A> {
37 Add(A, A),
38 Sub(A, A),
39 Mul(A, A),
40 LiteralInt(i64),
41 }
42
43 impl Display for ExprFrame<()> {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 match self {
46 ExprFrame::Add(_, _) => write!(f, "_ + _",),
47 ExprFrame::Sub(_, _) => write!(f, "_ - _",),
48 ExprFrame::Mul(_, _) => write!(f, "_ * _",),
49 ExprFrame::LiteralInt(x) => write!(f, "{}", x),
50 }
51 }
52 }
53
54 impl MappableFrame for ExprFrame<PartiallyApplied> {
55 type Frame<X> = ExprFrame<X>;
56 fn map_frame<A, B>(input: Self::Frame<A>, mut f: impl FnMut(A) -> B) -> Self::Frame<B> {
57 match input {
58 ExprFrame::Add(a, b) => ExprFrame::Add(f(a), f(b)),
59 ExprFrame::Sub(a, b) => ExprFrame::Sub(f(a), f(b)),
60 ExprFrame::Mul(a, b) => ExprFrame::Mul(f(a), f(b)),
61 ExprFrame::LiteralInt(x) => ExprFrame::LiteralInt(x),
62 }
63 }
64 }
65 impl<'a> Collapsible for &'a Expr {
66 type FrameToken = ExprFrame<PartiallyApplied>;
67 fn into_frame(self) -> <Self::FrameToken as MappableFrame>::Frame<Self> {
68 match self {
69 Expr::Add(a, b) => ExprFrame::Add(a, b),
70 Expr::Sub(a, b) => ExprFrame::Sub(a, b),
71 Expr::Mul(a, b) => ExprFrame::Mul(a, b),
72 Expr::LiteralInt(x) => ExprFrame::LiteralInt(*x),
73 }
74 }
75 }
76 impl Expandable for Expr {
77 type FrameToken = ExprFrame<PartiallyApplied>;
78 fn from_frame(val: <Self::FrameToken as MappableFrame>::Frame<Self>) -> Self {
79 match val {
80 ExprFrame::Add(a, b) => Expr::Add(Box::new(a), Box::new(b)),
81 ExprFrame::Sub(a, b) => Expr::Sub(Box::new(a), Box::new(b)),
82 ExprFrame::Mul(a, b) => Expr::Mul(Box::new(a), Box::new(b)),
83 ExprFrame::LiteralInt(x) => Expr::LiteralInt(x),
84 }
85 }
86 }
87
88 pub fn eval(e: &Expr) -> (i64, Viz) {
89 e.collapse_frames_v(|frame| match frame {
90 ExprFrame::Add(a, b) => a + b,
91 ExprFrame::Sub(a, b) => a - b,
92 ExprFrame::Mul(a, b) => a * b,
93 ExprFrame::LiteralInt(x) => x,
94 })
95 }
96
97 pub fn build_expr(depth: usize) -> (Expr, Viz) {
98 Expr::expand_frames_v(depth, |depth| {
99 if depth > 0 {
100 ExprFrame::Add(depth - 1, depth - 1)
101 } else {
102 ExprFrame::LiteralInt(1)
103 }
104 })
105 }
106}
107
108mod expr2 {
109 use std::fmt::Display;
110
111 use recursion::*;
112 use recursion_visualize::visualize::{CollapsibleVizExt, Viz};
113 pub enum Expr {
114 Add(Box<Expr>, Box<Expr>),
115 Sub(Box<Expr>, Box<Expr>),
116 Mul(Box<Expr>, Box<Expr>),
117 Div(Box<Expr>, Box<Expr>),
118 LiteralInt(i64),
119 }
120 impl Display for Expr {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 match self {
123 Expr::Add(a, b) => write!(f, "{} + {}", a, b),
124 Expr::Sub(a, b) => write!(f, "{} - {}", a, b),
125 Expr::Mul(a, b) => write!(f, "{} * {}", a, b),
126 Expr::Div(a, b) => write!(f, "{} / {}", a, b),
127 Expr::LiteralInt(x) => write!(f, "{}", x),
128 }
129 }
130 }
131 pub fn add(a: Expr, b: Expr) -> Expr {
132 Expr::Add(Box::new(a), Box::new(b))
133 }
134 pub fn subtract(a: Expr, b: Expr) -> Expr {
135 Expr::Sub(Box::new(a), Box::new(b))
136 }
137 pub fn multiply(a: Expr, b: Expr) -> Expr {
138 Expr::Mul(Box::new(a), Box::new(b))
139 }
140 pub fn divide(a: Expr, b: Expr) -> Expr {
141 Expr::Div(Box::new(a), Box::new(b))
142 }
143 pub fn literal(n: i64) -> Expr {
144 Expr::LiteralInt(n)
145 }
146 pub enum ExprFrame<A> {
147 Add(A, A),
148 Sub(A, A),
149 Mul(A, A),
150 Div(A, A),
151 LiteralInt(i64),
152 }
153 impl Display for ExprFrame<()> {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 match self {
156 ExprFrame::Add(_, _) => write!(f, "_ + _",),
157 ExprFrame::Sub(_, _) => write!(f, "_ - _",),
158 ExprFrame::Mul(_, _) => write!(f, "_ * _",),
159 ExprFrame::Div(_, _) => write!(f, "_ / _",),
160 ExprFrame::LiteralInt(x) => write!(f, "{}", x),
161 }
162 }
163 }
164 impl MappableFrame for ExprFrame<PartiallyApplied> {
165 type Frame<X> = ExprFrame<X>;
166 fn map_frame<A, B>(input: Self::Frame<A>, mut f: impl FnMut(A) -> B) -> Self::Frame<B> {
167 match input {
168 ExprFrame::Add(a, b) => ExprFrame::Add(f(a), f(b)),
169 ExprFrame::Sub(a, b) => ExprFrame::Sub(f(a), f(b)),
170 ExprFrame::Mul(a, b) => ExprFrame::Mul(f(a), f(b)),
171 ExprFrame::Div(a, b) => ExprFrame::Div(f(a), f(b)),
172 ExprFrame::LiteralInt(x) => ExprFrame::LiteralInt(x),
173 }
174 }
175 }
176 impl<'a> Collapsible for &'a Expr {
177 type FrameToken = ExprFrame<PartiallyApplied>;
178 fn into_frame(self) -> <Self::FrameToken as MappableFrame>::Frame<Self> {
179 match self {
180 Expr::Add(a, b) => ExprFrame::Add(a, b),
181 Expr::Sub(a, b) => ExprFrame::Sub(a, b),
182 Expr::Mul(a, b) => ExprFrame::Mul(a, b),
183 Expr::Div(a, b) => ExprFrame::Div(a, b),
184 Expr::LiteralInt(x) => ExprFrame::LiteralInt(*x),
185 }
186 }
187 }
188
189 pub fn try_eval(e: &Expr) -> (Result<i64, &str>, Viz) {
190 e.try_collapse_frames_v(|frame| match frame {
191 ExprFrame::Add(a, b) => Ok(a + b),
192 ExprFrame::Sub(a, b) => Ok(a - b),
193 ExprFrame::Mul(a, b) => Ok(a * b),
194 ExprFrame::Div(a, b) => {
195 if b == 0 {
196 Err("cannot divide by zero")
197 } else {
198 Ok(a / b)
199 }
200 }
201 ExprFrame::LiteralInt(x) => Ok(x),
202 })
203 }
204}
205
206fn main() {
207 {
208 use expr1::*;
209 let expr = multiply(subtract(literal(1), literal(2)), literal(3));
210
211 let (evaluated, viz) = eval(&expr);
212 assert_eq!(evaluated, -3);
213
214 viz.label("Evaluate Expr".to_string(), "(1 - 2) * 3".to_string())
215 .write("eval.html".to_string());
216
217 let (built_expr, viz) = build_expr(2);
218 let expected = add(add(literal(1), literal(1)), add(literal(1), literal(1)));
219
220 assert_eq!(built_expr, expected);
221
222 viz.label("Build Expr".to_string(), "1 + 1 + 1 + 1".to_string())
223 .write("build_expr.html".to_string());
224 }
225
226 {
227 use expr2::*;
228
229 let valid_expr = divide(subtract(literal(1), literal(7)), literal(3));
230 let invalid_expr = divide(multiply(literal(2), literal(3)), literal(0));
231
232 let (valid_res, valid_viz) = try_eval(&valid_expr);
233 let (invalid_res, invalid_viz) = try_eval(&invalid_expr);
234
235 assert_eq!(valid_res, Ok(-2));
236 assert_eq!(invalid_res, Err("cannot divide by zero"));
237
238 valid_viz
239 .label("Try Eval Valid Expr".to_string(), "(1 - 7) / 3".to_string())
240 .write("try_eval_valid.html".to_string());
241 invalid_viz
242 .label("Try Eval Expr".to_string(), "(2 * 3) / 0".to_string())
243 .write("try_eval_invalid.html".to_string());
244 }
245}