{-# LANGUAGE CPP #-}
#ifdef TRUSTWORTHY
# if MIN_VERSION_template_haskell(2,12,0)
{-# LANGUAGE Safe #-}
# else
{-# LANGUAGE Trustworthy #-}
# endif
#endif

#ifndef MIN_VERSION_template_haskell
#define MIN_VERSION_template_haskell(x,y,z) (defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 706)
#endif

#ifndef MIN_VERSION_containers
#define MIN_VERSION_containers(x,y,z) 1
#endif

#ifndef MIN_VERSION_base
#define MIN_VERSION_base(x,y,z) 1
#endif
-----------------------------------------------------------------------------
-- |
-- Module      :  Control.Lens.Internal.TH
-- Copyright   :  (C) 2013-2016 Edward Kmett and Eric Mertens
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
-- Stability   :  experimental
-- Portability :  non-portable
--
----------------------------------------------------------------------------
module Control.Lens.Internal.TH where

import Data.Functor.Contravariant
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import qualified Data.Map as Map
import qualified Data.Set as Set
#ifndef CURRENT_PACKAGE_KEY
import Data.Version (showVersion)
import Paths_lens (version)
#endif

-- | Apply arguments to a type constructor
appsT :: TypeQ -> [TypeQ] -> TypeQ
appsT :: TypeQ -> [TypeQ] -> TypeQ
appsT = (TypeQ -> TypeQ -> TypeQ) -> TypeQ -> [TypeQ] -> TypeQ
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl TypeQ -> TypeQ -> TypeQ
appT

-- | Apply arguments to a function
appsE1 :: ExpQ -> [ExpQ] -> ExpQ
appsE1 :: ExpQ -> [ExpQ] -> ExpQ
appsE1 = (ExpQ -> ExpQ -> ExpQ) -> ExpQ -> [ExpQ] -> ExpQ
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl ExpQ -> ExpQ -> ExpQ
appE

-- | Construct a tuple type given a list of types.
toTupleT :: [TypeQ] -> TypeQ
toTupleT :: [TypeQ] -> TypeQ
toTupleT [x :: TypeQ
x] = TypeQ
x
toTupleT xs :: [TypeQ]
xs = TypeQ -> [TypeQ] -> TypeQ
appsT (Int -> TypeQ
tupleT ([TypeQ] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [TypeQ]
xs)) [TypeQ]
xs

-- | Construct a tuple value given a list of expressions.
toTupleE :: [ExpQ] -> ExpQ
toTupleE :: [ExpQ] -> ExpQ
toTupleE [x :: ExpQ
x] = ExpQ
x
toTupleE xs :: [ExpQ]
xs = [ExpQ] -> ExpQ
tupE [ExpQ]
xs

-- | Construct a tuple pattern given a list of patterns.
toTupleP :: [PatQ] -> PatQ
toTupleP :: [PatQ] -> PatQ
toTupleP [x :: PatQ
x] = PatQ
x
toTupleP xs :: [PatQ]
xs = [PatQ] -> PatQ
tupP [PatQ]
xs

-- | Apply arguments to a type constructor.
conAppsT :: Name -> [Type] -> Type
conAppsT :: Name -> [Type] -> Type
conAppsT conName :: Name
conName = (Type -> Type -> Type) -> Type -> [Type] -> Type
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Type -> Type -> Type
AppT (Name -> Type
ConT Name
conName)


-- | Return 'Name' contained in a 'TyVarBndr'.
bndrName :: TyVarBndr -> Name
bndrName :: TyVarBndr -> Name
bndrName (PlainTV  n :: Name
n  ) = Name
n
bndrName (KindedTV n :: Name
n _) = Name
n

fromSet :: (k -> v) -> Set.Set k -> Map.Map k v
#if MIN_VERSION_containers(0,5,0)
fromSet :: (k -> v) -> Set k -> Map k v
fromSet = (k -> v) -> Set k -> Map k v
forall k a. (k -> a) -> Set k -> Map k a
Map.fromSet
#else
fromSet f x = Map.fromDistinctAscList [ (k,f k) | k <- Set.toAscList x ]
#endif

-- | Generate many new names from a given base name.
newNames :: String {- ^ base name -} -> Int {- ^ count -} -> Q [Name]
newNames :: String -> Int -> Q [Name]
newNames base :: String
base n :: Int
n = [Q Name] -> Q [Name]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [ String -> Q Name
newName (String
baseString -> String -> String
forall a. [a] -> [a] -> [a]
++Int -> String
forall a. Show a => a -> String
show Int
i) | Int
i <- [1..Int
n] ]

-- | Decompose an applied type into its individual components. For example, this:
--
-- @
-- Either Int Char
-- @
--
-- would be unfolded to this:
--
-- @
-- ('ConT' ''Either, ['ConT' ''Int, 'ConT' ''Char])
-- @
--
-- This function ignores explicit parentheses and visible kind applications.
unfoldType :: Type -> (Type, [Type])
unfoldType :: Type -> (Type, [Type])
unfoldType = [Type] -> Type -> (Type, [Type])
go []
  where
    go :: [Type] -> Type -> (Type, [Type])
    go :: [Type] -> Type -> (Type, [Type])
go acc :: [Type]
acc (ForallT _ _ ty :: Type
ty) = [Type] -> Type -> (Type, [Type])
go [Type]
acc Type
ty
    go acc :: [Type]
acc (AppT ty1 :: Type
ty1 ty2 :: Type
ty2)   = [Type] -> Type -> (Type, [Type])
go (Type
ty2Type -> [Type] -> [Type]
forall a. a -> [a] -> [a]
:[Type]
acc) Type
ty1
    go acc :: [Type]
acc (SigT ty :: Type
ty _)      = [Type] -> Type -> (Type, [Type])
go [Type]
acc Type
ty
#if MIN_VERSION_template_haskell(2,11,0)
    go acc :: [Type]
acc (ParensT ty :: Type
ty)     = [Type] -> Type -> (Type, [Type])
go [Type]
acc Type
ty
#endif
#if MIN_VERSION_template_haskell(2,15,0)
    go acc :: [Type]
acc (AppKindT ty :: Type
ty _)  = [Type] -> Type -> (Type, [Type])
go [Type]
acc Type
ty
#endif
    go acc :: [Type]
acc ty :: Type
ty               = (Type
ty, [Type]
acc)

------------------------------------------------------------------------
-- Manually quoted names
------------------------------------------------------------------------
-- By manually generating these names we avoid needing to use the
-- TemplateHaskell language extension when compiling the lens library.
-- This allows the library to be used in stage1 cross-compilers.

lensPackageKey         :: String
#ifdef CURRENT_PACKAGE_KEY
lensPackageKey :: String
lensPackageKey          = CURRENT_PACKAGE_KEY
#else
lensPackageKey          = "lens-" ++ showVersion version
#endif

mkLensName_tc          :: String -> String -> Name
mkLensName_tc :: String -> String -> Name
mkLensName_tc           = String -> String -> String -> Name
mkNameG_tc String
lensPackageKey

mkLensName_v           :: String -> String -> Name
mkLensName_v :: String -> String -> Name
mkLensName_v            = String -> String -> String -> Name
mkNameG_v String
lensPackageKey

traversalTypeName      :: Name
traversalTypeName :: Name
traversalTypeName       = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Traversal"

traversal'TypeName     :: Name
traversal'TypeName :: Name
traversal'TypeName      = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Traversal'"

lensTypeName           :: Name
lensTypeName :: Name
lensTypeName            = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Lens"

lens'TypeName          :: Name
lens'TypeName :: Name
lens'TypeName           = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Lens'"

isoTypeName            :: Name
isoTypeName :: Name
isoTypeName             = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Iso"

iso'TypeName           :: Name
iso'TypeName :: Name
iso'TypeName            = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Iso'"

getterTypeName         :: Name
getterTypeName :: Name
getterTypeName          = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Getter"

foldTypeName           :: Name
foldTypeName :: Name
foldTypeName            = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Fold"

prismTypeName          :: Name
prismTypeName :: Name
prismTypeName           = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Prism"

prism'TypeName         :: Name
prism'TypeName :: Name
prism'TypeName          = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Prism'"

reviewTypeName          :: Name
reviewTypeName :: Name
reviewTypeName           = String -> String -> Name
mkLensName_tc "Control.Lens.Type" "Review"

wrappedTypeName         :: Name
wrappedTypeName :: Name
wrappedTypeName          = String -> String -> Name
mkLensName_tc "Control.Lens.Wrapped" "Wrapped"

unwrappedTypeName       :: Name
unwrappedTypeName :: Name
unwrappedTypeName        = String -> String -> Name
mkLensName_tc "Control.Lens.Wrapped" "Unwrapped"

rewrappedTypeName       :: Name
rewrappedTypeName :: Name
rewrappedTypeName        = String -> String -> Name
mkLensName_tc "Control.Lens.Wrapped" "Rewrapped"

_wrapped'ValName        :: Name
_wrapped'ValName :: Name
_wrapped'ValName         = String -> String -> Name
mkLensName_v "Control.Lens.Wrapped" "_Wrapped'"

isoValName              :: Name
isoValName :: Name
isoValName               = String -> String -> Name
mkLensName_v "Control.Lens.Iso" "iso"

prismValName            :: Name
prismValName :: Name
prismValName             = String -> String -> Name
mkLensName_v "Control.Lens.Prism" "prism"

untoValName             :: Name
untoValName :: Name
untoValName              = String -> String -> Name
mkLensName_v "Control.Lens.Review" "unto"

phantomValName          :: Name
phantomValName :: Name
phantomValName           = String -> String -> Name
mkLensName_v "Control.Lens.Internal.TH" "phantom2"

phantom2 :: (Functor f, Contravariant f) => f a -> f b
phantom2 :: f a -> f b
phantom2 = f a -> f b
forall (f :: * -> *) a b.
(Functor f, Contravariant f) =>
f a -> f b
phantom
{-# INLINE phantom2 #-}

composeValName          :: Name
composeValName :: Name
composeValName           = String -> String -> String -> Name
mkNameG_v "base" "GHC.Base" "."

idValName               :: Name
idValName :: Name
idValName                = String -> String -> String -> Name
mkNameG_v "base" "GHC.Base" "id"

fmapValName             :: Name
fmapValName :: Name
fmapValName              = String -> String -> String -> Name
mkNameG_v "base" "GHC.Base" "fmap"

#if MIN_VERSION_base(4,8,0)
pureValName             :: Name
pureValName :: Name
pureValName              = String -> String -> String -> Name
mkNameG_v "base" "GHC.Base" "pure"

apValName               :: Name
apValName :: Name
apValName                = String -> String -> String -> Name
mkNameG_v "base" "GHC.Base" "<*>"
#else
pureValName             :: Name
pureValName              = mkNameG_v "base" "Control.Applicative" "pure"

apValName               :: Name
apValName                = mkNameG_v "base" "Control.Applicative" "<*>"
#endif

rightDataName           :: Name
rightDataName :: Name
rightDataName            = String -> String -> String -> Name
mkNameG_d "base" "Data.Either" "Right"

leftDataName            :: Name
leftDataName :: Name
leftDataName             = String -> String -> String -> Name
mkNameG_d "base" "Data.Either" "Left"


------------------------------------------------------------------------
-- Support for generating inline pragmas
------------------------------------------------------------------------

inlinePragma :: Name -> [DecQ]

#ifdef INLINING

#if MIN_VERSION_template_haskell(2,8,0)

# ifdef OLD_INLINE_PRAGMAS
-- 7.6rc1?
inlinePragma methodName = [pragInlD methodName (inlineSpecNoPhase Inline False)]
# else
-- 7.7.20120830
inlinePragma :: Name -> [DecQ]
inlinePragma methodName :: Name
methodName = [Name -> Inline -> RuleMatch -> Phases -> DecQ
pragInlD Name
methodName Inline
Inline RuleMatch
FunLike Phases
AllPhases]
# endif

#else
-- GHC <7.6, TH <2.8.0
inlinePragma methodName = [pragInlD methodName (inlineSpecNoPhase True False)]
#endif

#else

inlinePragma _ = []

#endif