use std::convert::Infallible;
use super::rep_name;
use crate::{AstKind, Cursor, Flow, Pattern, Visitor, visit};
impl Pattern {
#[must_use]
pub fn to_sexpr(&self) -> String {
match visit(self, SExpr::default()) {
Ok(output) => output,
Err(error) => match error {},
}
}
}
#[derive(Default)]
struct SExpr {
stack: Vec<SExprFrame>,
root: Option<String>,
}
struct SExprFrame {
head: String,
children: Vec<String>,
}
impl Visitor for SExpr {
type Output = String;
type Err = Infallible;
fn enter(&mut self, node: Cursor<'_>) -> Result<Flow, Self::Err> {
self.stack.push(SExprFrame {
head: node_head(node),
children: Vec::new(),
});
Ok(Flow::Continue)
}
fn leave(&mut self, _node: Cursor<'_>) -> Result<(), Self::Err> {
let frame = self.stack.pop().expect("enter precedes leave");
let completed = if frame.children.is_empty() {
format!("({})", frame.head)
} else {
format!("({} {})", frame.head, frame.children.join(" "))
};
if let Some(parent) = self.stack.last_mut() {
parent.children.push(completed);
} else {
self.root = Some(completed);
}
Ok(())
}
fn finish(self) -> Result<Self::Output, Self::Err> {
Ok(self.root.expect("pattern always has a root"))
}
}
fn node_head(node: Cursor<'_>) -> String {
match node.kind() {
AstKind::Empty => "empty".into(),
AstKind::Anchor { kind } => format!("anchor {kind:?}"),
AstKind::Literal { c, .. } => format!("literal {c:?}"),
AstKind::Dot => "dot".into(),
AstKind::Class { .. } => format!("class {:?}", node.text()),
AstKind::Group { .. } => "group".into(),
AstKind::Alt { .. } => "alt".into(),
AstKind::Concat { .. } => "concat".into(),
AstKind::Repeat { kind, greedy, .. } => format!(
"repeat {} {}",
rep_name(*kind),
if *greedy { "greedy" } else { "lazy" }
),
}
}