{- OPTIONS_DERIVE --module=Yhc.Core.Binary --derive=BinaryOld --output=Binary.hs -} {- OPTIONS_DERIVE --import --import=Yhc.Core.Internal.Binary --import=Control.Monad -} module Yhc.Core.Type where -- while it may seem tempting to add type signatures to Core -- it won't work - by this stage all the type signatures are -- wrong because of desugarring import Control.Monad(liftM) import Data.Maybe(fromMaybe, listToMaybe, mapMaybe) import Data.Char(isSpace) import Data.List(intersperse) import qualified Data.Map as Map {-! global: GhcBinary !-} type CoreVarName = String type CoreFuncName = String type CoreDataName = String type CoreCtorName = String type CoreFieldName = String -- module name, imports, items in the module data Core = Core {coreName :: String, coreImports :: [String], coreDatas :: [CoreData], coreFuncs :: [CoreFunc]} deriving (Eq,Ord) data CoreData = CoreData {coreDataName :: CoreDataName, coreDataTypes :: [String], coreDataCtors :: [CoreCtor]} deriving (Eq,Ord) -- Name, then list of maybe field names data CoreCtor = CoreCtor {coreCtorName :: CoreCtorName, coreCtorFields :: [(String, Maybe CoreFieldName)]} deriving (Eq,Ord) data CoreFunc = CoreFunc {coreFuncName :: CoreFuncName, coreFuncArgs :: [CoreVarName], coreFuncBody :: CoreExpr} | CorePrim { coreFuncName :: CoreFuncName, corePrimArity :: Int, corePrimExternal :: String, corePrimConv :: String, corePrimImport :: Bool, corePrimTypes :: [String] } deriving (Eq,Ord) isCoreFunc, isCorePrim :: CoreFunc -> Bool isCoreFunc (CoreFunc{}) = True; isCoreFunc _ = False isCorePrim (CorePrim{}) = True; isCorePrim _ = False coreFuncArity :: CoreFunc -> Int coreFuncArity (CorePrim{corePrimArity=x}) = x coreFuncArity x = length $ coreFuncArgs x -- An universal replacement for coreFuncArgs that now does not match in all cases coreFuncArgList :: CoreFunc -> [CoreVarName] coreFuncArgList (CorePrim{coreFuncName=n,corePrimArity=x}) = take x $ map (("__" ++ n ++ "_") ++) (map show [1..]) coreFuncArgList x = coreFuncArgs x type CoreFuncMap = Map.Map CoreFuncName CoreFunc data CoreExpr = CoreCon CoreCtorName | CoreVar CoreVarName | CoreFun CoreFuncName | CoreApp CoreExpr [CoreExpr] | CoreLam [CoreVarName] CoreExpr | CoreCase CoreExpr [(CorePat,CoreExpr)] | CoreLet [(CoreVarName,CoreExpr)] CoreExpr | CorePos String CoreExpr | CoreLit CoreLit deriving (Ord,Eq) data CoreLit = CoreInt Int | CoreInteger Integer | CoreChr Char | CoreStr String | CoreFloat Float | CoreDouble Double deriving (Ord,Eq,Show) data CorePat = PatCon {patCon :: CoreCtorName, patVars :: [CoreVarName]} | PatLit {patLit :: CoreLit} | PatDefault deriving (Ord,Eq,Show) -- smart constructors coreApp :: CoreExpr -> [CoreExpr] -> CoreExpr coreApp x [] = x coreApp x xs = CoreApp x xs coreLet :: [(CoreVarName,CoreExpr)] -> CoreExpr -> CoreExpr coreLet [] x = x coreLet xs x = CoreLet xs x coreLam :: [CoreVarName] -> CoreExpr -> CoreExpr coreLam [] x = x coreLam xs x = CoreLam xs x fromCoreLit :: CoreExpr -> CoreLit fromCoreLit (CoreLit x) = x fromCoreLit x = error $ "Yhc.Core.fromCoreLit on a non-literal" fromCoreCon, fromCoreVar, fromCoreFun :: CoreExpr -> String fromCoreCon (CoreCon x) = x fromCoreVar (CoreVar x) = x fromCoreFun (CoreFun x) = x fromCoreApp :: CoreExpr -> (CoreExpr,[CoreExpr]) fromCoreApp (CoreApp x y) = (x,y) fromCoreApp x = (x,[]) fromCoreLet :: CoreExpr -> ([(CoreVarName,CoreExpr)],CoreExpr) fromCoreLet (CoreLet x y) = (x,y) fromCoreLet x = ([],x) fromCoreLam :: CoreExpr -> ([CoreVarName],CoreExpr) fromCoreLam (CoreLam x y) = (x,y) fromCoreLam x = ([],x) isCoreCon, isCoreVar, isCoreFun, isCoreLam :: CoreExpr -> Bool isCorePos, isCoreLet, isCoreCase, isCoreLit :: CoreExpr -> Bool isCoreCon x = case x of {CoreCon{} -> True; _ -> False} isCoreVar x = case x of {CoreVar{} -> True; _ -> False} isCoreFun x = case x of {CoreFun{} -> True; _ -> False} isCoreLam x = case x of {CoreLam{} -> True; _ -> False} isCorePos x = case x of {CorePos{} -> True; _ -> False} isCoreLet x = case x of {CoreLet{} -> True; _ -> False} isCoreCase x = case x of {CoreCase{} -> True; _ -> False} isCoreLit x = case x of {CoreLit{} -> True; _ -> False} isCoreStr, isCoreChr, isCoreInt :: CoreLit -> Bool isCoreStr x = case x of {CoreStr{} -> True; _ -> False} isCoreChr x = case x of {CoreChr{} -> True; _ -> False} isCoreInt x = case x of {CoreInt{} -> True; _ -> False} isPatDefault, isPatLit, isPatCon :: CorePat -> Bool isPatDefault x = case x of {PatDefault{} -> True; _ -> False} isPatLit x = case x of {PatLit{} -> True; _ -> False} isPatCon x = case x of {PatCon{} -> True; _ -> False} {-# DEPRECATED fromPatLit "use patLit instead" #-} fromPatLit = patLit patVariables (PatCon _ xs) = xs patVariables _ = [] patToExpr :: CorePat -> CoreExpr patToExpr (PatCon c xs) = coreApp (CoreCon c) (map CoreVar xs) patToExpr (PatLit x) = CoreLit x patToExpr PatDefault = CoreVar "_" exprToPat :: CoreExpr -> CorePat exprToPat (CoreApp (CoreCon c) vs) = PatCon c (map fromCoreVar vs) exprToPat (CoreCon c) = PatCon c [] exprToPat (CoreLit x) = PatLit x exprToPat (CoreVar _) = PatDefault -- | Returns true for constants that take a small, bounded -- amount of space isCoreLitSmall :: CoreLit -> Bool isCoreLitSmall x = isCoreInt x || isCoreChr x remCorePos :: CoreExpr -> CoreExpr remCorePos (CorePos _ x) = x remCorePos x = x -- | drop a module from a Core declaration dropModule :: String -> String dropModule x = f x False x where f x False (';':_) = x f _ True (';':x) = f x False x f x _ (_:xs) = f x True xs f x _ [] = x -- | Get a function from a Core type -- crashes if the function does not exist coreFunc :: Core -> CoreFuncName -> CoreFunc coreFunc core name = fromMaybe (error msg) (coreFuncMaybe core name) where msg = "Yhc.Core.Type.coreFunc, function not found: " ++ name -- | A non-crashing version of 'coreFunc' -- returns Nothing if the function does not exist. -- If multiple functions with the same name exist, this crashes. coreFuncMaybe :: Core -> CoreFuncName -> Maybe CoreFunc coreFuncMaybe core name = case [x | x <- coreFuncs core, coreFuncName x == name] of [] -> Nothing [x] -> Just x xs -> error $ "Yhc.Core.Type.mbCoreFunc, found found " ++ show (length xs) ++ " times: " ++ name -- | Get a 'CoreData' from a field (the snd element of 'coreCtorFields') coreFieldDataMaybe :: Core -> CoreFieldName -> Maybe CoreData coreFieldDataMaybe core name = coreFieldCtorMaybe core name >>= coreCtorDataMaybe core . coreCtorName -- | Get a 'CoreData' from a ctor name coreCtorDataMaybe :: Core -> CoreCtorName -> Maybe CoreData coreCtorDataMaybe core name = listToMaybe [dat | dat <- coreDatas core, name `elem` map coreCtorName (coreDataCtors dat)] -- | Get a 'CoreCtor' from a field name coreFieldCtorMaybe :: Core -> CoreFieldName -> Maybe CoreCtor coreFieldCtorMaybe core name = listToMaybe [ctr | dat <- coreDatas core, ctr <- coreDataCtors dat , name `elem` mapMaybe snd (coreCtorFields ctr)] coreFieldData :: Core -> CoreFieldName -> CoreData coreFieldData core name = fromMaybe (error msg) $ coreFieldDataMaybe core name where msg = "Yhc.Core.coreFieldData, looking for " ++ name coreCtorData :: Core -> CoreCtorName -> CoreData coreCtorData core = fromMaybe (error "Yhc.Core.coreCtorData") . coreCtorDataMaybe core coreFieldCtor :: Core -> CoreFieldName -> CoreCtor coreFieldCtor core = fromMaybe (error "Yhc.Core.coreFieldCtor") . coreFieldCtorMaybe core coreCtor :: Core -> CoreCtorName -> CoreCtor coreCtor core name = head [ctr | dat <- coreDatas core, ctr <- coreDataCtors dat, coreCtorName ctr == name] coreData :: Core -> CoreDataName -> CoreData coreData core name = head [dat | dat <- coreDatas core, coreDataName dat == name] -- | Take a function that operates on bodies, and apply it to a program applyBodyCore :: (CoreExpr -> CoreExpr) -> (Core -> Core) applyBodyCore f = applyFuncCore (applyBodyFunc f) -- | Take a function that operates on bodies, and apply it to a function applyBodyFunc :: (CoreExpr -> CoreExpr) -> (CoreFunc -> CoreFunc) applyBodyFunc f func | isCoreFunc func = func{coreFuncBody = f (coreFuncBody func)} | otherwise = func -- | Take a function that operates on functions, and apply it to a program applyFuncCore :: (CoreFunc -> CoreFunc) -> (Core -> Core) applyFuncCore f core = core{coreFuncs = map f (coreFuncs core)} applyCtorCore :: (CoreCtor -> CoreCtor) -> (Core -> Core) applyCtorCore f = applyDataCore (applyCtorData f) applyDataCore :: (CoreData -> CoreData) -> (Core -> Core) applyDataCore f core = core{coreDatas = map f (coreDatas core)} applyCtorData :: (CoreCtor -> CoreCtor) -> (CoreData -> CoreData) applyCtorData f dat = dat{coreDataCtors = map f (coreDataCtors dat)} applyBodyCoreM :: Monad m => (CoreExpr -> m CoreExpr) -> Core -> m Core applyBodyCoreM f = applyFuncCoreM g where g (CoreFunc a b c) = liftM (CoreFunc a b) $ f c g x = return x applyFuncCoreM :: Monad m => (CoreFunc -> m CoreFunc) -> Core -> m Core applyFuncCoreM f c = do res <- mapM f (coreFuncs c) return $ c{coreFuncs = res} -- | Split up a coreDataType into lexical elements -- None of the result elements will be space, or blank -- Some may be "(", ")" or "!" coreDataTypeSplit :: String -> [String] coreDataTypeSplit [] = [] coreDataTypeSplit (x:xs) | x `elem` special = [x] : coreDataTypeSplit xs | isSpace x = coreDataTypeSplit xs | otherwise = let (a,b) = break (\x -> isSpace x || x `elem` special) (x:xs) in a : coreDataTypeSplit b where special = "!()" -- | can pretty print much nicer, just something that works for now coreDataTypeJoin :: [String] -> String coreDataTypeJoin = concat . intersperse " " fromCoreFuncMap :: Core -> CoreFuncMap -> Core fromCoreFuncMap core fm = core{coreFuncs = Map.elems fm} toCoreFuncMap :: Core -> CoreFuncMap toCoreFuncMap core = Map.fromList [(coreFuncName x, x) | x <- coreFuncs core] coreFuncMap :: CoreFuncMap -> CoreFuncName -> CoreFunc coreFuncMap fm name = fromMaybe (error $ "Yhc.Core.coreFuncMap, function not found, " ++ name) $ Map.lookup name fm coreFuncMapMaybe :: CoreFuncMap -> CoreFuncName -> Maybe CoreFunc coreFuncMapMaybe fm name = Map.lookup name fm