{-# LANGUAGE DataKinds              #-}
{-# LANGUAGE GADTs                  #-}
{-# LANGUAGE TypeFamilies           #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE UndecidableInstances   #-}
module Data.Emacs.Module.Args
  ( Nat(..)
  , EmacsArgs
  , EmacsInvocation(..)
  , GetArities(..)
    
  , R(..)
  , O(..)
  , Rest(..)
  , Stop(..)
  ) where
import Control.Monad.Base
import Data.Kind
import Data.Proxy
import Foreign
import Foreign.C.Types (CPtrdiff)
import Data.Emacs.Module.Raw.Env (variadicFunctionArgs)
import Data.Emacs.Module.Raw.Value
data Nat = Z | S Nat
class NatValue (n :: Nat) where
  natValue :: Proxy n -> Int
instance NatValue 'Z where
  {-# INLINE natValue #-}
  natValue :: Proxy 'Z -> Int
natValue Proxy 'Z
_ = Int
0
instance forall n. NatValue n => NatValue ('S n) where
  {-# INLINE natValue #-}
  natValue :: Proxy ('S n) -> Int
natValue Proxy ('S n)
_ = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Proxy n -> Int
forall (n :: Nat). NatValue n => Proxy n -> Int
natValue (forall {k} (t :: k). Proxy t
forall (t :: Nat). Proxy t
Proxy @n)
data R a b = R !a !b
data O a b = O !(Maybe a) !b
newtype Rest a = Rest [a]
data Stop a = Stop
type family EmacsArgs (req :: Nat) (opt :: Nat) (rest :: Bool) (a :: Type) = (r :: Type) | r -> req opt rest a where
  EmacsArgs ('S n) opt    rest   a = R a (EmacsArgs n  opt rest a)
  EmacsArgs 'Z     ('S k) rest   a = O a (EmacsArgs 'Z k   rest a)
  EmacsArgs 'Z     'Z     'True  a = Rest a
  EmacsArgs 'Z     'Z     'False a = Stop a
class EmacsInvocation req opt rest where
  supplyEmacsArgs
    :: MonadBase IO m
    => Int
    -> Ptr (RawValue 'Regular)
    -> (RawValue 'Regular -> m a)
    -> (EmacsArgs req opt rest a -> m b)
    -> m b
instance EmacsInvocation 'Z 'Z 'False where
  {-# INLINE supplyEmacsArgs #-}
  supplyEmacsArgs :: forall (m :: * -> *) a b.
MonadBase IO m =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs 'Z 'Z 'False a -> m b)
-> m b
supplyEmacsArgs Int
_nargs Ptr (RawValue 'Regular)
_startPtr RawValue 'Regular -> m a
_mkInput EmacsArgs 'Z 'Z 'False a -> m b
f = EmacsArgs 'Z 'Z 'False a -> m b
f EmacsArgs 'Z 'Z 'False a
Stop a
forall {k} (a :: k). Stop a
Stop
instance EmacsInvocation 'Z 'Z 'True where
  {-# INLINE supplyEmacsArgs #-}
  supplyEmacsArgs
    :: MonadBase IO m
    => Int
    -> Ptr (RawValue 'Regular)
    -> (RawValue 'Regular -> m a)
    -> (Rest a -> m b)
    -> m b
  supplyEmacsArgs :: forall (m :: * -> *) a b.
MonadBase IO m =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (Rest a -> m b)
-> m b
supplyEmacsArgs Int
nargs Ptr (RawValue 'Regular)
startPtr RawValue 'Regular -> m a
mkArg Rest a -> m b
f =
    case Int
nargs of
      Int
0 -> Rest a -> m b
f ([a] -> Rest a
forall a. [a] -> Rest a
Rest [])
      Int
n -> Rest a -> m b
f (Rest a -> m b) -> ([a] -> Rest a) -> [a] -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Rest a
forall a. [a] -> Rest a
Rest ([a] -> m b) -> m [a] -> m b
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (RawValue 'Regular -> m a) -> [RawValue 'Regular] -> m [a]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse RawValue 'Regular -> m a
mkArg ([RawValue 'Regular] -> m [a]) -> m [RawValue 'Regular] -> m [a]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO [RawValue 'Regular] -> m [RawValue 'Regular]
forall α. IO α -> m α
forall (b :: * -> *) (m :: * -> *) α. MonadBase b m => b α -> m α
liftBase (Int -> Ptr (RawValue 'Regular) -> IO [RawValue 'Regular]
forall a. Storable a => Int -> Ptr a -> IO [a]
peekArray Int
n Ptr (RawValue 'Regular)
startPtr)
{-# INLINE advanceEmacsValuePtr #-}
advanceEmacsValuePtr :: forall p. Ptr (RawValue p) -> Ptr (RawValue p)
advanceEmacsValuePtr :: forall (p :: Pinning). Ptr (RawValue p) -> Ptr (RawValue p)
advanceEmacsValuePtr =
  (Ptr (RawValue p) -> Int -> Ptr (RawValue p)
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (RawValue p -> Int
forall a. Storable a => a -> Int
sizeOf (RawValue p
forall a. HasCallStack => a
undefined :: RawValue p)))
instance EmacsInvocation 'Z n rest => EmacsInvocation 'Z ('S n) rest where
  {-# INLINE supplyEmacsArgs #-}
  supplyEmacsArgs
    :: forall m a b. MonadBase IO m
    => Int
    -> Ptr (RawValue 'Regular)
    -> (RawValue 'Regular -> m a)
    -> (O a (EmacsArgs 'Z n rest a) -> m b)
    -> m b
  supplyEmacsArgs :: forall (m :: * -> *) a b.
MonadBase IO m =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (O a (EmacsArgs 'Z n rest a) -> m b)
-> m b
supplyEmacsArgs Int
nargs Ptr (RawValue 'Regular)
startPtr RawValue 'Regular -> m a
mkArg O a (EmacsArgs 'Z n rest a) -> m b
f =
    case Int
nargs of
      Int
0 -> Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs 'Z n rest a -> m b)
-> m b
forall (req :: Nat) (opt :: Nat) (rest :: Bool) (m :: * -> *) a b.
(EmacsInvocation req opt rest, MonadBase IO m) =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs req opt rest a -> m b)
-> m b
forall (m :: * -> *) a b.
MonadBase IO m =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs 'Z n rest a -> m b)
-> m b
supplyEmacsArgs Int
nargs Ptr (RawValue 'Regular)
startPtr RawValue 'Regular -> m a
mkArg (O a (EmacsArgs 'Z n rest a) -> m b
f (O a (EmacsArgs 'Z n rest a) -> m b)
-> (EmacsArgs 'Z n rest a -> O a (EmacsArgs 'Z n rest a))
-> EmacsArgs 'Z n rest a
-> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe a -> EmacsArgs 'Z n rest a -> O a (EmacsArgs 'Z n rest a)
forall a b. Maybe a -> b -> O a b
O Maybe a
forall a. Maybe a
Nothing)
      Int
_ -> do
        a
arg <- RawValue 'Regular -> m a
mkArg (RawValue 'Regular -> m a) -> m (RawValue 'Regular) -> m a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO (RawValue 'Regular) -> m (RawValue 'Regular)
forall α. IO α -> m α
forall (b :: * -> *) (m :: * -> *) α. MonadBase b m => b α -> m α
liftBase (Ptr (RawValue 'Regular) -> IO (RawValue 'Regular)
forall a. Storable a => Ptr a -> IO a
peek Ptr (RawValue 'Regular)
startPtr)
        Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs 'Z n rest a -> m b)
-> m b
forall (req :: Nat) (opt :: Nat) (rest :: Bool) (m :: * -> *) a b.
(EmacsInvocation req opt rest, MonadBase IO m) =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs req opt rest a -> m b)
-> m b
forall (m :: * -> *) a b.
MonadBase IO m =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs 'Z n rest a -> m b)
-> m b
supplyEmacsArgs
          (Int
nargs Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
          (Ptr (RawValue 'Regular) -> Ptr (RawValue 'Regular)
forall (p :: Pinning). Ptr (RawValue p) -> Ptr (RawValue p)
advanceEmacsValuePtr Ptr (RawValue 'Regular)
startPtr)
          RawValue 'Regular -> m a
mkArg
          (O a (EmacsArgs 'Z n rest a) -> m b
f (O a (EmacsArgs 'Z n rest a) -> m b)
-> (EmacsArgs 'Z n rest a -> O a (EmacsArgs 'Z n rest a))
-> EmacsArgs 'Z n rest a
-> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe a -> EmacsArgs 'Z n rest a -> O a (EmacsArgs 'Z n rest a)
forall a b. Maybe a -> b -> O a b
O (a -> Maybe a
forall a. a -> Maybe a
Just a
arg))
instance EmacsInvocation n opt rest => EmacsInvocation ('S n) opt rest where
  {-# INLINE supplyEmacsArgs #-}
  supplyEmacsArgs
    :: MonadBase IO m
    => Int
    -> Ptr (RawValue 'Regular)
    -> (RawValue 'Regular -> m a)
    -> (R a (EmacsArgs n opt rest a) -> m b)
    -> m b
  supplyEmacsArgs :: forall (m :: * -> *) a b.
MonadBase IO m =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (R a (EmacsArgs n opt rest a) -> m b)
-> m b
supplyEmacsArgs Int
nargs Ptr (RawValue 'Regular)
startPtr RawValue 'Regular -> m a
mkArg R a (EmacsArgs n opt rest a) -> m b
f = do
    a
arg <- RawValue 'Regular -> m a
mkArg (RawValue 'Regular -> m a) -> m (RawValue 'Regular) -> m a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO (RawValue 'Regular) -> m (RawValue 'Regular)
forall α. IO α -> m α
forall (b :: * -> *) (m :: * -> *) α. MonadBase b m => b α -> m α
liftBase (Ptr (RawValue 'Regular) -> IO (RawValue 'Regular)
forall a. Storable a => Ptr a -> IO a
peek Ptr (RawValue 'Regular)
startPtr)
    Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs n opt rest a -> m b)
-> m b
forall (req :: Nat) (opt :: Nat) (rest :: Bool) (m :: * -> *) a b.
(EmacsInvocation req opt rest, MonadBase IO m) =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs req opt rest a -> m b)
-> m b
forall (m :: * -> *) a b.
MonadBase IO m =>
Int
-> Ptr (RawValue 'Regular)
-> (RawValue 'Regular -> m a)
-> (EmacsArgs n opt rest a -> m b)
-> m b
supplyEmacsArgs (Int
nargs Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Ptr (RawValue 'Regular) -> Ptr (RawValue 'Regular)
forall (p :: Pinning). Ptr (RawValue p) -> Ptr (RawValue p)
advanceEmacsValuePtr Ptr (RawValue 'Regular)
startPtr) RawValue 'Regular -> m a
mkArg (R a (EmacsArgs n opt rest a) -> m b
f (R a (EmacsArgs n opt rest a) -> m b)
-> (EmacsArgs n opt rest a -> R a (EmacsArgs n opt rest a))
-> EmacsArgs n opt rest a
-> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> EmacsArgs n opt rest a -> R a (EmacsArgs n opt rest a)
forall a b. a -> b -> R a b
R a
arg)
class GetArities (req :: Nat) (opt :: Nat) (rest :: Bool) where
  arities :: Proxy req -> Proxy opt -> Proxy rest -> (CPtrdiff, CPtrdiff)
instance (NatValue req, NatValue opt) => GetArities req opt 'False where
  {-# INLINE arities #-}
  arities :: Proxy req -> Proxy opt -> Proxy 'False -> (CPtrdiff, CPtrdiff)
arities Proxy req
preq Proxy opt
popt Proxy 'False
_ = (CPtrdiff
req, CPtrdiff
req CPtrdiff -> CPtrdiff -> CPtrdiff
forall a. Num a => a -> a -> a
+ CPtrdiff
opt)
    where
      req :: CPtrdiff
req = Int -> CPtrdiff
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy req -> Int
forall (n :: Nat). NatValue n => Proxy n -> Int
natValue Proxy req
preq)
      opt :: CPtrdiff
opt = Int -> CPtrdiff
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy opt -> Int
forall (n :: Nat). NatValue n => Proxy n -> Int
natValue Proxy opt
popt)
instance NatValue req => GetArities req opt 'True where
  {-# INLINE arities #-}
  arities :: Proxy req -> Proxy opt -> Proxy 'True -> (CPtrdiff, CPtrdiff)
arities Proxy req
preq Proxy opt
_ Proxy 'True
_ =
    (Int -> CPtrdiff
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy req -> Int
forall (n :: Nat). NatValue n => Proxy n -> Int
natValue Proxy req
preq), CPtrdiff
variadicFunctionArgs)