packages feed

exference-1.6.0.0: src/Language/Haskell/Exference/BindingsFromHaskellSrc.hs

{-# LANGUAGE TupleSections #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MonadComprehensions #-}

module Language.Haskell.Exference.BindingsFromHaskellSrc
  ( getDecls
  , declToBinding
  , getDataConss
  , getClassMethods
  , getDataTypes
  )
where



import Language.Haskell.Exts.Syntax
import Language.Haskell.Exts.Pretty
import Language.Haskell.Exference.Core.FunctionBinding
import Language.Haskell.Exference.TypeFromHaskellSrc
import Language.Haskell.Exference.TypeDeclsFromHaskellSrc
import Language.Haskell.Exference.Core.Types
import Language.Haskell.Exference.Core.TypeUtils
import Language.Haskell.Exference.FunctionDecl

import Control.Applicative ( (<$>), (<*>) )

import Control.Monad ( join )
import Control.Monad.Identity
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Either
import Control.Monad.State.Strict
import qualified Data.Map as M
import Data.List ( find )

import Control.Monad.Trans.MultiRWS
import Data.HList.ContainsType

import Debug.Trace



getDecls
  :: (Monad m, Functor m)
  => [QualifiedName]
  -> [HsTypeClass]
  -> TypeDeclMap
  -> [Module]
  -> MultiRWST r w s m [Either String HsFunctionDecl]
getDecls ds tcs tDeclMap modules = fmap (>>= either (return.Left) (map Right))
                                $ sequence
                                $ do
  Module _loc mn _pragma _warning _mexp _imp decls <- modules
  d <- decls
  return $ runEitherT $ transformDecl tcs ds mn tDeclMap d

transformDecl
  :: (Monad m, Functor m)
  => [HsTypeClass]
  -> [QualifiedName]
  -> ModuleName
  -> TypeDeclMap
  -> Decl
  -> EitherT String (MultiRWST r w s m) [HsFunctionDecl]
transformDecl tcs ds mn tDeclMap (TypeSig _loc names qtype)
  = insName qtype $ do
      (ctype, _) <- convertType tcs (Just mn) ds tDeclMap qtype
      return $ helper mn ctype <$> names
transformDecl _ _ _ _ _ = return []

transformDecl'
  :: (MonadMultiState ConvData m, Monad m, Functor m)
  => [HsTypeClass]
  -> [QualifiedName]
  -> ModuleName
  -> TypeDeclMap
  -> Decl
  -> EitherT String m [HsFunctionDecl]
transformDecl' tcs ds mn tDeclMap (TypeSig _loc names qtype)
  = insName qtype $ do
      ctype <- convertTypeInternal tcs (Just mn) ds tDeclMap qtype
      return $ helper mn ctype <$> names
transformDecl' _ _ _ _ _ = return []

insName :: (Functor m, Monad m)
        => Type -> EitherT String m a -> EitherT String m a
insName qtype = bimapEitherT (\x -> x ++ " in " ++ prettyPrint qtype) id

helper :: ModuleName -> HsType -> Name -> HsFunctionDecl
helper mn t x = (convertModuleName mn x, forallify t)

getDataConss
  :: (Monad m)
  => [HsTypeClass]
  -> [QualifiedName]
  -> TypeDeclMap
  -> [Module]
  -> MultiRWST
       r
       w
       s
       m
       [Either String ([HsFunctionDecl], DeconstructorBinding)]
getDataConss tcs ds tDeclMap modules = sequence $ do
  Module _loc moduleName _pragma _warning _mexp _imp decls <- modules
  DataDecl _loc _newtflag cntxt name params conss _derives <- decls
  let
    rTypeM :: ( MonadMultiState ConvData m )
           => EitherT String m HsType
    rTypeM = do
      let rName = convertModuleName moduleName name
      ps  <- mapM pTransform params
      return $ (forallify . foldl TypeApp (TypeCons rName)) ps
    pTransform :: MonadMultiState ConvData m => TyVarBind -> EitherT String m HsType
    pTransform (KindedVar _ _) = left "KindedVar"
    pTransform (UnkindedVar n) = TypeVar <$> getVar n
  --let
  --  tTransform (UnBangedTy t) = convertTypeInternal t
  --  tTransform x              = lift $ left $ "unknown Type: " ++ show x
  let
    typeM :: ( MonadMultiState ConvData m )
          => QualConDecl
          -> EitherT String m (QualifiedName, [HsType])
    typeM (QualConDecl _loc cbindings ccntxt conDecl) = do
      case cntxt of
        [] -> right ()
        _  -> left "context in data type"
      case (cbindings, ccntxt) of
        ([],[]) -> right ()
        _       -> left "constraint or existential type for constructor"
      (cname,tys) <- case conDecl of
        ConDecl c t -> right (c, t)
        x           -> left $ "unknown ConDecl: " ++ show x
      convTs <- convertTypeInternal tcs (Just moduleName) ds tDeclMap `mapM` tys
      let qName = convertModuleName moduleName cname
      return $ (qName, convTs)
  let
    addConsMsg = (++) $ show name ++ ": "
  let
    convAction :: ( MonadMultiState ConvData m )
               => EitherT String m ([HsFunctionDecl], DeconstructorBinding)
    convAction = do
      rtype  <- rTypeM
      consDatas <- mapM typeM conss
      return $ ( [ (n, foldr TypeArrow rtype ts)
                 | (n, ts) <- consDatas
                 ]
               , (rtype, consDatas, False)
               )
        -- TODO: actually determine if stuff is recursive or not
  return $ do
    convResult <- withMultiStateA (ConvData 0 M.empty) $ runEitherT convAction
    return $ either (Left . addConsMsg) Right convResult
    -- TODO: replace this by bimap..

getClassMethods
  :: (Monad m, Functor m)
  => [HsTypeClass]
  -> [QualifiedName]
  -> TypeDeclMap
  -> [Module]
  -> MultiRWST r w s m [Either String HsFunctionDecl]
getClassMethods tcs ds tDeclMap modules = fmap join $ sequence $ do
  Module _loc moduleName _pragma _warning _mexp _imp decls <- modules
  ClassDecl _ _ name@(Ident nameStr) vars _ cdecls <- decls
  return $ do
    let errorMod = (++) ("class method for "++show name++": ")
    let tcsTuples = (\tc -> (tclass_name tc, tc)) <$> tcs
    let searchF (QualifiedName _ n) = n==nameStr
        searchF _                   = False
    let maybeClass = snd <$> find (searchF . fst) tcsTuples
    case maybeClass of
      Nothing -> return [Left $ "unknown type class: "++show name]
      Just cls -> do
        let cnstrA = HsConstraint cls <$> mapM ((TypeVar <$>) . tyVarTransform) vars
        --     action :: ( MonadMultiState ConvData m ) => m [Either String [HsFunctionDecl]]
        rEithers <- withMultiStateA (ConvData 0 M.empty) $ do
          cnstrE <- runEitherT cnstrA
          case cnstrE of
            Left x -> return [Left x]
            Right cnstr ->
              mapM ( runEitherT
                   . fmap (map (addConstraint cnstr))
                   . transformDecl' tcs ds moduleName tDeclMap)
                $ [ d | ClsDecl d <- cdecls ]
        let _ = rEithers :: [Either String [HsFunctionDecl]]
        return $ concatMap (either (return . Left . errorMod) (map Right))
               $ rEithers
  where
    addConstraint :: HsConstraint -> HsFunctionDecl -> HsFunctionDecl
    addConstraint c (n, TypeForall vs cs t) = (n, TypeForall vs (c:cs) t)
    addConstraint _ _                       = error "addConstraint for non-forall type = bad"
      --(n, ForallType [] [c] t)

getDataTypes :: [Module] -> [QualifiedName]
getDataTypes modules = d1 ++ d2
 where
  d1 = do
    Module _loc moduleName _pragma _warning _mexp _imp decls <- modules
    DataDecl _ _ _ name _ _ _ <- decls
    return $ convertModuleName moduleName name
  d2 = do
    Module _loc moduleName _pragma _warning _mexp _imp decls <- modules
    TypeDecl _ name _ _ <- decls
    return $ convertModuleName moduleName name