check match coverage across multiple arguments
This commit is contained in:
1 file changed
+81
@@ -0,0 +1,81 @@
|
|||||||
|
module Tessera.Graph where
|
||||||
|
|
||||||
|
import Tessera.Matrix (Key (..))
|
||||||
|
import Tessera.Tree
|
||||||
|
|
||||||
|
data Rendered = Rendered
|
||||||
|
{ renderedNext :: Int
|
||||||
|
, renderedRoot :: Int
|
||||||
|
, renderedNodes :: [(Int, String, String)]
|
||||||
|
, renderedEdges :: [(Int, Int, String)]
|
||||||
|
}
|
||||||
|
|
||||||
|
buildGraph :: Tree -> Rendered
|
||||||
|
buildGraph tree =
|
||||||
|
let (next, root, nodes, edges) = go tree 0
|
||||||
|
in Rendered next root nodes edges
|
||||||
|
where
|
||||||
|
go node next = case node of
|
||||||
|
Success index ->
|
||||||
|
(next + 1, next, [(next, "clause " ++ show index, "success")], [])
|
||||||
|
Failure ->
|
||||||
|
(next + 1, next, [(next, "fail", "failure")], [])
|
||||||
|
Bind occurrence name inner ->
|
||||||
|
let (next', root', nodes', edges') = go inner (next + 1)
|
||||||
|
in (next', next, (next, "bind " ++ renderPath (occurrencePath occurrence) ++ " " ++ name, "bind") : nodes', (next, root', "bind") : edges')
|
||||||
|
Switch occurrence branches fallback ->
|
||||||
|
let (afterBranches, branchRoots, branchNodes, branchEdges) = goBranches branches (next + 1) [] [] []
|
||||||
|
(afterFallback, fallbackRoots, fallbackNodes, fallbackEdges) = case fallback of
|
||||||
|
Nothing -> (afterBranches, [], [], [])
|
||||||
|
Just defaultTree ->
|
||||||
|
let (finalNext, root', nodes', edges') = go defaultTree afterBranches
|
||||||
|
in (finalNext, [(root', "default")], nodes', edges')
|
||||||
|
node = (next, "switch " ++ renderPath (occurrencePath occurrence), "switch")
|
||||||
|
edges = [(next, r, l) | (r, l) <- branchRoots] ++ [(next, r, l) | (r, l) <- fallbackRoots]
|
||||||
|
in (afterFallback, next, node : branchNodes ++ fallbackNodes, edges ++ branchEdges ++ fallbackEdges)
|
||||||
|
|
||||||
|
goBranches [] next roots nodes edges = (next, reverse roots, nodes, edges)
|
||||||
|
goBranches ((key, subtree) : rest) next roots nodes edges =
|
||||||
|
let (next', root', nodes', edges') = go subtree next
|
||||||
|
in goBranches rest next' ((root', renderKey key) : roots) (nodes ++ nodes') (edges ++ edges')
|
||||||
|
|
||||||
|
renderPath :: [Int] -> String
|
||||||
|
renderPath [] = "root"
|
||||||
|
renderPath [x] = show x
|
||||||
|
renderPath (x : rest) = show x ++ "." ++ renderPath rest
|
||||||
|
|
||||||
|
renderKey :: Key -> String
|
||||||
|
renderKey key = case key of
|
||||||
|
KeyCon name -> name
|
||||||
|
KeyInt n -> show n
|
||||||
|
KeyBool b -> if b then "True" else "False"
|
||||||
|
KeyTuple n -> "tuple/" ++ show n
|
||||||
|
|
||||||
|
renderDot :: Tree -> String
|
||||||
|
renderDot tree = unlines (header ++ map renderNode (renderedNodes graph) ++ map renderEdge (renderedEdges graph) ++ ["}"])
|
||||||
|
where
|
||||||
|
graph = buildGraph tree
|
||||||
|
header =
|
||||||
|
[ "digraph tessera {"
|
||||||
|
, " graph [bgcolor=\"white\", rankdir=TB, nodesep=0.35, ranksep=0.5];"
|
||||||
|
, " node [shape=box, style=\"rounded,filled\", color=\"#444444\", fontcolor=\"#1c1c1a\", fillcolor=\"#ffffff\", fontname=\"Helvetica\", fontsize=11];"
|
||||||
|
, " edge [color=\"#666666\", fontcolor=\"#333333\", fontname=\"Helvetica\", fontsize=10];"
|
||||||
|
]
|
||||||
|
renderNode (identifier, label, kind) =
|
||||||
|
" n" ++ show identifier ++ " [label=\"" ++ escape label ++ "\"" ++ fillFor kind ++ "];"
|
||||||
|
renderEdge (from, to, label) =
|
||||||
|
" n" ++ show from ++ " -> n" ++ show to ++ " [label=\"" ++ escape label ++ "\"];"
|
||||||
|
fillFor kind = case kind of
|
||||||
|
"success" -> ", fillcolor=\"#e7efe4\""
|
||||||
|
"failure" -> ", fillcolor=\"#f4e6e4\""
|
||||||
|
"switch" -> ", fillcolor=\"#f7f7f5\""
|
||||||
|
_ -> ""
|
||||||
|
|
||||||
|
escape :: String -> String
|
||||||
|
escape = concatMap escapeChar
|
||||||
|
where
|
||||||
|
escapeChar c = case c of
|
||||||
|
'"' -> "\\\""
|
||||||
|
'\\' -> "\\\\"
|
||||||
|
'\n' -> "\\n"
|
||||||
|
_ -> [c]
|
||||||
Reference in new issue
Block a user