1use super::{Expr, ExprKind};
18
19#[derive(Debug)]
22pub struct ExprIterator<'a, T = ()> {
23 expression_stack: Vec<&'a Expr<T>>,
29}
30
31impl<'a, T> ExprIterator<'a, T> {
32 pub fn new(expr: &'a Expr<T>) -> Self {
34 Self {
35 expression_stack: vec![expr],
36 }
37 }
38}
39
40impl<'a, T> Iterator for ExprIterator<'a, T> {
41 type Item = &'a Expr<T>;
42
43 fn next(&mut self) -> Option<Self::Item> {
44 let next_expr = self.expression_stack.pop()?;
45 match next_expr.expr_kind() {
46 ExprKind::Lit(_) => (),
47 ExprKind::Unknown(_) => (),
48 ExprKind::Slot(_) => (),
49 ExprKind::Var(_) => (),
50 ExprKind::If {
51 test_expr,
52 then_expr,
53 else_expr,
54 } => {
55 self.expression_stack.push(test_expr);
56 self.expression_stack.push(then_expr);
57 self.expression_stack.push(else_expr);
58 }
59 ExprKind::And { left, right } | ExprKind::Or { left, right } => {
60 self.expression_stack.push(left);
61 self.expression_stack.push(right);
62 }
63 ExprKind::UnaryApp { arg, .. } => {
64 self.expression_stack.push(arg);
65 }
66 ExprKind::BinaryApp { arg1, arg2, .. } => {
67 self.expression_stack.push(arg1);
68 self.expression_stack.push(arg2);
69 }
70 ExprKind::GetAttr { expr, attr: _ }
71 | ExprKind::HasAttr { expr, attr: _ }
72 | ExprKind::Like { expr, pattern: _ }
73 | ExprKind::Is {
74 expr,
75 entity_type: _,
76 } => {
77 self.expression_stack.push(expr);
78 }
79 ExprKind::ExtensionFunctionApp { args: exprs, .. } | ExprKind::Set(exprs) => {
80 self.expression_stack.extend(exprs.as_ref());
81 }
82 ExprKind::Record(map) => {
83 self.expression_stack.extend(map.values());
84 }
85 #[cfg(feature = "tolerant-ast")]
86 ExprKind::Error { .. } => (),
87 }
88 Some(next_expr)
89 }
90}
91
92#[cfg(test)]
93mod test {
94 use std::collections::HashSet;
95
96 use crate::ast::{BinaryOp, Expr, SlotId, UnaryOp, Var};
97
98 #[test]
99 fn literals() {
100 let e = Expr::val(true);
101 let v: HashSet<_> = e.subexpressions().collect();
102
103 assert_eq!(v.len(), 1);
104 assert!(v.contains(&Expr::val(true)));
105 }
106
107 #[test]
108 fn slots() {
109 let e = Expr::slot(SlotId::principal());
110 let v: HashSet<_> = e.subexpressions().collect();
111 assert_eq!(v.len(), 1);
112 assert!(v.contains(&Expr::slot(SlotId::principal())));
113 }
114
115 #[test]
116 fn variables() {
117 let e = Expr::var(Var::Principal);
118 let v: HashSet<_> = e.subexpressions().collect();
119 let s = HashSet::from([&e]);
120 assert_eq!(v, s);
121 }
122
123 #[test]
124 fn ite() {
125 let e = Expr::ite(Expr::val(true), Expr::val(false), Expr::val(0));
126 let v: HashSet<_> = e.subexpressions().collect();
127 assert_eq!(
128 v,
129 HashSet::from([&e, &Expr::val(true), &Expr::val(false), &Expr::val(0)])
130 );
131 }
132
133 #[test]
134 fn and() {
135 let e = Expr::and(Expr::val(1), Expr::val(false));
138 println!("{e:?}");
139 let v: HashSet<_> = e.subexpressions().collect();
140 assert_eq!(v, HashSet::from([&e, &Expr::val(1), &Expr::val(false)]));
141 }
142
143 #[test]
144 fn or() {
145 let e = Expr::or(Expr::val(1), Expr::val(false));
148 let v: HashSet<_> = e.subexpressions().collect();
149 assert_eq!(v, HashSet::from([&e, &Expr::val(1), &Expr::val(false)]));
150 }
151
152 #[test]
153 fn unary() {
154 let e = Expr::unary_app(UnaryOp::Not, Expr::val(false));
155 assert_eq!(
156 e.subexpressions().collect::<HashSet<_>>(),
157 HashSet::from([&e, &Expr::val(false)])
158 );
159 }
160
161 #[test]
162 fn binary() {
163 let e = Expr::binary_app(BinaryOp::Eq, Expr::val(false), Expr::val(true));
164 assert_eq!(
165 e.subexpressions().collect::<HashSet<_>>(),
166 HashSet::from([&e, &Expr::val(false), &Expr::val(true)])
167 );
168 }
169
170 #[test]
171 fn ext() {
172 let e = Expr::call_extension_fn(
173 "test".parse().unwrap(),
174 vec![Expr::val(false), Expr::val(true)],
175 );
176 assert_eq!(
177 e.subexpressions().collect::<HashSet<_>>(),
178 HashSet::from([&e, &Expr::val(false), &Expr::val(true)])
179 );
180 }
181
182 #[test]
183 fn has_attr() {
184 let e = Expr::has_attr(Expr::val(false), "test".into());
185 assert_eq!(
186 e.subexpressions().collect::<HashSet<_>>(),
187 HashSet::from([&e, &Expr::val(false)])
188 );
189 }
190
191 #[test]
192 fn get_attr() {
193 let e = Expr::get_attr(Expr::val(false), "test".into());
194 assert_eq!(
195 e.subexpressions().collect::<HashSet<_>>(),
196 HashSet::from([&e, &Expr::val(false)])
197 );
198 }
199
200 #[test]
201 fn set() {
202 let e = Expr::set(vec![Expr::val(false), Expr::val(true)]);
203 assert_eq!(
204 e.subexpressions().collect::<HashSet<_>>(),
205 HashSet::from([&e, &Expr::val(false), &Expr::val(true)])
206 );
207 }
208
209 #[test]
210 fn set_duplicates() {
211 let e = Expr::set(vec![Expr::val(true), Expr::val(true)]);
212 let v: Vec<_> = e.subexpressions().collect();
213 assert_eq!(v.len(), 3);
214 assert!(v.contains(&&Expr::val(true)));
215 }
216
217 #[test]
218 fn record() {
219 let e = Expr::record(vec![
220 ("test".into(), Expr::val(true)),
221 ("another".into(), Expr::val(false)),
222 ])
223 .unwrap();
224 assert_eq!(
225 e.subexpressions().collect::<HashSet<_>>(),
226 HashSet::from([&e, &Expr::val(false), &Expr::val(true)])
227 );
228 }
229
230 #[test]
231 fn is() {
232 let e = Expr::is_entity_type(Expr::val(1), "T".parse().unwrap());
233 assert_eq!(
234 e.subexpressions().collect::<HashSet<_>>(),
235 HashSet::from([&e, &Expr::val(1)])
236 );
237 }
238
239 #[test]
240 fn duplicates() {
241 let e = Expr::ite(Expr::val(true), Expr::val(true), Expr::val(true));
242 let v: Vec<_> = e.subexpressions().collect();
243 assert_eq!(v.len(), 4);
244 assert!(v.contains(&&e));
245 assert!(v.contains(&&Expr::val(true)));
246 }
247
248 #[test]
249 fn deeply_nested() {
250 let e = Expr::get_attr(
251 Expr::get_attr(Expr::and(Expr::val(1), Expr::val(0)), "attr2".into()),
252 "attr1".into(),
253 );
254 let set: HashSet<_> = e.subexpressions().collect();
255 assert!(set.contains(&e));
256 assert!(set.contains(&Expr::get_attr(
257 Expr::and(Expr::val(1), Expr::val(0)),
258 "attr2".into()
259 )));
260 assert!(set.contains(&Expr::and(Expr::val(1), Expr::val(0))));
261 assert!(set.contains(&Expr::val(1)));
262 assert!(set.contains(&Expr::val(0)));
263 }
264}