Skip to content

Commit

Permalink
Implement missing graphviz
Browse files Browse the repository at this point in the history
  • Loading branch information
froth committed May 29, 2024
1 parent a9b04d9 commit 756a42d
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 49 deletions.
60 changes: 53 additions & 7 deletions src/graphviz_converter/expression.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use graphviz_rust::{dot_generator::*, dot_structures::*};

use crate::{
ast::expr::{Expr, ExprType},
ast::{
expr::{Expr, ExprType},
name::Name,
token::Token,
},
graphviz_converter::random_id,
};

Expand All @@ -19,8 +23,8 @@ impl GraphvizConverter for ExprType {
ExprType::Assign(name, expr) => {
single_child(format!("Assignment to \"{}\"", name.name).as_str(), expr)
}
ExprType::Binary(_, _, _) => todo!(),
ExprType::Logical(_, _, _) => todo!(),
ExprType::Binary(left, token, right) => binary(token, left, right),
ExprType::Logical(left, token, right) => binary(token, left, right),
ExprType::Grouping(expr) => single_child("Gouping", expr),
ExprType::Literal(literal) => {
GraphvizRepr::single(expr(format!("Literal: {}", literal).as_str()))
Expand All @@ -31,11 +35,11 @@ impl GraphvizConverter for ExprType {
ExprType::Variable(name_expr) => {
GraphvizRepr::single(expr(format!("Variable: {}", name_expr.name).as_str()))
}
ExprType::Call(_, _) => todo!(),
ExprType::Call(callee, arguments) => call(callee, arguments),
ExprType::Get(expr, name) => {
single_child(format!("Get expression \"{}\"", name.name).as_str(), expr)
}
ExprType::Set(_, _, _) => todo!(),
ExprType::Set(object, name, value) => set(object, &name.name, value),
ExprType::This => GraphvizRepr::single(expr("this")),
ExprType::Super(name) => {
GraphvizRepr::single(expr(format!("super.{}", name.name).as_str()))
Expand All @@ -50,8 +54,50 @@ fn expr(label: &str) -> Node {

fn single_child(label: &str, expression: &Expr) -> GraphvizRepr {
let mut node = GraphvizRepr::single(expr(label));
let mut expr_repr = expression.to_graphviz();
node.stmts.append(&mut expr_repr.stmts);
let expr_repr = expression.to_graphviz();
node.stmts.extend(expr_repr.stmts);
node.push(edge!(node.id.clone() => expr_repr.id.clone()));
node
}

fn binary(token: &Token, left: &Expr, right: &Expr) -> GraphvizRepr {
let mut node = GraphvizRepr::single(expr(token.token_type.to_string().as_str()));
let left = left.to_graphviz();
node.stmts.extend(left.stmts);
node.push(edge!(node.id.clone() => left.id.clone(); attr!("label", "left")));

let right = right.to_graphviz();
node.stmts.extend(right.stmts);
node.push(edge!(node.id.clone() => right.id.clone(); attr!("label", "right")));
node
}

fn call(callee: &Expr, arguments: &[Expr]) -> GraphvizRepr {
let mut node = GraphvizRepr::single(expr("call"));
let callee = callee.to_graphviz();
node.stmts.extend(callee.stmts);
node.push(edge!(node.id.clone() => callee.id.clone(); attr!("label", "callee")));

let mut args = GraphvizRepr::single(expr("arguments"));
arguments.iter().for_each(|a| {
let a = a.to_graphviz();
args.append(a.stmts);
args.push(edge!(args.id.clone() => a.id))
});

node.stmts.extend(args.stmts);
node.push(edge!(node.id.clone() => args.id.clone(); attr!("label", "arguments")));
node
}

fn set(object: &Expr, name: &Name, value: &Expr) -> GraphvizRepr {
let mut node = GraphvizRepr::single(expr(format!("set {}", name).as_str()));
let object = object.to_graphviz();
node.stmts.extend(object.stmts);
node.push(edge!(node.id.clone() => object.id.clone(); attr!("label", "object")));

let value = value.to_graphviz();
node.stmts.extend(value.stmts);
node.push(edge!(node.id.clone() => value.id.clone(); attr!("label", "value")));
node
}
154 changes: 112 additions & 42 deletions src/graphviz_converter/statement.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
use crate::ast::{
self,
expr::Expr,
name::{Name, NameExpr},
stmt::{self, Function, StmtType},
};
use graphviz_rust::{
attributes::{rank, SubgraphAttributes},
dot_generator::*,
dot_structures::*,
};
use graphviz_rust::{dot_generator::*, dot_structures::*};
use std::fmt::Write;

use super::{random_cluster_id, random_id, GraphvizConverter, GraphvizRepr};
Expand All @@ -23,21 +19,23 @@ impl GraphvizConverter for StmtType {
match self {
StmtType::Expression(expr) => single_expr("Expr", expr),
StmtType::Print(expr) => single_expr("print", expr),
StmtType::Var { name, initializer } => todo!(),
StmtType::Var { name, initializer } => {
single_with_option_expr(format!("var {}", name).as_str(), initializer)
}
StmtType::Function(f) => function(f, "fun"),
StmtType::Return(_) => todo!(),
StmtType::Block(_) => todo!(),
StmtType::Return(expr) => single_with_option_expr("return", expr),
StmtType::Block(stmts) => block(stmts, "block"),
StmtType::If {
condition,
then_stmt,
else_stmt,
} => convert_if(condition, then_stmt, else_stmt.as_deref()),
StmtType::While { condition, body } => todo!(),
StmtType::While { condition, body } => convert_while(condition, body),
StmtType::Class {
name,
methods,
superclass,
} => todo!(),
} => class(name, methods, superclass),
}
}
}
Expand All @@ -50,6 +48,42 @@ fn single_expr(label: &str, expr: &Expr) -> GraphvizRepr {
print
}

fn rank_subgraph(ids: &[NodeId]) -> (Subgraph, Vec<Stmt>) {
let mut rank_subgraph = subgraph!(esc random_id());
ids.iter().for_each(|id| {
rank_subgraph
.stmts
.push(Node::new(id.clone(), vec![]).into())
});
rank_subgraph.stmts.push(attr!("rank", "same").into());
let invisible_edges = ids
.windows(2)
.map(|window| edge!(window[0].clone() => window[1].clone(); attr!("style", "invis")).into())
.collect();
(rank_subgraph, invisible_edges)
}

fn block(block: &[stmt::Stmt], label: &str) -> GraphvizRepr {
let mut node = GraphvizRepr::single(stmt(label));
let node_id = node.id.clone();
let (ids, stmts): (Vec<_>, Vec<_>) = block
.iter()
.map(|s| s.to_graphviz())
.map(|g| (g.id, g.stmts))
.unzip();
let mut stmts: Vec<Stmt> = stmts.into_iter().flatten().collect();
let mut subgraph = subgraph!(esc random_cluster_id());
subgraph.stmts.append(&mut stmts);
subgraph.stmts.push(attr!("style", "dotted").into());
let (rank_subgraph, mut rank_edges) = rank_subgraph(&ids);
subgraph.stmts.push(rank_subgraph.into());
subgraph.stmts.append(&mut rank_edges);
node.push(subgraph);
ids.into_iter()
.for_each(|id| node.push(edge!(node_id.clone() => id; attr!("style", "dashed"))));
node
}

fn function(function: &Function, function_type: &str) -> GraphvizRepr {
let name = &function.name;
let mut parameters = String::new();
Expand All @@ -59,37 +93,7 @@ fn function(function: &Function, function_type: &str) -> GraphvizRepr {
.for_each(|arg| write!(&mut parameters, "{arg}, ").unwrap());
let parameters = parameters.trim_end_matches(", ");
let label = format!("{function_type} {name}({parameters})");
let mut node = GraphvizRepr::single(stmt(label.as_str()));
let node_id = node.id.clone();
let (body_ids, body_stmts): (Vec<_>, Vec<_>) = function
.body
.iter()
.map(|s| s.to_graphviz())
.map(|g| (g.id, g.stmts))
.unzip();
let mut body_stmts: Vec<Stmt> = body_stmts.into_iter().flatten().collect();
let mut body_subgraph = subgraph!(esc random_cluster_id());
body_subgraph.stmts.append(&mut body_stmts);
body_ids.windows(2).for_each(|window| {
body_subgraph
.stmts
.push(edge!(window[0].clone() => window[1].clone(); attr!("style", "invis")).into())
});
body_subgraph.stmts.push(attr!("style", "dotted").into());
body_subgraph.stmts.push(attr!("label", "body").into());
let mut rank_subgraph = subgraph!(esc random_id());
body_ids.iter().for_each(|id| {
rank_subgraph
.stmts
.push(Node::new(id.clone(), vec![]).into())
});
rank_subgraph.stmts.push(attr!("rank", "min").into());
body_subgraph.stmts.push(rank_subgraph.into());
node.push(body_subgraph);
body_ids.into_iter().for_each(|id| {
node.push(edge!(node_id.clone() => id; attr!("style", "dashed"), attr!("weight","0.9")))
});
node
block(&function.body, label.as_str())
}

fn convert_if(
Expand All @@ -98,9 +102,75 @@ fn convert_if(
else_stmt: Option<&stmt::Stmt>,
) -> GraphvizRepr {
let mut node = GraphvizRepr::single(stmt("if"));
let mut ids = vec![];
let condition = condition.to_graphviz();
ids.push(condition.id.clone());
node.append(condition.stmts);
node.push(edge!(node.id.clone() => condition.id; attr!("label", "condition")));
let then = then_stmt.to_graphviz();
ids.push(then.id.clone());
node.append(then.stmts);
node.push(edge!(node.id.clone() => then.id; attr!("label", "then")));
else_stmt.into_iter().for_each(|e| {
let else_node = e.to_graphviz();
ids.push(else_node.id.clone());
node.append(else_node.stmts);
node.push(edge!(node.id.clone() => else_node.id; attr!("label", "else")));
});
node
}

fn convert_while(condition: &Expr, body: &stmt::Stmt) -> GraphvizRepr {
let mut node = GraphvizRepr::single(stmt("while"));
let mut ids = vec![];
let condition = condition.to_graphviz();
let mut subgraph = subgraph!(esc random_id());
ids.push(condition.id.clone());
subgraph.stmts.extend(condition.stmts);
let body = body.to_graphviz();
ids.push(body.id.clone());
subgraph.stmts.extend(body.stmts);
let (rank_subgraph, mut rank_edges) = rank_subgraph(&ids);
subgraph.stmts.push(rank_subgraph.into());
node.push(edge!(node.id.clone() => condition.id; attr!("label", "condition")));
node.push(edge!(node.id.clone() => body.id; attr!("label", "body")));
node.stmts.push(subgraph.into());
node.stmts.append(&mut rank_edges);
node
}

fn single_with_option_expr(label: &str, expr: &Option<Expr>) -> GraphvizRepr {
let mut node = GraphvizRepr::single(stmt(label));
expr.iter().for_each(|e| {
let e = e.to_graphviz();
node.append(e.stmts);
node.stmts.push(edge!(node.id.clone() => e.id).into());
});
node
}

fn class(name: &Name, methods: &[Function], superclass: &Option<NameExpr>) -> GraphvizRepr {
let label = match superclass {
Some(superclass) => format!("class {} < {}", name, superclass.name),
None => format!("class {}", name),
};
let mut node = GraphvizRepr::single(stmt(label.as_str()));
let node_id = node.id.clone();
let (ids, stmts): (Vec<_>, Vec<_>) = methods
.iter()
.map(|f| function(f, "method"))
.map(|g| (g.id, g.stmts))
.unzip();
let mut stmts: Vec<Stmt> = stmts.into_iter().flatten().collect();
let mut subgraph = subgraph!(esc random_cluster_id());
subgraph.stmts.append(&mut stmts);
subgraph.stmts.push(attr!("style", "dotted").into());
let (rank_subgraph, mut rank_edges) = rank_subgraph(&ids);
subgraph.stmts.push(rank_subgraph.into());
subgraph.stmts.append(&mut rank_edges);
node.push(subgraph);
ids.into_iter()
.for_each(|id| node.push(edge!(node_id.clone() => id; attr!("style", "dashed"))));
node
}

Expand Down

0 comments on commit 756a42d

Please sign in to comment.