content: {-# OPTIONS_GHC -Wno-orphans #-}
  {-# LANGUAGE UndecidableInstances,
               CPP #-}
  #if __GLASGOW_HASKELL__ >= 810
  {-# LANGUAGE StandaloneKindSignatures #-}
  #endif
  module Parsley.Internal.Common.Utils (WQ(..), Code, Quapplicative(..), intercalate, intercalateDiff) where
  
  import Data.List   (intersperse)
  import Data.String (IsString(..))
  
  #if __GLASGOW_HASKELL__ >= 810
  import Data.Kind   (Type)
  import GHC.Exts    (TYPE, RuntimeRep)
  #endif
  
  #if __GLASGOW_HASKELL__ < 900
  import Language.Haskell.TH (TExp, Q)
  #else
  import qualified Language.Haskell.TH as TH (Code, Q)
  #endif
  
  {-|
  A type alias for typed template haskell code, which represents the Haskell AST for a given value.
  
  @since 0.1.0.0
  -}
  #if __GLASGOW_HASKELL__ >= 810
  type Code :: forall (r :: RuntimeRep). TYPE r -> Type
  #endif
  #if __GLASGOW_HASKELL__ < 900
  type Code a = Q (TExp a)
  #else
  type Code a = TH.Code TH.Q a
  #endif
  
  {-|
  Pronounced \"with code\", this datatype is the representation for user-land values. It pairs
  a value up with its representation as Haskell @Code@. It should be manipulated using
  `Quapplicative`.
  
  @since 0.1.0.0
  -}
  data WQ a = WQ { __val :: a, __code :: Code a }
  
  {-|
  This class is used to manipulate the representations of both user-land values and defunctionalised
  representations. It can be used to construct these values as well as extract their underlying value
  and code representation on demand.
  
  It is named after the @Applicative@ class, with the @Q@ standing for \"code\". The @(`>*<`)@ operator
  is analogous to @(\<*>)@ and `makeQ` analogous to @pure@.
  
  @since 0.1.0.0
  -}
  class Quapplicative q where
    {-|
    Combines a value with its representation to build one of the representation types.
  
    @since 0.1.0.0
    -}
    makeQ :: a -> Code a -> q a
  
    {-|
    Extracts the regular value out of the representation.
  
    @since 0.1.0.0
    -}
    _val :: q a -> a
  
    {-|
    Extracts the representation of the value as code.
  
    @since 0.1.0.0
    -}
    _code :: q a -> Code a
  
    {-|
    Pronounced \"quapp\", this can be used to combine the code of a function with the code of a value.
  
    > const5 = makeQ const [||const||] >*< makeQ 5 [||5||]
  
    is the same as saying
  
    > const5 = makeQ (const 5) [||const 5||]
  
    It is more idiomatically found as the output to the @IdiomsPlugin@.
  
    @since 0.1.0.0
    -}
    (>*<) :: q (a -> b) -> q a -> q b
    f >*< x = makeQ (_val f (_val x)) [||$$(_code f) $$(_code x)||]
  infixl 9 >*<
  
  {-|
  This instance is used to manipulate values of `WQ`.
  
  @since 0.1.0.0
  -}
  instance Quapplicative WQ where
    makeQ = WQ
    _code = __code
    _val = __val
  
  intercalate :: Monoid w => w -> [w] -> w
  intercalate xs xss = mconcat (intersperse xs xss)
  
  instance IsString (String -> String) where
    fromString = showString
  
  newtype Id a = Id {unId :: a -> a}
  instance Semigroup (Id a) where f <> g = Id $ unId f . unId g
  instance Monoid (Id a) where mempty = Id id
  
  intercalateDiff :: (a -> a) -> [a -> a] -> a -> a
  intercalateDiff sep xs = unId $ intercalate (Id sep) (map Id xs)
  