1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use super::*;
pub trait ToDot {
fn dot(&self) -> String;
}
impl ToDot for Automaton {
fn dot(&self) -> String {
let states = self.states
.iter()
.enumerate()
.map(|(id,s)|
format!["s{} {};", id, attrs(&vec![
("label", s.label(id, &self.variables)),
("shape", (if s.accepting { "doublecircle" } else { "circle" }).to_string()),
])
])
.collect::<Vec<String>>()
.join("\n")
;
let transitions = self.transitions
.iter_all()
.map(|(ref source, ref transitions)| {
transitions.iter()
.map(|&(ref t, ref dest)| {
format!["s{} -> s{} [ label = \"{}\" ];", source, dest, t.dot()]
})
.collect::<Vec<String>>()
.join("\n")
})
.collect::<Vec<String>>()
.join("\n")
;
format!["digraph {{\nrankdir=LR;\n{}\n\n{}\n}}", states, transitions]
}
}
impl ToDot for Transition {
fn dot(&self) -> String {
let cause = self.cause.name();
let result = self.result.short_name();
if result.len() == 0 {
cause
} else {
format!["{} «{}»", cause, result]
}
}
}
fn attrs(attrs: &[(&str,String)]) -> String {
format!["[ {} ]",
attrs.iter()
.map(|&(ref k, ref v)|
format!["{} = {}", k, dot_value(v)])
.collect::<Vec<String>>()
.join(", ")
]
}
fn dot_value<T>(value: &T) -> String
where T : Clone + Into<String>
{
let s = value.clone().into();
if s.len() > 2 && s.starts_with('<') && s.ends_with('>') {
s
} else {
format!["\"{}\"", s]
}
}