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); self.cbox(INDENT); 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); 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); self.word("{"); 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("}"); self.end(); }
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("["); 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}