module DDC.Core.Tetra.Prim.DaConTetra
        ( typeDaConTetra
        , readDaConTetra
        , xTuple2
        , dcTuple2
        , dcTupleN )
where
import DDC.Core.Tetra.Prim.Base
import DDC.Core.Tetra.Prim.TyConTetra
import DDC.Core.Exp.Simple.Compounds
import DDC.Core.Exp.Simple.Exp
import DDC.Base.Pretty
import Control.DeepSeq
import Data.Char
import Data.List


instance NFData DaConTetra where
 rnf !_ = ()
 

instance Pretty DaConTetra where
 ppr dc
  = case dc of
        DaConTetraTuple n       -> text "T" <> int n <> text "#"


-- | Read the name of a baked-in data constructor.
readDaConTetra :: String -> Maybe DaConTetra
readDaConTetra str
        | Just rest     <- stripPrefix "T" str
        , (ds, "#")     <- span isDigit rest
        , not $ null ds
        , arity         <- read ds
        = Just $ DaConTetraTuple arity

        | otherwise
        = Nothing


-- | Yield the type of a baked-in data constructor.
typeDaConTetra :: DaConTetra -> Type Name
typeDaConTetra (DaConTetraTuple n)
        = tForalls (replicate n kData)
        $ \args -> foldr tFun (tTupleN args) args


-- | Construct a @Tuple2#@
xTuple2 :: Type Name  -> Type Name 
        -> Exp a Name -> Exp a Name 
        -> Exp a Name

xTuple2 t1 t2 x1 x2
        = xApps (XCon dcTuple2) 
                [XType t1, XType t2, x1, x2]


-- | Data constructor for @Tuple2#@
dcTuple2 :: DaCon Name
dcTuple2  = DaConPrim   (NameDaConTetra (DaConTetraTuple 2))
                        (typeDaConTetra (DaConTetraTuple 2))


-- | Data constructor for n-tuples
dcTupleN :: Int -> DaCon Name
dcTupleN n
          = DaConPrim   (NameDaConTetra (DaConTetraTuple n))
                        (typeDaConTetra (DaConTetraTuple n))