| 219 | } |
| 220 | |
| 221 | fn visit<V: Visitor>( |
| 222 | &mut self, |
| 223 | mut ast: &'a Ast, |
| 224 | mut visitor: V, |
| 225 | ) -> Result<V::Output, V::Err> { |
| 226 | self.stack.clear(); |
| 227 | self.stack_class.clear(); |
| 228 | |
| 229 | visitor.start(); |
| 230 | loop { |
| 231 | visitor.visit_pre(ast)?; |
| 232 | if let Some(x) = self.induct(ast, &mut visitor)? { |
| 233 | let child = x.child(); |
| 234 | self.stack.push((ast, x)); |
| 235 | ast = child; |
| 236 | continue; |
| 237 | } |
| 238 | // No induction means we have a base case, so we can post visit |
| 239 | // it now. |
| 240 | visitor.visit_post(ast)?; |
| 241 | |
| 242 | // At this point, we now try to pop our call stack until it is |
| 243 | // either empty or we hit another inductive case. |
| 244 | loop { |
| 245 | let (post_ast, frame) = match self.stack.pop() { |
| 246 | None => return visitor.finish(), |
| 247 | Some((post_ast, frame)) => (post_ast, frame), |
| 248 | }; |
| 249 | // If this is a concat/alternate, then we might have additional |
| 250 | // inductive steps to process. |
| 251 | if let Some(x) = self.pop(frame) { |
| 252 | if let Frame::Alternation {..} = x { |
| 253 | visitor.visit_alternation_in()?; |
| 254 | } |
| 255 | ast = x.child(); |
| 256 | self.stack.push((post_ast, x)); |
| 257 | break; |
| 258 | } |
| 259 | // Otherwise, we've finished visiting all the child nodes for |
| 260 | // this AST, so we can post visit it now. |
| 261 | visitor.visit_post(post_ast)?; |
| 262 | } |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | /// Build a stack frame for the given AST if one is needed (which occurs if |
| 267 | /// and only if there are child nodes in the AST). Otherwise, return None. |