smt_str/automata/
dot.rs

1//! Facilities to generate a DOT representation of an NFA.
2
3use super::{StateId, Transition, TransitionType, NFA};
4
5impl<'a> dot::Labeller<'a, StateId, (StateId, Transition, StateId)> for NFA {
6    fn graph_id(&'a self) -> dot::Id<'a> {
7        dot::Id::new("automaton").unwrap()
8    }
9
10    fn node_id(&'a self, n: &StateId) -> dot::Id<'a> {
11        dot::Id::new(format!("q{}", n)).unwrap()
12    }
13
14    fn node_shape(&'a self, node: &StateId) -> Option<dot::LabelText<'a>> {
15        if self.finals.contains(node) {
16            return Some(dot::LabelText::LabelStr("doublecircle".into()));
17        }
18
19        None
20    }
21
22    fn node_label(&'a self, n: &StateId) -> dot::LabelText<'a> {
23        if let Some(q0) = self.initial {
24            if q0 == *n {
25                return dot::LabelText::LabelStr(
26                    format!("{} (Init)", self.node_id(n).name()).into(),
27                );
28            }
29        }
30        dot::LabelText::LabelStr(self.node_id(n).name())
31    }
32
33    fn edge_label(&'a self, e: &(StateId, Transition, StateId)) -> dot::LabelText<'a> {
34        match e.1.get_type() {
35            TransitionType::Range(r) => dot::LabelText::LabelStr(format!("{}", r).into()),
36            TransitionType::NotRange(r) => dot::LabelText::LabelStr(format!("not({})", r).into()),
37            TransitionType::Epsilon => dot::LabelText::LabelStr("".into()),
38        }
39    }
40
41    fn node_style(&'a self, _n: &StateId) -> dot::Style {
42        dot::Style::None
43    }
44
45    fn node_color(&'a self, _node: &StateId) -> Option<dot::LabelText<'a>> {
46        None
47    }
48
49    fn kind(&self) -> dot::Kind {
50        dot::Kind::Digraph
51    }
52}
53
54impl<'a> dot::GraphWalk<'a, StateId, (StateId, Transition, StateId)> for NFA {
55    fn nodes(&'a self) -> dot::Nodes<'a, StateId> {
56        self.states
57            .iter()
58            .enumerate()
59            .map(|(i, _)| i)
60            .collect::<Vec<_>>()
61            .into()
62    }
63
64    fn edges(&'a self) -> dot::Edges<'a, (StateId, Transition, StateId)> {
65        let mut edges: Vec<(StateId, Transition, StateId)> = vec![];
66        for (i, state) in self.states.iter().enumerate() {
67            for transition in state.transitions() {
68                edges.push((i, transition.clone(), transition.get_dest()));
69            }
70        }
71        edges.into()
72    }
73
74    fn source(&'a self, edge: &(StateId, Transition, StateId)) -> StateId {
75        edge.0
76    }
77
78    fn target(&'a self, edge: &(StateId, Transition, StateId)) -> StateId {
79        edge.2
80    }
81}