1use pest::iterators::Pair;
6use pest::Parser;
7
8pub use either;
9use either::Either;
10use std::collections::HashSet;
11use std::error::Error;
12use std::fmt::{Display, Formatter};
13use std::iter::FromIterator;
14use std::path::Path;
15
16#[cfg(feature = "to_tokens")]
17use quote::{ToTokens, quote, TokenStreamExt};
18#[cfg(feature = "to_tokens")]
19use proc_macro2::*;
20
21mod parser {
22 use pest_derive::Parser;
23
24 #[derive(Parser)]
25 #[grammar = "parser/dot.pest"]
26 pub struct DotParser;
27}
28
29use self::parser::DotParser;
30use self::parser::Rule;
31
32pub type PestError = pest::error::Error<Rule>;
34pub type IOError = std::io::Error;
36
37#[derive(Debug, Clone)]
41pub enum ParseError<'a> {
42 ExpectRule {
45 expect: Vec<Rule>,
47 found: Rule,
49 },
50 MissingPair {
52 parent: Pair<'a, Rule>,
54 expect: Vec<Rule>,
56 },
57}
58
59impl<'a> ParseError<'a> {
60 fn expect_rule(expect: Vec<Rule>, found: Rule) -> Self {
61 ParseError::ExpectRule { expect, found }
62 }
63
64 fn missing_pair(parent: Pair<'a, Rule>, expect: Vec<Rule>) -> Self {
65 ParseError::MissingPair { parent, expect }
66 }
67}
68
69impl Display for ParseError<'_> {
70 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
71 match self {
72 ParseError::ExpectRule { expect, found } => {
73 let expected = expect
74 .iter()
75 .fold(String::new(), |acc, r| format!("{}\"{:?}\", ", acc, r));
76 write!(
77 f,
78 "Expect one rule of {}but \"{:?}\" found.",
79 expected, found
80 )?;
81 }
82 ParseError::MissingPair { parent, expect } => {
83 let mut expected = expect
84 .iter()
85 .fold(String::new(), |acc, r| format!("{}\"{:?}\", ", acc, r));
86 expected.pop();
88 expected.pop();
89 write!(
90 f,
91 "The Pair:\n{}\nterminates early. Expected one of {}.",
92 parent.as_str(),
93 expected
94 )?;
95 }
96 }
97 Ok(())
98 }
99}
100
101impl Error for ParseError<'_> {}
102
103#[derive(Debug)]
105pub enum GraphFromFileError<'a> {
106 FileError(IOError),
108 PestParseError(PestError),
110 ParseError(ParseError<'a>),
113}
114
115impl Display for GraphFromFileError<'_> {
116 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
117 match self {
118 Self::FileError(e) => write!(f, "{}", e),
119 Self::PestParseError(e) => write!(f, "{}", e),
120 Self::ParseError(e) => write!(f, "{}", e),
121 }
122 }
123}
124
125impl Error for GraphFromFileError<'_> {}
126
127impl From<IOError> for GraphFromFileError<'_> {
128 fn from(e: IOError) -> Self {
129 Self::FileError(e)
130 }
131}
132
133impl From<PestError> for GraphFromFileError<'_> {
134 fn from(e: PestError) -> Self {
135 Self::PestParseError(e)
136 }
137}
138
139impl<'a> From<ParseError<'a>> for GraphFromFileError<'a> {
140 fn from(e: ParseError<'a>) -> Self {
141 Self::ParseError(e)
142 }
143}
144
145#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
146pub struct Graph<A> {
152 pub strict: bool,
156 pub is_digraph: bool,
158 pub name: Option<String>,
160 pub stmts: StmtList<A>,
162}
163
164#[cfg(feature = "to_tokens")]
165impl ToTokens for Graph<(String, String)> {
166 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
167 let name = match &self.name {
168 Some(name) => quote! { std::option::Option::Some( #name.to_string() ) },
169 None => quote! { std::option::Option::None },
170 };
171 let strict = self.strict;
172 let is_digraph = self.is_digraph;
173 let stmts = &self.stmts;
174 let tokens = quote! {
175 dot_parser::ast::Graph::<(&'static str, &'static str)> {
176 strict: #strict,
177 is_digraph: #is_digraph,
178 name: #name,
179 stmts: #stmts
180 }
181 };
182 ts.append_all(tokens);
183 }
184}
185
186impl<'a, A> TryFrom<Pair<'a, Rule>> for Graph<A>
187where
188 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
189{
190 type Error = ParseError<'a>;
191 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
192 let mut inner = p.clone().into_inner();
193 let mut strict = false;
194 let mut name = None;
195 let mut pair = inner.next().ok_or(ParseError::missing_pair(
196 p.clone(),
197 vec![Rule::strict, Rule::digraph, Rule::graph],
198 ))?;
199 if let Rule::strict = pair.as_rule() {
200 strict = true;
201 pair = inner.next().ok_or(ParseError::missing_pair(
202 p.clone(),
203 vec![Rule::digraph, Rule::graph],
204 ))?;
205 }
206 let is_digraph = match pair.as_rule() {
207 Rule::digraph => true,
208 Rule::graph => false,
209 r => {
210 return Err(ParseError::expect_rule(vec![Rule::digraph, Rule::graph], r));
211 }
212 };
213 pair = inner.next().ok_or(ParseError::missing_pair(
214 p.clone(),
215 vec![Rule::ident, Rule::stmt_list],
216 ))?;
217 if let Rule::ident = pair.as_rule() {
218 name = Some(String::from(pair.as_str()));
219 pair = inner
220 .next()
221 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::stmt_list]))?;
222 }
223 let stmts = StmtList::try_from(pair)?;
224 Ok(Graph {
225 strict,
226 is_digraph,
227 name,
228 stmts,
229 })
230 }
231}
232
233impl Graph<(String, String)> {
234#[allow(clippy::result_large_err)]
236 pub fn from_file<'a, P>(p: P) -> Result<Self, GraphFromFileError<'a>>
240 where
241 P: AsRef<Path>,
242 {
243 let s = std::fs::read_to_string(p)?;
244 let mut pairs = DotParser::parse(Rule::dotgraph, &s)?;
245 let pair = pairs.next().expect("The toplevel `Pairs` is empty.");
246 match Graph::try_from(pair) {
247 Ok(g) => Ok(g),
248 Err(e) => panic!("{}", e),
249 }
250 }
251}
252
253impl<'a> TryFrom<&'a str> for Graph<(&'a str, &'a str)> {
254 type Error = PestError;
255 fn try_from(s: &'a str) -> Result<Self, PestError> {
256 let mut pairs = DotParser::parse(Rule::dotgraph, s)?;
257 match pairs.next() {
258 None => {
259 panic!("The toplevel `Pairs` is empty.")
260 }
261 Some(pair) => Ok(Graph::try_from(pair).unwrap()),
262 }
263 }
264}
265
266impl<A> Graph<A> {
267 pub fn filter_map<B>(self, f: &dyn Fn(A) -> Option<B>) -> Graph<B> {
275 let new_stmts: StmtList<B> = self.stmts.filter_map_attr(f);
276 Graph {
277 strict: self.strict,
278 is_digraph: self.is_digraph,
279 name: self.name,
280 stmts: new_stmts,
281 }
282 }
283
284 pub fn get_node_ids(self) -> HashSet<NodeID> {
286 let clone = self.stmts;
287 clone.get_node_ids()
288 }
289}
290
291pub struct Graphs<A> {
293 pub graphs: Vec::<Graph<A>>
295}
296
297impl <'a, A> TryFrom<Pair<'a, Rule>> for Graphs<A>
298where
299 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
300{
301 type Error = ParseError<'a>;
302 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
303 let mut inner = p.clone().into_inner().into_iter();
304 let first_graph_pair = inner.next().ok_or(ParseError::missing_pair(
305 p.clone(),
306 vec![Rule::dotfile],
307 ))?;
308 let mut graphs = vec!(Graph::try_from(first_graph_pair)?);
309 for p in inner {
310 graphs.push(Graph::try_from(p)?);
311 }
312 Ok(Graphs { graphs })
313 }
314}
315
316impl<'a> TryFrom<&'a str> for Graphs<(&'a str, &'a str)> {
317 type Error = PestError;
318 fn try_from(s: &'a str) -> Result<Self, PestError> {
319 DotParser::parse(Rule::dotfile, s).map(|mut p| match p.next() {
320 None => {
321 panic!("The toplevel `Pairs` is empty.")
322 }
323 Some(pair) => match Graphs::try_from(pair) {
324 Ok(g) => g,
325 Err(e) => panic!("{}", e),
326 },
327 })
328 }
329}
330
331impl Graphs<(String, String)> {
332#[allow(clippy::result_large_err)]
334 pub fn from_file<'a, P>(p: P) -> Result<Self, GraphFromFileError<'a>>
338 where
339 P: AsRef<Path>,
340 {
341 let s = std::fs::read_to_string(p)?;
342 let mut pairs = DotParser::parse(Rule::dotfile, &s)?;
343 println!("{:#?}", pairs);
344 let pair = pairs.next().expect("The toplevel `Pairs` is empty.");
345 match Graphs::try_from(pair) {
346 Ok(g) => Ok(g),
347 Err(e) => panic!("{}", e),
348 }
349 }
350}
351
352#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
355pub struct StmtList<A> {
356 pub stmts: Vec<Stmt<A>>,
358}
359
360#[cfg(feature = "to_tokens")]
361impl ToTokens for StmtList<(String, String)> {
362 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
363 let stmts = &self.stmts;
364 let tokens = quote! {
365 dot_parser::ast::StmtList {
366 stmts: std::vec![ #( #stmts ),* ],
367 }
368 };
369 ts.append_all(tokens);
370 }
371}
372
373impl<'a, A> TryFrom<Pair<'a, Rule>> for StmtList<A>
374where
375 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
376{
377 type Error = ParseError<'a>;
378 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
379 let inner = p.into_inner();
380 let mut stmts = Vec::new();
381 for stmt in inner {
382 stmts.push(Stmt::try_from(stmt)?);
383 }
384 Ok(StmtList { stmts })
385 }
386}
387
388impl<'a, A> StmtList<A> {
389 fn filter_map_attr<B>(self, f: &'a dyn Fn(A) -> Option<B>) -> StmtList<B> {
390 self.stmts
391 .into_iter()
392 .map(|stmt| stmt.filter_map_attr(f))
393 .collect()
394 }
395
396 fn get_node_ids(&self) -> HashSet<NodeID> {
397 let mut hs = HashSet::new();
398 for stmt in self {
399 hs = hs.union(&stmt.get_node_ids()).cloned().collect();
400 }
401 hs
402 }
403}
404
405impl<A> IntoIterator for StmtList<A> {
406 type Item = Stmt<A>;
407 type IntoIter = std::vec::IntoIter<Self::Item>;
408
409 fn into_iter(self) -> Self::IntoIter {
410 self.stmts.into_iter()
411 }
412}
413
414impl<'a, A> IntoIterator for &'a StmtList<A> {
415 type Item = &'a Stmt<A>;
416 type IntoIter = std::slice::Iter<'a, Stmt<A>>;
417
418 fn into_iter(self) -> Self::IntoIter {
419 self.stmts.iter()
420 }
421}
422
423impl<A> FromIterator<Stmt<A>> for StmtList<A> {
424 fn from_iter<T>(iter: T) -> Self
425 where
426 T: IntoIterator<Item = Stmt<A>>,
427 {
428 Self {
429 stmts: iter.into_iter().collect(),
430 }
431 }
432}
433
434#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
437pub enum Stmt<A> {
438 NodeStmt(NodeStmt<A>),
440 EdgeStmt(EdgeStmt<A>),
442 AttrStmt(AttrStmt<A>),
444 IDEq(String, String),
446 Subgraph(Subgraph<A>),
448}
449
450#[cfg(feature = "to_tokens")]
451impl ToTokens for Stmt<(String, String)> {
452 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
453 let tokens = match &self {
454 Self::NodeStmt(stmt) => {
455 quote! {
456 dot_parser::ast::Stmt::NodeStmt( #stmt )
457 }
458 },
459 Self::EdgeStmt(stmt) => {
460 quote! {
461 dot_parser::ast::Stmt::EdgeStmt( #stmt )
462 }
463 },
464 Self::AttrStmt(stmt) => {
465 quote! {
466 dot_parser::ast::Stmt::AttrStmt( #stmt )
467 }
468 },
469 Self::IDEq(s1, s2) => {
470 quote!{
471 dot_parser::ast::Stmt::IDEq( #s1.to_string(), #s2.to_string() )
472 }
473 },
474 Self::Subgraph(sub) => {
475 quote!{
476 dot_parser::ast::Stmt::Subgraph( #sub )
477 }
478 },
479 };
480 ts.append_all(tokens);
481 }
482}
483
484impl<'a, A> TryFrom<Pair<'a, Rule>> for Stmt<A>
485where
486 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
487{
488 type Error = ParseError<'a>;
489 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
490 let inner = p
491 .clone()
492 .into_inner()
493 .next()
494 .ok_or(ParseError::missing_pair(
495 p.clone(),
496 std::vec![
497 Rule::node_stmt,
498 Rule::edge_stmt,
499 Rule::attr_stmt,
500 Rule::id_eq,
501 Rule::subgraph,
502 ],
503 ))?;
504 match inner.as_rule() {
505 Rule::node_stmt => NodeStmt::try_from(inner).map(Stmt::NodeStmt),
506 Rule::edge_stmt => EdgeStmt::try_from(inner).map(Stmt::EdgeStmt),
507 Rule::attr_stmt => AttrStmt::try_from(inner).map(Stmt::AttrStmt),
508 Rule::id_eq => {
509 let mut inners = inner.into_inner();
510 let id1 = inners
511 .next()
512 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
513 .as_str().into();
514 let id2 = inners
515 .next()
516 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
517 .as_str().into();
518 Ok(Stmt::IDEq(id1, id2))
519 }
520 Rule::subgraph => Subgraph::try_from(inner).map(Stmt::Subgraph),
521 other => {
522 let error = ParseError::expect_rule(
523 vec![
524 Rule::node_stmt,
525 Rule::edge_stmt,
526 Rule::attr_stmt,
527 Rule::id_eq,
528 Rule::subgraph,
529 ],
530 other,
531 );
532 Err(error)
533 }
534 }
535 }
536}
537
538impl<'a, A> Stmt<A> {
539 fn filter_map_attr<B>(self, f: &'a dyn Fn(A) -> Option<B>) -> Stmt<B> {
542 match self {
543 Stmt::NodeStmt(node) => Stmt::NodeStmt(node.filter_map_attr(f)),
544 Stmt::EdgeStmt(edge) => Stmt::EdgeStmt(edge.filter_map_attr(f)),
545 Stmt::AttrStmt(attr) => Stmt::AttrStmt(attr.filter_map_attr(f)),
546 Stmt::IDEq(a, b) => Stmt::IDEq(a, b),
547 Stmt::Subgraph(sub) => Stmt::Subgraph(sub.filter_map_attr(f)),
548 }
549 }
550
551 pub fn is_node_stmt(&self) -> bool {
553 matches!(self, Stmt::NodeStmt(_))
554 }
555
556 pub fn get_node_ref(&self) -> Option<&NodeStmt<A>> {
559 if let Stmt::NodeStmt(node) = self {
560 Some(node)
561 } else {
562 None
563 }
564 }
565
566 pub fn get_node(self) -> Option<NodeStmt<A>> {
569 if let Stmt::NodeStmt(node) = self {
570 Some(node)
571 } else {
572 None
573 }
574 }
575
576 pub fn is_edge_stmt(&self) -> bool {
578 matches!(self, Stmt::EdgeStmt(_))
579 }
580
581 pub fn get_edge_ref(&self) -> Option<&EdgeStmt<A>> {
584 if let Stmt::EdgeStmt(edge) = self {
585 Some(edge)
586 } else {
587 None
588 }
589 }
590
591 pub fn get_edge(self) -> Option<EdgeStmt<A>> {
594 if let Stmt::EdgeStmt(edge) = self {
595 Some(edge)
596 } else {
597 None
598 }
599 }
600
601 pub fn is_attr_stmt(&self) -> bool {
603 matches!(self, Stmt::AttrStmt(_))
604 }
605
606 pub fn get_attr_ref(&self) -> Option<&AttrStmt<A>> {
609 if let Stmt::AttrStmt(attr) = self {
610 Some(attr)
611 } else {
612 None
613 }
614 }
615
616 pub fn get_attr(self) -> Option<AttrStmt<A>> {
619 if let Stmt::AttrStmt(attr) = self {
620 Some(attr)
621 } else {
622 None
623 }
624 }
625
626 pub fn is_ideq_stmt(&self) -> bool {
628 matches!(self, Stmt::IDEq(..))
629 }
630
631 pub fn get_ideq_ref(&self) -> Option<(&str, &str)> {
634 if let Stmt::IDEq(id1, id2) = self {
635 Some((id1, id2))
636 } else {
637 None
638 }
639 }
640
641 pub fn is_subgraph(&self) -> bool {
643 matches!(self, Stmt::Subgraph(..))
644 }
645
646 fn get_node_ids(&self) -> HashSet<NodeID> {
648 match self {
649 Stmt::Subgraph(g) => g.get_node_ids(),
650 Stmt::EdgeStmt(e) => e.get_node_ids(),
651 Stmt::NodeStmt(n) => HashSet::from_iter([n.get_node_id().clone()]),
652 _ => HashSet::new(),
653 }
654 }
655}
656
657#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
660pub enum AttrStmt<A> {
661 Graph(AttrList<A>),
663 Node(AttrList<A>),
665 Edge(AttrList<A>),
667}
668
669#[cfg(feature = "to_tokens")]
670impl ToTokens for AttrStmt<(String, String)> {
671 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
672 let new_tokens = match self {
673 AttrStmt::Graph(attrs) => quote!{ dot_parser::ast::AttrStmt::Graph(#attrs) },
674 AttrStmt::Node(attrs) => quote!{ dot_parser::ast::AttrStmt::Node(#attrs) },
675 AttrStmt::Edge(attrs) => quote!{ dot_parser::ast::AttrStmt::Edge(#attrs) },
676 };
677 ts.append_all(new_tokens);
678 }
679}
680
681impl<'a, A> TryFrom<Pair<'a, Rule>> for AttrStmt<A>
682where
683 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
684{
685 type Error = ParseError<'a>;
686 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
687 let mut inners = p.clone().into_inner();
688 let kind = inners
689 .next()
690 .ok_or(ParseError::missing_pair(
691 p.clone(),
692 vec![Rule::graph, Rule::node, Rule::edge],
693 ))?
694 .as_rule();
695 let attr_list_pair = inners
696 .next()
697 .ok_or(ParseError::missing_pair(p, vec![Rule::attr_list]))?;
698 let attr = AttrList::try_from(attr_list_pair)?;
699 match kind {
700 Rule::graph => Ok(AttrStmt::Graph(attr)),
701 Rule::node => Ok(AttrStmt::Node(attr)),
702 Rule::edge => Ok(AttrStmt::Edge(attr)),
703 r => Err(ParseError::expect_rule(
704 vec![Rule::graph, Rule::node, Rule::edge],
705 r,
706 )),
707 }
708 }
709}
710
711impl<A> AttrStmt<A> {
712 pub (in crate) fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> AttrStmt<B> {
713 match self {
714 AttrStmt::Graph(attr) => AttrStmt::Graph(attr.filter_map_attr(f)),
715 AttrStmt::Node(attr) => AttrStmt::Node(attr.filter_map_attr(f)),
716 AttrStmt::Edge(attr) => AttrStmt::Edge(attr.filter_map_attr(f)),
717 }
718 }
719}
720
721#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
727pub struct AttrList<A> {
728 pub elems: Vec<AList<A>>,
730}
731
732#[cfg(feature = "to_tokens")]
733impl ToTokens for AttrList<(String, String)> {
734 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
735 let elems = &self.elems;
736 let tokens = quote! {
737 dot_parser::ast::AttrList {
738 elems: std::vec![ #( #elems ),* ]
739 }
740 };
741 ts.append_all(tokens);
742 }
743}
744
745impl<'a, A> TryFrom<Pair<'a, Rule>> for AttrList<A>
746where
747 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
748{
749 type Error = ParseError<'a>;
750 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
751 let mut v: Vec<AList<A>> = Vec::new();
752 let mut inners = p.clone().into_inner();
753 let alist_pair = inners
754 .next()
755 .ok_or(ParseError::missing_pair(p, vec![Rule::a_list]))?;
756 let alist = AList::try_from(alist_pair)?;
757 let mut tail = inners
758 .next()
759 .map(|p| {
760 AttrList::try_from(p)
761 .map(|alist| alist.elems)
762 .unwrap_or_default()
763 })
764 .unwrap_or_default();
765 v.push(alist);
766 v.append(&mut tail);
767
768 Ok(AttrList { elems: v })
769 }
770}
771
772impl<A> AttrList<A> {
773 pub (in crate) fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> AttrList<B> {
774 AttrList {
775 elems: self
776 .into_iter()
777 .map(|alist| alist.filter_map_attr(f))
778 .collect(),
779 }
780 }
781
782 pub fn flatten(self) -> AList<A> {
785 self.into()
786 }
787
788 pub fn flatten_ref(&self) -> AList<&A> {
791 self.into()
792 }
793}
794
795impl<A> FromIterator<AList<A>> for AttrList<A> {
796 fn from_iter<T>(iter: T) -> Self
797 where
798 T: IntoIterator<Item = AList<A>>,
799 {
800 Self {
801 elems: iter.into_iter().map(|u| u.into_iter().collect()).collect(),
802 }
803 }
804}
805
806impl<A> IntoIterator for AttrList<A> {
807 type Item = AList<A>;
808 type IntoIter = std::vec::IntoIter<Self::Item>;
809
810 fn into_iter(self) -> Self::IntoIter {
811 self.elems.into_iter()
812 }
813}
814
815impl<'a, A> IntoIterator for &'a AttrList<A> {
816 type Item = &'a AList<A>;
817 type IntoIter = std::slice::Iter<'a, AList<A>>;
818
819 fn into_iter(self) -> Self::IntoIter {
820 self.elems.iter()
821 }
822}
823
824#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
827pub struct AList<A> {
828 pub elems: Vec<A>,
830}
831
832#[cfg(feature = "to_tokens")]
833impl ToTokens for AList<(String, String)> {
834 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
835 let elems = &self.elems;
836 let elems = elems.iter().map(|(s1, s2)| quote!{ (#s1, #s2) });
837 let tokens = quote! {
838 dot_parser::ast::AList {
839 elems: std::vec![ #( #elems ),* ]
840 }
841 };
842 ts.append_all(tokens);
843 }
844}
845
846#[cfg(feature = "display")]
847impl<A> Display for AList<A>
848where
849 A: Display,
850{
851 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
852 for attr in &self.elems {
853 write!(f, "{}; ", attr)?;
854 }
855 Ok(())
856 }
857}
858
859impl<'a> TryFrom<Pair<'a, Rule>> for AList<(&'a str, &'a str)> {
860 type Error = ParseError<'a>;
861 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
862 let mut v = Vec::new();
863 let mut inners = p.clone().into_inner();
864 let id1 = inners
865 .next()
866 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
867 .as_str();
868 let id2 = inners
869 .next()
870 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
871 .as_str();
872 let mut tail = inners
873 .next()
874 .map(|p| AList::try_from(p).map(|alist| alist.elems).unwrap_or_default())
875 .unwrap_or_default();
876 v.push((id1, id2));
877 v.append(&mut tail);
878
879 Ok(AList {
880 elems: v,
881 })
882 }
883}
884
885impl<'a> TryFrom<Pair<'a, Rule>> for AList<(String, String)> {
886 type Error = ParseError<'a>;
887 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
888 let mut v: Vec<(String, String)> = Vec::new();
889 let mut inners = p.clone().into_inner();
890 let id1 = inners
891 .next()
892 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
893 .as_str().into();
894 let id2 = inners
895 .next()
896 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
897 .as_str().into();
898 let mut tail = inners
899 .next()
900 .map(|p| AList::try_from(p).map(|alist| alist.elems).unwrap_or_default())
901 .unwrap_or_default();
902 v.push((id1, id2));
903 v.append(&mut tail);
904
905 Ok(AList {
906 elems: v,
907 })
908 }
909}
910
911impl<A> AList<A> {
912 pub(crate) fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> AList<B> {
913 AList {
914 elems: self.into_iter().filter_map(f).collect(),
915 }
916 }
917
918 pub(crate) fn empty() -> Self {
919 AList {
920 elems: Vec::new(),
921 }
922 }
923
924 #[cfg(feature = "display")]
925 pub(crate) fn is_empty(&self) -> bool {
927 self.elems.is_empty()
928 }
929}
930
931impl<A> FromIterator<A> for AList<A> {
932 fn from_iter<T>(iter: T) -> Self
933 where
934 T: IntoIterator<Item = A>,
935 {
936 Self {
937 elems: iter.into_iter().collect(),
938 }
939 }
940}
941
942impl<A> IntoIterator for AList<A> {
943 type Item = A;
944 type IntoIter = std::vec::IntoIter<Self::Item>;
945
946 fn into_iter(self) -> Self::IntoIter {
947 self.elems.into_iter()
948 }
949}
950
951impl<'a, A> IntoIterator for &'a AList<A> {
952 type Item = &'a A;
953 type IntoIter = std::slice::Iter<'a, A>;
954
955 fn into_iter(self) -> Self::IntoIter {
956 self.elems.iter()
957 }
958}
959
960impl<A> From<AttrList<A>> for AList<A> {
961 fn from(attr: AttrList<A>) -> Self {
962 attr.into_iter().flatten().collect()
963 }
964}
965
966impl<'a, A> From<&'a AttrList<A>> for AList<&'a A> {
967 fn from(attr: &'a AttrList<A>) -> Self {
968 attr.into_iter().flatten().collect()
969 }
970}
971
972#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
975pub struct EdgeStmt<A> {
976 pub from: Either<NodeID, Subgraph<A>>,
978 pub next: EdgeRHS<A>,
980 pub attr: Option<AttrList<A>>,
982}
983
984#[cfg(feature = "to_tokens")]
985impl ToTokens for EdgeStmt<(String, String)> {
986 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
987 let from = match &self.from {
988 Either::Left(id) => {
989 quote!{ dot_parser::ast::either::Either::Left( #id ) }
990 },
991 Either::Right(sub) => {
992 quote!{ dot_parser::ast::either::Either::Right( #sub ) }
993 },
994 };
995 let attr = match &self.attr {
996 Some(attr) => {
997 quote!{ std::option::Option::Some( #attr ) }
998 },
999 None => {
1000 quote!{ std::option::Option::None }
1001 },
1002 };
1003 let next = &self.next;
1004 let tokens = quote! {
1005 dot_parser::ast::EdgeStmt {
1006 from: #from,
1007 next: #next,
1008 attr: #attr,
1009 }
1010 };
1011 ts.append_all(tokens);
1012 }
1013}
1014
1015impl<'a, A> TryFrom<Pair<'a, Rule>> for EdgeStmt<A>
1016where
1017 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
1018{
1019 type Error = ParseError<'a>;
1020 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1021 let mut inners = p.clone().into_inner();
1022 let from_pair = inners.next().ok_or(ParseError::missing_pair(
1023 p.clone(),
1024 vec![Rule::node_id, Rule::subgraph],
1025 ))?;
1026 let rule = from_pair.as_rule();
1027 let from = match rule {
1028 Rule::node_id => Either::Left(NodeID::try_from(from_pair)?),
1029 Rule::subgraph => Either::Right(Subgraph::try_from(from_pair)?),
1030 r => {
1031 return Err(ParseError::expect_rule(
1032 vec![Rule::node_id, Rule::subgraph],
1033 r,
1034 ));
1035 }
1036 };
1037 let next = inners
1038 .next()
1039 .map(EdgeRHS::try_from)
1040 .transpose()?
1041 .ok_or(ParseError::missing_pair(p, vec![Rule::edge_rhs]))?;
1042 let attr = inners.next().map(AttrList::try_from).transpose()?;
1043
1044 Ok(EdgeStmt { from, next, attr })
1045 }
1046}
1047
1048impl<'a, A> EdgeStmt<A> {
1049 fn filter_map_attr<B>(self, f: &'a dyn Fn(A) -> Option<B>) -> EdgeStmt<B> {
1050 let new_from = match self.from {
1051 Either::Left(node_id) => Either::Left(node_id),
1052 Either::Right(subgraph) => Either::Right(subgraph.filter_map_attr(f)),
1053 };
1054
1055 let new_next = self.next.filter_map_attr(f);
1056
1057 EdgeStmt {
1058 from: new_from,
1059 next: new_next,
1060 attr: self.attr.map(|a| a.filter_map_attr(f)),
1061 }
1062 }
1063
1064 pub fn flatten(self) -> Vec<EdgeStmt<A>>
1066 where
1067 A: Clone,
1068 {
1069 let mut from = self.from;
1070 let mut to = self.next;
1071 let attr = self.attr;
1072
1073 let mut v = Vec::new();
1074
1075 loop {
1076 let next_step = EdgeStmt {
1077 from: from.clone(),
1078 next: EdgeRHS {
1079 to: to.to.clone(),
1080 next: None,
1081 },
1082 attr: attr.clone(),
1083 };
1084 v.push(next_step);
1085 match to.next {
1086 None => return v,
1087 Some(rhs) => {
1088 from = to.to;
1089 to = *rhs;
1090 }
1091 }
1092 }
1093 }
1094
1095 fn get_node_ids(&self) -> HashSet<NodeID> {
1096 let mut nexts = self.next.get_node_ids();
1097 match &self.from {
1098 Either::Left(node_id) => {
1099 nexts.insert(node_id.clone());
1100 }
1101 Either::Right(subgraph) => {
1102 return nexts.union(&subgraph.get_node_ids()).cloned().collect();
1103 }
1104 };
1105 nexts
1106 }
1107}
1108
1109#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1114pub struct EdgeRHS<A> {
1115 pub to: Either<NodeID, Subgraph<A>>,
1117 pub next: Option<Box<EdgeRHS<A>>>,
1119}
1120
1121#[cfg(feature = "to_tokens")]
1122impl ToTokens for EdgeRHS<(String, String)> {
1123 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1124 let to = match &self.to {
1125 Either::Left(id) => quote!{ dot_parser::ast::either::Either::Left( #id ) },
1126 Either::Right(sub) => quote!{ dot_parser::ast::either::Either::Right( #sub ) },
1127 };
1128 let next = match &self.next {
1129 Some(next) => quote! {
1130 std::option::Option::Some(
1131 std::boxed::Box::new( #next )
1132 )
1133 },
1134 None => quote! {
1135 std::option::Option::None
1136 }
1137 };
1138 let tokens = quote! {
1139 dot_parser::ast::EdgeRHS {
1140 to: #to,
1141 next: #next,
1142 }
1143 };
1144 ts.append_all(tokens);
1145 }
1146}
1147
1148impl<'a, A> TryFrom<Pair<'a, Rule>> for EdgeRHS<A>
1149where
1150 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
1151{
1152 type Error = ParseError<'a>;
1153 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1154 let mut inners = p.clone().into_inner();
1155 let to_pair = inners.next().ok_or(ParseError::missing_pair(
1156 p,
1157 vec![Rule::node_id, Rule::subgraph],
1158 ))?;
1159 let to = match to_pair.as_rule() {
1160 Rule::node_id => Either::Left(NodeID::try_from(to_pair)?),
1161 Rule::subgraph => {
1162 Either::Right(Subgraph::try_from(to_pair)?)
1164 }
1165 r => {
1166 return Err(ParseError::expect_rule(
1167 vec![Rule::node_id, Rule::subgraph],
1168 r,
1169 ));
1170 }
1171 };
1172 let next = inners.next().map(EdgeRHS::try_from).transpose()?.map(Box::new);
1173 Ok(EdgeRHS { to, next })
1174 }
1175}
1176
1177impl<'a, A> EdgeRHS<A> {
1178 fn filter_map_attr<B>(self, f: &'a dyn Fn(A) -> Option<B>) -> EdgeRHS<B> {
1179 let to = match self.to {
1180 Either::Left(node_id) => Either::Left(node_id),
1181 Either::Right(subgraph) => Either::Right(subgraph.filter_map_attr(f)),
1182 };
1183
1184 let next = self.next.map(|e| Box::new(e.filter_map_attr(f)));
1185
1186 EdgeRHS { to, next }
1187 }
1188
1189 fn get_node_ids(&self) -> HashSet<NodeID> {
1190 let mut nexts: HashSet<NodeID> = self
1191 .next
1192 .as_ref()
1193 .map(|n| n.get_node_ids())
1194 .unwrap_or_default();
1195 match &self.to {
1196 Either::Left(node_id) => {
1197 nexts.insert(node_id.clone());
1198 }
1199 Either::Right(subgraph) => {
1200 return nexts.union(&subgraph.get_node_ids()).cloned().collect();
1201 }
1202 };
1203 nexts
1204 }
1205}
1206
1207#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1210pub struct NodeStmt<A> {
1211 pub node: NodeID,
1213 pub attr: Option<AttrList<A>>,
1215}
1216
1217#[cfg(feature = "to_tokens")]
1218impl ToTokens for NodeStmt<(String, String)> {
1219 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1220 let node = &self.node;
1221 let attrs = match &self.attr {
1222 Some(a) => quote! { std::option::Option::Some(#a) },
1223 None => quote! { std::option::Option::None }
1224 };
1225 let tokens = quote! {
1226 dot_parser::ast::NodeStmt {
1227 node: #node,
1228 attr: #attrs
1229 }
1230 };
1231 ts.append_all(tokens);
1232 }
1233}
1234
1235impl<'a, A> TryFrom<Pair<'a, Rule>> for NodeStmt<A>
1236where
1237 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
1238{
1239 type Error = ParseError<'a>;
1240 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1241 let mut inners = p.clone().into_inner();
1242 let node = inners
1243 .next()
1244 .map(NodeID::try_from)
1245 .transpose()?
1246 .ok_or(ParseError::missing_pair(p, vec![Rule::node_id]))?;
1247 let attr = inners.next().map(AttrList::try_from).transpose()?;
1248 Ok(NodeStmt { node, attr })
1249 }
1250}
1251
1252impl<A> NodeStmt<A> {
1253 pub (in crate) fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> NodeStmt<B> {
1254 NodeStmt {
1255 node: self.node,
1256 attr: self.attr.map(|a| a.filter_map_attr(f)),
1257 }
1258 }
1259
1260 pub fn name(&self) -> &str {
1263 &self.node.id
1264 }
1265
1266 pub (in crate) fn get_node_id(&self) -> &NodeID {
1267 &self.node
1268 }
1269}
1270
1271#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1274pub struct NodeID {
1275 pub id: String,
1277 pub port: Option<Port>,
1279}
1280
1281#[cfg(feature = "to_tokens")]
1282impl ToTokens for NodeID {
1283 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1284 let id = &self.id;
1285 let port = match &self.port {
1286 Some(port) => quote!{ std::option::Option::Some(#port) },
1287 None => quote! { std::option::Option::None },
1288 };
1289 let tokens = quote!{
1290 dot_parser::ast::NodeID {
1291 id: #id.to_string(),
1292 port: #port,
1293 }
1294 };
1295 ts.append_all(tokens);
1296 }
1297}
1298
1299impl<'a> TryFrom<Pair<'a, Rule>> for NodeID
1300{
1301 type Error = ParseError<'a>;
1302 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1303 let mut inners = p.clone().into_inner();
1304 let id = inners
1305 .next()
1306 .ok_or(ParseError::missing_pair(p, vec![Rule::node_id]))?
1307 .as_str()
1308 .to_string();
1309 let port = inners.next().map(Port::try_from).transpose()?;
1310 Ok(NodeID { id, port })
1311 }
1312}
1313
1314#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
1316pub enum Port {
1317 ID(String, Option<CompassPt>),
1319 Compass(CompassPt),
1321}
1322
1323#[cfg(feature = "to_tokens")]
1324impl ToTokens for Port {
1325 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1326 let tokens = match self {
1327 Port::ID(s, cpss) => {
1328 match cpss {
1329 Some(cpss) => {
1330 quote!{ dot_parser::ast::Port::ID(#s.to_string(), std::option::Option::Some(#cpss)) }
1331 },
1332 None => {
1333 quote!{ dot_parser::ast::Port::ID(#s.to_string(), std::option::Option::None) }
1334 }
1335 }
1336 },
1337 Port::Compass(cpss) => {
1338 quote!{ dot_parser::ast::Port::Compass(#cpss) }
1339 }
1340 };
1341 ts.append_all(tokens);
1342 }
1343}
1344
1345impl<'a> TryFrom<Pair<'a, Rule>> for Port
1346{
1347 type Error = ParseError<'a>;
1348 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1349 let mut inners = p.clone().into_inner();
1350 let inner = inners.next().ok_or(ParseError::missing_pair(
1351 p,
1352 vec![Rule::compass_pt, Rule::ident],
1353 ))?;
1354 match inner.as_rule() {
1355 Rule::compass_pt => Ok(Port::Compass(CompassPt::try_from(inner)?)),
1356 Rule::ident => {
1357 let opt_comp = inners.next().map(CompassPt::try_from).transpose()?;
1358 Ok(Port::ID(inner.as_str().to_string(), opt_comp))
1359 }
1360 r => Err(ParseError::expect_rule(
1361 vec![Rule::compass_pt, Rule::ident],
1362 r,
1363 )),
1364 }
1365 }
1366}
1367
1368#[cfg(feature = "display")]
1369impl Display for Port {
1370 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
1371 match self {
1372 Port::ID(name, Some(cpss)) => {
1373 write!(f, ": {name} : {cpss}")
1374 }
1375 Port::ID(name, None) => {
1376 write!(f, ": {name}")
1377 }
1378 Port::Compass(cpss) => {
1379 write!(f, ": {}", cpss)
1380 }
1381 }
1382 }
1383}
1384
1385#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1387pub struct Subgraph<A> {
1388 pub id: Option<String>,
1390 pub stmts: StmtList<A>,
1392}
1393
1394#[cfg(feature = "to_tokens")]
1395impl ToTokens for Subgraph<(String, String)> {
1396 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1397 let id = match &self.id {
1398 Some(s) => quote!{ std::option::Some(#s) },
1399 None => quote! { std::option::None },
1400 };
1401 let stmts = &self.stmts;
1402 let tokens = quote! {
1403 dot_parser::ast::Subgraph {
1404 id: #id,
1405 stmts: #stmts,
1406 }
1407 };
1408 ts.append_all(tokens);
1409 }
1410}
1411
1412impl<'a, A> TryFrom<Pair<'a, Rule>> for Subgraph<A>
1413where
1414 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
1415{
1416 type Error = ParseError<'a>;
1417 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1418 let mut inners = p.clone().into_inner();
1419 let mut inner = inners.next().ok_or(ParseError::missing_pair(
1420 p.clone(),
1421 vec![Rule::ident, Rule::stmt_list],
1422 ))?;
1423 let id = if let Rule::ident = inner.as_rule() {
1424 let id_str = inner.as_str().to_string();
1425 inner = inners
1426 .next()
1427 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::stmt_list]))?;
1428 Some(id_str)
1429 } else {
1430 None
1431 };
1432 let stmts = StmtList::try_from(inner)?;
1433 Ok(Subgraph { id, stmts })
1434 }
1435}
1436
1437impl<A> Subgraph<A> {
1438 fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> Subgraph<B> {
1439 Subgraph {
1440 id: self.id,
1441 stmts: self
1442 .stmts
1443 .into_iter()
1444 .map(|stmt| stmt.filter_map_attr(f))
1445 .collect(),
1446 }
1447 }
1448
1449 pub (in crate) fn into_graph(self, strict: bool, is_digraph: bool) -> Graph<A> {
1451 Graph {
1452 strict,
1453 is_digraph,
1454 name: self.id.map(String::from),
1455 stmts: self.stmts,
1456 }
1457 }
1458
1459 fn get_node_ids(&self) -> HashSet<NodeID> {
1460 self.stmts.get_node_ids()
1461 }
1462}
1463
1464#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
1466pub enum CompassPt {
1467 N,
1469 NE,
1471 E,
1473 SE,
1475 S,
1477 SW,
1479 W,
1481 NW,
1483 C,
1485 Underscore,
1487}
1488
1489#[cfg(feature = "display")]
1490impl Display for CompassPt {
1491 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
1492 match self {
1493 CompassPt::N => write!(f, "n"),
1494 CompassPt::NE => write!(f, "ne"),
1495 CompassPt::E => write!(f, "e"),
1496 CompassPt::SE => write!(f, "se"),
1497 CompassPt::S => write!(f, "s"),
1498 CompassPt::SW => write!(f, "sw"),
1499 CompassPt::W => write!(f, "w"),
1500 CompassPt::NW => write!(f, "nw"),
1501 CompassPt::C => write!(f, "c"),
1502 CompassPt::Underscore => write!(f, "_"),
1503 }
1504 }
1505}
1506
1507impl<'a> TryFrom<Pair<'a, Rule>> for CompassPt {
1508 type Error = ParseError<'a>;
1509 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1510 match p
1511 .clone()
1512 .into_inner()
1513 .next()
1514 .ok_or(ParseError::missing_pair(
1515 p,
1516 vec![
1517 Rule::n,
1518 Rule::ne,
1519 Rule::e,
1520 Rule::se,
1521 Rule::s,
1522 Rule::sw,
1523 Rule::w,
1524 Rule::nw,
1525 Rule::c,
1526 Rule::underscore,
1527 ],
1528 ))?
1529 .as_rule()
1530 {
1531 Rule::n => Ok(CompassPt::N),
1532 Rule::ne => Ok(CompassPt::NE),
1533 Rule::e => Ok(CompassPt::E),
1534 Rule::se => Ok(CompassPt::SE),
1535 Rule::s => Ok(CompassPt::S),
1536 Rule::sw => Ok(CompassPt::SW),
1537 Rule::w => Ok(CompassPt::W),
1538 Rule::nw => Ok(CompassPt::NW),
1539 Rule::c => Ok(CompassPt::C),
1540 Rule::underscore => Ok(CompassPt::Underscore),
1541 r => Err(ParseError::expect_rule(
1542 vec![
1543 Rule::n,
1544 Rule::ne,
1545 Rule::e,
1546 Rule::se,
1547 Rule::s,
1548 Rule::sw,
1549 Rule::w,
1550 Rule::nw,
1551 Rule::c,
1552 Rule::underscore,
1553 ],
1554 r,
1555 )),
1556 }
1557 }
1558}
1559
1560#[cfg(feature = "to_tokens")]
1561impl ToTokens for CompassPt {
1562 fn to_tokens(&self, tokens: &mut TokenStream) {
1563 let new_tokens = match self {
1564 CompassPt::N => quote!{ dot_parser::ast::CompassPt::N},
1565 CompassPt::NE => quote!{ dot_parser::ast::CompassPt::NE},
1566 CompassPt::E => quote!{ dot_parser::ast::CompassPt::E},
1567 CompassPt::SE => quote!{ dot_parser::ast::CompassPt::SE},
1568 CompassPt::S => quote!{ dot_parser::ast::CompassPt::S},
1569 CompassPt::SW => quote!{ dot_parser::ast::CompassPt::SW},
1570 CompassPt::W => quote!{ dot_parser::ast::CompassPt::W},
1571 CompassPt::NW => quote!{ dot_parser::ast::CompassPt::NW},
1572 CompassPt::C => quote!{ dot_parser::ast::CompassPt::C},
1573 CompassPt::Underscore => quote!{ dot_parser::ast::CompassPt::Underscore},
1574 };
1575 tokens.append_all(new_tokens);
1576 }
1577}