graphviz_parser 0.1.0

An AST definition and parser for graphviz files
Documentation
use super::lex::PeekableLexer;
use anyhow::Result;


pub(crate) trait Constructable: Sized {
    type Output;
    fn from_lexer(
        token_stream: PeekableLexer,
    ) -> Result<(Self::Output, PeekableLexer), anyhow::Error>;
}

pub(crate) struct ParseOR<T: Constructable, V: Constructable> {
    pub t_val: Option<T::Output>,
    pub v_val: Option<V::Output>,
}

impl<T, V> Constructable for ParseOR<T, V>
where
    T: Constructable,
    V: Constructable,
{
    type Output = ParseOR<T, V>;

    fn from_lexer(token_stream: PeekableLexer) -> Result<(Self, PeekableLexer), anyhow::Error> {
        if let Ok((val, tok_s)) = T::from_lexer(token_stream.clone()) {
            Ok((
                Self {
                    t_val: Some(val),
                    v_val: None,
                },
                tok_s,
            ))
        } else if let Ok((val, tok_s)) = V::from_lexer(token_stream.clone()) {
            Ok((
                Self {
                    t_val: None,
                    v_val: Some(val),
                },
                tok_s,
            ))
        } else {
            Err(anyhow::anyhow!(
                "Invalid or expression; neither arm parsed successfully"
            ))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Constructable;
    use super::ParseOR;
    use crate::ast_nodes::{Assignment, Node};
    use crate::ast_nodes::{Directed, Graph};
    use crate::lex::PeekableLexer;

    fn test_for_file(file_path: &str) -> Graph<Directed> {
        let test_str = ::std::fs::read_to_string(file_path).unwrap();
        let pb = PeekableLexer::from(&test_str);
        Graph::<Directed>::from_lexer(pb).unwrap().0
    }

    #[test]
    fn or_op_sanity_test1() {
        let test_str = "color = green";
        let pb = PeekableLexer::from(test_str);
        let result: ParseOR<Assignment, Node> = ParseOR::from_lexer(pb).unwrap().0;
        assert!(result.t_val.is_some());
        assert_eq!(result.t_val.unwrap(), Assignment::new("color", "green"));
    }

    #[test]
    fn test_ast_build_sanity1() {
        let test_str = "digraph G { subgraph t1 { A [color = green] } }";
        let pb = PeekableLexer::from(test_str);
        let g = Graph::<Directed>::from_lexer(pb).unwrap().0;
        assert_eq!(g.id, String::from("G"));
        assert_eq!(g.statements.len(), 1);
    }

    #[test]
    fn test_ast_build_basic1_test() {
        let g = test_for_file("samples/basic1.dot");
        let reference = std::fs::read_to_string("samples/reference/basic1.ref").unwrap();
        assert_eq!(reference, format!("{:?}\n", g));
    }

    #[test]
    fn test_ast_build_basic2_test() {
        let g = test_for_file("samples/basic2.dot");
        let reference = std::fs::read_to_string("samples/reference/basic2.ref").unwrap();
        assert_eq!(reference, format!("{:#?}\n", g));
    }

    #[test]
    fn test_ast_build_basic3_test() {
        let g = test_for_file("samples/basic3.dot");
        println!("{:#?}", g);
        let reference = std::fs::read_to_string("samples/reference/basic3.ref").unwrap();
        assert_eq!(reference, format!("{:#?}\n", g));
    }

    #[test]
    fn test_ast_build_basic4_test() {
        let g = test_for_file("samples/basic4.dot");
        // let reference = std::fs::read_to_string("samples/reference/basic4.ref").unwrap();
        println!("{:#?}", g);
        // assert_eq!(reference, format!("{:#?}\n", g));
    }

}