regast_syntax/print/
sexpr.rs1use std::convert::Infallible;
2
3use super::rep_name;
4use crate::{AstKind, Cursor, Flow, Pattern, Visitor, visit};
5
6impl Pattern {
7 #[must_use]
8 pub fn to_sexpr(&self) -> String {
9 match visit(self, SExpr::default()) {
10 Ok(output) => output,
11 Err(error) => match error {},
12 }
13 }
14}
15
16#[derive(Default)]
17struct SExpr {
18 stack: Vec<SExprFrame>,
19 root: Option<String>,
20}
21
22struct SExprFrame {
23 head: String,
24 children: Vec<String>,
25}
26
27impl Visitor for SExpr {
28 type Output = String;
29 type Err = Infallible;
30
31 fn enter(&mut self, node: Cursor<'_>) -> Result<Flow, Self::Err> {
32 self.stack.push(SExprFrame {
33 head: node_head(node),
34 children: Vec::new(),
35 });
36 Ok(Flow::Continue)
37 }
38
39 fn leave(&mut self, _node: Cursor<'_>) -> Result<(), Self::Err> {
40 let frame = self.stack.pop().expect("enter precedes leave");
41 let completed = if frame.children.is_empty() {
42 format!("({})", frame.head)
43 } else {
44 format!("({} {})", frame.head, frame.children.join(" "))
45 };
46 if let Some(parent) = self.stack.last_mut() {
47 parent.children.push(completed);
48 } else {
49 self.root = Some(completed);
50 }
51 Ok(())
52 }
53
54 fn finish(self) -> Result<Self::Output, Self::Err> {
55 Ok(self.root.expect("pattern always has a root"))
56 }
57}
58
59fn node_head(node: Cursor<'_>) -> String {
60 match node.kind() {
61 AstKind::Empty => "empty".into(),
62 AstKind::Anchor { kind } => format!("anchor {kind:?}"),
63 AstKind::Literal { c, .. } => format!("literal {c:?}"),
64 AstKind::Dot => "dot".into(),
65 AstKind::Class { .. } => format!("class {:?}", node.text()),
66 AstKind::Group { .. } => "group".into(),
67 AstKind::Alt { .. } => "alt".into(),
68 AstKind::Concat { .. } => "concat".into(),
69 AstKind::Repeat { kind, greedy, .. } => format!(
70 "repeat {} {}",
71 rep_name(*kind),
72 if *greedy { "greedy" } else { "lazy" }
73 ),
74 }
75}