Skip to content

Instantly share code, notes, and snippets.

@Krever
Last active April 21, 2023 06:41
Show Gist options
  • Save Krever/75b2bb75eb7c42ab2c19c33c08dc887f to your computer and use it in GitHub Desktop.
Save Krever/75b2bb75eb7c42ab2c19c33c08dc887f to your computer and use it in GitHub Desktop.
Graphviz Dot AST
object DotRenderer {
def render(graph: Graph): String = {
graph match {
case DirectedGraph(strict, id, stmtList) =>
s"${if (strict) "strict " else ""}digraph ${id.getOrElse("")} {${renderStmtList(stmtList)}}"
case UndirectedGraph(strict, id, stmtList) =>
s"${if (strict) "strict " else ""}graph ${id.getOrElse("")} {${renderStmtList(stmtList)}}"
}
}
def renderStmtList(stmtList: List[Stmt]): String =
stmtList.map(renderStmt).mkString(";\n")
def renderStmt(stmt: Stmt): String = stmt match {
case NodeStmt(nodeId, attrList) =>
s"${renderNodeId(nodeId)}${attrList.map(renderAttrList).getOrElse("")}"
case EdgeStmt(from, edgeRHS, attrList) =>
s"${renderFrom(from)}${edgeRHS.map{case (op, target) => s"${renderEdgeOp(op)}${renderFrom(target)}"}.mkString}${attrList.map(renderAttrList).getOrElse("")}"
case AttrStmt(attrType, attrList) =>
s"${renderAttrType(attrType)}${renderAttrList(attrList)}"
case Assignment(id1, id2) =>
s"$id1=$id2"
case SubgraphStmt(subgraph) =>
renderSubgraph(subgraph)
}
def renderAttrType(attrType: AttrType): String = attrType match {
case GraphAttr => "graph"
case NodeAttr => "node"
case EdgeAttr => "edge"
}
def renderAttrList(attrList: AttrList): String =
attrList.aList.map { case (k, v) => s"$k=$v" }.mkString("[", ";", "]")
def renderEdgeOp(edgeOp: EdgeOp): String = edgeOp match {
case DirectedEdgeOp => "->"
case UndirectedEdgeOp => "--"
}
def renderNodeId(nodeId: NodeId): String =
s"${nodeId.id}${nodeId.port.map(renderPort).getOrElse("")}"
def renderPort(port: Port): String = port match {
case PortName(name, compassPt) => s":$name${compassPt.map(cp => s":$cp").getOrElse("")}"
case PortCompassPt(compassPt) => s":$compassPt"
}
def renderCompassPt(compassPt: CompassPt): String = compassPt match {
case North => "n"
case NorthEast => "ne"
case East => "e"
case SouthEast => "se"
case South => "s"
case SouthWest => "sw"
case West => "w"
case NorthWest => "nw"
case Center => "c"
case Any => "_"
}
def renderSubgraph(subgraph: Subgraph): String =
s"${if (subgraph.id.isDefined) s"subgraph ${subgraph.id.get}" else ""}{${renderStmtList(subgraph.stmtList)}}"
def renderFrom(from: Either[NodeId, Subgraph]): String =
from match {
case Left(nodeId) => renderNodeId(nodeId)
case Right(subgraph) => renderSubgraph(subgraph)
}
}
// This code was generated by ChatGPT from DOT grammar available at https://graphviz.org/doc/info/lang.html
sealed trait Graph
case class DirectedGraph(strict: Boolean, id: Option[String], stmtList: List[Stmt]) extends Graph
case class UndirectedGraph(strict: Boolean, id: Option[String], stmtList: List[Stmt]) extends Graph
sealed trait Stmt
case class NodeStmt(nodeId: NodeId, attrList: Option[AttrList]) extends Stmt
case class EdgeStmt(from: Either[NodeId, Subgraph], edgeRHS: List[(EdgeOp, Either[NodeId, Subgraph])], attrList: Option[AttrList]) extends Stmt
case class AttrStmt(attrType: AttrType, attrList: AttrList) extends Stmt
case class Assignment(id1: String, id2: String) extends Stmt
case class SubgraphStmt(subgraph: Subgraph) extends Stmt
sealed trait AttrType
case object GraphAttr extends AttrType
case object NodeAttr extends AttrType
case object EdgeAttr extends AttrType
case class AttrList(aList: List[(String, String)])
sealed trait EdgeOp
case object DirectedEdgeOp extends EdgeOp
case object UndirectedEdgeOp extends EdgeOp
case class NodeId(id: String, port: Option[Port])
sealed trait Port
case class PortName(name: String, compassPt: Option[CompassPt]) extends Port
case class PortCompassPt(compassPt: CompassPt) extends Port
sealed trait CompassPt
case object North extends CompassPt
case object NorthEast extends CompassPt
case object East extends CompassPt
case object SouthEast extends CompassPt
case object South extends CompassPt
case object SouthWest extends CompassPt
case object West extends CompassPt
case object NorthWest extends CompassPt
case object Center extends CompassPt
case object Any extends CompassPt
case class Subgraph(id: Option[String], stmtList: List[Stmt])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment