packages feed

Frames-0.7.4: test/PrettyTH.hs

{-# LANGUAGE OverloadedStrings #-}
module PrettyTH where
import Data.Char (isSpace)
import Frames
import Language.Haskell.TH
import Language.Haskell.TH.PprLib
import Text.PrettyPrint
import Text.Regex.Applicative

import Temp

generateCode :: String -> String -> Q Exp
generateCode rowName txt =
    withTempContents
      txt
      (\fp -> tableTypes rowName fp
              >>= stringE
              . makePretty
              . renderStyle (style {ribbonsPerLine=1.0, lineLength=150})
              . to_HPJ_Doc . ppr)

-- | Make template haskell-generated code more readable by
-- unqualifying common names, making type operators infix, erasing
-- inferable types, and adding a bit of whitespace.
makePretty :: String -> String
makePretty = -- Add new lines before type synonym definitions
             replace' "\ntype " "\n\ntype "
             -- Make :-> and ': type operators infix
             . (!! 10) . iterate (replace infixCons)
             . replace infixNil
             . replace infixCol
               -- Erase inferable type
             . replace ((\x y -> x ++ " ∈ " ++ y)
                        <$> ("RElem " *> some (psym (not . isSpace)))
                        <*> ((some (psym isSpace) *> some (psym (not . isSpace)))
                             <* " (RIndex " <* some (psym (/= ')')) <* ")"))
               -- Unqualify names
             . replace' "Frames.CSV.ParserOptions" "ParserOptions"
             . replace' "GHC.Maybe." ""
             . replace' "GHC.Base." ""
             . replace' "GHC.Types." ""
             . replace' "Data.Vinyl.Core." ""
             . replace' "Data.Vinyl.Derived." ""
             . replace' "Data.Vinyl.Lens." ""
             . replace' "Data.Vinyl.TypeLevel." ""
             . replace' "Frames.Rec." ""
             . replace' "Frames.RecLens." ""
             . replace' "Data.Proxy." ""
             . replace' "Data.Text." "T."
             . replace' "Data.Text.Internal." "T."
             . replace' "'GHC.Types.:" "(':)"
  where replace' orig replacement = replace (replacement <$ string orig)
        infixCol = (\x y -> '"' : x ++ "\" :-> " ++ y)
                   <$> ("(Frames.Col.:->) \"" *> (some (psym (/= '"'))) <* "\""
                        <* some (psym isSpace))
                   <*> some (psym (/= ' '))
        infixNil = (\x -> '[' : x ++ "]")
                   <$> ("('(:) " *> some (psym (/= ' '))
                        <* some (psym isSpace) <* "'[])")
        infixCons = (\x y -> '[' : x ++ ", " ++ y ++ "]")
                    <$> ("('(:) " *> some (psym (/= ' '))
                         <* some (psym isSpace) <* "[")
                    <*> (some (psym (/= ']')) <* "])")