module FormalLanguage.CFG.PrettyPrint.ANSI
where
import Control.Lens hiding (outside,Index)
import Control.Monad.Reader
import Data.List (intersperse)
import Prelude hiding ((<$>))
import qualified Data.Map as M
import qualified Data.Set as S
import System.IO (stdout)
import Text.PrettyPrint.ANSI.Leijen
import Data.Char (toUpper)
import FormalLanguage.CFG.Grammar
genGrammarDoc :: Grammar -> Doc
genGrammarDoc g = runReader (grammarDoc g) g
grammarDoc :: Grammar -> Reader Grammar Doc
grammarDoc g = do
let numR = length $ g^..rules.folded
ga <- indexDoc $ g^..params.folded
ss <- fmap (ind "syntactic symbols:" 2 . vcat) . mapM steDoc $ g^..synvars.folded
os <- fmap (ind "syntactic terminals:" 2 . vcat) . mapM steDoc $ g^..synterms.folded
ts <- fmap (ind "terminals:" 2 . vcat) . mapM steDoc $ g^..termvars.folded
s <- fmap (ind "start symbol:" 2) $ symbolDoc (g^.start)
rs <- fmap (ind ("rules (" ++ show numR ++ "):") 2 . vcat) . rulesDoc $ g^..rules.folded
ind <- undefined
return $ text "Grammar: " <+> (text $ g^.grammarName) <+> ga <$> indent 2 (vsep $ [ss] ++ [os | Outside _ <- [g^.outside]] ++ [ts, s, rs]) <$> line
where ind s k d = text s <$> indent k d
rulesDoc :: [Rule] -> Reader Grammar [Doc]
rulesDoc rs = mapM ruleDoc rs
ruleDoc :: Rule -> Reader Grammar Doc
ruleDoc (Rule lhs fun rhs)
= do l <- symbolDoc lhs
rs <- fmap (intersperse (text " ")) . mapM (fmap (fill 5) . symbolDoc) $ rhs
return $ fill 10 l <+> text "->" <+> f <+> text "<<<" <+> hcat rs
where f = fill 10 . text . concat . (over (_tail.traverse._head) toUpper) $ fun^..folded.getAttr
steDoc :: SynTermEps -> Reader Grammar Doc
steDoc (SynVar n i s k) = indexDoc i >>= return . blue . (text (n^.getSteName) <>)
steDoc (SynTerm n i ) = indexDoc i >>= return . magenta . (text (n^.getSteName) <>)
steDoc (Term n i ) = return . green . text $ n^.getSteName
steDoc (Epsilon ) = return . red . text $ "ε"
steDoc (Deletion ) = return . red . text $ "-"
indexDoc :: [Index] -> Reader Grammar Doc
indexDoc [] = return empty
indexDoc xs = fmap (encloseSep lbrace rbrace comma) . mapM iDoc $ xs
where iDoc (Index n i _ is s) = do ps <- asks _params
return $ (if n `M.member` ps then red else id) $ if (not $ null is)
then text $ _getIndexName n ++ "∈" ++ show is
else text $ _getIndexName n ++ "=" ++ show i
sDoc s | s==0 = empty
| s>=0 = text $ "+" ++ show s
| s< 0 = text $ show s
symbolDoc :: Symbol -> Reader Grammar Doc
symbolDoc (Symbol [x])
| SynVar _ _ n k <- x
, n > 1 = fmap (<> text "_" <> integer k) $ steDoc x
| otherwise = steDoc x
symbolDoc s@(Symbol xs )
| isAllSplit s = fmap (encloseSep langle rangle comma) . mapM steDoc $ xs
| otherwise = fmap list . mapM steDoc $ xs
printDoc :: Doc -> IO ()
printDoc d = displayIO stdout (renderPretty 0.8 160 $ d <> linebreak)