{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Trustworthy #-}
module Generic.Data.Internal.Read where
import Data.Coerce
import Data.Functor.Classes (Read1(..))
import Data.Functor.Identity
import Data.Proxy
import Generic.Data.Internal.Utils (isSymDataCon, isSymVar)
import GHC.Generics hiding (prec)
import GHC.Read (expectP, list)
import GHC.Show (appPrec, appPrec1)
import Text.ParserCombinators.ReadPrec
import Text.Read (Read(..), parens)
import Text.Read.Lex (Lexeme(..))
greadPrec :: (Generic a, GRead0 (Rep a)) => ReadPrec a
greadPrec = to <$> gPrecRead Proxy
type GRead0 = GRead Proxy
gliftReadPrec
:: (Generic1 f, GRead1 (Rep1 f))
=> ReadPrec a -> ReadPrec [a]
-> ReadPrec (f a)
gliftReadPrec readPrec' readList' =
to1 <$> gPrecRead (Identity (readPrec', readList'))
type GRead1 = GRead Identity
class GRead p f where
gPrecRead :: p (ReadPrec a, ReadPrec [a]) -> ReadPrec (f a)
instance (GRead p f, IsNullaryDataType f) => GRead p (M1 D d f) where
gPrecRead p = coerceM1 (parensIfNonNullary (gPrecRead p))
where
x :: f a
x = undefined
parensIfNonNullary :: ReadPrec a -> ReadPrec a
parensIfNonNullary = if isNullaryDataType x
then id
else parens
instance (GRead p f, GRead p g) => GRead p (f :+: g) where
gPrecRead p = fmap L1 (gPrecRead p) +++ fmap R1 (gPrecRead p)
instance (Constructor c, GReadC p c f) => GRead p (M1 C c f) where
gPrecRead p = gPrecReadC p (conName x) (conFixity x)
where
x :: M1 C c f a
x = undefined
instance GRead p V1 where
gPrecRead _ = pfail
class IsNullaryDataType f where
isNullaryDataType :: f a -> Bool
instance IsNullaryDataType (f :+: g) where
isNullaryDataType _ = False
instance IsNullaryDataType (C1 c f) where
isNullaryDataType _ = False
instance IsNullaryDataType V1 where
isNullaryDataType _ = True
class GReadC p c f where
gPrecReadC :: p (ReadPrec a, ReadPrec [a]) -> String -> Fixity -> ReadPrec (M1 C c f a)
instance GReadFields p f => GReadC p ('MetaCons s y 'False) f where
gPrecReadC :: forall a. p (ReadPrec a, ReadPrec [a]) -> String -> Fixity
-> ReadPrec (M1 C ('MetaCons s y 'False) f a)
gPrecReadC p name fixity
| Infix _ fy <- fixity, Branch k1 k2 <- fields
= coerceM1 $ prec fy $ do
k1' <- toReadPrec k1
if isSymDataCon name
then expectP (Symbol name)
else mapM_ expectP ([Punc "`"] ++ identHLexemes name ++ [Punc "`"])
k2' <- toReadPrec k2
pure (k1' :*: k2')
| otherwise
= coerceM1 $ prec appPrec $ do
readPrefixCon name
toReadPrec fields
where
fields :: ReadPrecTree (f a)
fields = gPrecReadFields p
instance GReadNamed p f => GReadC p ('MetaCons s y 'True) f where
gPrecReadC p name _fixity = coerceM1 $ prec appPrec1 $ do
readPrefixCon name
readSurround '{' fields '}'
where
fields = gPrecReadNamed p
class GReadFields p f where
gPrecReadFields :: p (ReadPrec a, ReadPrec [a]) -> ReadPrecTree (f a)
instance (GReadFields p f, GReadFields p g) => GReadFields p (f :*: g) where
gPrecReadFields p = Branch (gPrecReadFields p) (gPrecReadFields p)
instance GReadSingle p f => GReadFields p (M1 S c f) where
gPrecReadFields p = M1Leaf (step (gPrecReadSingle p))
instance GReadFields p U1 where
gPrecReadFields _ = U1Leaf
class GReadNamed p f where
gPrecReadNamed :: p (ReadPrec a, ReadPrec [a]) -> ReadPrec (f a)
instance (GReadNamed p f, GReadNamed p g) => GReadNamed p (f :*: g) where
gPrecReadNamed p = do
l <- gPrecReadNamed p
expectP (Punc ",")
r <- gPrecReadNamed p
pure (l :*: r)
instance (Selector c, GReadSingle p f) => GReadNamed p (M1 S c f) where
gPrecReadNamed p = coerceM1 $ do
mapM_ expectP snameLexemes
expectP (Punc "=")
reset (gPrecReadSingle p)
where
x :: M1 S c f a
x = undefined
sname :: String
sname = selName x
snameLexemes :: [Lexeme]
snameLexemes | isSymVar sname
= [Punc "(", Symbol sname, Punc ")"]
| otherwise
= identHLexemes sname
instance GReadNamed p U1 where
gPrecReadNamed _ = pure U1
class GReadSingle p f where
gPrecReadSingle :: p (ReadPrec a, ReadPrec [a]) -> ReadPrec (f a)
instance Read a => GReadSingle p (K1 i a) where
gPrecReadSingle _ = coerceK1 readPrec
where
coerceK1 :: ReadPrec a -> ReadPrec (K1 i a x)
coerceK1 = coerce
instance Read1 f => GReadSingle Identity (Rec1 f) where
gPrecReadSingle (Identity p) = coerceRec1 (liftReadPrecCompat p)
where
coerceRec1 :: ReadPrec (f a) -> ReadPrec (Rec1 f a)
coerceRec1 = coerce
instance GReadSingle Identity Par1 where
gPrecReadSingle (Identity (readPrec', _)) = coercePar1 readPrec'
where
coercePar1 :: ReadPrec p -> ReadPrec (Par1 p)
coercePar1 = coerce
instance (Read1 f, GReadSingle p g) => GReadSingle p (f :.: g) where
gPrecReadSingle :: forall a. p (ReadPrec a, ReadPrec [a]) -> ReadPrec ((f :.: g) a)
gPrecReadSingle p = coerceComp1 (liftReadPrecCompat (readPrec_, readList_))
where
readPrec_ :: ReadPrec (g a)
readPrec_ = gPrecReadSingle p
readList_ :: ReadPrec [g a]
readList_ = list readPrec_
coerceComp1 :: ReadPrec (f (g a)) -> ReadPrec ((f :.: g) a)
coerceComp1 = coerce
coerceM1 :: ReadPrec (f p) -> ReadPrec (M1 i c f p)
coerceM1 = coerce
liftReadPrecCompat :: Read1 f => (ReadPrec a, ReadPrec [a]) -> ReadPrec (f a)
liftReadPrecCompat (readPrec', readList') =
#if MIN_VERSION_base(4,10,0)
liftReadPrec readPrec' readList'
#else
readS_to_Prec (liftReadsPrec (readPrec_to_S readPrec')
(readPrec_to_S readList' 0))
#endif
data ReadPrecTree a where
U1Leaf :: ReadPrecTree (U1 a)
M1Leaf :: ReadPrec (f a) -> ReadPrecTree (M1 i c f a)
Branch :: ReadPrecTree (f a) -> ReadPrecTree (g a) -> ReadPrecTree ((f :*: g) a)
toReadPrec :: ReadPrecTree a -> ReadPrec a
toReadPrec U1Leaf = pure U1
toReadPrec (M1Leaf f) = coerceM1 f
toReadPrec (Branch f g) = (:*:) <$> toReadPrec f <*> toReadPrec g
identHLexemes :: String -> [Lexeme]
identHLexemes s | Just (ss, '#') <- snocView s = [Ident ss, Symbol "#"]
| otherwise = [Ident s]
readPrefixCon :: String -> ReadPrec ()
readPrefixCon name
| isSymDataCon name
= readSurround '(' (expectP (Symbol name)) ')'
| otherwise
= mapM_ expectP (identHLexemes name)
readSurround :: Char -> ReadPrec a -> Char -> ReadPrec a
readSurround c1 r c2 = do
expectP (Punc [c1])
r' <- r
expectP (Punc [c2])
pure r'
snocView :: [a] -> Maybe ([a], a)
snocView [] = Nothing
snocView xs = go [] xs
where
go acc [a] = Just (reverse acc, a)
go acc (a:as) = go (a:acc) as
go _ [] = error "Util: snocView"