1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use rustc::mir::repr::*;
13 use std::borrow::IntoCow;
15 #[derive(Copy, Clone, PartialEq, Eq)]
16 pub struct EdgeIndex {
22 impl<'a,'tcx> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
23 fn graph_id(&'a self) -> dot::Id<'a> {
24 dot::Id::new("Mir").unwrap()
27 fn node_id(&'a self, n: &BasicBlock) -> dot::Id<'a> {
28 dot::Id::new(format!("BB{}", n.index())).unwrap()
31 fn node_shape(&'a self, _: &BasicBlock) -> Option<dot::LabelText<'a>> {
32 Some(dot::LabelText::label("none"))
35 fn node_label(&'a self, &n: &BasicBlock) -> dot::LabelText<'a> {
36 let mut buffer = String::new();
37 buffer.push_str("<TABLE ALIGN=\"LEFT\">");
39 buffer.push_str("<TR><TD>");
40 buffer.push_str(&format!("{:?}", n));
41 buffer.push_str("</TD></TR>");
43 let data = self.basic_block_data(n);
44 for statement in &data.statements {
45 buffer.push_str("<TR><TD>");
46 buffer.push_str(&escape(format!("{:?}", statement)));
47 buffer.push_str("</TD></TR>");
50 buffer.push_str("<TR><TD>");
51 buffer.push_str(&escape(format!("{:?}", &data.terminator)));
52 buffer.push_str("</TD></TR>");
54 buffer.push_str("</TABLE>");
56 dot::LabelText::html(buffer)
59 fn edge_label(&'a self, edge: &EdgeIndex) -> dot::LabelText<'a> {
60 dot::LabelText::label(format!("{}", edge.index))
64 impl<'a,'tcx> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
65 fn nodes(&'a self) -> dot::Nodes<'a, BasicBlock> {
66 self.all_basic_blocks().into_cow()
69 fn edges(&'a self) -> dot::Edges<'a, EdgeIndex> {
70 self.all_basic_blocks()
73 self.basic_block_data(source)
78 .map(move |(index, &target)| {
90 fn source(&'a self, edge: &EdgeIndex) -> BasicBlock {
94 fn target(&'a self, edge: &EdgeIndex) -> BasicBlock {
99 fn escape(text: String) -> String {
100 let text = dot::escape_html(&text);
101 let text = all_to_subscript("Temp", text);
102 let text = all_to_subscript("Var", text);
103 let text = all_to_subscript("Arg", text);
104 let text = all_to_subscript("BB", text);
108 /// A call like `all_to_subscript("Temp", "Temp(123)")` will convert
110 fn all_to_subscript(header: &str, mut text: String) -> String {
112 while offset < text.len() {
113 if let Some(text1) = to_subscript1(header, &text, &mut offset) {
119 /// Looks for `Foo(\d*)` where `header=="Foo"` and replaces the `\d` with subscripts.
120 /// Updates `offset` to point to the next location where we might want to search.
121 /// Returns an updated string if changes were made, else None.
122 fn to_subscript1(header: &str, text: &str, offset: &mut usize) -> Option<String> {
123 let a = match text[*offset..].find(header) {
125 *offset = text.len();
128 Some(a) => a + *offset,
134 // text: ....Foo(123)...
138 let b = a + header.len();
141 let mut chars = text[b..].chars();
142 if Some('(') != chars.next() {
146 let mut result = String::new();
147 result.push_str(&text[..b]);
149 while let Some(c) = chars.next() {
157 // 0x208 is _0 in unicode, 0x209 is _1, etc
158 const SUBSCRIPTS: &'static str = "₀₁₂₃₄₅₆₇₈₉";
159 let n = (c as usize) - ('0' as usize);
160 result.extend(SUBSCRIPTS.chars().skip(n).take(1));
163 result.extend(chars);