-- | 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 -} -}