exference-1.6.0.0: src/Language/Haskell/Exference/TypeFromHaskellSrc.hs
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MonadComprehensions #-}
module Language.Haskell.Exference.TypeFromHaskellSrc
( ConvData(..)
, convertTypeNoDecl
, convertTypeNoDeclInternal
, convertName
, convertQName
, convertModuleName
, getVar
-- , ConversionMonad
, parseQualifiedName
, tyVarTransform
, haskellSrcExtsParseMode
, findInvalidNames
)
where
import Language.Haskell.Exts.Syntax
import qualified Language.Haskell.Exts.Parser as P
import qualified Language.Haskell.Exference.Core.Types as T
import qualified Language.Haskell.Exference.Core.TypeUtils as TU
import qualified Data.Map as M
import Control.Applicative ( (<$>), (<*>), Applicative, liftA2 )
import Data.Maybe ( fromMaybe )
import Data.List ( find )
import Control.Arrow ( (&&&) )
import Control.Monad.State.Strict
import Control.Monad.Trans.Maybe
import Control.Monad.Identity
import Control.Monad.Trans.Either
import Data.List.Split ( wordsBy )
import Control.Monad.Trans.MultiRWS
import Control.Monad.Trans.MultiState ( MonadMultiState(..) )
import Data.HList.ContainsType
import Language.Haskell.Exts.Extension ( Language (..)
, Extension (..)
, KnownExtension (..) )
import Debug.Trace
-- type ConversionMonad = EitherT String (State (Int, ConvMap))
data ConvData = ConvData Int T.TypeVarIndex
haskellSrcExtsParseMode :: String -> P.ParseMode
haskellSrcExtsParseMode s = P.ParseMode (s++".hs")
Haskell2010
exts2
False
False
Nothing
False
where
exts1 = [ TypeOperators
, ExplicitForAll
, ExistentialQuantification
, TypeFamilies
, FunctionalDependencies
, FlexibleContexts
, MultiParamTypeClasses ]
exts2 = map EnableExtension exts1
convertTypeNoDecl
:: Monad m
=> [T.HsTypeClass]
-> Maybe ModuleName
-> [T.QualifiedName]
-> Type
-> EitherT
String
(MultiRWST r w s m)
(T.HsType, T.TypeVarIndex)
convertTypeNoDecl tcs mn ds t =
mapEitherT conv $ convertTypeNoDeclInternal tcs mn ds t
where
conv m = [ [ (r, index)
| r <- eith
]
| (eith, ConvData _ index) <- withMultiStateAS (ConvData 0 M.empty) m
]
convertTypeNoDeclInternal
:: (MonadMultiState ConvData m)
=> [T.HsTypeClass]
-> Maybe ModuleName -- default (for unqualified stuff)
-- Nothing uses a broad search for lookups
-> [T.QualifiedName] -- list of fully qualified data types
-- (to keep things unique)
-> Type
-> EitherT String m T.HsType
convertTypeNoDeclInternal tcs defModuleName ds ty = helper ty
where
helper (TyFun a b) = T.TypeArrow
<$> helper a
<*> helper b
helper (TyTuple _ ts) | n <- length ts
= foldl T.TypeApp (T.TypeCons $ T.TupleCon n)
<$> mapM helper ts
helper (TyApp a b) = T.TypeApp
<$> helper a
<*> helper b
helper (TyVar vname) = do
i <- getVar vname
return $ T.TypeVar i
helper (TyCon name) = return
$ T.TypeCons
$ convertQName defModuleName ds name
helper (TyList t) = T.TypeApp (T.TypeCons T.ListCon) <$> helper t
helper (TyParen t) = helper t
helper TyInfix{} = left "infix operator"
helper TyKind{} = left "kind annotation"
helper TyPromoted{} = left "promoted type"
helper (TyForall maybeTVars cs t) =
T.TypeForall
<$> case maybeTVars of
Nothing -> return []
Just tvs -> tyVarTransform `mapM` tvs
<*> convertConstraint tcs defModuleName ds `mapM` cs
<*> helper t
helper x = left $ "unknown type element: " ++ show x -- TODO
getVar :: MonadMultiState ConvData m => Name -> m Int
getVar n = do
ConvData next m <- mGet
case M.lookup n m of
Nothing -> do
mSet $ ConvData (next+1) (M.insert n next m)
return next
Just i ->
return i
-- defaultModule -> potentially-qualified-name-thingy -> exference-q-name
convertQName :: Maybe ModuleName -> [T.QualifiedName] -> QName -> T.QualifiedName
convertQName _ _ (Special UnitCon) = T.TupleCon 0
convertQName _ _ (Special ListCon) = T.ListCon
convertQName _ _ (Special FunCon) = error "no support for FunCon" -- i wonder how we reach this..
convertQName _ _ (Special (TupleCon _ i)) = T.TupleCon i
convertQName _ _ (Special Cons) = T.Cons
convertQName _ _ (Special UnboxedSingleCon) = T.TupleCon 0
convertQName _ _ (Qual mn s) = convertModuleName mn s
convertQName (Just d) _ (UnQual s) = convertModuleName d s
convertQName Nothing ds (UnQual (Ident s)) = fromMaybe (T.QualifiedName [] s)
$ find p ds
where
p (T.QualifiedName _ x) = x==s
p _ = False
convertQName Nothing _ (UnQual s) = convertName s
convertName :: Name -> T.QualifiedName
convertName (Ident s) = T.QualifiedName [] s
convertName (Symbol s) = T.QualifiedName [] $ "(" ++ s ++ ")"
convertModuleName :: ModuleName -> Name -> T.QualifiedName
convertModuleName (ModuleName n) (Ident s) = parseQualifiedName
$ n ++ "." ++ s
convertModuleName (ModuleName n) (Symbol s) = parseQualifiedName
$ "(" ++ n ++ "." ++ s ++ ")"
parseQualifiedName :: String -> T.QualifiedName
parseQualifiedName s = let (prebracket, operator) = span (/='(') s
in liftA2 T.QualifiedName init last $ wordsBy (=='.') prebracket ++ words operator
convertConstraint
:: (MonadMultiState ConvData m)
=> [T.HsTypeClass]
-> Maybe ModuleName
-> [T.QualifiedName]
-> Asst
-> EitherT String m T.HsConstraint
convertConstraint tcs defModuleName@(Just _) ds (ClassA qname types)
| str <- convertQName defModuleName ds qname
, ctypes <- mapM (convertTypeNoDeclInternal tcs defModuleName ds) types
= do
ts <- ctypes
return $ T.HsConstraint ( fromMaybe TU.unknownTypeClass
$ find ((==str) . T.tclass_name)
$ tcs)
ts
convertConstraint tcs Nothing ds (ClassA (UnQual (Symbol "[]")) types)
| ctypes <- mapM (convertTypeNoDeclInternal tcs Nothing ds) types
= do
ts <- ctypes
return $ T.HsConstraint
( fromMaybe TU.unknownTypeClass
$ find ((==T.ListCon) . T.tclass_name)
$ tcs )
ts
convertConstraint tcs Nothing ds (ClassA (UnQual (Ident name)) types)
| ctypes <- mapM (convertTypeNoDeclInternal tcs Nothing ds) types
= do
ts <- ctypes
let tcsTuples = (\tc -> (T.tclass_name tc, tc)) <$> tcs
let searchF (T.QualifiedName _ n) = n==name
searchF _ = False
let tc = fromMaybe TU.unknownTypeClass
$ snd <$> find (searchF . fst) tcsTuples
return $ T.HsConstraint tc ts
convertConstraint tcs _ ds (ClassA q@(Qual {}) types)
| ctypes <- mapM (convertTypeNoDeclInternal tcs Nothing ds) types
, name <- convertQName Nothing ds q
= do
ts <- ctypes
return $ T.HsConstraint
( fromMaybe TU.unknownTypeClass
$ find (\(T.HsTypeClass n _ _)
-> n==name) tcs
)
ts
convertConstraint _ Nothing _ cls@ClassA{} = error $ "convertConstraint" ++ show cls
convertConstraint env defModuleName ds (ParenA c)
= convertConstraint env defModuleName ds c
convertConstraint _ _ _ c
= left $ "bad constraint: " ++ show c
tyVarTransform :: MonadMultiState ConvData m
=> TyVarBind
-> EitherT String m T.TVarId
tyVarTransform (KindedVar _ _) = left $ "KindedVar"
tyVarTransform (UnkindedVar n) = getVar n
findInvalidNames :: [T.QualifiedName] -> T.HsType -> [T.QualifiedName]
findInvalidNames _ T.TypeVar {} = []
findInvalidNames _ T.TypeConstant {} = []
findInvalidNames valids (T.TypeCons qn) = case qn of
n@(T.QualifiedName _ _) -> [ n | n `notElem` valids ]
_ -> []
findInvalidNames valids (T.TypeArrow t1 t2) =
findInvalidNames valids t1 ++ findInvalidNames valids t2
findInvalidNames valids (T.TypeApp t1 t2) =
findInvalidNames valids t1 ++ findInvalidNames valids t2
findInvalidNames valids (T.TypeForall _ _ t1) =
findInvalidNames valids t1