Skip to content

Instantly share code, notes, and snippets.

@Krever
Last active April 21, 2023 06:41
Show Gist options
  • Select an option

  • Save Krever/75b2bb75eb7c42ab2c19c33c08dc887f to your computer and use it in GitHub Desktop.

Select an option

Save Krever/75b2bb75eb7c42ab2c19c33c08dc887f to your computer and use it in GitHub Desktop.

Revisions

  1. Krever renamed this gist Apr 21, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. Krever revised this gist Apr 21, 2023. 2 changed files with 70 additions and 0 deletions.
    70 changes: 70 additions & 0 deletions DotRenderer
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,70 @@
    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)
    }
    }
    File renamed without changes.
  3. Krever created this gist Apr 21, 2023.
    43 changes: 43 additions & 0 deletions Graphviz Dot AST.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    // 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])