FormalGrammars-0.2.0.0: FormalLanguage/CFG/PrettyPrint/Haskell.hs
-- | A PrettyPrinter that generates "almost useable" Haskell modules. The
-- signature and grammar are created but the algebras are (obviously) missing.
module FormalLanguage.CFG.PrettyPrint.Haskell
( grammarHaskell
) where
import Control.Lens
import Data.Function (on)
import Data.List (nub,sort,intersperse,nubBy,groupBy,foldl')
import qualified Data.Set as S
import System.IO (stdout)
import Text.PrettyPrint.ANSI.Leijen
import Text.Printf
import Control.Arrow hiding ((<+>))
import Prelude hiding ((<$>))
import FormalLanguage.CFG.Grammar
import FormalLanguage.CFG.Parser
-- | Render grammar
grammarHaskell :: Grammar -> Doc
grammarHaskell g = error "grammarHaskell" -- signatureD g <$> empty <$> grammarD g <$> empty <$> productD g
{-
signatureD :: Grammar -> Doc
signatureD = error "signatureD"
{-
signatureD g = hdr <$> indent 2 fns where
hdr = text $ printf "data Sig%s {-Monad-} m {-NT-} nt hResT {-T-} %s = Sig%s" (g^.grammarName) {- ns -} ts (g^.grammarName)
ns = concat . intersperse " " . nub . sort . map ntS . filter isSyntactic $ (g^..rules.folded.lhs) ++ (g^..rules.folded.rhs.folded)
ts = concat . intersperse " " . nub . sort
. map (view (name.getSteName)) . filter (\case (Term _ _) -> True ; z -> False)
$ g^..synterms.folded.getSymbolList.folded
-- es = concat . intersperse " " . map (addEps . view tnName) $ g^..epsis.folded
-- fns = encloseSep lbrace rbrace comma . map (text . concat) . (++[["h"]]) . nub . sort $ g^..rules.folded.fun
fns = encloseSep lbrace rbrace comma . (++[h]) . map ruleSigDoc . nubBy ((==) `on` _fun) . sort $ g^..rules.folded
h = text "h :: Data.Vector.Fusion.Stream.Monadic.Stream m nt -> m hResT"
-}
-- | Generate rule signatures for the 'Signature' data ctor.
--
-- TODO extend to allow classified dp (need more than one NT type)
ruleSigDoc :: Rule -> Doc
ruleSigDoc (Rule lhs fun rhs) =
text (concat fun) <+>
text "::" <+>
cat (punctuate (text " -> ") rs) <+>
text "-> nt"
where
rs = map tOrNt rhs
tOrNt r
{-
| isSymbE r = case (r^.symb) of
[x] -> text $ addEps $ x^.tnName
xs -> encloseSep (text "(Z:.") rparen (text ":.") $ map (text . addEps . view tnName) xs
-}
| isSyntactic r = text "nt"
| isTerminal r = case (r^.getSymbolList) of
[x] -> text $ x^.name
xs -> encloseSep (text "(Z:.") rparen (text ":.") $ map sigT xs
| otherwise = error $ "ruleSigDoc: " ++ show r
where sigT (Term s) = text s
sigT Epsilon = text "()" -- important, EMIT NOTHING emits @()@
ntS :: Symbol -> String
ntS (Symbol io []) = error "zero-dim symbol"
ntS (Symbol io xs) = "_" ++ concatMap (\x -> x^.name ++ addIndex x) xs
addIndex :: SynTermEps -> String
addIndex (SynVar _ []) = ""
addIndex (SynVar _ is) = show "???" ++ show is ++ "???"
addIndex _ = ""
-- |
--
-- TODO collect all rules with same lhs
grammarD :: Grammar -> Doc
grammarD g = text ("grammar" ++ g^.grammarName) <+>
text ("Sig" ++ g^.grammarName ++ "{..}") <+>
text "{-NT-}" <+> hsep (map (text . ntS) . nub . sort $ g^..rules.folded.lhs) <+>
text "{-T-}" <+> hsep (map (text . view name) . nub . sort
. filter (\case (Term _ _) -> True ; z -> False)
$ g^..synterms.folded.getSymbolList.folded) <+>
-- text "{-E-}" <+> hsep (map (text . addEps . view tnName) . nub . sort $ g^..epsis.folded) <+>
text "="<$>
indent 2 (tupled xs)
where
xs = map genForNT . groupBy ((==) `on` _lhs) $ g^..rules.folded
addEps "" = "eps"
addEps s = s
genForNT xs = tupled [l,r] where
l = text . ntS $ head xs ^. lhs
r = encloseSep empty (text " ... h") (text " ||| ") $ map genApp xs
genApp x = (text $ concat $ (undefined :: [String])) -- x^.getAttr)
<+> text "<<<"
<+> (encloseSep empty empty (text " % ") $ map genSymb $ x^.rhs)
genSymb x
{-
| isSymbE x = case (x^.symb) of
[z] -> text $ theName z
zs -> encloseSep (text "(Z:.") rparen (text ":.") $ map (text . theName) zs
-}
| isSyntactic x = text $ ntS x
| isTerminal x = case (x^.getSymbolList) of
[z] -> text $ theName z
zs -> encloseSep (text "(T:!") rparen (text ":!") $ map (text . theName) zs
where
theName (Epsilon e) = e^.getSteName
theName (Term s i ) = s^.getSteName
productD g = (text $ printf "(<**) f g = Sig%s" (g^.grammarName)) <$> indent 2 fs <$> bnd where
fs = encloseSep lbrace rbrace comma $ (map productFun . nubBy ((==) `on` _attr) . sort $ g^..rules.folded) ++ [h]
h = vcat $ map text
[ "h xs = do"
, " hfs <- _Fh . Data.Vector.Fusion.Stream.Monadic.map fst $ xs"
, " let phfs = Data.Vector.Fusion.Stream.Monadic.concatMapM snd"
, " . Data.Vector.Fusion.Stream.Monadic.filter ((hfs==) . fst) $ xs"
, " _Gh phfs"
]
bnd = indent 2 ((text "where") <$> indent 2 (bF <$> bG))
bF = vcat $ map (\f -> let z = concat $ (f^..attr.folded.getAttr) in text $ printf "_F%s = %s f" z z)
$ fnubs ++ [Rule undefined [Attr "h"] undefined]
bG = vcat $ map (\f -> let z = concat $ (f^..attr.folded.getAttr) in text $ printf "_G%s = %s g" z z)
$ fnubs ++ [Rule undefined [Attr "h"] undefined]
{-
bF = text (printf "Sig%s" (g^.name))
<> (encloseSep lbrace rbrace comma . map text . (++["h_F"]) . map (("_F"++) . concat . _fun) $ fnubs)
<> text " =f"
bG = text (printf "Sig%s" (g^.name))
<> (encloseSep lbrace rbrace comma . map text . (++["h_G"]) . map (("_G"++) . concat . _fun) $ fnubs)
<> text " =g"
-}
fnubs = nubBy ((==) `on` _attr) . sort $ g^..rules.folded
productFun (Rule l f rs) = text (concat $ f^..folded.getAttr) <> text " = \\" <> vars <> text " -> " <> parens (callF <> comma <> callG)
where
vars = hsep $ zipWith mkVars rs vs
callF = text (concat $ "_F" : (f^..folded.getAttr)) <+> (hcat . punctuate space . map text $ take (length rs) vs)
callG = let ns = map snd . filter (isSyntactic . fst) $ zip rs vs
in text . genS $ zip rs vs
vs = let az = ['a'..'z'] ; bs = [[]] ++ [ a:b | b<-bs, a<-az ] in drop 1 bs
mkVars r v
| isTerminal r = text v
| isSyntactic r = parens (text v <> comma <> text (v++"N"))
genS zs = let go (ns,as) (r,v)
| isTerminal r = (ns, as ++ [v])
| isSyntactic r = (ns++ [v++"N", ">>= Data.Vector.Fusion.Stream.Monadic.concatMap (\\", v, "->"], as ++ [v])
postAddBrackets = (++ (replicate (length . filter isSyntactic . map fst $ zs) ')'))
in postAddBrackets
. concat
. intersperse " "
. uncurry (++)
. foldl' go ([],["Data.Vector.Fusion.Stream.Monadic.singleton $", (concat $ "_S" : (f^..folded.getAttr))])
$ zs
{-
test = printDoc $ grammarHaskell asG where
printDoc :: Doc -> IO ()
printDoc d = displayIO stdout (renderPretty 0.8 160 $ d <> linebreak)
<<<<<<< HEAD
-}
-}