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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
use crate::util::escape_html;
use std::io::{self, Write};
use serde::{Deserialize, Serialize};
/// NodeStyle defines some style of [Node](struct.Node.html)
#[derive(Clone, Serialize, Deserialize)]
pub struct NodeStyle {
/// Override the title color of the title
/// To color the title of the node differently in graphviz
pub title_bg: Option<String>,
/// Print a seperator b/w the rest of the statements and the last one
pub last_stmt_sep: bool,
}
impl Default for NodeStyle {
fn default() -> NodeStyle {
NodeStyle {
title_bg: None,
last_stmt_sep: false,
}
}
}
/// A graph node
#[derive(Clone, Serialize, Deserialize)]
pub struct Node {
/// A list of statements.
pub stmts: Vec<String>,
/// A unique identifier for the given node.
pub label: String,
/// The title is printed on the top of BB, the index of the basic block
pub(crate) title: String,
/// Can be used to override the default styles
pub(crate) style: NodeStyle,
}
impl Node {
pub fn new(stmts: Vec<String>, label: String, title: String, style: NodeStyle) -> Node {
Node {
stmts,
label,
title,
style,
}
}
pub fn to_dot<W: Write>(&self, w: &mut W) -> io::Result<()> {
write!(w, r#"<table border="0" cellborder="1" cellspacing="0">"#)?;
let bg_attr = match &self.style.title_bg {
Some(color) => format!(r#"bgcolor="{}""#, color),
None => "".into(),
};
write!(
w,
r#"<tr><td {bg_attr} {attrs} colspan="{colspan}">{blk}</td></tr>"#,
attrs = r#"align="center""#,
// TODO: Not sure what this is for
colspan = 1,
blk = self.title,
bg_attr = bg_attr
)?;
let stmts_len = self.stmts.len();
if !self.stmts.is_empty() {
if self.stmts.len() > 1 {
write!(w, r#"<tr><td align="left" balign="left">"#)?;
for statement in &self.stmts[..stmts_len - 1] {
write!(w, "{}<br/>", escape_html(statement))?;
}
write!(w, "</td></tr>")?;
}
if !self.style.last_stmt_sep {
write!(w, r#"<tr><td align="left">"#)?;
write!(w, "{}", escape_html(&self.stmts[stmts_len - 1]))?;
} else {
write!(w, r#"<tr><td align="left" balign="left">"#)?;
write!(w, "{}", escape_html(&self.stmts[stmts_len - 1]))?;
}
write!(w, "</td></tr>")?;
}
write!(w, "</table>")
}
}
/// A directed graph edge
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Edge {
/// The label of the source node of the edge.
pub from: String,
/// The label of the target node of the edge.
pub to: String,
/// The label (title) of the edge. This doesn't have to unique.
// TODO: Rename this to title?
pub label: String,
}
impl Edge {
pub fn new(from: String, to: String, label: String) -> Edge {
Edge { from, to, label }
}
pub fn to_dot<W: Write>(&self, w: &mut W) -> io::Result<()> {
writeln!(
w,
r#" {} -> {} [label="{}"];"#,
self.from, self.to, self.label
)
}
}
|