polka 0.1.2

A dot language parser for Rust; based on Parser Expression Grammar (PEG) using the excellent pest crate as the underpinning.
Documentation
use crate::dot::{Graph, SubGraph};
use crate::parser::ident::ident;
use crate::parser::statement::statements;
use crate::parser::symbols::{graph_type, id, space, strict_symbol, subgraph_symbol};
use pom::parser::{call, Parser};
use std::char;

pub fn graph<'a>() -> Parser<'a, char, Graph> {
  let pattern = strict_symbol().opt() - space() + graph_type().opt() - space() + id().opt()
    - space()
    + call(statements);

  pattern.map(|(((strict, graph_type), id), statements)| Graph {
    strict: strict.is_some(),
    graph_type,
    id,
    statements,
  })
}

pub fn sub_graph<'a>() -> Parser<'a, char, SubGraph> {
  ((subgraph_symbol() * space() * ident().opt()).opt() - space() + call(statements)).map(
    |(id, statements)| SubGraph {
      id: id.unwrap_or_else(|| None),
      statements,
    },
  )
}

#[cfg(test)]
mod test {

  #[cfg(test)]
  mod graph {
    use super::super::*;
    use crate::dot::{Attribute, Graph, GraphType, Statement};
    use pretty_assertions::assert_eq;

    #[test]
    fn test() {
      let input1: Vec<char> = "strict digraph cool_graph { a=b; \"b\"=\"c\"; c=d }"
        .chars()
        .collect();
      let res1 = Graph {
        strict: true,
        graph_type: Some(GraphType::Digraph),
        id: Some("cool_graph".to_string()),
        statements: vec![
          Statement::IdPair(Attribute {
            key: "a".to_string(),
            value: "b".to_string(),
          }),
          Statement::IdPair(Attribute {
            key: "b".to_string(),
            value: "c".to_string(),
          }),
          Statement::IdPair(Attribute {
            key: "c".to_string(),
            value: "d".to_string(),
          }),
        ],
      };

      match graph().parse(&input1) {
        Ok(r) => assert_eq!(r, res1),
        Err(e) => panic!(format!(
          "failed with input: {:?} and error: {:?}",
          input1, e
        )),
      };
    }
  }

  #[cfg(test)]
  mod sub_graph {
    use super::super::*;

    use crate::dot::{Attribute, Statement};
    use pretty_assertions::assert_eq;
    #[test]
    fn mixed_tokens() {
      let input1: Vec<char> = "subgraph awesome_subgraph_id { a=b; c=d }"
        .chars()
        .collect();
      let res1 = SubGraph {
        id: Some("awesome_subgraph_id".to_string()),
        statements: vec![
          Statement::IdPair(Attribute {
            key: "a".to_string(),
            value: "b".to_string(),
          }),
          Statement::IdPair(Attribute {
            key: "c".to_string(),
            value: "d".to_string(),
          }),
        ],
      };

      match sub_graph().parse(&input1) {
        Ok(r) => assert_eq!(r, res1),
        Err(e) => panic!(format!(
          "failed with input: {:?} and error: {:?}",
          input1, e
        )),
      };

      let input2: Vec<char> = "subgraph { a=b; c=d }".chars().collect();
      let res2 = SubGraph {
        id: None,
        statements: vec![
          Statement::IdPair(Attribute {
            key: "a".to_string(),
            value: "b".to_string(),
          }),
          Statement::IdPair(Attribute {
            key: "c".to_string(),
            value: "d".to_string(),
          }),
        ],
      };

      match sub_graph().parse(&input2) {
        Ok(r) => assert_eq!(r, res2),
        Err(e) => panic!(format!(
          "failed with input: {:?} and error: {:?}",
          input2, e
        )),
      };

      let input3: Vec<char> = "{ a=b; c=d }".chars().collect();
      let res3 = SubGraph {
        id: None,
        statements: vec![
          Statement::IdPair(Attribute {
            key: "a".to_string(),
            value: "b".to_string(),
          }),
          Statement::IdPair(Attribute {
            key: "c".to_string(),
            value: "d".to_string(),
          }),
        ],
      };

      match sub_graph().parse(&input3) {
        Ok(r) => assert_eq!(r, res3),
        Err(e) => panic!(format!(
          "failed with input: {:?} and error: {:?}",
          input2, e
        )),
      };

      let i = "subraph awesome_subgraph_id [a=b]";
      let input4: Vec<char> = i.chars().collect();
      if sub_graph().parse(&input4).is_ok() {
        panic!("Should have failed with input {:?}, passed instead.", i)
      }
    }
  }
}