86 lines
2.8 KiB
Scala
86 lines
2.8 KiB
Scala
package tf.bug.fancadetagless
|
|
|
|
import cats._
|
|
import cats.implicits._
|
|
import higherkindness.droste.data._
|
|
import polymorphic._
|
|
import scalax.collection.Graph
|
|
import scalax.collection.GraphEdge.DiHyperEdge
|
|
import tf.bug.fancadegraph.Block
|
|
import tf.bug.fancadegraph.Level
|
|
import tf.bug.fancadegraph.Pin
|
|
import tf.bug.fancadegraph.PinDefinition
|
|
import tf.bug.fancadegraph.Template
|
|
import tf.bug.fancadescodec.Position
|
|
|
|
sealed trait FancadeF[A] {
|
|
val template: Exists[Template]
|
|
val pins: Vector[PinDefinition]
|
|
}
|
|
|
|
object FancadeF {
|
|
|
|
implicit val fancadeTraverse: Traverse[FancadeF] = new Traverse[FancadeF] {
|
|
override def traverse[G[_]: Applicative, A, B](fa: FancadeF[A])(f: A => G[B]): G[FancadeF[B]] =
|
|
fa match {
|
|
case Capture(t, p) => Capture[B](t, p).pure[G].widen
|
|
case Use(c, t, i, o) =>
|
|
c.traverse(f).map { newC => Use(newC, t, i, o) }
|
|
}
|
|
|
|
override def foldLeft[A, B](fa: FancadeF[A], b: B)(f: (B, A) => B): B =
|
|
fa match {
|
|
case Capture(_, _) => b
|
|
case Use(c, _, _, _) => c.foldLeft(b)(f)
|
|
}
|
|
|
|
override def foldRight[A, B](fa: FancadeF[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
|
|
fa match {
|
|
case Capture(_, _) => lb
|
|
case Use(c, _, _, _) => Traverse[Vector].foldRight(c, lb)(f)
|
|
}
|
|
}
|
|
|
|
case class Capture[A](template: Exists[Template], pins: Vector[PinDefinition]) extends FancadeF[A]
|
|
case class Use[A](children: Vector[A], template: Exists[Template], inputs: Vector[PinDefinition], pins: Vector[PinDefinition]) extends FancadeF[A]
|
|
|
|
def render(f: Fix[FancadeF]): Level = {
|
|
val pc = PointerChain.deduplicate[Id, FancadeF](f)
|
|
val pcvi = pc.vertices.zipWithIndex
|
|
val blocks: Set[Block] = pcvi.map {
|
|
case (block, y) =>
|
|
Block(
|
|
Position(0, y, 0),
|
|
block.template
|
|
)
|
|
}.toSet
|
|
val wires: Graph[Pin, DiHyperEdge] =
|
|
pcvi.foldLeft(Graph.empty[Pin, DiHyperEdge]) {
|
|
case (graph, (block, y)) =>
|
|
block match {
|
|
case Capture(_, _) => graph
|
|
case Use(children, template, inputs, _) =>
|
|
val thisBlock = Block(
|
|
Position(0, y, 0),
|
|
template
|
|
)
|
|
val thesePins = inputs.map(Pin(thisBlock, _))
|
|
val childrenPins: Vector[Pin] = children.flatMap { child =>
|
|
val childInst = pc.vertices(child)
|
|
val childBlock = Block(
|
|
Position(0, child, 0),
|
|
childInst.template
|
|
)
|
|
childInst.pins.map(Pin(childBlock, _))
|
|
}
|
|
val newEdges: Vector[DiHyperEdge[Pin]] = childrenPins.zip(thesePins).map {
|
|
case (from, to) => DiHyperEdge(from, to)
|
|
}
|
|
graph ++ newEdges
|
|
}
|
|
}
|
|
Level(blocks, wires)
|
|
}
|
|
|
|
}
|