module DDC.Core.Parser.DataDef
        ( DataDef    (..)
        , pDataDef)
where
import DDC.Core.Exp.Annot
import DDC.Core.Parser.Type
import DDC.Core.Parser.Context
import DDC.Core.Parser.Base
import DDC.Core.Lexer.Tokens
import DDC.Type.DataDef
import Control.Monad
import qualified DDC.Base.Parser        as P


pDataDef :: Ord n => Context n -> Parser n (DataDef n)
pDataDef c
 = do   pTokSP KData
        nData   <- pName 
        bsParam <- liftM concat $ P.many (pDataParam c)

        P.choice
         [ -- Data declaration with constructors that have explicit types.
           do   pTok KWhere
                pTok KBraceBra
                ctors      <- P.sepEndBy1 (pDataCtor c nData bsParam) (pTok KSemiColon)
                let ctors' = [ ctor { dataCtorTag = tag }
                                | ctor <- ctors
                                | tag  <- [0..] ]
                pTok KBraceKet
                return  $ DataDef 
                        { dataDefTypeName       = nData
                        , dataDefParams         = bsParam 
                        , dataDefCtors          = Just ctors'
                        , dataDefIsAlgebraic    = True }
         
           -- Data declaration with no data constructors.
         , do   return  $ DataDef 
                        { dataDefTypeName       = nData
                        , dataDefParams         = bsParam
                        , dataDefCtors          = Just []
                        , dataDefIsAlgebraic    = True }

         ]


-- | Parse a type parameter to a data type.
pDataParam :: Ord n => Context n -> Parser n [Bind n]
pDataParam c 
 = do   pTok KRoundBra
        ns      <- P.many1 pName
        pTokSP (KOp ":")
        k       <- pType c
        pTok KRoundKet
        return  [BName n k | n <- ns]


-- | Parse a data constructor declaration.
pDataCtor 
        :: Ord n 
        => Context n
        -> n                    -- ^ Name of data type constructor.
        -> [Bind n]             -- ^ Type parameters of data type constructor.
        -> Parser n (DataCtor n)

pDataCtor c nData bsParam
 = do   n       <- pName
        pTokSP (KOp ":")
        t       <- pType c
        let (tsArg, tResult)    
                = takeTFunArgResult t

        return  $ DataCtor
                { dataCtorName          = n

                -- Set tag to 0 for now. We fix this up in pDataDef above.
                , dataCtorTag           = 0
                
                , dataCtorFieldTypes    = tsArg
                , dataCtorResultType    = tResult 
                , dataCtorTypeName      = nData 
                , dataCtorTypeParams    = bsParam }