module UHC.Light.Compiler.EHC.BuildFunction
( module Data.Functor.Identity
, BFun' (..)
, BFun (..)
, BFunCacheEntry (..)
, BCache, emptyBCache, bcacheCache, bcacheDpdRel
, bcacheLookup, bcacheInsert, bcacheInsertDpd
, BRef (..)
, BState, emptyBState, bstateCache, bstateCallStack )
where
import UHC.Light.Compiler.EHC.Common
import UHC.Light.Compiler.EHC.CompileUnit
import Control.Applicative
import Data.Functor.Identity
import qualified Data.Map as Map
import qualified Data.IntMap as IMap
import Data.Maybe
import UHC.Util.Hashable
import UHC.Util.Lens
import qualified UHC.Util.RelMap as Rel
import Data.Typeable
import UHC.Util.Time
deriving instance Typeable Identity
data BFun' res where
FPathSearchForFile
:: !String
-> !FilePath
-> BFun' (HsName, FPath)
FPathOfImported
:: !HsName
-> BFun' FPath
ImportsOf
:: !HsName
-> BFun' [HsName]
EcuOfName
:: !HsName
-> BFun' EHCompileUnit
EcuOfNameAndPath
:: !(Maybe PrevSearchInfo)
-> !(HsName,Maybe FPath)
-> BFun' EHCompileUnit
EHCOptsOf
:: !HsName
-> BFun' EHCOpts
ASTFromFile
:: !(HsName,Maybe FPath)
-> !ASTType
-> !ASTSuffixKey
-> !ASTFileTiming
-> BFun' res
ModfTimeOfFile
:: !HsName
-> !ASTType
-> !ASTSuffixKey
-> !ASTFileTiming
-> BFun' (Maybe ClockTime)
bfunCompare :: BFun' res1 -> BFun' res2 -> Ordering
bfunCompare f1 f2 = case (f1,f2) of
(FPathSearchForFile a1 b1 , FPathSearchForFile a2 b2 ) -> lexico [a1 `compare` a2, b1 `compare` b2]
(FPathOfImported a1 , FPathOfImported a2 ) -> a1 `compare` a2
(ImportsOf a1 , ImportsOf a2 ) -> a1 `compare` a2
(EcuOfName a1 , EcuOfName a2 ) -> a1 `compare` a2
(EcuOfNameAndPath a1 b1 , EcuOfNameAndPath a2 b2 ) -> lexico [a1 `compare` a2, b1 `compare` b2]
(EHCOptsOf a1 , EHCOptsOf a2 ) -> a1 `compare` a2
(ASTFromFile a1 b1 c1 d1 , ASTFromFile a2 b2 c2 d2 ) -> lexico [a1 `compare` a2, b1 `compare` b2, c1 `compare` c2, d1 `compare` d2]
(ModfTimeOfFile a1 b1 c1 d1 , ModfTimeOfFile a2 b2 c2 d2 ) -> lexico [a1 `compare` a2, b1 `compare` b2, c1 `compare` c2, d1 `compare` d2]
where lexico (x:xs)
| x == EQ = lexico xs
| otherwise = x
lexico [] = EQ
instance Ord (BFun' res) where
compare = bfunCompare
deriving instance Eq (BFun' res)
deriving instance Show (BFun' res)
deriving instance Typeable BFun'
instance Hashable (BFun' res) where
hashWithSalt salt x = case x of
FPathSearchForFile a b -> salt `hashWithSalt` (0::Int) `hashWithSalt` a `hashWithSalt` b
FPathOfImported a -> salt `hashWithSalt` (1::Int) `hashWithSalt` a
ImportsOf a -> salt `hashWithSalt` (2::Int) `hashWithSalt` a
EcuOfName a -> salt `hashWithSalt` (3::Int) `hashWithSalt` a
EHCOptsOf a -> salt `hashWithSalt` (4::Int) `hashWithSalt` a
EcuOfNameAndPath a b -> salt `hashWithSalt` (5::Int) `hashWithSalt` a `hashWithSalt` b
ASTFromFile a b c d -> salt `hashWithSalt` (6::Int) `hashWithSalt` a `hashWithSalt` b `hashWithSalt` c `hashWithSalt` d
ModfTimeOfFile a b c d -> salt `hashWithSalt` (7::Int) `hashWithSalt` a `hashWithSalt` b `hashWithSalt` c `hashWithSalt` d
data BFun
= forall res
. ( Typeable res)
=> BFun
{ bfcdFun :: !(BFun' res)
}
instance Eq BFun where
(BFun {bfcdFun=f1}) == (BFun {bfcdFun=f2}) = bfunCompare f1 f2 == EQ
instance Ord BFun where
(BFun {bfcdFun=f1}) `compare` (BFun {bfcdFun=f2}) = bfunCompare f1 f2
instance Hashable BFun where
hashWithSalt salt (BFun {bfcdFun=x}) = hashWithSalt salt x
data BFunCacheEntry
= forall f res
. (Typeable f, Typeable res)
=> BFunCacheEntry
{ bfceFun :: !(BFun' res)
, bfceVal :: !(f res)
}
data BCache
= BCache
{ _bcacheCache :: IMap.IntMap [BFunCacheEntry]
, _bcacheDpdRel :: Rel.Rel BFun BFun
}
mkLabel ''BCache
emptyBCache :: BCache
emptyBCache = BCache IMap.empty Rel.empty
bcacheLookup :: (Typeable res, Typeable f) => BFun' res -> BCache -> Maybe (f res)
bcacheLookup key (BCache {_bcacheCache=cache}) = do
vals <- IMap.lookup (hash key) cache
lookup key $ catMaybes $ map cvt vals
where
cvt (BFunCacheEntry {bfceFun=f, bfceVal=v}) = case (cast f, cast v) of
(Just f', Just v') -> Just (f',v')
_ -> Nothing
bcacheInsert :: (Typeable res, Typeable f) => BFun' res -> f res -> BCache -> BCache
bcacheInsert k v bc@(BCache {_bcacheCache=c}) = bc { _bcacheCache = IMap.insertWith (++) (hash k) [BFunCacheEntry k v] c }
bcacheInsertDpd
:: (Typeable res1, Typeable res2)
=>
BFun' res1
-> BFun' res2
-> BCache -> BCache
bcacheInsertDpd f1 f2 bc@(BCache {_bcacheDpdRel=dpd}) = bc { _bcacheDpdRel = Rel.insert (BFun f1) (BFun f2) dpd }
data BRef val where
BRef_ECU
:: !HsName
-> BRef EHCompileUnit
BRef_AST
:: !HsName
-> ASTType
-> ASTSuffixKey
-> ASTFileTiming
-> BRef val
BRef_EHCOpts
:: !HsName
-> BRef EHCOpts
deriving instance Typeable BRef
data BState
= BState
{ _bstateCache :: !BCache
, _bstateCallStack :: ![BFun]
}
mkLabel ''BState
emptyBState :: BState
emptyBState = BState emptyBCache []