tlex-debug-0.1.0.0: src/Language/Lexer/Tlex/Plugin/Debug.hs
module Language.Lexer.Tlex.Plugin.Debug (
outputDfaToDot,
Graphviz.outputAst,
) where
import Language.Lexer.Tlex.Prelude
import qualified Data.HashMap.Strict as HashMap
import qualified Data.IntMap.Strict as IntMap
import qualified Data.IntSet as IntSet
import qualified Language.Lexer.Tlex.Data.EnumMap as EnumMap
import qualified Language.Lexer.Tlex.Machine.DFA as DFA
import qualified Language.Lexer.Tlex.Machine.State as MState
import qualified Language.Lexer.Tlex.Plugin.Debug.Graphviz as Graphviz
import qualified Prelude
newtype EdgeBuilder = EdgeBuilder
{ unEdgeBuilder :: HashMap.HashMap
(MState.StateNum, MState.StateNum)
IntSet.IntSet
}
instance Semigroup EdgeBuilder where
EdgeBuilder m1 <> EdgeBuilder m2 = EdgeBuilder do HashMap.unionWith (<>) m1 m2
instance Monoid EdgeBuilder where
mempty = EdgeBuilder HashMap.empty
edgeBuilder :: MState.StateNum -> Int -> MState.StateNum -> EdgeBuilder
edgeBuilder sf lb st = EdgeBuilder do HashMap.singleton (sf, st) do IntSet.singleton lb
outputDfaToDot :: DFA.DFA a -> Graphviz.Ast
outputDfaToDot dfa = Graphviz.Ast
{ Graphviz.nodes = initialNode :
[ node sn dst
| (sn, dst) <- MState.arrayAssocs do DFA.dfaTrans dfa
]
, Graphviz.edges = initialEdges ++
concatMap
do \(sn, dst) -> edges sn dst
do MState.arrayAssocs do DFA.dfaTrans dfa
}
where
initialNode = Graphviz.Node
{ Graphviz.nodeId = "init"
, Graphviz.nodeLabel = Nothing
, Graphviz.nodeShape = Nothing
}
node sn dst = Graphviz.Node
{ Graphviz.nodeId = show do fromEnum sn
, Graphviz.nodeLabel = Nothing
, Graphviz.nodeShape = case DFA.dstAccepts dst of
[] -> Nothing
_ -> Just Graphviz.DoubleCircle
}
initialEdges =
[ Graphviz.Edge
{ Graphviz.edgeFrom = "init"
, Graphviz.edgeTo = show do fromEnum sn
, Graphviz.edgeLabel = Nothing
}
| (_, sn) <- EnumMap.assocs do DFA.dfaInitials dfa
]
edges sn dst =
let builder =
do case DFA.dstOtherTrans dst of
Nothing -> mempty
Just ot -> edgeBuilder sn -1 ot
<> foldMap
do \(lb, to) -> edgeBuilder sn lb to
do IntMap.assocs do DFA.dstTrans dst
in
[ edge fr lb to
| ((fr, to), lb) <- HashMap.toList do unEdgeBuilder builder
]
edge :: MState.StateNum -> IntSet.IntSet -> MState.StateNum -> Graphviz.Edge
edge fr lb to = Graphviz.Edge
{ Graphviz.edgeFrom = show do fromEnum fr
, Graphviz.edgeTo = show do fromEnum to
, Graphviz.edgeLabel = edgeLabel lb
}
edgeLabel :: IntSet.IntSet -> Maybe Prelude.String
edgeLabel xs0 = case IntSet.toAscList xs0 of
[] -> Nothing
x0:xs ->
let endPrevRange (s, p, b) = case b of
True -> s
False -> s . ("-" ++) . (show p ++)
s0 = endPrevRange
do foldl'
do \ctx@(!s, !p, _) x -> if
| x == p + 1 -> (s, x, False)
| otherwise ->
( endPrevRange ctx . ("," ++) . (show x ++)
, x
, True
)
do ((show x0 ++), x0, True)
do xs
in Just do "[" ++ s0 "]"