{- |
Serialisation/deserialisation of 'Data.FsmActions.FSM's in edge list
format.
An 'Data.FsmActions.FSM' may be represented textually as list of
{source_state->destination_state,label} strings, each of which
represents an edge in its directed graph. (This representation is
interesting because it's used by Mathematica for graph I/O.)
-}moduleData.FsmActions.FsmEdges(-- * I/OloadFsmEdges,saveFsmEdges,-- * ParsingparseFsmEdges,-- * Pretty-printingprintFsmEdges)whereimportControl.ExceptionimportqualifiedData.Graph.Inductive.GraphasGimportData.Graph.Inductive.Tree(Gr)importData.ListimportqualifiedText.ParsecasPimportqualifiedText.Parsec.LanguageasLimportText.Parsec.StringimportqualifiedText.Parsec.TokenasTimportText.PrettyPrint.HughesPJimportData.FsmActionsimportData.FsmActions.ErrorimportData.FsmActions.Graph-- The intermediate result of parsing will be a list of edges.dataEdge=EdgeIntegerIntegerStringderiving(Eq,Show)-- | Load an 'Data.FsmActions.FSM' from an FsmEdges file.loadFsmEdges::FilePath->IO(FSMString)loadFsmEdgespath=docontents<-readFilepathletresult=parseFsmEdgescontentscaseresultofRightfsm->returnfsmLefte->throw$FsmError(showe)path-- | Save an 'Data.FsmActions.FSM' to an FsmMatrix file.saveFsmEdges::FSMString->FilePath->IO()saveFsmEdgesfsmmxPath=doletmx=printFsmEdgesfsmwriteFilemxPathmx-- | Parse an FsmEdges-formatted FSM held in a string. Includes-- normalisation and well-formedness checks.parseFsmEdges::String->ReadFsmMonad(FSMString)parseFsmEdgesfsmString=caseP.parsefsmEdgesParser""fsmStringofRightedges->do(fsm,_)<-(fglToFsm.edgesToFGL)edgesreturnfsmLefterr->throw$FsmError"FSM edges parse error"(showerr)-- FsmEdges-format parser.fsmEdgesParser::Parser[Edge]fsmEdgesParser=T.bracesl$T.commaSeplfsmEdgeParserwherefsmEdgeParser::ParserEdgefsmEdgeParser=T.bracesl$dosource<-T.naturall_<-T.symboll"->"destination<-T.naturall_<-T.commallabel<-T.identifierlreturn$Edgesourcedestinationlabell::T.TokenParserstl=T.makeTokenParserL.emptyDef-- Turn a list of edges into an FGL graph, inferring the node list-- from those mentioned in the edges.edgesToFGL::[Edge]->Gr()StringedgesToFGLedges=G.mkGraphgNodesgEdgeswheregEdges=mapfstextractedgNodes=sort$nub$concatMapsndextractedextracted=mapedgeExtractedges-- Turn an FsmEdges Edge into an FGL (LEdge, [LNodes]) pair.edgeExtract::Edge->(G.LEdgeString,[G.LNode()])edgeExtract(Edges'd'l)=((s,d,l),[(s,()),(d,())])wheres=fromIntegers'd=fromIntegerd'-- | Pretty-print a string FSM in FsmMatrix format.printFsmEdges::FSMString->StringprintFsmEdges=show.ppFsmEdges-- Pretty printer to FsmEdges format (building Doc not String).ppFsmEdges::FSMString->DocppFsmEdgesfsm=ppFsmEdges'$maptweakEdge$G.labEdges$fsmToFGLfsmTrimwhere-- Convert fgl-format Edge to the ones used by this module.tweakEdge::CleanShowsy=>G.LEdgesy->EdgetweakEdge(s,d,l)=Edge(toIntegers)(toIntegerd)(cleanShowl)ppFsmEdges'::[Edge]->DocppFsmEdges'=braces.vcat.punctuatecomma.mapppFsmEdgeppFsmEdge::Edge->DocppFsmEdge(Edgesrcdestlabel)=braces$integersrc<>text"->"<>integerdest<>comma<>textlabel