{-# LANGUAGE CPP                   #-}
{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE MonoLocalBinds        #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell       #-}
module Data.Array.Accelerate.Classes.FromIntegral (
  FromIntegral(..),
) where
import Data.Array.Accelerate.Smart
import Data.Array.Accelerate.Type
import Data.Array.Accelerate.Classes.Integral
import Language.Haskell.TH                                          hiding ( Exp )
import Prelude                                                      hiding ( Integral )
class FromIntegral a b where
  
  fromIntegral :: Integral a => Exp a -> Exp b
$(runQ $ do
    let
        
        digItOut :: Name -> Q [Name]
        digItOut name = do
#if __GLASGOW_HASKELL__ < 800
          TyConI (DataD _ _ _   cons _) <- reify name
#else
          TyConI (DataD _ _ _ _ cons _) <- reify name
#endif
          let
            
            
            dig (NormalC _ [(_, AppT (ConT n) (VarT _))])               = digItOut n
#if __GLASGOW_HASKELL__ < 800
            dig (ForallC _ _ (NormalC _ [(_, AppT (ConT _) (ConT n))])) = return [n]
#else
            
            
            
            dig (ForallC _ _ (GadtC _ [(_, AppT (ConT n) (VarT _))] _)) = digItOut n
            dig (GadtC _ _ (AppT (ConT _) (ConT n)))                    = return [n]
#endif
            dig _ = error "Unexpected case generating FromIntegral instances"
            
          concat `fmap` mapM dig cons
        thFromIntegral :: Name -> Name -> Q Dec
        thFromIntegral a b =
          let
              ty  = AppT (AppT (ConT (mkName "FromIntegral")) (ConT a)) (ConT b)
              dec = ValD (VarP (mkName "fromIntegral")) (NormalB (VarE (mkName "mkFromIntegral"))) []
          in
          instanceD (return []) (return ty) [return dec]
    
    as <- digItOut ''IntegralType
    bs <- digItOut ''NumType
    sequence [ thFromIntegral a b | a <- as, b <- bs ]
 )