text-generic-pretty-1.2.1: src/Text/PrettyPrint/GenericStructure.hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
module Text.PrettyPrint.GenericStructure
( Structure(..)
, Generic
, displayStructure
, structure
) where
import qualified Data.HashMap.Strict
import qualified Data.IntMap
import Data.IxSet.Typed (Indexable)
import qualified Data.IxSet.Typed
import qualified Data.Map
import Data.String.Conversions (cs)
import qualified Data.Text as T
import Data.Text.Lazy (Text, append, fromStrict,
intercalate, singleton,
unlines, unwords)
import Data.Time
import GHC.Generics
import Protolude hiding (Text, bool,
intercalate, intersperse)
-- | The class 'Structure' is the equivalent of 'Prelude.Show'
--
-- It provides conversion of values to structure printable Structure.Text's.
--
class Structure a where
structure :: a -> Text
default structure :: (Generic a, GStructure (Rep a)) =>
a -> Text
structure x =
intercalate
"\n"
[ "structure begin"
, intercalate "\n" ((gstructure . from) x)
, "structure end"
]
-- structure x = case (gstructure . from) x of
-- (o:[]) -> o
-- os -> PP.list os
--'GStructure' is a helper class used to output the Sum-of-Products type, since it has kind *->*,
-- so can't be an instance of 'Structure'
class GStructure f
-- |'gstructure' is the (*->*) kind equivalent of 'docPrec'
where
gstructure :: f x -> [Text]
-- if empty, output nothing, this is a null constructor
instance GStructure U1 where
gstructure _ = ["M1 U Begin" <> "M1 U End"]
-- , append "datatypeName: " ((show . datatypeName) a)
-- , append "moduleName: " ((cs . moduleName) d)
-- , append "packageName: " ((cs . packageName) d)
-- , append "isNewtype: " ((show . isNewtype) d)
instance (GStructure f) =>
GStructure (M1 D c f) where
gstructure (M1 a) =
[ intercalate
"\n"
["M1 D Begin", intercalate "\n" (gstructure a), "M1 D End"]
]
instance (GStructure f, Selector c) =>
GStructure (M1 S c f) where
gstructure s@(M1 a) =
[ intercalate
"\n"
[ "M1 S Begin"
, "selName: " <> (cs . selName) s
, intercalate "\n" (gstructure a)
, "M1 S End"
]
]
-- constructor
-- here the real type and parens flag is set and propagated forward via t and n, the precedence factor is updated
instance (GStructure f, Constructor c) =>
GStructure (M1 C c f) where
gstructure c@(M1 a) =
[ intercalate
"\n"
[ "M1 C Begin"
, "conName: " <> (cs . conName) c
, "conFixity: " <> (show . conFixity) c
, "conIsRecord: " <> (show . conIsRecord) c
, intercalate "\n" (gstructure a)
, "M1 C End"
]
]
-- ignore tagging, call docPrec since these are concrete types
instance (Structure f) =>
GStructure (K1 t f) where
gstructure (K1 a) = [intercalate "\n" ["M1 K Begin", structure a, "M1 K End"]]
-- just continue to the corresponding side of the OR
instance (GStructure a, GStructure b) =>
GStructure (a :+: b) where
gstructure (L1 x) =
[ intercalate
"\n"
["M1 :+: L1 Begin", intercalate "\n" (gstructure x), "M1 :+: L1 End"]
]
gstructure (R1 x) =
[ intercalate
"\n"
["M1 :*: R1 Begin", intercalate "\n" (gstructure x), "M1 :*: R1 End"]
]
-- output both sides of the product, possible separated by a comma or an infix operator
instance (GStructure a, GStructure b) =>
GStructure (a :*: b) where
gstructure (x :*: y) =
[ intercalate
"\n"
[ "M1 :*: Begin"
, intercalate "\n" (gstructure x)
, ":*:"
, intercalate "\n" (gstructure y)
, "M1 :*: End"
]
]
instance Structure Char where
structure = singleton
instance Structure Text where
structure = identity
instance Structure T.Text where
structure = fromStrict
instance Structure Int where
structure = show
instance Structure Integer where
structure = show
instance Structure Float where
structure = show
instance Structure Double where
structure = show
instance Structure Rational where
structure = show
instance Structure Bool where
structure = show
instance Structure ByteString where
structure = cs
instance Structure a =>
Structure [a] where
structure = show . fmap structure
instance Structure a =>
Structure (Maybe a) where
structure Nothing = "Nothing"
structure (Just x) = "Just " <> structure x
instance (Structure a, Structure b) =>
Structure (Either a b) where
structure (Left x) = "Left " <> structure x
structure (Right y) = "Right " <> structure y
instance (Structure a, Structure b) =>
Structure (a, b) where
structure (a, b) =
"(" <> show (structure a) <> " , " <> show (structure b) <> ")"
instance (Structure a, Structure b) =>
Structure (Data.Map.Map a b) where
structure v = "fromList " <> structure v
instance Structure UTCTime where
structure = cs . formatTime defaultTimeLocale rfc822DateFormat
instance (Show a, Indexable ixs a) =>
Structure (Data.IxSet.Typed.IxSet ixs a) where
structure = show
instance Structure Word where
structure = (structure :: Integer -> Text) . fromIntegral
instance Structure Word8 where
structure = (structure :: Integer -> Text) . fromIntegral
instance Structure Word16 where
structure = (structure :: Integer -> Text) . fromIntegral
instance Structure Word32 where
structure = (structure :: Integer -> Text) . fromIntegral
instance Structure Word64 where
structure = (structure :: Integer -> Text) . fromIntegral
instance Structure Int8 where
structure = (structure :: Integer -> Text) . fromIntegral
instance Structure Int16 where
structure = (structure :: Integer -> Text) . fromIntegral
instance Structure Int32 where
structure = (structure :: Integer -> Text) . fromIntegral
instance Structure Int64 where
structure = (structure :: Integer -> Text) . fromIntegral
displayStructure
:: Structure a
=> a -> T.Text
displayStructure = toStrict . structure