Skip to content

Instantly share code, notes, and snippets.

@ayende
Created March 4, 2019 07:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayende/a4c7cf92c4258d435c0475282de94d1a to your computer and use it in GitHub Desktop.
Save ayende/a4c7cf92c4258d435c0475282de94d1a to your computer and use it in GitHub Desktop.
public class WorkflowGraphGenerator : Esprima.Utils.AstVisitor
{
StringBuilder _sb = new StringBuilder();
Stack<string> _current = new Stack<string>();
Stack<string> _conditionals = new Stack<string>();
private string _code;
public string Graph => _sb.ToString() + "\r\n}";
public WorkflowGraphGenerator(string code)
{
_code = code;
_sb.AppendLine("digraph G {");
}
protected override void VisitIfStatement(Esprima.Ast.IfStatement ifStatement)
{
var text = _code.Substring(ifStatement.Test.Range.Start, ifStatement.Test.Range.End - ifStatement.Test.Range.Start);
_conditionals.Push(
text.Replace("\"", "\\\"")
);
base.VisitIfStatement(ifStatement);
_conditionals.Pop();
}
protected override void VisitReturnStatement(Esprima.Ast.ReturnStatement returnStatement)
{
if(returnStatement.Argument is Esprima.Ast.Literal explain)
{
_sb.Append($"\"{_current.Peek()}\" -> \"{explain.StringValue}\" ");
if (_conditionals.Count > 0)
{
_sb.Append("[ label=\"").AppendJoin(" AND ", _conditionals).Append("\" ]");
}
_sb.AppendLine(";");
}
base.VisitReturnStatement(returnStatement);
}
protected override void VisitCallExpression(Esprima.Ast.CallExpression callExpression)
{
var depth = _current.Count;
if (callExpression.Callee is Esprima.Ast.Identifier id)
{
switch (id.Name)
{
case "on":
if(callExpression.Arguments.Count > 0 && callExpression.Arguments[0] is Esprima.Ast.Literal onLabel)
{
_current.Push(onLabel.StringValue);
}
break;
case "next":
if (callExpression.Arguments.Count > 0 && callExpression.Arguments[0] is Esprima.Ast.Literal nextLabel)
{
_sb.Append($"\"{_current.Peek()}\" -> \"{nextLabel.StringValue}\" ");
if(_conditionals.Count > 0)
{
_sb.Append("[ label=\"").AppendJoin(" AND ", _conditionals).Append("\" ]");
}
_sb.AppendLine(";");
}
break;
default:
break;
}
}
base.VisitCallExpression(callExpression);
if (depth != _current.Count)
_current.Pop();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment