use crate::dot::{Edge, EdgeOp, EdgeRhs, EdgeStatement};
use crate::parser::graph::sub_graph;
use crate::parser::node::node_id;
use pom::parser::{tag, Parser};
use crate::parser::statement::attribute_list;
use crate::parser::symbols::space;
use std::char;
pub fn edge_op<'a>() -> Parser<'a, char, EdgeOp> {
let arrow = tag("->").map(|_| EdgeOp::Arrow);
let line = tag("--").map(|_| EdgeOp::Line);
arrow | line
}
fn edge_node_or_subgraph<'a>() -> Parser<'a, char, Edge> {
(sub_graph().map(Edge::Subgraph)) | node_id().map(Edge::NodeId)
}
pub fn edge_rhs_list<'a>() -> Parser<'a, char, Vec<EdgeRhs>> {
let pattern = edge_op() - space() + edge_node_or_subgraph() - space();
let edge_rhs = pattern.map(|(edge_op, edge)| EdgeRhs { edge_op, edge });
edge_rhs.repeat(1..)
}
pub fn edge_statement<'a>() -> Parser<'a, char, EdgeStatement> {
let pattern =
edge_node_or_subgraph() - space() + edge_rhs_list() - space() + attribute_list().opt();
pattern.map(|((edge, edge_rhs_list), attributes)| EdgeStatement {
edge,
edge_rhs_list,
attributes,
})
}
#[cfg(test)]
mod test {
#[cfg(test)]
mod edge_statement {
use super::super::*;
use crate::dot::{
Attribute, Compass, Edge, EdgeOp, EdgeRhs, EdgeStatement, NodeId, Port, Statement, SubGraph,
};
use pretty_assertions::assert_eq;
#[test]
fn mixed_tokens() {
let edge1 = Edge::Subgraph(SubGraph {
id: Some("test".to_string()),
statements: vec![Statement::IdPair(Attribute {
key: "a".to_string(),
value: "b".to_string(),
})],
});
let edge2 = Edge::NodeId(NodeId {
node_id: "awesome_edge".to_string(),
port: None,
});
let edge_rhs_list = vec![
EdgeRhs {
edge_op: EdgeOp::Line,
edge: Edge::NodeId(NodeId {
node_id: "awesome_id".to_string(),
port: None,
}),
},
EdgeRhs {
edge_op: EdgeOp::Arrow,
edge: Edge::NodeId(NodeId {
node_id: "cool_id".to_string(),
port: Some(Port {
port_id: Some("a34".to_string()),
compass: Some(Compass::E),
}),
}),
},
EdgeRhs {
edge_op: EdgeOp::Line,
edge: Edge::NodeId(NodeId {
node_id: "niceId".to_string(),
port: None,
}),
},
];
let attributes = None;
let res1 = EdgeStatement {
edge: edge1,
edge_rhs_list: edge_rhs_list.clone(),
attributes: attributes.clone(),
};
let res2 = EdgeStatement {
edge: edge2,
edge_rhs_list: edge_rhs_list.clone(),
attributes: attributes.clone(),
};
let input1: Vec<char> = "subgraph test {a=b} -- awesome_id -> cool_id:a34:E -- niceId"
.chars()
.collect();
match edge_statement().parse(&input1) {
Ok(r) => assert_eq!(r, res1),
Err(e) => panic!(format!(
"failed with input: {:?} and error: {:?}",
input1, e
)),
};
let input2: Vec<char> = "awesome_edge -- awesome_id -> cool_id:a34:E -- niceId"
.chars()
.collect();
match edge_statement().parse(&input2) {
Ok(r) => assert_eq!(r, res2),
Err(e) => panic!(format!(
"failed with input: {:?} and error: {:?}",
input1, e
)),
};
let input3: Vec<char> = "- > awesome - - test".chars().collect();
if edge_statement().parse(&input3).is_ok() {
panic!(
"Should have failed with input {:?}, passed instead.",
input3
)
}
}
}
#[cfg(test)]
mod edge_rhs_list {
use super::super::*;
use crate::dot::{Compass, Edge, EdgeOp, EdgeRhs, NodeId, Port};
use pretty_assertions::assert_eq;
#[test]
fn mixed_tokens() {
let input1: Vec<char> = "-- awesome_id -> cool_id:a34:E -- niceId".chars().collect();
let res1 = vec![
EdgeRhs {
edge_op: EdgeOp::Line,
edge: Edge::NodeId(NodeId {
node_id: "awesome_id".to_string(),
port: None,
}),
},
EdgeRhs {
edge_op: EdgeOp::Arrow,
edge: Edge::NodeId(NodeId {
node_id: "cool_id".to_string(),
port: Some(Port {
port_id: Some("a34".to_string()),
compass: Some(Compass::E),
}),
}),
},
EdgeRhs {
edge_op: EdgeOp::Line,
edge: Edge::NodeId(NodeId {
node_id: "niceId".to_string(),
port: None,
}),
},
];
match edge_rhs_list().parse(&input1) {
Ok(r) => assert_eq!(r, res1),
Err(e) => panic!(format!(
"failed with input: {:?} and error: {:?}",
input1, e
)),
};
let input2: Vec<char> = "- > awesome - - test".chars().collect();
if edge_rhs_list().parse(&input2).is_ok() {
panic!(
"Should have failed with input {:?}, passed instead.",
input2
)
}
}
}
#[cfg(test)]
mod edge_op {
use super::super::*;
use crate::dot::EdgeOp;
use pretty_assertions::assert_eq;
#[test]
fn mixed_tokens() {
let input1: Vec<char> = "->".chars().collect();
let res1 = EdgeOp::Arrow;
match edge_op().parse(&input1) {
Ok(r) => assert_eq!(r, res1),
Err(e) => panic!(format!(
"failed with input: {:?} and error: {:?}",
input1, e
)),
};
let input2: Vec<char> = "--".chars().collect();
let res2 = EdgeOp::Line;
match edge_op().parse(&input2) {
Ok(r) => assert_eq!(r, res2),
Err(e) => panic!(format!(
"failed with input: {:?} and error: {:?}",
input2, e
)),
};
let input3: Vec<char> = "- >".chars().collect();
if edge_op().parse(&input3).is_ok() {
panic!(
"Should have failed with input {:?}, passed instead.",
input3
)
}
}
}
}