graphviz_parser 0.1.0

An AST definition and parser for graphviz files
Documentation
use super::Statement;
use super::ID;

use crate::lex::{Peekable, Token};
use crate::parse::Constructable;

use super::edge::GraphDirection;

#[derive(Debug)]
pub struct Subgraph<T> {
    pub id: Option<ID>,
    pub statements: Vec<Statement<T>>,
}

impl<T: GraphDirection> Constructable for Subgraph<T> {
    type Output = Self;

    fn from_lexer(
        mut token_stream: crate::lex::PeekableLexer,
    ) -> anyhow::Result<(Self::Output, crate::lex::PeekableLexer), anyhow::Error> {

        token_stream.clear_filler();
        let mut id = None;
        if let Some(&Token::Subgraph) = token_stream.peek() {
            token_stream.next();
        }

        if let Some(&Token::ID) = token_stream.peek() {
            token_stream.next();
            id = Some(String::from(token_stream.slice()));
        }
        if let Some(Token::OpenParen) = token_stream.next() {
            let (statements, mut tok_stream) = Vec::<Statement<T>>::from_lexer(token_stream)?;
            tok_stream.clear_filler();
            if let Some(Token::CloseParen) = tok_stream.next() {
                Ok((Self { id, statements }, tok_stream))
            } else {
                Err(anyhow::anyhow!("Invalid closing paren for subgraph"))
            }
        } else {
            Err(anyhow::anyhow!("Invalid construction of subgraph"))
        }
    }
}

#[cfg(test)]
mod tests {

    use super::super::edge::Directed;
    use super::Subgraph;
    use crate::lex::PeekableLexer;
    use crate::parse::Constructable;

    #[test]
    fn test_subgraph_sanity1_test() {
        let test_str = "test1 { A, B }";
        let pb = PeekableLexer::from(test_str);
        let subgraph = Subgraph::<Directed>::from_lexer(pb).unwrap().0;

        assert!(subgraph.id == Some(String::from("test1")));
        assert_eq!(subgraph.statements.len(), 2);
    }

    #[test]
    fn test_subgraph_sanity2_test() {
        let test_str = "{ A, B }";
        let pb = PeekableLexer::from(test_str);
        let subgraph = Subgraph::<Directed>::from_lexer(pb).unwrap().0;

        assert!(subgraph.id.is_none());
        assert_eq!(subgraph.statements.len(), 2);
    }

    #[test]
    fn test_subgraph_sanity3_test() {
        let test_str = "subgraph g { A, B }";

        let pb = PeekableLexer::from(test_str);
        let subgraph = Subgraph::<Directed>::from_lexer(pb).unwrap().0;

        assert_eq!(subgraph.id, Some(String::from("g")));
        assert_eq!(subgraph.statements.len(), 2);
    }

    #[test]
    fn test_subgraph_sample3_subset_test() {
        let test_str = "subgraph cluster_R {
            nd_3_l -> nd_3 -> nd_3_r [color=grey, arrowhead=none]
        }";
        let pb = PeekableLexer::from(test_str);
        let subgraph = Subgraph::<Directed>::from_lexer(pb).unwrap().0;
        assert_eq!(subgraph.id, Some(String::from("cluster_R")));
        assert_eq!(subgraph.statements.len(), 1);
    }

    #[test]
    fn test_subgraph_sample3_commaless_test() {
        let test_str = "subgraph cluster_R {
            nd_3_l -> nd_3 -> nd_3_r [color=grey arrowhead=none]
        }";
        let pb = PeekableLexer::from(test_str);
        let subgraph = Subgraph::<Directed>::from_lexer(pb).unwrap().0;
        assert_eq!(subgraph.id, Some(String::from("cluster_R")));
        assert_eq!(subgraph.statements.len(), 1);
    }

    #[test]
    fn test_subgraph_anonymous_undelimited_statement_test() {
        let test_str = "{rank=same nd_3_l nd_3 nd_3_r}";
        let pb = PeekableLexer::from(test_str);
        let subgraph = Subgraph::<Directed>::from_lexer(pb).unwrap().0;
        assert_eq!(subgraph.id, None);
        assert_eq!(subgraph.statements.len(), 4);
    }

    #[test]
    fn test_subgraph_statement_sanity4_test() {
        let test_str = "subgraph cluster_c2 {
                            label = \"Child two\";
                            te;
                        }";
        let pb = PeekableLexer::from(test_str);
        let subgraph = Subgraph::<Directed>::from_lexer(pb).unwrap().0;
        assert_eq!(subgraph.id, Some(String::from("cluster_c2")));
        assert_eq!(subgraph.statements.len(), 2);
        println!("{:#?}", subgraph);
    }
}