tdlib-gen-0.1.0: src/Language/Haskell/Codegen.hs
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedLabels #-}
module Language.Haskell.Codegen where
import Control.Lens
import Data.Generics.Labels ()
import Data.List
import Data.Map.Strict (Map)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Prettyprint.Doc
import Data.Text.Prettyprint.Doc.Internal
import GHC.Generics
type Ann = Maybe Text
io :: Type
io = Type "IO"
prettyDoc :: Ann -> Doc ann
prettyDoc (Just d) =
let ls = T.lines d
ds = fmap unsafeTextWithoutNewlines ls
in "-- |" <+> foldl1 (<>) (intersperse (line <> "--" <> line <> "--") ds) <> line
prettyDoc Nothing = mempty
data ADT
= ADT
{ name :: Text,
ann :: Ann,
constr :: [Constr],
mapping :: Map String String
}
deriving (Show, Eq, Generic)
prettyConstrs :: [Doc ann] -> Doc ann
prettyConstrs [] = mempty
prettyConstrs (x : xs) =
vsep
[ foldl1 (<>) (intersperse (line <> "| ") (("=" <+> x) : xs)),
"deriving (Show, Eq, Generic)"
]
instance Pretty ADT where
pretty ADT {..} =
let doc = prettyDoc ann
n = unsafeTextWithoutNewlines name
cs = fmap pretty constr
in doc
<> vsep
[ "data" <+> n,
indent 2 (prettyConstrs cs)
]
-- >>> pretty $ ADT "A" (Just "A") [Constr "A" Nothing [("a", Type "A"), ("b", Type "A")], Constr "B" Nothing []]
data Field
= Field
{ name :: Text,
ann :: Ann,
ty :: Type
}
deriving (Show, Eq, Generic)
instance Pretty Field where
pretty Field {..} =
prettyDoc ann
<> unsafeTextWithoutNewlines name <+> "::" <+> pretty ty
data Constr
= Constr
{ name :: Text,
ann :: Ann,
fields :: [Field]
}
deriving (Show, Eq, Generic)
instance Pretty Constr where
pretty Constr {..} =
let doc = prettyDoc ann
n = unsafeTextWithoutNewlines name
fs = foldl (<>) mempty (intersperse ("," <> line) (fmap pretty fields))
in doc
<> vsep
[ n,
indent 2 ("{" <+> align fs <> line <> "}")
]
data Type
= Type Text
| Arr Type Type
| App Type Type
deriving (Show, Eq, Generic)
instance Pretty Type where
pretty (Type t) = unsafeTextWithoutNewlines t
pretty (Arr ty ty') = pretty ty <+> "->" <+> pretty ty'
pretty (App tyCon ty) = "(" <> pretty tyCon <> ")" <+> "(" <> pretty ty <> ")"
data TypeSig
= Result
{ ty :: Type,
ann :: Ann
}
| Conn
{ ty :: Type,
ann :: Ann,
name :: Text,
res :: TypeSig
}
deriving (Show, Eq, Generic)
instance Pretty TypeSig where
pretty (Result ty doc) =
prettyDoc doc <> pretty (App io ty)
pretty (Conn ty doc _ res) =
prettyDoc doc
<> vsep
[ pretty ty <+> "->",
pretty res
]
data FunDef
= FunDef
{ name :: Text,
ann :: Ann,
constr :: Constr,
res :: Type
}
deriving (Show, Eq, Generic)
instance Pretty FunDef where
pretty FunDef {..} =
let doc = prettyDoc ann
n = unsafeTextWithoutNewlines name
cmd = unsafeTextWithoutNewlines (constr ^. #name)
resTy = pretty res
in doc
<> vsep
[ n <+> "::" <+> "Member TDLib r" <+> "=>" <+> cmd <+> "->" <+> "Sem r (Error :+: " <> resTy <> ")",
n <+> "=" <+> "runCmd"
]