{-# language OverloadedStrings #-} {-# options_ghc -Wno-unused-imports #-} -- | Mostly-complete implementation of the GML format -- -- https://en.wikipedia.org/wiki/Graph_Modelling_Language module Algebra.Graph.IO.GML (gmlGraph, gmlGraphP, GMLGraph(..), GMLNode(..), GMLEdge(..)) where import Control.Applicative hiding (many, some) import Data.Char (isAlpha, isSpace) import Data.Functor (void) import Data.Void (Void) -- algebraic-graphs import qualified Algebra.Graph as G (Graph, empty, vertex, edge, overlay) -- megaparsec import Text.Megaparsec (Parsec, parse, parseTest, satisfy, ()) import Text.Megaparsec.Char (space1) import qualified Text.Megaparsec.Char.Lexer as L -- parser-combinators import Control.Monad.Combinators (many, some, between, skipManyTill) -- text import Data.Text (Text) import Data.Text.IO (readFile) import Prelude hiding (readFile, takeWhile) import Algebra.Graph.IO.Internal.Megaparsec (Parser, lexeme, symbol, anyString) -- | Construct a 'G.Graph' using the edge data contained in a 'GMLGraph' gmlGraph :: GMLGraph a b -> G.Graph a gmlGraph (GMLGraph _ _ es) = foldl (\gr (GMLEdge a b _ _) -> G.edge a b `G.overlay` gr) G.empty es -- | Graph entities of the GML graph format data GMLGraph a b = GMLGraph { gmlHeader :: Maybe String , gmlNodes :: [GMLNode a] , gmlEdges :: [GMLEdge a b] } deriving (Show) -- | Parser for the GML graph format gmlGraphP :: Parser a -- ^ parser for node id's -> Parser b -> Parser (GMLGraph a b) gmlGraphP p p2 = do header <- optional creator -- header void $ symbol "graph" sqBkts $ do ns <- many $ gmlNode p es <- many $ gmlEdge p p2 pure $ GMLGraph header ns es creator :: Parser String creator = do void $ symbol "Creator" quoted $ many $ satisfy (/= '\"') -- | GML nodes data GMLNode a = GMLNode a (Maybe String) deriving (Show) gmlNode :: Parser a -> Parser (GMLNode a) gmlNode p = do void $ symbol "node" sqBkts $ do n <- symbol "id" *> lexeme p l <- optional gmlLabel pure $ GMLNode n l sqBkts :: Parser a -> Parser a sqBkts = between (symbol "[") (symbol "]") quoted :: Parser a -> Parser a quoted = between (symbol "\"") (symbol "\"") -- | GML edges data GMLEdge a b = GMLEdge a a (Maybe b) (Maybe String) deriving (Show) gmlEdge :: Parser a -> Parser b -> Parser (GMLEdge a b) gmlEdge pa pb = do void $ symbol "edge" sqBkts $ do a <- source pa b <- target pa v <- optional (value pb) l <- optional gmlLabel pure $ GMLEdge a b v l -- attributes source, target, value :: Parser a -> Parser a source = attr "source" target = attr "target" value = attr "value" gmlLabel :: Parser String gmlLabel = symbol "label" *> lexeme (quoted p) where p = many $ satisfy (/= '\"') attr :: Text -> Parser a -> Parser a attr str p = symbol str *> lexeme p -- gmlValue :: Parser a -> Parser a -- gmlValue p = symbol "value" *> lexeme p