syn_graphs/
unparse.rs

1pub fn dot(graph: &crate::dot::Graph) -> String {
2    let mut p = crate::prettyplease::algorithm::Printer::new();
3    p.graph(graph);
4    p.eof()
5}
6
7mod dot {
8    use crate::dot::*;
9    use crate::prettyplease::{algorithm, iter::IterDelimited as _};
10    use crate::INDENT;
11
12    impl algorithm::Printer {
13        pub fn graph(
14            &mut self,
15            Graph {
16                strict,
17                directedness,
18                id,
19                brace_token: _,
20                stmt_list: StmtList { stmts },
21            }: &Graph,
22        ) {
23            self.cbox(0); // Printer::file
24            self.cbox(INDENT); // Printer::item_mod
25            if strict.is_some() {
26                self.word("strict ");
27            }
28            match directedness {
29                GraphDirectedness::Graph(_) => self.word("graph "),
30                GraphDirectedness::Digraph(_) => self.word("digraph "),
31            }
32            if let Some(id) = id {
33                self.id(id)
34            }
35            self.word(" {");
36            self.hardbreak_if_nonempty();
37            for (stmt, _semi) in stmts {
38                self.stmt(stmt);
39            }
40            self.offset(-INDENT); // Printer::item_mod
41            self.end();
42            self.word("}");
43            self.hardbreak()
44        }
45        fn stmt(&mut self, stmt: &Stmt) {
46            match stmt {
47                Stmt::Assign(StmtAssign {
48                    left,
49                    eq_token: _,
50                    right,
51                }) => {
52                    self.id(left);
53                    self.word(" = ");
54                    self.id(right);
55                }
56                Stmt::Attr(StmtAttr { target, attrs }) => {
57                    match target {
58                        AttrTarget::Graph(_) => self.word("graph "),
59                        AttrTarget::Node(_) => self.word("node "),
60                        AttrTarget::Edge(_) => self.word("edge "),
61                    };
62                    self.attrs(attrs);
63                }
64                Stmt::Node(StmtNode { node_id, attrs }) => {
65                    self.node_id(node_id);
66                    self.nbsp();
67                    if let Some(attrs) = attrs {
68                        self.attrs(attrs);
69                    }
70                }
71                Stmt::Edge(StmtEdge { from, edges, attrs }) => {
72                    self.edge_target(from);
73                    for (directedness, to) in edges {
74                        match directedness {
75                            EdgeDirectedness::Directed(_) => self.word(" -> "),
76                            EdgeDirectedness::Undirected(_) => self.word(" -- "),
77                        }
78                        self.edge_target(to)
79                    }
80                    if let Some(attrs) = attrs {
81                        self.nbsp();
82                        self.attrs(attrs);
83                    }
84                }
85                Stmt::Subgraph(subgraph) => self.stmt_subgraph(subgraph),
86            }
87            self.word(";");
88            self.hardbreak();
89        }
90        fn edge_target(&mut self, it: &EdgeTarget) {
91            match it {
92                EdgeTarget::Subgraph(subgraph) => self.stmt_subgraph(subgraph),
93                EdgeTarget::NodeId(node_id) => self.node_id(node_id),
94            }
95        }
96        fn stmt_subgraph(
97            &mut self,
98            StmtSubgraph {
99                prelude,
100                brace_token: _,
101                statements: StmtList { stmts },
102            }: &StmtSubgraph,
103        ) {
104            self.word("subgraph ");
105            if let Some((_subgraph, Some(id))) = prelude {
106                self.id(id);
107                self.nbsp()
108            }
109            self.cbox(INDENT); // Printer::expr_block
110            self.word("{"); // Printer::small_block
111            if !stmts.is_empty() {
112                self.space();
113                for (stmt, _semi) in stmts {
114                    self.stmt(stmt)
115                }
116                self.offset(-INDENT);
117            }
118            self.word("}"); // Printer::small_block
119            self.end(); // Printer::expr_block
120        }
121        fn id(&mut self, id: &ID) {
122            match id {
123                ID::AnyIdent(ident) => self.ident(ident),
124                ID::AnyLit(lit) => self.lit(lit),
125                ID::Html(
126                    html @ HtmlString {
127                        lt: _,
128                        stream,
129                        gt: _,
130                    },
131                ) => match html.source() {
132                    Some(source) => {
133                        self.word("<");
134                        self.word(source);
135                        self.word(">");
136                    }
137                    None => self.word(format!("< {} >", stream)),
138                },
139                ID::DotInt(DotInt { dot: _, int }) => {
140                    self.word(".");
141                    self.word(int.token().to_string())
142                }
143            }
144        }
145        fn node_id(&mut self, NodeId { id, port }: &NodeId) {
146            self.id(id);
147            if let Some(port) = port {
148                self.word(":");
149                match port {
150                    Port::ID { colon: _, id } => self.id(id),
151                    Port::Compass { colon: _, compass } => self.word(compass.to_string()),
152                    Port::IDAndCompass {
153                        colon1: _,
154                        id,
155                        colon2: _,
156                        compass,
157                    } => {
158                        self.id(id);
159                        self.word(":");
160                        self.word(compass.to_string())
161                    }
162                }
163            }
164        }
165        fn attrs(&mut self, Attrs { lists }: &Attrs) {
166            for attr_list in lists {
167                self.attr_list(attr_list)
168            }
169        }
170        fn attr_list(
171            &mut self,
172            AttrList {
173                bracket_token: _,
174                assigns,
175            }: &AttrList,
176        ) {
177            self.word("["); // Printer::expr_array
178            self.nbsp();
179            self.cbox(INDENT);
180            self.zerobreak();
181            for element in assigns.iter().delimited() {
182                self.attr_assign(&element);
183                self.trailing_comma(element.is_last);
184            }
185            self.offset(-INDENT);
186            self.end();
187            self.nbsp();
188            self.word("]");
189        }
190        fn attr_assign(
191            &mut self,
192            AttrAssign {
193                left,
194                eq_token: _,
195                right,
196                trailing: _,
197            }: &AttrAssign,
198        ) {
199            self.id(left);
200            self.word(" = ");
201            self.id(right);
202        }
203    }
204}