{-# LANGUAGE TemplateHaskell #-}

{- |

Module      :  Type.Spine.TH
Copyright   :  (c) The University of Kansas 2011
License     :  BSD3

Maintainer  :  nicolas.frisby@gmail.com
Stability   :  experimental
Portability :  see LANGUAGE pragmas (... GHC)

Template Haskell in support of the spine-view on types.

-}
module Type.Spine.TH where

import Language.Haskell.TH
import Language.Haskell.TH.Syntax



-- | A TemplateHaskell-lifter for 'NameG's.
liftNameG :: Name -> Q Exp
liftNameG n = do
  TyConI (DataD _ (Name occ (NameG _ pkg mod)) _ _ _) <- reify n
  [| mkNameG_tc $(stringE $ pkgString pkg) $(stringE $ modString mod) $(stringE $ occString occ) |]


-- | Returns the kinds of a type constructor's type paratemers and range.
tyConSignature :: Name -> Q ([Kind], Kind)
tyConSignature n = do
  let bad = fail "Type.Spine.TH.tyConSignature expects the name of a data/newtype/data family"
  i <- reify n
  case i of
    TyConI dec -> case dec of
      DataD _ _ tvbs _ _ -> return (map tvb_kind tvbs, StarK)
      NewtypeD _ _ tvbs _ _ -> return (map tvb_kind tvbs, StarK)
      FamilyD DataFam _ tvbs mk -> return (map tvb_kind tvbs, maybe StarK (peel tvbs) mk)
        where peel [] k = k
              peel (_ : l) (ArrowK _ r) = peel l r
              peel _ _ = error "Type.Spine.TH: bad FamilyD kind"
      _ -> bad
    PrimTyConI _ i _ -> return (replicate i StarK, StarK)
    _ -> bad

tvb_kind :: TyVarBndr -> Kind
tvb_kind (PlainTV _) = StarK
tvb_kind (KindedTV _ k) = k