{-# LANGUAGE CPP             #-}
{-# LANGUAGE LambdaCase      #-}
{-# LANGUAGE TemplateHaskell #-}
module Free.Scoped.TH where

import           Control.Monad       (replicateM)
import           Free.Scoped
import           Language.Haskell.TH

mkConP :: Name -> [Pat] -> Pat
#if __GLASGOW_HASKELL__ >= 902
mkConP :: Name -> [Pat] -> Pat
mkConP Name
name [Pat]
pats = Name -> [Type] -> [Pat] -> Pat
ConP Name
name [] [Pat]
pats
#else
mkConP name pats = ConP name pats
#endif

makePatternsAll :: Name -> Q [Dec]
makePatternsAll :: Name -> Q [Dec]
makePatternsAll Name
ty = do
  TyConI Dec
tyCon <- Name -> Q Info
reify Name
ty
  case Dec
tyCon of
    DataD [Type]
_ Name
_ [TyVarBndr ()]
_ Maybe Type
_ [Con]
cs [DerivClause]
_ -> [[Dec]] -> [Dec]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Dec]] -> [Dec]) -> Q [[Dec]] -> Q [Dec]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
      [[Dec]]
xs <- (Con -> Q [Dec]) -> [Con] -> Q [[Dec]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Con -> Q [Dec]
makePatternFor [Con]
cs
      [Dec]
xs' <- [Con] -> Q [Dec]
makeCompletePragma [Con]
cs
      [[Dec]]
ys <- (Con -> Q [Dec]) -> [Con] -> Q [[Dec]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Con -> Q [Dec]
makePatternEFor [Con]
cs
      [Dec]
ys' <- [Con] -> Q [Dec]
makeCompletePragmaE [Con]
cs
      [[Dec]]
zs <- (Con -> Q [Dec]) -> [Con] -> Q [[Dec]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Con -> Q [Dec]
makePatternTFor [Con]
cs
      [Dec]
zs' <- [Con] -> Q [Dec]
makeCompletePragmaT [Con]
cs
      [[Dec]]
ws <- (Con -> Q [Dec]) -> [Con] -> Q [[Dec]]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Con -> Q [Dec]
makePatternTEFor [Con]
cs
      [Dec]
ws' <- [Con] -> Q [Dec]
makeCompletePragmaTE [Con]
cs
      [[Dec]] -> Q [[Dec]]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return ([[Dec]]
xs [[Dec]] -> [[Dec]] -> [[Dec]]
forall a. [a] -> [a] -> [a]
++ [[Dec]
xs'] [[Dec]] -> [[Dec]] -> [[Dec]]
forall a. [a] -> [a] -> [a]
++ [[Dec]]
ys [[Dec]] -> [[Dec]] -> [[Dec]]
forall a. [a] -> [a] -> [a]
++ [[Dec]
ys'] [[Dec]] -> [[Dec]] -> [[Dec]]
forall a. [a] -> [a] -> [a]
++ [[Dec]]
zs [[Dec]] -> [[Dec]] -> [[Dec]]
forall a. [a] -> [a] -> [a]
++ [[Dec]
zs'] [[Dec]] -> [[Dec]] -> [[Dec]]
forall a. [a] -> [a] -> [a]
++ [[Dec]]
ws [[Dec]] -> [[Dec]] -> [[Dec]]
forall a. [a] -> [a] -> [a]
++ [[Dec]
ws'])

    Dec
_                  -> String -> Q [Dec]
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Can only make patterns for data types."


makeCompletePragma :: [Con] -> Q [Dec]
makeCompletePragma :: [Con] -> Q [Dec]
makeCompletePragma [Con]
cs = do
  DataConI Name
varName Type
_ Name
_ <- Name -> Q Info
reify 'Pure
  let names :: [Name]
names = [String -> Name
mkName (String -> String
forall {a}. [a] -> [a]
removeF (Name -> String
nameBase Name
name)) | NormalC Name
name [BangType]
_ <- [Con]
cs]
  [Dec] -> Q [Dec]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return [Pragma -> Dec
PragmaD ([Name] -> Maybe Name -> Pragma
CompleteP (Name
varName Name -> [Name] -> [Name]
forall a. a -> [a] -> [a]
: [Name]
names) Maybe Name
forall a. Maybe a
Nothing)]
  where
    removeF :: [a] -> [a]
removeF [a]
s = Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take ([a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) [a]
s

makeCompletePragmaE :: [Con] -> Q [Dec]
makeCompletePragmaE :: [Con] -> Q [Dec]
makeCompletePragmaE [Con]
cs = do
  DataConI Name
varName Type
_ Name
_ <- Name -> Q Info
reify 'Pure
  PatSynI Name
extName Type
_ <- Name -> Q Info
reify 'ExtE
  let names :: [Name]
names = [String -> Name
mkName (String -> String
removeF (Name -> String
nameBase Name
name)) | NormalC Name
name [BangType]
_ <- [Con]
cs]
  [Dec] -> Q [Dec]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return [Pragma -> Dec
PragmaD ([Name] -> Maybe Name -> Pragma
CompleteP (Name
varName Name -> [Name] -> [Name]
forall a. a -> [a] -> [a]
: Name
extName Name -> [Name] -> [Name]
forall a. a -> [a] -> [a]
: [Name]
names) Maybe Name
forall a. Maybe a
Nothing)]
  where
    removeF :: String -> String
removeF String
s = Int -> String -> String
forall a. Int -> [a] -> [a]
take (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) String
s String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"E"

makeCompletePragmaT :: [Con] -> Q [Dec]
makeCompletePragmaT :: [Con] -> Q [Dec]
makeCompletePragmaT [Con]
cs = do
  DataConI Name
varName Type
_ Name
_ <- Name -> Q Info
reify 'Pure
  let names :: [Name]
names = [String -> Name
mkName (String -> String
removeF (Name -> String
nameBase Name
name)) | NormalC Name
name [BangType]
_ <- [Con]
cs]
  [Dec] -> Q [Dec]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return [Pragma -> Dec
PragmaD ([Name] -> Maybe Name -> Pragma
CompleteP (Name
varName Name -> [Name] -> [Name]
forall a. a -> [a] -> [a]
: [Name]
names) Maybe Name
forall a. Maybe a
Nothing)]
  where
    removeF :: String -> String
removeF String
s = Int -> String -> String
forall a. Int -> [a] -> [a]
take (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) String
s String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"T"

makeCompletePragmaTE :: [Con] -> Q [Dec]
makeCompletePragmaTE :: [Con] -> Q [Dec]
makeCompletePragmaTE [Con]
cs = do
  DataConI Name
varName Type
_ Name
_ <- Name -> Q Info
reify 'Pure
  let names :: [Name]
names = [String -> Name
mkName (String -> String
removeF (Name -> String
nameBase Name
name)) | NormalC Name
name [BangType]
_ <- [Con]
cs]
  [Dec] -> Q [Dec]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return [Pragma -> Dec
PragmaD ([Name] -> Maybe Name -> Pragma
CompleteP (Name
varName Name -> [Name] -> [Name]
forall a. a -> [a] -> [a]
: [Name]
names) Maybe Name
forall a. Maybe a
Nothing)]
  where
    removeF :: String -> String
removeF String
s = Int -> String -> String
forall a. Int -> [a] -> [a]
take (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) String
s String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"TE"

makePatternFor :: Con -> Q [Dec]
makePatternFor :: Con -> Q [Dec]
makePatternFor = \case
  NormalC Name
name [BangType]
xs -> do
    [Name]
args <- Int -> Q Name -> Q [Name]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM ([BangType] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [BangType]
xs) (String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"x")
    let patName :: Name
patName = String -> Name
mkName (String -> String
forall {a}. [a] -> [a]
removeF (Name -> String
nameBase Name
name))
        patArgs :: PatSynArgs
patArgs = [Name] -> PatSynArgs
PrefixPatSyn [Name]
args
        dir :: PatSynDir
dir = PatSynDir
ImplBidir
    Pat
pat <- [p| Free $(Pat -> Q Pat
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Name -> [Pat] -> Pat
mkConP Name
name (Name -> Pat
VarP (Name -> Pat) -> [Name] -> [Pat]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Name]
args))) |]
    [Dec] -> Q [Dec]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return [Name -> PatSynArgs -> PatSynDir -> Pat -> Dec
PatSynD Name
patName PatSynArgs
patArgs PatSynDir
dir Pat
pat]
  Con
_ -> String -> Q [Dec]
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Can only make patterns for NormalC constructors"
  where
    removeF :: [a] -> [a]
removeF [a]
s = Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take ([a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) [a]
s

makePatternEFor :: Con -> Q [Dec]
makePatternEFor :: Con -> Q [Dec]
makePatternEFor = \case
  NormalC Name
name [BangType]
xs -> do
    [Name]
args <- Int -> Q Name -> Q [Name]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM ([BangType] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [BangType]
xs) (String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"x")
    let patName :: Name
patName = String -> Name
mkName (String -> String
removeF (Name -> String
nameBase Name
name))
        patArgs :: PatSynArgs
patArgs = [Name] -> PatSynArgs
PrefixPatSyn [Name]
args
        dir :: PatSynDir
dir = PatSynDir
ImplBidir
    Pat
pat <- [p| Free (InL $(Pat -> Q Pat
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Name -> [Pat] -> Pat
mkConP Name
name (Name -> Pat
VarP (Name -> Pat) -> [Name] -> [Pat]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Name]
args)))) |]
    [Dec] -> Q [Dec]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return [Name -> PatSynArgs -> PatSynDir -> Pat -> Dec
PatSynD Name
patName PatSynArgs
patArgs PatSynDir
dir Pat
pat]
  Con
_ -> String -> Q [Dec]
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Can only make patterns for NormalC constructors"
  where
    removeF :: String -> String
removeF String
s = Int -> String -> String
forall a. Int -> [a] -> [a]
take (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) String
s String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"E"

makePatternTFor :: Con -> Q [Dec]
makePatternTFor :: Con -> Q [Dec]
makePatternTFor = \case
  NormalC Name
name [BangType]
xs -> do
    Name
t <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"type_"
    [Name]
args <- Int -> Q Name -> Q [Name]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM ([BangType] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [BangType]
xs) (String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"x")
    let patName :: Name
patName = String -> Name
mkName (String -> String
removeF (Name -> String
nameBase Name
name))
        patArgs :: PatSynArgs
patArgs = [Name] -> PatSynArgs
PrefixPatSyn (Name
t Name -> [Name] -> [Name]
forall a. a -> [a] -> [a]
: [Name]
args)
        dir :: PatSynDir
dir = PatSynDir
ImplBidir
    Pat
pat <- [p| Free (AnnF $(Pat -> Q Pat
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Name -> Pat
VarP Name
t)) $(Pat -> Q Pat
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Name -> [Pat] -> Pat
mkConP Name
name (Name -> Pat
VarP (Name -> Pat) -> [Name] -> [Pat]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Name]
args)))) |]
    [Dec] -> Q [Dec]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return [Name -> PatSynArgs -> PatSynDir -> Pat -> Dec
PatSynD Name
patName PatSynArgs
patArgs PatSynDir
dir Pat
pat]
  Con
_ -> String -> Q [Dec]
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Can only make patterns for NormalC constructors"
  where
    removeF :: String -> String
removeF String
s = Int -> String -> String
forall a. Int -> [a] -> [a]
take (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) String
s String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"T"

makePatternTEFor :: Con -> Q [Dec]
makePatternTEFor :: Con -> Q [Dec]
makePatternTEFor = \case
  NormalC Name
name [BangType]
xs -> do
    Name
t <- String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"type_"
    [Name]
args <- Int -> Q Name -> Q [Name]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM ([BangType] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [BangType]
xs) (String -> Q Name
forall (m :: * -> *). Quote m => String -> m Name
newName String
"x")
    let patName :: Name
patName = String -> Name
mkName (String -> String
removeF (Name -> String
nameBase Name
name))
        patArgs :: PatSynArgs
patArgs = [Name] -> PatSynArgs
PrefixPatSyn (Name
t Name -> [Name] -> [Name]
forall a. a -> [a] -> [a]
: [Name]
args)
        dir :: PatSynDir
dir = PatSynDir
ImplBidir
    Pat
pat <- [p| Free (InL (AnnF $(Pat -> Q Pat
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Name -> Pat
VarP Name
t)) $(Pat -> Q Pat
forall a. a -> Q a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Name -> [Pat] -> Pat
mkConP Name
name (Name -> Pat
VarP (Name -> Pat) -> [Name] -> [Pat]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Name]
args))))) |]
    [Dec] -> Q [Dec]
forall a. a -> Q a
forall (m :: * -> *) a. Monad m => a -> m a
return [Name -> PatSynArgs -> PatSynDir -> Pat -> Dec
PatSynD Name
patName PatSynArgs
patArgs PatSynDir
dir Pat
pat]
  Con
_ -> String -> Q [Dec]
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Can only make patterns for NormalC constructors"
  where
    removeF :: String -> String
removeF String
s = Int -> String -> String
forall a. Int -> [a] -> [a]
take (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) String
s String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
"TE"