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( std::string::ToString::to_string(#name) ) },
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 let pair = pairs.next().expect("The toplevel `Pairs` is empty.");
344 match Graphs::try_from(pair) {
345 Ok(g) => Ok(g),
346 Err(e) => panic!("{}", e),
347 }
348 }
349}
350
351#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
354pub struct StmtList<A> {
355 pub stmts: Vec<Stmt<A>>,
357}
358
359#[cfg(feature = "to_tokens")]
360impl ToTokens for StmtList<(String, String)> {
361 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
362 let stmts = &self.stmts;
363 let tokens = quote! {
364 dot_parser::ast::StmtList {
365 stmts: std::vec![ #( #stmts ),* ],
366 }
367 };
368 ts.append_all(tokens);
369 }
370}
371
372impl<'a, A> TryFrom<Pair<'a, Rule>> for StmtList<A>
373where
374 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
375{
376 type Error = ParseError<'a>;
377 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
378 let inner = p.into_inner();
379 let mut stmts = Vec::new();
380 for stmt in inner {
381 stmts.push(Stmt::try_from(stmt)?);
382 }
383 Ok(StmtList { stmts })
384 }
385}
386
387impl<'a, A> StmtList<A> {
388 fn filter_map_attr<B>(self, f: &'a dyn Fn(A) -> Option<B>) -> StmtList<B> {
389 self.stmts
390 .into_iter()
391 .map(|stmt| stmt.filter_map_attr(f))
392 .collect()
393 }
394
395 fn get_node_ids(&self) -> HashSet<NodeID> {
396 let mut hs = HashSet::new();
397 for stmt in self {
398 hs = hs.union(&stmt.get_node_ids()).cloned().collect();
399 }
400 hs
401 }
402}
403
404impl<A> IntoIterator for StmtList<A> {
405 type Item = Stmt<A>;
406 type IntoIter = std::vec::IntoIter<Self::Item>;
407
408 fn into_iter(self) -> Self::IntoIter {
409 self.stmts.into_iter()
410 }
411}
412
413impl<'a, A> IntoIterator for &'a StmtList<A> {
414 type Item = &'a Stmt<A>;
415 type IntoIter = std::slice::Iter<'a, Stmt<A>>;
416
417 fn into_iter(self) -> Self::IntoIter {
418 self.stmts.iter()
419 }
420}
421
422impl<A> FromIterator<Stmt<A>> for StmtList<A> {
423 fn from_iter<T>(iter: T) -> Self
424 where
425 T: IntoIterator<Item = Stmt<A>>,
426 {
427 Self {
428 stmts: iter.into_iter().collect(),
429 }
430 }
431}
432
433#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
436pub enum Stmt<A> {
437 NodeStmt(NodeStmt<A>),
439 EdgeStmt(EdgeStmt<A>),
441 AttrStmt(AttrStmt<A>),
443 IDEq(String, String),
445 Subgraph(Subgraph<A>),
447}
448
449#[cfg(feature = "to_tokens")]
450impl ToTokens for Stmt<(String, String)> {
451 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
452 let tokens = match &self {
453 Self::NodeStmt(stmt) => {
454 quote! {
455 dot_parser::ast::Stmt::NodeStmt( #stmt )
456 }
457 },
458 Self::EdgeStmt(stmt) => {
459 quote! {
460 dot_parser::ast::Stmt::EdgeStmt( #stmt )
461 }
462 },
463 Self::AttrStmt(stmt) => {
464 quote! {
465 dot_parser::ast::Stmt::AttrStmt( #stmt )
466 }
467 },
468 Self::IDEq(s1, s2) => {
469 quote!{
470 dot_parser::ast::Stmt::IDEq( std::string::ToString::to_string(#s1), std::string::ToString::to_string(#s2) )
471 }
472 },
473 Self::Subgraph(sub) => {
474 quote!{
475 dot_parser::ast::Stmt::Subgraph( #sub )
476 }
477 },
478 };
479 ts.append_all(tokens);
480 }
481}
482
483impl<'a, A> TryFrom<Pair<'a, Rule>> for Stmt<A>
484where
485 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
486{
487 type Error = ParseError<'a>;
488 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
489 let inner = p
490 .clone()
491 .into_inner()
492 .next()
493 .ok_or(ParseError::missing_pair(
494 p.clone(),
495 std::vec![
496 Rule::node_stmt,
497 Rule::edge_stmt,
498 Rule::attr_stmt,
499 Rule::id_eq,
500 Rule::subgraph,
501 ],
502 ))?;
503 match inner.as_rule() {
504 Rule::node_stmt => NodeStmt::try_from(inner).map(Stmt::NodeStmt),
505 Rule::edge_stmt => EdgeStmt::try_from(inner).map(Stmt::EdgeStmt),
506 Rule::attr_stmt => AttrStmt::try_from(inner).map(Stmt::AttrStmt),
507 Rule::id_eq => {
508 let mut inners = inner.into_inner();
509 let id1 = inners
510 .next()
511 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
512 .as_str().into();
513 let id2 = inners
514 .next()
515 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
516 .as_str().into();
517 Ok(Stmt::IDEq(id1, id2))
518 }
519 Rule::subgraph => Subgraph::try_from(inner).map(Stmt::Subgraph),
520 other => {
521 let error = ParseError::expect_rule(
522 vec![
523 Rule::node_stmt,
524 Rule::edge_stmt,
525 Rule::attr_stmt,
526 Rule::id_eq,
527 Rule::subgraph,
528 ],
529 other,
530 );
531 Err(error)
532 }
533 }
534 }
535}
536
537impl<'a, A> Stmt<A> {
538 fn filter_map_attr<B>(self, f: &'a dyn Fn(A) -> Option<B>) -> Stmt<B> {
541 match self {
542 Stmt::NodeStmt(node) => Stmt::NodeStmt(node.filter_map_attr(f)),
543 Stmt::EdgeStmt(edge) => Stmt::EdgeStmt(edge.filter_map_attr(f)),
544 Stmt::AttrStmt(attr) => Stmt::AttrStmt(attr.filter_map_attr(f)),
545 Stmt::IDEq(a, b) => Stmt::IDEq(a, b),
546 Stmt::Subgraph(sub) => Stmt::Subgraph(sub.filter_map_attr(f)),
547 }
548 }
549
550 pub fn is_node_stmt(&self) -> bool {
552 matches!(self, Stmt::NodeStmt(_))
553 }
554
555 pub fn get_node_ref(&self) -> Option<&NodeStmt<A>> {
558 if let Stmt::NodeStmt(node) = self {
559 Some(node)
560 } else {
561 None
562 }
563 }
564
565 pub fn get_node(self) -> Option<NodeStmt<A>> {
568 if let Stmt::NodeStmt(node) = self {
569 Some(node)
570 } else {
571 None
572 }
573 }
574
575 pub fn is_edge_stmt(&self) -> bool {
577 matches!(self, Stmt::EdgeStmt(_))
578 }
579
580 pub fn get_edge_ref(&self) -> Option<&EdgeStmt<A>> {
583 if let Stmt::EdgeStmt(edge) = self {
584 Some(edge)
585 } else {
586 None
587 }
588 }
589
590 pub fn get_edge(self) -> Option<EdgeStmt<A>> {
593 if let Stmt::EdgeStmt(edge) = self {
594 Some(edge)
595 } else {
596 None
597 }
598 }
599
600 pub fn is_attr_stmt(&self) -> bool {
602 matches!(self, Stmt::AttrStmt(_))
603 }
604
605 pub fn get_attr_ref(&self) -> Option<&AttrStmt<A>> {
608 if let Stmt::AttrStmt(attr) = self {
609 Some(attr)
610 } else {
611 None
612 }
613 }
614
615 pub fn get_attr(self) -> Option<AttrStmt<A>> {
618 if let Stmt::AttrStmt(attr) = self {
619 Some(attr)
620 } else {
621 None
622 }
623 }
624
625 pub fn is_ideq_stmt(&self) -> bool {
627 matches!(self, Stmt::IDEq(..))
628 }
629
630 pub fn get_ideq_ref(&self) -> Option<(&str, &str)> {
633 if let Stmt::IDEq(id1, id2) = self {
634 Some((id1, id2))
635 } else {
636 None
637 }
638 }
639
640 pub fn is_subgraph(&self) -> bool {
642 matches!(self, Stmt::Subgraph(..))
643 }
644
645 fn get_node_ids(&self) -> HashSet<NodeID> {
647 match self {
648 Stmt::Subgraph(g) => g.get_node_ids(),
649 Stmt::EdgeStmt(e) => e.get_node_ids(),
650 Stmt::NodeStmt(n) => HashSet::from_iter([n.get_node_id().clone()]),
651 _ => HashSet::new(),
652 }
653 }
654}
655
656#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
659pub enum AttrStmt<A> {
660 Graph(AttrList<A>),
662 Node(AttrList<A>),
664 Edge(AttrList<A>),
666}
667
668#[cfg(feature = "to_tokens")]
669impl ToTokens for AttrStmt<(String, String)> {
670 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
671 let new_tokens = match self {
672 AttrStmt::Graph(attrs) => quote!{ dot_parser::ast::AttrStmt::Graph(#attrs) },
673 AttrStmt::Node(attrs) => quote!{ dot_parser::ast::AttrStmt::Node(#attrs) },
674 AttrStmt::Edge(attrs) => quote!{ dot_parser::ast::AttrStmt::Edge(#attrs) },
675 };
676 ts.append_all(new_tokens);
677 }
678}
679
680impl<'a, A> TryFrom<Pair<'a, Rule>> for AttrStmt<A>
681where
682 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
683{
684 type Error = ParseError<'a>;
685 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
686 let mut inners = p.clone().into_inner();
687 let kind = inners
688 .next()
689 .ok_or(ParseError::missing_pair(
690 p.clone(),
691 vec![Rule::graph, Rule::node, Rule::edge],
692 ))?
693 .as_rule();
694 let attr_list_pair = inners
695 .next()
696 .ok_or(ParseError::missing_pair(p, vec![Rule::attr_list]))?;
697 let attr = AttrList::try_from(attr_list_pair)?;
698 match kind {
699 Rule::graph => Ok(AttrStmt::Graph(attr)),
700 Rule::node => Ok(AttrStmt::Node(attr)),
701 Rule::edge => Ok(AttrStmt::Edge(attr)),
702 r => Err(ParseError::expect_rule(
703 vec![Rule::graph, Rule::node, Rule::edge],
704 r,
705 )),
706 }
707 }
708}
709
710impl<A> AttrStmt<A> {
711 pub (in crate) fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> AttrStmt<B> {
712 match self {
713 AttrStmt::Graph(attr) => AttrStmt::Graph(attr.filter_map_attr(f)),
714 AttrStmt::Node(attr) => AttrStmt::Node(attr.filter_map_attr(f)),
715 AttrStmt::Edge(attr) => AttrStmt::Edge(attr.filter_map_attr(f)),
716 }
717 }
718}
719
720#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
726pub struct AttrList<A> {
727 pub elems: Vec<AList<A>>,
729}
730
731#[cfg(feature = "to_tokens")]
732impl ToTokens for AttrList<(String, String)> {
733 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
734 let elems = &self.elems;
735 let tokens = quote! {
736 dot_parser::ast::AttrList {
737 elems: std::vec![ #( #elems ),* ]
738 }
739 };
740 ts.append_all(tokens);
741 }
742}
743
744impl<'a, A> TryFrom<Pair<'a, Rule>> for AttrList<A>
745where
746 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
747{
748 type Error = ParseError<'a>;
749 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
750 let mut v: Vec<AList<A>> = Vec::new();
751 let mut inners = p.clone().into_inner();
752 let alist_pair = inners
753 .next()
754 .ok_or(ParseError::missing_pair(p, vec![Rule::a_list]))?;
755 let alist = AList::try_from(alist_pair)?;
756 let mut tail = inners
757 .next()
758 .map(|p| {
759 AttrList::try_from(p)
760 .map(|alist| alist.elems)
761 .unwrap_or_default()
762 })
763 .unwrap_or_default();
764 v.push(alist);
765 v.append(&mut tail);
766
767 Ok(AttrList { elems: v })
768 }
769}
770
771impl<A> AttrList<A> {
772 pub (in crate) fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> AttrList<B> {
773 AttrList {
774 elems: self
775 .into_iter()
776 .map(|alist| alist.filter_map_attr(f))
777 .collect(),
778 }
779 }
780
781 pub fn flatten(self) -> AList<A> {
784 self.into()
785 }
786
787 pub fn flatten_ref(&self) -> AList<&A> {
790 self.into()
791 }
792}
793
794impl<A> FromIterator<AList<A>> for AttrList<A> {
795 fn from_iter<T>(iter: T) -> Self
796 where
797 T: IntoIterator<Item = AList<A>>,
798 {
799 Self {
800 elems: iter.into_iter().map(|u| u.into_iter().collect()).collect(),
801 }
802 }
803}
804
805impl<A> IntoIterator for AttrList<A> {
806 type Item = AList<A>;
807 type IntoIter = std::vec::IntoIter<Self::Item>;
808
809 fn into_iter(self) -> Self::IntoIter {
810 self.elems.into_iter()
811 }
812}
813
814impl<'a, A> IntoIterator for &'a AttrList<A> {
815 type Item = &'a AList<A>;
816 type IntoIter = std::slice::Iter<'a, AList<A>>;
817
818 fn into_iter(self) -> Self::IntoIter {
819 self.elems.iter()
820 }
821}
822
823#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
826pub struct AList<A> {
827 pub elems: Vec<A>,
829}
830
831#[cfg(feature = "to_tokens")]
832impl ToTokens for AList<(String, String)> {
833 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
834 let elems = &self.elems;
835 let elems = elems.iter().map(|(s1, s2)| quote!{ (#s1, #s2) });
836 let tokens = quote! {
837 dot_parser::ast::AList {
838 elems: std::vec![ #( #elems ),* ]
839 }
840 };
841 ts.append_all(tokens);
842 }
843}
844
845#[cfg(feature = "display")]
846impl<A> Display for AList<A>
847where
848 A: Display,
849{
850 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
851 for attr in &self.elems {
852 write!(f, "{}; ", attr)?;
853 }
854 Ok(())
855 }
856}
857
858impl<'a> TryFrom<Pair<'a, Rule>> for AList<(&'a str, &'a str)> {
859 type Error = ParseError<'a>;
860 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
861 let mut v = Vec::new();
862 let mut inners = p.clone().into_inner();
863 let id1 = inners
864 .next()
865 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
866 .as_str();
867 let id2 = inners
868 .next()
869 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
870 .as_str();
871 let mut tail = inners
872 .next()
873 .map(|p| AList::try_from(p).map(|alist| alist.elems).unwrap_or_default())
874 .unwrap_or_default();
875 v.push((id1, id2));
876 v.append(&mut tail);
877
878 Ok(AList {
879 elems: v,
880 })
881 }
882}
883
884impl<'a> TryFrom<Pair<'a, Rule>> for AList<(String, String)> {
885 type Error = ParseError<'a>;
886 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
887 let mut v: Vec<(String, String)> = Vec::new();
888 let mut inners = p.clone().into_inner();
889 let id1 = inners
890 .next()
891 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
892 .as_str().into();
893 let id2 = inners
894 .next()
895 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::ident]))?
896 .as_str().into();
897 let mut tail = inners
898 .next()
899 .map(|p| AList::try_from(p).map(|alist| alist.elems).unwrap_or_default())
900 .unwrap_or_default();
901 v.push((id1, id2));
902 v.append(&mut tail);
903
904 Ok(AList {
905 elems: v,
906 })
907 }
908}
909
910impl<A> AList<A> {
911 pub(crate) fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> AList<B> {
912 AList {
913 elems: self.into_iter().filter_map(f).collect(),
914 }
915 }
916
917 pub(crate) fn empty() -> Self {
918 AList {
919 elems: Vec::new(),
920 }
921 }
922
923 #[cfg(feature = "display")]
924 pub(crate) fn is_empty(&self) -> bool {
926 self.elems.is_empty()
927 }
928}
929
930impl<A> FromIterator<A> for AList<A> {
931 fn from_iter<T>(iter: T) -> Self
932 where
933 T: IntoIterator<Item = A>,
934 {
935 Self {
936 elems: iter.into_iter().collect(),
937 }
938 }
939}
940
941impl<A> IntoIterator for AList<A> {
942 type Item = A;
943 type IntoIter = std::vec::IntoIter<Self::Item>;
944
945 fn into_iter(self) -> Self::IntoIter {
946 self.elems.into_iter()
947 }
948}
949
950impl<'a, A> IntoIterator for &'a AList<A> {
951 type Item = &'a A;
952 type IntoIter = std::slice::Iter<'a, A>;
953
954 fn into_iter(self) -> Self::IntoIter {
955 self.elems.iter()
956 }
957}
958
959impl<A> From<AttrList<A>> for AList<A> {
960 fn from(attr: AttrList<A>) -> Self {
961 attr.into_iter().flatten().collect()
962 }
963}
964
965impl<'a, A> From<&'a AttrList<A>> for AList<&'a A> {
966 fn from(attr: &'a AttrList<A>) -> Self {
967 attr.into_iter().flatten().collect()
968 }
969}
970
971#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
974pub struct EdgeStmt<A> {
975 pub from: Either<NodeID, Subgraph<A>>,
977 pub next: EdgeRHS<A>,
979 pub attr: Option<AttrList<A>>,
981}
982
983#[cfg(feature = "to_tokens")]
984impl ToTokens for EdgeStmt<(String, String)> {
985 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
986 let from = match &self.from {
987 Either::Left(id) => {
988 quote!{ dot_parser::ast::either::Either::Left( #id ) }
989 },
990 Either::Right(sub) => {
991 quote!{ dot_parser::ast::either::Either::Right( #sub ) }
992 },
993 };
994 let attr = match &self.attr {
995 Some(attr) => {
996 quote!{ std::option::Option::Some( #attr ) }
997 },
998 None => {
999 quote!{ std::option::Option::None }
1000 },
1001 };
1002 let next = &self.next;
1003 let tokens = quote! {
1004 dot_parser::ast::EdgeStmt {
1005 from: #from,
1006 next: #next,
1007 attr: #attr,
1008 }
1009 };
1010 ts.append_all(tokens);
1011 }
1012}
1013
1014impl<'a, A> TryFrom<Pair<'a, Rule>> for EdgeStmt<A>
1015where
1016 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
1017{
1018 type Error = ParseError<'a>;
1019 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1020 let mut inners = p.clone().into_inner();
1021 let from_pair = inners.next().ok_or(ParseError::missing_pair(
1022 p.clone(),
1023 vec![Rule::node_id, Rule::subgraph],
1024 ))?;
1025 let rule = from_pair.as_rule();
1026 let from = match rule {
1027 Rule::node_id => Either::Left(NodeID::try_from(from_pair)?),
1028 Rule::subgraph => Either::Right(Subgraph::try_from(from_pair)?),
1029 r => {
1030 return Err(ParseError::expect_rule(
1031 vec![Rule::node_id, Rule::subgraph],
1032 r,
1033 ));
1034 }
1035 };
1036 let next = inners
1037 .next()
1038 .map(EdgeRHS::try_from)
1039 .transpose()?
1040 .ok_or(ParseError::missing_pair(p, vec![Rule::edge_rhs]))?;
1041 let attr = inners.next().map(AttrList::try_from).transpose()?;
1042
1043 Ok(EdgeStmt { from, next, attr })
1044 }
1045}
1046
1047impl<'a, A> EdgeStmt<A> {
1048 fn filter_map_attr<B>(self, f: &'a dyn Fn(A) -> Option<B>) -> EdgeStmt<B> {
1049 let new_from = match self.from {
1050 Either::Left(node_id) => Either::Left(node_id),
1051 Either::Right(subgraph) => Either::Right(subgraph.filter_map_attr(f)),
1052 };
1053
1054 let new_next = self.next.filter_map_attr(f);
1055
1056 EdgeStmt {
1057 from: new_from,
1058 next: new_next,
1059 attr: self.attr.map(|a| a.filter_map_attr(f)),
1060 }
1061 }
1062
1063 pub fn flatten(self) -> Vec<EdgeStmt<A>>
1065 where
1066 A: Clone,
1067 {
1068 let mut from = self.from;
1069 let mut to = self.next;
1070 let attr = self.attr;
1071
1072 let mut v = Vec::new();
1073
1074 loop {
1075 let next_step = EdgeStmt {
1076 from: from.clone(),
1077 next: EdgeRHS {
1078 to: to.to.clone(),
1079 next: None,
1080 },
1081 attr: attr.clone(),
1082 };
1083 v.push(next_step);
1084 match to.next {
1085 None => return v,
1086 Some(rhs) => {
1087 from = to.to;
1088 to = *rhs;
1089 }
1090 }
1091 }
1092 }
1093
1094 fn get_node_ids(&self) -> HashSet<NodeID> {
1095 let mut nexts = self.next.get_node_ids();
1096 match &self.from {
1097 Either::Left(node_id) => {
1098 nexts.insert(node_id.clone());
1099 }
1100 Either::Right(subgraph) => {
1101 return nexts.union(&subgraph.get_node_ids()).cloned().collect();
1102 }
1103 };
1104 nexts
1105 }
1106}
1107
1108#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1113pub struct EdgeRHS<A> {
1114 pub to: Either<NodeID, Subgraph<A>>,
1116 pub next: Option<Box<EdgeRHS<A>>>,
1118}
1119
1120#[cfg(feature = "to_tokens")]
1121impl ToTokens for EdgeRHS<(String, String)> {
1122 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1123 let to = match &self.to {
1124 Either::Left(id) => quote!{ dot_parser::ast::either::Either::Left( #id ) },
1125 Either::Right(sub) => quote!{ dot_parser::ast::either::Either::Right( #sub ) },
1126 };
1127 let next = match &self.next {
1128 Some(next) => quote! {
1129 std::option::Option::Some(
1130 std::boxed::Box::new( #next )
1131 )
1132 },
1133 None => quote! {
1134 std::option::Option::None
1135 }
1136 };
1137 let tokens = quote! {
1138 dot_parser::ast::EdgeRHS {
1139 to: #to,
1140 next: #next,
1141 }
1142 };
1143 ts.append_all(tokens);
1144 }
1145}
1146
1147impl<'a, A> TryFrom<Pair<'a, Rule>> for EdgeRHS<A>
1148where
1149 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
1150{
1151 type Error = ParseError<'a>;
1152 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1153 let mut inners = p.clone().into_inner();
1154 let to_pair = inners.next().ok_or(ParseError::missing_pair(
1155 p,
1156 vec![Rule::node_id, Rule::subgraph],
1157 ))?;
1158 let to = match to_pair.as_rule() {
1159 Rule::node_id => Either::Left(NodeID::try_from(to_pair)?),
1160 Rule::subgraph => {
1161 Either::Right(Subgraph::try_from(to_pair)?)
1163 }
1164 r => {
1165 return Err(ParseError::expect_rule(
1166 vec![Rule::node_id, Rule::subgraph],
1167 r,
1168 ));
1169 }
1170 };
1171 let next = inners.next().map(EdgeRHS::try_from).transpose()?.map(Box::new);
1172 Ok(EdgeRHS { to, next })
1173 }
1174}
1175
1176impl<'a, A> EdgeRHS<A> {
1177 fn filter_map_attr<B>(self, f: &'a dyn Fn(A) -> Option<B>) -> EdgeRHS<B> {
1178 let to = match self.to {
1179 Either::Left(node_id) => Either::Left(node_id),
1180 Either::Right(subgraph) => Either::Right(subgraph.filter_map_attr(f)),
1181 };
1182
1183 let next = self.next.map(|e| Box::new(e.filter_map_attr(f)));
1184
1185 EdgeRHS { to, next }
1186 }
1187
1188 fn get_node_ids(&self) -> HashSet<NodeID> {
1189 let mut nexts: HashSet<NodeID> = self
1190 .next
1191 .as_ref()
1192 .map(|n| n.get_node_ids())
1193 .unwrap_or_default();
1194 match &self.to {
1195 Either::Left(node_id) => {
1196 nexts.insert(node_id.clone());
1197 }
1198 Either::Right(subgraph) => {
1199 return nexts.union(&subgraph.get_node_ids()).cloned().collect();
1200 }
1201 };
1202 nexts
1203 }
1204}
1205
1206#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1209pub struct NodeStmt<A> {
1210 pub node: NodeID,
1212 pub attr: Option<AttrList<A>>,
1214}
1215
1216#[cfg(feature = "to_tokens")]
1217impl ToTokens for NodeStmt<(String, String)> {
1218 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1219 let node = &self.node;
1220 let attrs = match &self.attr {
1221 Some(a) => quote! { std::option::Option::Some(#a) },
1222 None => quote! { std::option::Option::None }
1223 };
1224 let tokens = quote! {
1225 dot_parser::ast::NodeStmt {
1226 node: #node,
1227 attr: #attrs
1228 }
1229 };
1230 ts.append_all(tokens);
1231 }
1232}
1233
1234impl<'a, A> TryFrom<Pair<'a, Rule>> for NodeStmt<A>
1235where
1236 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
1237{
1238 type Error = ParseError<'a>;
1239 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1240 let mut inners = p.clone().into_inner();
1241 let node = inners
1242 .next()
1243 .map(NodeID::try_from)
1244 .transpose()?
1245 .ok_or(ParseError::missing_pair(p, vec![Rule::node_id]))?;
1246 let attr = inners.next().map(AttrList::try_from).transpose()?;
1247 Ok(NodeStmt { node, attr })
1248 }
1249}
1250
1251impl<A> NodeStmt<A> {
1252 pub (in crate) fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> NodeStmt<B> {
1253 NodeStmt {
1254 node: self.node,
1255 attr: self.attr.map(|a| a.filter_map_attr(f)),
1256 }
1257 }
1258
1259 pub fn name(&self) -> &str {
1262 &self.node.id
1263 }
1264
1265 pub (in crate) fn get_node_id(&self) -> &NodeID {
1266 &self.node
1267 }
1268}
1269
1270#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1273pub struct NodeID {
1274 pub id: String,
1276 pub port: Option<Port>,
1278}
1279
1280#[cfg(feature = "to_tokens")]
1281impl ToTokens for NodeID {
1282 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1283 let id = &self.id;
1284 let port = match &self.port {
1285 Some(port) => quote!{ std::option::Option::Some(#port) },
1286 None => quote! { std::option::Option::None },
1287 };
1288 let tokens = quote!{
1289 dot_parser::ast::NodeID {
1290 id: std::string::ToString::to_string(#id),
1291 port: #port,
1292 }
1293 };
1294 ts.append_all(tokens);
1295 }
1296}
1297
1298impl<'a> TryFrom<Pair<'a, Rule>> for NodeID
1299{
1300 type Error = ParseError<'a>;
1301 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1302 let mut inners = p.clone().into_inner();
1303 let id = inners
1304 .next()
1305 .ok_or(ParseError::missing_pair(p, vec![Rule::node_id]))?
1306 .as_str()
1307 .to_string();
1308 let port = inners.next().map(Port::try_from).transpose()?;
1309 Ok(NodeID { id, port })
1310 }
1311}
1312
1313#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
1315pub enum Port {
1316 ID(String, Option<CompassPt>),
1318 Compass(CompassPt),
1320}
1321
1322#[cfg(feature = "to_tokens")]
1323impl ToTokens for Port {
1324 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1325 let tokens = match self {
1326 Port::ID(s, cpss) => {
1327 match cpss {
1328 Some(cpss) => {
1329 quote!{ dot_parser::ast::Port::ID(std::string::ToString::to_string(#s), std::option::Option::Some(#cpss)) }
1330 },
1331 None => {
1332 quote!{ dot_parser::ast::Port::ID(std::string::ToString::to_string(#s), std::option::Option::None) }
1333 }
1334 }
1335 },
1336 Port::Compass(cpss) => {
1337 quote!{ dot_parser::ast::Port::Compass(#cpss) }
1338 }
1339 };
1340 ts.append_all(tokens);
1341 }
1342}
1343
1344impl<'a> TryFrom<Pair<'a, Rule>> for Port
1345{
1346 type Error = ParseError<'a>;
1347 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1348 let mut inners = p.clone().into_inner();
1349 let inner = inners.next().ok_or(ParseError::missing_pair(
1350 p,
1351 vec![Rule::compass_pt, Rule::ident],
1352 ))?;
1353 match inner.as_rule() {
1354 Rule::compass_pt => Ok(Port::Compass(CompassPt::try_from(inner)?)),
1355 Rule::ident => {
1356 let opt_comp = inners.next().map(CompassPt::try_from).transpose()?;
1357 Ok(Port::ID(inner.as_str().to_string(), opt_comp))
1358 }
1359 r => Err(ParseError::expect_rule(
1360 vec![Rule::compass_pt, Rule::ident],
1361 r,
1362 )),
1363 }
1364 }
1365}
1366
1367#[cfg(feature = "display")]
1368impl Display for Port {
1369 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
1370 match self {
1371 Port::ID(name, Some(cpss)) => {
1372 write!(f, ": {name} : {cpss}")
1373 }
1374 Port::ID(name, None) => {
1375 write!(f, ": {name}")
1376 }
1377 Port::Compass(cpss) => {
1378 write!(f, ": {}", cpss)
1379 }
1380 }
1381 }
1382}
1383
1384#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
1386pub struct Subgraph<A> {
1387 pub id: Option<String>,
1389 pub stmts: StmtList<A>,
1391}
1392
1393#[cfg(feature = "to_tokens")]
1394impl ToTokens for Subgraph<(String, String)> {
1395 fn to_tokens(&self, ts: &mut proc_macro2::TokenStream) {
1396 let id = match &self.id {
1397 Some(s) => quote!{ std::option::Some(#s) },
1398 None => quote! { std::option::None },
1399 };
1400 let stmts = &self.stmts;
1401 let tokens = quote! {
1402 dot_parser::ast::Subgraph {
1403 id: #id,
1404 stmts: #stmts,
1405 }
1406 };
1407 ts.append_all(tokens);
1408 }
1409}
1410
1411impl<'a, A> TryFrom<Pair<'a, Rule>> for Subgraph<A>
1412where
1413 AList<A>: TryFrom<Pair<'a, Rule>, Error = ParseError<'a>>
1414{
1415 type Error = ParseError<'a>;
1416 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1417 let mut inners = p.clone().into_inner();
1418 let mut inner = inners.next().ok_or(ParseError::missing_pair(
1419 p.clone(),
1420 vec![Rule::ident, Rule::stmt_list],
1421 ))?;
1422 let id = if let Rule::ident = inner.as_rule() {
1423 let id_str = inner.as_str().to_string();
1424 inner = inners
1425 .next()
1426 .ok_or(ParseError::missing_pair(p.clone(), vec![Rule::stmt_list]))?;
1427 Some(id_str)
1428 } else {
1429 None
1430 };
1431 let stmts = StmtList::try_from(inner)?;
1432 Ok(Subgraph { id, stmts })
1433 }
1434}
1435
1436impl<A> Subgraph<A> {
1437 fn filter_map_attr<B>(self, f: &dyn Fn(A) -> Option<B>) -> Subgraph<B> {
1438 Subgraph {
1439 id: self.id,
1440 stmts: self
1441 .stmts
1442 .into_iter()
1443 .map(|stmt| stmt.filter_map_attr(f))
1444 .collect(),
1445 }
1446 }
1447
1448 pub (in crate) fn into_graph(self, strict: bool, is_digraph: bool) -> Graph<A> {
1450 Graph {
1451 strict,
1452 is_digraph,
1453 name: self.id.map(String::from),
1454 stmts: self.stmts,
1455 }
1456 }
1457
1458 fn get_node_ids(&self) -> HashSet<NodeID> {
1459 self.stmts.get_node_ids()
1460 }
1461}
1462
1463#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
1465pub enum CompassPt {
1466 N,
1468 NE,
1470 E,
1472 SE,
1474 S,
1476 SW,
1478 W,
1480 NW,
1482 C,
1484 Underscore,
1486}
1487
1488#[cfg(feature = "display")]
1489impl Display for CompassPt {
1490 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
1491 match self {
1492 CompassPt::N => write!(f, "n"),
1493 CompassPt::NE => write!(f, "ne"),
1494 CompassPt::E => write!(f, "e"),
1495 CompassPt::SE => write!(f, "se"),
1496 CompassPt::S => write!(f, "s"),
1497 CompassPt::SW => write!(f, "sw"),
1498 CompassPt::W => write!(f, "w"),
1499 CompassPt::NW => write!(f, "nw"),
1500 CompassPt::C => write!(f, "c"),
1501 CompassPt::Underscore => write!(f, "_"),
1502 }
1503 }
1504}
1505
1506impl<'a> TryFrom<Pair<'a, Rule>> for CompassPt {
1507 type Error = ParseError<'a>;
1508 fn try_from(p: Pair<'a, Rule>) -> Result<Self, ParseError<'a>> {
1509 match p
1510 .clone()
1511 .into_inner()
1512 .next()
1513 .ok_or(ParseError::missing_pair(
1514 p,
1515 vec![
1516 Rule::n,
1517 Rule::ne,
1518 Rule::e,
1519 Rule::se,
1520 Rule::s,
1521 Rule::sw,
1522 Rule::w,
1523 Rule::nw,
1524 Rule::c,
1525 Rule::underscore,
1526 ],
1527 ))?
1528 .as_rule()
1529 {
1530 Rule::n => Ok(CompassPt::N),
1531 Rule::ne => Ok(CompassPt::NE),
1532 Rule::e => Ok(CompassPt::E),
1533 Rule::se => Ok(CompassPt::SE),
1534 Rule::s => Ok(CompassPt::S),
1535 Rule::sw => Ok(CompassPt::SW),
1536 Rule::w => Ok(CompassPt::W),
1537 Rule::nw => Ok(CompassPt::NW),
1538 Rule::c => Ok(CompassPt::C),
1539 Rule::underscore => Ok(CompassPt::Underscore),
1540 r => Err(ParseError::expect_rule(
1541 vec![
1542 Rule::n,
1543 Rule::ne,
1544 Rule::e,
1545 Rule::se,
1546 Rule::s,
1547 Rule::sw,
1548 Rule::w,
1549 Rule::nw,
1550 Rule::c,
1551 Rule::underscore,
1552 ],
1553 r,
1554 )),
1555 }
1556 }
1557}
1558
1559#[cfg(feature = "to_tokens")]
1560impl ToTokens for CompassPt {
1561 fn to_tokens(&self, tokens: &mut TokenStream) {
1562 let new_tokens = match self {
1563 CompassPt::N => quote!{ dot_parser::ast::CompassPt::N},
1564 CompassPt::NE => quote!{ dot_parser::ast::CompassPt::NE},
1565 CompassPt::E => quote!{ dot_parser::ast::CompassPt::E},
1566 CompassPt::SE => quote!{ dot_parser::ast::CompassPt::SE},
1567 CompassPt::S => quote!{ dot_parser::ast::CompassPt::S},
1568 CompassPt::SW => quote!{ dot_parser::ast::CompassPt::SW},
1569 CompassPt::W => quote!{ dot_parser::ast::CompassPt::W},
1570 CompassPt::NW => quote!{ dot_parser::ast::CompassPt::NW},
1571 CompassPt::C => quote!{ dot_parser::ast::CompassPt::C},
1572 CompassPt::Underscore => quote!{ dot_parser::ast::CompassPt::Underscore},
1573 };
1574 tokens.append_all(new_tokens);
1575 }
1576}