1use std::borrow;
6use std::fmt;
7
8use dot;
9use specs;
10
11use ir;
12use ir::component::element;
13use ir::component::layout;
14use ir::component::symbol;
15use ir::component::ty;
16
17pub struct Graph<'a> {
19 entities: specs::Entities<'a>,
20 elements: specs::ReadStorage<'a, element::Element>,
21 layouts: specs::ReadStorage<'a, layout::Layout>,
22 symbols: specs::ReadStorage<'a, symbol::Symbol>,
23 types: specs::ReadStorage<'a, ty::Type>,
24}
25
26#[derive(Clone, Copy, Debug)]
28pub struct Node(specs::Entity);
29
30#[derive(Clone, Copy, Debug)]
32pub struct Edge<'a> {
33 source: Node,
34 target: Node,
35 label: Label<'a>,
36}
37
38#[derive(Clone, Copy, Debug)]
39enum Label<'a> {
40 RecordField(&'a str),
41 TupleField(usize),
42 VariableInitializer,
43 SelectField(&'a str),
44 AppliedFunction,
45 AppliedParameter(usize),
46 ParameterSignature,
47 ClosureCaptureDefinition(&'a str),
48 ClosureCaptureUsage(usize),
49 ClosureParameter(usize),
50 ClosureStatement(usize),
51 ClosureSignature,
52 ClosureResult,
53 ModuleDefinition(&'a str),
54 UnOperand,
55 BiLhs,
56 BiRhs,
57}
58
59struct PrettyTy<T>(T);
60
61impl<'a> Graph<'a> {
62 pub(crate) fn new(ir: &'a ir::Ir) -> Graph<'a> {
64 let world = &ir.world;
65 let entities = world.entities();
66 let elements = world.read_storage();
67 let layouts = world.read_storage();
68 let symbols = world.read_storage();
69 let types = world.read_storage();
70
71 Graph {
72 entities,
73 elements,
74 layouts,
75 symbols,
76 types,
77 }
78 }
79}
80
81impl<'a> dot::GraphWalk<'a, Node, Edge<'a>> for Graph<'a> {
82 fn nodes(&'a self) -> borrow::Cow<'a, [Node]> {
83 use specs::Join;
84
85 borrow::Cow::Owned(
86 self.entities
87 .join()
88 .filter(|e| self.elements.contains(*e))
89 .map(Node)
90 .collect::<Vec<_>>(),
91 )
92 }
93
94 fn edges(&'a self) -> borrow::Cow<'a, [Edge<'a>]> {
95 use specs::Join;
96
97 let mut edges = Vec::new();
98
99 for entity in self.entities.join() {
100 if let Some(element) = self.elements.get(entity) {
101 match element {
102 element::Element::NumberValue(_) => {}
103 element::Element::StringValue(_) => {}
104 element::Element::Tuple(element::Tuple { fields }) => {
105 for (idx, field) in fields.iter().enumerate() {
106 edges.push(Edge {
107 source: Node(entity),
108 target: Node(*field),
109 label: Label::TupleField(idx),
110 });
111 }
112 }
113 element::Element::Record(element::Record { fields }) => {
114 for (name, field) in fields {
115 edges.push(Edge {
116 source: Node(entity),
117 target: Node(*field),
118 label: Label::RecordField(name),
119 });
120 }
121 }
122 element::Element::UnOp(element::UnOp { operand, .. }) => {
123 edges.push(Edge {
124 source: Node(entity),
125 target: Node(*operand),
126 label: Label::UnOperand,
127 });
128 }
129 element::Element::BiOp(element::BiOp { lhs, rhs, .. }) => {
130 edges.push(Edge {
131 source: Node(entity),
132 target: Node(*lhs),
133 label: Label::BiLhs,
134 });
135 edges.push(Edge {
136 source: Node(entity),
137 target: Node(*rhs),
138 label: Label::BiRhs,
139 });
140 }
141 element::Element::Variable(element::Variable { initializer, .. }) => edges
142 .push(Edge {
143 source: Node(entity),
144 target: Node(*initializer),
145 label: Label::VariableInitializer,
146 }),
147 element::Element::Select(element::Select { record, field }) => {
148 edges.push(Edge {
149 source: Node(entity),
150 target: Node(*record),
151 label: Label::SelectField(field),
152 });
153 }
154 element::Element::Apply(element::Apply {
155 function,
156 parameters,
157 }) => {
158 edges.push(Edge {
159 source: Node(entity),
160 target: Node(*function),
161 label: Label::AppliedFunction,
162 });
163 for (idx, parameter) in parameters.iter().enumerate() {
164 edges.push(Edge {
165 source: Node(entity),
166 target: Node(*parameter),
167 label: Label::AppliedParameter(idx),
168 });
169 }
170 }
171 element::Element::Parameter(element::Parameter { signature, .. }) => {
172 if let Some(signature) = signature {
173 edges.push(Edge {
174 source: Node(entity),
175 target: Node(*signature),
176 label: Label::ParameterSignature,
177 });
178 }
179 }
180 element::Element::Capture(element::Capture { ref name, captured }) => edges
181 .push(Edge {
182 source: Node(entity),
183 target: Node(*captured),
184 label: Label::ClosureCaptureDefinition(name),
185 }),
186 element::Element::Closure(element::Closure {
187 captures,
188 parameters,
189 statements,
190 signature,
191 result,
192 }) => {
193 for (idx, capture) in captures.iter().enumerate() {
194 edges.push(Edge {
195 source: Node(entity),
196 target: Node(*capture),
197 label: Label::ClosureCaptureUsage(idx),
198 });
199 }
200 for (idx, parameter) in parameters.iter().enumerate() {
201 edges.push(Edge {
202 source: Node(entity),
203 target: Node(*parameter),
204 label: Label::ClosureParameter(idx),
205 });
206 }
207 for (idx, statement) in statements.iter().enumerate() {
208 edges.push(Edge {
209 source: Node(entity),
210 target: Node(*statement),
211 label: Label::ClosureStatement(idx),
212 });
213 }
214 if let Some(signature) = signature {
215 edges.push(Edge {
216 source: Node(entity),
217 target: Node(*signature),
218 label: Label::ClosureSignature,
219 });
220 }
221 edges.push(Edge {
222 source: Node(entity),
223 target: Node(*result),
224 label: Label::ClosureResult,
225 });
226 }
227 element::Element::Module(element::Module { variables }) => {
228 for (name, variable) in variables {
229 edges.push(Edge {
230 source: Node(entity),
231 target: Node(*variable),
232 label: Label::ModuleDefinition(name),
233 });
234 }
235 }
236 }
237 }
238 }
239
240 borrow::Cow::Owned(edges)
241 }
242
243 fn source(&'a self, edge: &Edge) -> Node {
244 edge.source
245 }
246
247 fn target(&'a self, edge: &Edge) -> Node {
248 edge.target
249 }
250}
251
252impl<'a> dot::Labeller<'a, Node, Edge<'a>> for Graph<'a> {
253 fn graph_id(&'a self) -> dot::Id<'a> {
254 dot::Id::new("ir").unwrap()
255 }
256
257 fn node_id(&'a self, n: &Node) -> dot::Id<'a> {
258 dot::Id::new(format!("n{}", n.0.id())).unwrap()
259 }
260
261 fn node_shape(&'a self, _n: &Node) -> Option<dot::LabelText<'a>> {
262 Some(dot::LabelText::LabelStr("record".into()))
263 }
264
265 fn node_label(&'a self, n: &Node) -> dot::LabelText<'a> {
266 use std::fmt::Write;
267
268 let mut result = format!("({}) ", n.0.id());
269
270 if let Some(element) = self.elements.get(n.0) {
271 match element {
272 element::Element::NumberValue(n) => write!(result, "num <b>{:?}</b>", n).unwrap(),
273 element::Element::StringValue(element::StringValue(s)) => {
274 write!(result, "str <b>{:?}</b>", s).unwrap()
275 }
276 element::Element::Tuple(element::Tuple { fields }) => {
277 write!(result, "tuple <br/> <b>{:?}</b> fields", fields.len()).unwrap()
278 }
279 element::Element::Record(element::Record { fields }) => {
280 write!(result, "record <br/> <b>{:?}</b> fields", fields.len()).unwrap()
281 }
282 element::Element::UnOp(element::UnOp { operator, .. }) => {
283 write!(result, "un op <b>{}</b>", operator).unwrap()
284 }
285 element::Element::BiOp(element::BiOp { operator, .. }) => {
286 write!(result, "bi op <b>{}</b>", operator).unwrap()
287 }
288 element::Element::Variable(element::Variable { name, .. }) => {
289 write!(result, "variable <b>{:?}</b>", name).unwrap()
290 }
291 element::Element::Select(element::Select { .. }) => {
292 write!(result, "select").unwrap()
293 }
294 element::Element::Apply(element::Apply { parameters, .. }) => {
295 write!(result, "apply <br/> <b>{:?}</b> params", parameters.len()).unwrap()
296 }
297 element::Element::Parameter(element::Parameter { name, .. }) => {
298 write!(result, "param <b>{:?}</b>", name).unwrap()
299 }
300 element::Element::Capture(element::Capture { name, .. }) => {
301 write!(result, "capture <b>{:?}</b>", name).unwrap()
302 }
303 element::Element::Closure(element::Closure {
304 captures,
305 parameters,
306 ..
307 }) => write!(
308 result,
309 "closure <br/> <b>{:?}</b> parameters <br/> <b>{:?}</b> captures",
310 parameters.len(),
311 captures.len()
312 )
313 .unwrap(),
314
315 element::Element::Module(element::Module { variables }) => write!(
316 result,
317 "module <br/> <b>{:?}</b> variables",
318 variables.len()
319 )
320 .unwrap(),
321 }
322 } else {
323 write!(result, "(unknown)").unwrap();
324 };
325
326 if let Some(ty) = self.types.get(n.0) {
327 write!(result, "<br/> <font color=\"blue\">{}</font>", PrettyTy(ty)).unwrap();
328 }
329
330 if let Some(layout) = self.layouts.get(n.0) {
331 write!(result, "<br/> <font color=\"brown\">{}</font>", layout).unwrap();
332 }
333
334 if let Some(symbol) = self.symbols.get(n.0) {
335 if symbol.is_empty() {
336 write!(result, "<br/> <font color=\"purple\">(root)</font>").unwrap();
337 } else {
338 write!(result, "<br/> <font color=\"purple\">{}</font>", symbol).unwrap();
339 }
340 }
341
342 dot::LabelText::HtmlStr(result.into())
343 }
344
345 fn edge_label(&'a self, e: &Edge<'a>) -> dot::LabelText<'a> {
346 match e.label {
347 Label::RecordField(ref name) => {
348 dot::LabelText::HtmlStr(format!("field <b>{}</b>", name).into())
349 }
350 Label::TupleField(idx) => {
351 dot::LabelText::HtmlStr(format!("field <b>{}</b>", idx).into())
352 }
353 Label::VariableInitializer => dot::LabelText::LabelStr("initializer".into()),
354 Label::SelectField(ref name) => {
355 dot::LabelText::HtmlStr(format!("select <b>{}</b>", name).into())
356 }
357 Label::AppliedFunction => dot::LabelText::LabelStr("func".into()),
358 Label::AppliedParameter(idx) => {
359 dot::LabelText::HtmlStr(format!("param <b>{}</b>", idx).into())
360 }
361 Label::ParameterSignature => dot::LabelText::LabelStr("sig".into()),
362 Label::ClosureCaptureDefinition(ref name) => {
363 dot::LabelText::HtmlStr(format!("capture definition <b>{}</b>", name).into())
364 }
365 Label::ClosureCaptureUsage(idx) => {
366 dot::LabelText::HtmlStr(format!("capture usage <b>{}</b>", idx).into())
367 }
368 Label::ClosureParameter(idx) => {
369 dot::LabelText::HtmlStr(format!("param <b>{}</b>", idx).into())
370 }
371 Label::ClosureStatement(idx) => {
372 dot::LabelText::HtmlStr(format!("stmt <b>{}</b>", idx).into())
373 }
374 Label::ClosureResult => dot::LabelText::HtmlStr("result".into()),
375 Label::ClosureSignature => dot::LabelText::LabelStr("sig".into()),
376 Label::ModuleDefinition(ref name) => {
377 dot::LabelText::HtmlStr(format!("def <b>{}</b>", name).into())
378 }
379 Label::UnOperand => dot::LabelText::LabelStr("operand".into()),
380 Label::BiLhs => dot::LabelText::LabelStr("lhs".into()),
381 Label::BiRhs => dot::LabelText::LabelStr("rhs".into()),
382 }
383 }
384
385 fn edge_style(&'a self, e: &Edge<'a>) -> dot::Style {
386 match e.label {
387 Label::RecordField(_) => dot::Style::None,
388 Label::TupleField(_) => dot::Style::None,
389 Label::VariableInitializer => dot::Style::None,
390 Label::SelectField(_) => dot::Style::None,
391 Label::AppliedFunction => dot::Style::None,
392 Label::AppliedParameter(_) => dot::Style::None,
393 Label::ParameterSignature => dot::Style::Dotted,
394 Label::ClosureCaptureDefinition(_) => dot::Style::Dashed,
395 Label::ClosureCaptureUsage(_) => dot::Style::None,
396 Label::ClosureParameter(_) => dot::Style::None,
397 Label::ClosureStatement(_) => dot::Style::Dashed,
398 Label::ClosureResult => dot::Style::None,
399 Label::ClosureSignature => dot::Style::Dotted,
400 Label::ModuleDefinition(_) => dot::Style::None,
401 Label::UnOperand => dot::Style::None,
402 Label::BiLhs => dot::Style::None,
403 Label::BiRhs => dot::Style::None,
404 }
405 }
406}
407
408impl<'a> fmt::Debug for Graph<'a> {
409 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
410 f.debug_struct("Graph").finish()
411 }
412}
413
414impl<'a> fmt::Display for PrettyTy<&'a ty::Type> {
415 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
416 match self.0 {
417 ty::Type::Boolean => write!(f, "bool"),
418 ty::Type::Number(ref number) => PrettyTy(number).fmt(f),
419 ty::Type::String => write!(f, "str"),
420 ty::Type::Tuple(ref tuple) => PrettyTy(tuple).fmt(f),
421 ty::Type::Record(ref record) => PrettyTy(record).fmt(f),
422 ty::Type::Function(ref function) => PrettyTy(function).fmt(f),
423 ty::Type::Conflict(ref conflict) => PrettyTy(conflict).fmt(f),
424 ty::Type::Any => write!(f, "any"),
425 }
426 }
427}
428
429impl<'a> fmt::Display for PrettyTy<&'a ty::Number> {
430 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
431 match self.0 {
432 ty::Number::U8 => write!(f, "u8"),
433 ty::Number::U16 => write!(f, "u16"),
434 ty::Number::U32 => write!(f, "u32"),
435 ty::Number::U64 => write!(f, "u64"),
436 ty::Number::I8 => write!(f, "i8"),
437 ty::Number::I16 => write!(f, "i16"),
438 ty::Number::I32 => write!(f, "i32"),
439 ty::Number::I64 => write!(f, "i64"),
440 ty::Number::F32 => write!(f, "f32"),
441 ty::Number::F64 => write!(f, "f64"),
442 }
443 }
444}
445
446impl<'a> fmt::Display for PrettyTy<&'a ty::Tuple> {
447 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
448 write!(f, "(")?;
449 let mut needs_sep = false;
450 for ty in &self.0.fields {
451 if needs_sep {
452 write!(f, ",")?;
453 }
454 PrettyTy(ty).fmt(f)?;
455 needs_sep = true;
456 }
457 write!(f, ")")?;
458 Ok(())
459 }
460}
461
462impl<'a> fmt::Display for PrettyTy<&'a ty::Record> {
463 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
464 write!(f, "\\{{")?;
465 let mut needs_sep = false;
466 for (id, ty) in &self.0.fields {
467 if needs_sep {
468 write!(f, ",")?;
469 }
470 write!(f, "{}:", id)?;
471 PrettyTy(ty).fmt(f)?;
472 needs_sep = true;
473 }
474 write!(f, "\\}}")?;
475 Ok(())
476 }
477}
478
479impl<'a> fmt::Display for PrettyTy<&'a ty::Function> {
480 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
481 write!(f, "\\|")?;
482 let mut needs_sep = false;
483 for ty in &self.0.parameters {
484 if needs_sep {
485 write!(f, ",")?;
486 }
487 PrettyTy(ty).fmt(f)?;
488 needs_sep = true;
489 }
490 write!(f, "\\|:")?;
491 PrettyTy(&*self.0.result).fmt(f)?;
492 Ok(())
493 }
494}
495
496impl<'a> fmt::Display for PrettyTy<&'a ty::Conflict> {
497 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
498 PrettyTy(&self.0.expected).fmt(f)?;
499 write!(f, "!=")?;
500 PrettyTy(&*self.0.actual).fmt(f)?;
501 Ok(())
502 }
503}
504
505impl<'a> fmt::Display for PrettyTy<&'a ty::ExpectedType> {
506 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
507 match *self.0 {
508 ty::ExpectedType::Specific(ref ty) => PrettyTy(&**ty).fmt(f),
509 ty::ExpectedType::ScalarClass(ref class) => PrettyTy(class).fmt(f),
510 }
511 }
512}
513
514impl<'a> fmt::Display for PrettyTy<&'a ty::ScalarClass> {
515 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
516 match *self.0 {
517 ty::ScalarClass::Boolean => f.write_str("(any bool type)"),
518 ty::ScalarClass::Integral(ty::IntegralScalarClass::Unsigned) => {
519 f.write_str("(any unsigned integer type)")
520 }
521 ty::ScalarClass::Integral(ty::IntegralScalarClass::Signed) => {
522 f.write_str("(any signed integer type)")
523 }
524 ty::ScalarClass::Integral(ty::IntegralScalarClass::Any) => {
525 f.write_str("(any integer type)")
526 }
527 ty::ScalarClass::Fractional => f.write_str("(any floating point type)"),
528 ty::ScalarClass::Complex => f.write_str("(any complex type)"),
529 ty::ScalarClass::Undefined => f.write_str("(any non-scalar type)"),
530 }
531 }
532}