fregel-1.2.0: compiler/TypeInstantiation.hs
{-# Language TypeSynonymInstances,FlexibleInstances,MultiParamTypeClasses,FunctionalDependencies,RankNTypes,FlexibleContexts,KindSignatures,ScopedTypeVariables #-}
{-
Instantiating VertComp/VertInit/GraphFun for each use of them (7th step)
Assumption:
- no function definition (other than the above)
- let-bindings are located at the top level (of the above functions)
-}
module TypeInstantiation where
import Spec
import ASTData
import TypeChecker
import Control.Monad.State
import Data.Maybe
import Data.List
import Numeric (showHex)
import Debug.Trace
type DTypeInstances = (DGroundDef DASTData, [(DTypeInfo, DGroundDef DASTData)])
type DTypeInstanceBinding = ([DVarName], DTypeInstances)
type DTypeInstanceBindings = [DTypeInstanceBinding]
-- uniq id, stack, stack head indices
type DEnvTI = (DUnique, DTypeInstanceBindings, [Int])
class TypeInstantiable a where
typeInstantiation :: a -> State DEnvTI a -- functions are replaced with their instances
typeInstantiation x = return x -- default
-- entry point
runTypeInstantiation :: forall (t :: * -> *) a . TypeInstantiable (t DASTData) => (t DASTData) -> DUnique -> (t DASTData, DUnique)
runTypeInstantiation p uid = let (p', (uid', _, _)) = runState (typeInstantiation p) (uid, [], [])
in (p', uid')
-- TODO: built-in functions?
addNewBind :: DVarName -> DGroundDef DASTData -> State DEnvTI ()
addNewBind n def = do (i, bds, ks) <- get
let bds' = rec bds
put (i, bds', ks)
where rec [] = []
rec ((ns, (org, ins)):xs) = case elemIndex n ns of
Just _ -> (ns, (org, (typeOf (getData def), def):ins)):xs
Nothing -> (ns, (org, ins)):rec xs
getNewName :: String -> State (DEnvTI) DVarName
getNewName s =
do (i, bds, ks) <- get
let (n, i') = genNewName i (getBaseName s)
put (i', bds, ks)
return n
getBinds :: State DEnvTI DTypeInstanceBindings
getBinds = do (i, bds, ks) <- get
return bds
addBindsByDefs :: [DGroundDef DASTData] -> State DEnvTI ()
addBindsByDefs defs = do addBinds (map (\def -> (getNames def, (def, []))) defs)
addBindsByDefsS :: [DSmplDef DASTData] -> State DEnvTI ()
addBindsByDefsS defs = addBindsByDefs (map (\def -> DGDefSmpl def (getData def)) defs)
addBindsByDefsV :: [DDefGraphVar DASTData] -> State DEnvTI ()
addBindsByDefsV defs = addBindsByDefs (map (\def -> DGDefGV def (getData def)) defs)
addBinds :: DTypeInstanceBindings -> State DEnvTI ()
addBinds bds = do (i, bds', ks) <- get
put (i, bds++bds', length bds:ks)
lookupBind :: DVarName -> State DEnvTI (Maybe (DTypeInstances, Int))
lookupBind n = do bds <- getBinds
return (rec bds)
where rec [] = Nothing
rec ((ns, ins):xs) = case elemIndex n ns of
Just i -> (Just (ins, if length ns == 1 then -1 else i))
Nothing -> rec xs
popBinds :: State DEnvTI DTypeInstanceBindings
popBinds = do xx <- get
let (i, bds, k:ks) = xx
put (i, drop k bds, ks)
return (take k bds)
isSmplDef (DGDefSmpl def a) = True
isSmplDef _ = False
isVertFunDef (DGDefVI def a) = True
isVertFunDef (DGDefVC def a) = True
isVertFunDef _ = False
isGraphFunVarDef (DGDefGV def a) = True
isGraphFunVarDef (DGDefGF def a) = True
isGraphFunVarDef _ = False
instance TypeInstantiable (DProgramSpec DASTData) where
typeInstantiation (DProgramSpec rs p a) =
do p' <- typeInstantiation p
return (DProgramSpec rs p' a)
instance TypeInstantiable (DProg DASTData) where
typeInstantiation (DProg f defs e a) =
do -- add the defs. to the env
addBindsByDefs defs
e' <- typeInstantiation e
defs' <- popBinds
let defs'' = concatMap (\(_, (_, ds)) -> map snd ds) defs'
return (DProg f defs'' e' a)
instance TypeInstantiable (DGraphExpr DASTData) where
typeInstantiation (DPregel f0 ft x g a) =
do f0' <- typeInstantiation f0
ft' <- typeInstantiation ft
x' <- typeInstantiation x
g' <- typeInstantiation g
return (DPregel f0' ft' x' g' a)
typeInstantiation (DGMap f g a) =
do f' <- typeInstantiation f
g' <- typeInstantiation g
return (DGMap f' g' a)
typeInstantiation (DGZip g1 g2 a) =
do g1' <- typeInstantiation g1
g2' <- typeInstantiation g2
return (DGZip g1' g2' a)
typeInstantiation (DGIter f0 ft x g a) =
do f0' <- typeInstantiation f0
ft' <- typeInstantiation ft
x' <- typeInstantiation x
g' <- typeInstantiation g
return (DGIter f0' ft' x' g' a)
typeInstantiation (DGVar v a) =
do v' <- typeInstantiation v
return (DGVar v' a)
------------------ giving new names when instantiating
class NameRefreshable a where
refreshNames :: a -> State DEnvTI a
instance NameRefreshable (DGroundDef DASTData) where
refreshNames (DGDefVC d a) = do d' <- refreshNames d
return (DGDefVC d' a)
refreshNames (DGDefVI d a) = do d' <- refreshNames d
return (DGDefVI d' a)
refreshNames (DGDefSmpl d a) = do d' <- refreshNames d
return (DGDefSmpl d' a)
refreshNames (DGDefGV d a) =
do d' <- refreshNames d
return (DGDefGV d' a)
refreshNames (DGDefGF d a) = do d' <- refreshNames d
return (DGDefGF d' a)
replaceNames :: [(DVarName, DVarName)] -> DExpr DASTData -> DExpr DASTData
replaceNames subsv e = rec e
where
rec (DIf p t e a) =
let p' = rec p
t' = rec t
e' = rec e
in (DIf p' t' e' a)
rec (DTuple es a) =
let es' = map rec es
in (DTuple es' a)
rec (DFunAp f es a) =
let es' = map rec es
in (DFunAp f es' a)
rec (DConsAp c es a) =
let es' = map rec es
in (DConsAp c es' a)
rec (x@(DFieldAcc t fs a)) = x
rec (x@(DFieldAccE e fs a)) = x
rec (DAggr a' e g es a) =
let e' = rec e
es' = map rec es
in (DAggr a' e' g es' a)
rec (x@(DVExp (DVar v av) a)) =
case lookup v subsv of
Just v' -> (DVExp (DVar v' av) a)
Nothing -> x
rec (x@(DCExp c a)) = x
instance NameRefreshable (DFun DASTData) where
refreshNames (DFun f a) =
do f' <- getNewName f
return (DFun f' a)
refreshNames (DBinOp f a) =
do f' <- getNewName f
return (DBinOp f' a)
instance NameRefreshable (DVar DASTData) where
refreshNames (DVar v a) =
do v' <- getNewName v
return (DVar v' a)
instance NameRefreshable (DDefVertComp DASTData) where
refreshNames (DDefVertComp f defs e a) =
do f' <- refreshNames f
return (DDefVertComp f' defs e a)
instance NameRefreshable (DDefVertInit DASTData) where
refreshNames (DDefVertInit f defs e a) =
do f' <- refreshNames f
return (DDefVertInit f' defs e a)
instance NameRefreshable (DDefGraphVar DASTData) where
refreshNames (DDefGraphVar v e a) =
do v' <- refreshNames v
return (DDefGraphVar v' e a)
replaceNamesF subse (DFun f a) =
case lookup f subse of
Nothing -> (DFun f a)
Just f' -> (DFun f' a)
replaceNamesV subse (DVar v a) =
case lookup v subse of
Nothing -> (DVar v a)
Just v' -> (DVar v' a)
replaceNamesG subse (DPregel f0 ft x g a) =
let f0' = replaceNamesF subse f0
ft' = replaceNamesF subse ft
x' = x
g' = replaceNamesG subse g
in (DPregel f0' ft' x' g' a)
replaceNamesG subse (DGMap f g a) =
let f' = replaceNamesF subse f
g' = replaceNamesG subse g
in (DGMap f' g' a)
replaceNamesG subse (DGZip g1 g2 a) =
let g1' = replaceNamesG subse g1
g2' = replaceNamesG subse g2
in (DGZip g1' g2' a)
replaceNamesG subse (DGIter f0 ft x g a) =
let f0' = replaceNamesF subse f0
ft' = replaceNamesF subse ft
x' = x
g' = replaceNamesG subse g
in (DGIter f0' ft' x' g' a)
replaceNamesG subse (DGVar v a) =
let v' = replaceNamesV subse v
in (DGVar v' a)
replaceNamesGV subse (DDefGraphVar v e a) =
let e' = (replaceNamesG subse e)
in (DDefGraphVar v e' a)
instance NameRefreshable (DDefGraphFun DASTData) where
refreshNames (DDefGraphFun f v defs e a) =
do f' <- refreshNames f
v' <- refreshNames v
defs' <- mapM refreshNames defs
let subse = [(getName f, getName f'), (getName v, getName v')] ++ zipWith (\o n -> (getName o, getName n)) defs defs'
e' = replaceNamesG subse e
defs'' = map (replaceNamesGV subse) defs'
return (DDefGraphFun f' v' defs'' e' a)
instance NameRefreshable (DSmplDef DASTData) where
refreshNames (DDefVar v [] e a) =
do v' <- refreshNames v
let subse = [(getName v, getName v')]
e' = replaceNames subse e
return (DDefVar v [] e' a)
refreshNames (DDefTuple vs [] e a) =
do vs' <- mapM refreshNames vs
let subse = zip (map getName vs) (map getName vs')
e' = replaceNames subse e
return (DDefTuple vs' [] e' a)
refreshNames x = error $ "something wrong in refreshNames : x = " ++ show x
----------------------------------------------------------------
instance TypeInstantiable (DGroundDef DASTData) where
typeInstantiation (DGDefVC d a) = do d' <- typeInstantiation d
return (DGDefVC d' a)
typeInstantiation (DGDefVI d a) = do d' <- typeInstantiation d
return (DGDefVI d' a)
typeInstantiation (DGDefSmpl d a) = do d' <- typeInstantiation d
return (DGDefSmpl d' a)
typeInstantiation (DGDefGV d a) = do d' <- typeInstantiation d
return (DGDefGV d' a)
typeInstantiation (DGDefGF d a) = do d' <- typeInstantiation d
return (DGDefGF d' a)
makeDefs defs = concatMap (\(_, (_, ds)) -> map (\(DGDefSmpl def _) -> def) (map snd ds)) defs
makeDefsGV defs = concatMap (\(_, (_, ds)) -> map (\(DGDefGV def _) -> def) (map snd ds)) defs
instance TypeInstantiable (DDefVertComp DASTData) where
typeInstantiation (DDefVertComp f defs e a) =
do addBindsByDefsS defs
e' <- typeInstantiation e
defs' <- popBinds
let defs'' = makeDefs defs'
return (DDefVertComp f defs'' e' a)
instance TypeInstantiable (DDefVertInit DASTData) where
typeInstantiation (DDefVertInit f defs e a) =
do addBindsByDefsS defs
e' <- typeInstantiation e
defs' <- popBinds
let defs'' = makeDefs defs'
return (DDefVertInit f defs'' e' a)
instance TypeInstantiable (DDefGraphVar DASTData) where
typeInstantiation (DDefGraphVar v e a) =
do e' <- typeInstantiation e
return (DDefGraphVar v e' a)
instance TypeInstantiable (DDefGraphFun DASTData) where
typeInstantiation (DDefGraphFun f v defs e a) =
do addBindsByDefsV defs
e' <- typeInstantiation e
defs' <- popBinds
let defs'' = makeDefsGV defs'
return (DDefGraphFun f v defs'' e' a)
instance TypeInstantiable (DSmplDef DASTData) where
typeInstantiation (DDefFun f vs defs e a) =
do addBindsByDefsS defs
e' <- typeInstantiation e
defs' <- popBinds
let defs'' = makeDefs defs'
return (DDefFun f vs defs'' e' a)
typeInstantiation (DDefVar v defs e a) =
do addBindsByDefsS defs
e' <- typeInstantiation e
defs' <- popBinds
let defs'' = makeDefs defs'
return (DDefVar v defs'' e' a)
typeInstantiation (DDefTuple vs defs e a) =
do addBindsByDefsS defs
e' <- typeInstantiation e
defs' <- popBinds
let defs'' = makeDefs defs'
return (DDefTuple vs defs'' e' a)
instance TypeInstantiable (DTermination DASTData) where
typeInstantiation (DTermF a) = return (DTermF a)
typeInstantiation (DTermI e a) =
do e' <- typeInstantiation e
return (DTermI e' a)
typeInstantiation (DTermU e a) =
do e' <- typeInstantiation e
return (DTermU e' a)
instance TypeInstantiable (DExpr DASTData) where
typeInstantiation (DIf p t e a) =
do p' <- typeInstantiation p
t' <- typeInstantiation t
e' <- typeInstantiation e
return (DIf p' t' e' a)
typeInstantiation (DTuple es a) =
do es' <- mapM typeInstantiation es
return (DTuple es' a)
typeInstantiation (DFunAp f es a) =
do f' <- typeInstantiation f
es' <- mapM typeInstantiation es
return (DFunAp f' es' a)
typeInstantiation (DConsAp c es a) =
do c' <- typeInstantiation c
es' <- mapM typeInstantiation es
return (DConsAp c' es' a)
typeInstantiation (DFieldAcc t fs a) =
do t' <- typeInstantiation t
fs' <- mapM typeInstantiation fs
return (DFieldAcc t' fs' a)
typeInstantiation (DFieldAccE e fs a) =
do e' <- typeInstantiation e
fs' <- mapM typeInstantiation fs
return (DFieldAccE e' fs' a)
typeInstantiation (DAggr a' e g es a) =
do a'' <- typeInstantiation a'
g' <- typeInstantiation g
e' <- typeInstantiation e
es' <- mapM typeInstantiation es
return (DAggr a'' e' g' es' a)
typeInstantiation (DVExp v a) =
do v' <- typeInstantiation v
return (DVExp v' a)
typeInstantiation (DCExp c a) =
do c' <- typeInstantiation c
return (DCExp c' a)
unifyUpdate def t =
do s <- unify' [(typeOf (getData def), t)]
return (mapData (\a -> a { typeOf = apply s (typeOf a)}) def)
instance TypeInstantiable (DFun DASTData) where
typeInstantiation (DBinOp f a) = instantiation DBinOp f a
typeInstantiation (DFun f a) = instantiation DFun f a
instance TypeInstantiable (DVar DASTData) where
typeInstantiation (DVar v a) = instantiation DVar v a
instantiation
:: (DVarName -> DASTData -> b)
-> DVarName
-> DASTData
-> State DEnvTI b
instantiation build v a =
do r <- lookupBind v
case r of
Nothing -> return (build v a) -- temporary things?
Just ((def, ins), pos) ->
case def of
(DGDefGF _ _) -> do def' <- refreshNames def -- always duplicate it
let defe'' = unifyUpdate def' (typeOf a)
case defe'' of
Right def'' ->
do def''' <- typeInstantiation def'' -- instantiate it
addNewBind v def''' -- add it to the env
return (build (getNames def''' !! (max pos 0)) a) -- use it
Left str -> error (str ++ "\nerror during unifying " ++ show def' ++ " and " ++ show (typeOf a) ++ "\nv="++show v ++ "\na="++show a)
otherwise ->
case lookupAt pos (typeOf a) ins of
Just def' -> return (build (getNames def' !! (max pos 0)) a) -- already instantiated
Nothing -> if typeAt pos (typeOf (getData def)) == (typeOf a)
then do def'' <- typeInstantiation def
addNewBind v def'' -- use the original one
return (build (getNames def'' !! (max pos 0)) a)
else do def' <- refreshNames def -- gives new names
let defe'' = unifyUpdate def' (typeOf a)
case defe'' of
Right def'' ->
do def''' <- typeInstantiation def'' -- instantiate it
addNewBind v def''' -- add it to the env
return (build (getNames def''' !! (max pos 0)) a) -- use it
Left str -> error (str ++ "\nerror during unifying2 " ++ show def' ++ " and " ++ show (typeOf a) ++ "\nv="++show v ++ "\na="++show a ++ "\nins="++show ins ++ "\npos="++show pos )
typeAt (-1) t = t
typeAt pos (DTypeTerm "(,)" ts) = (ts!!pos)
lookupBy' :: Eq b => (a -> b) -> b -> [(a, x)] -> Maybe x
lookupBy' _ _ [] = Nothing
lookupBy' f key ((a,x):xs) = if f a == key then Just x else lookupBy' f key xs
lookupAt :: Int -> DTypeInfo -> [(DTypeInfo, x)] -> Maybe x
lookupAt pos t ins | pos == -1 = lookup t ins
| otherwise = lookupBy' (typeAt pos) t ins -- tuple case
instance TypeInstantiable (DAgg DASTData)
instance TypeInstantiable (DGen DASTData)
instance TypeInstantiable (DEdge DASTData)
instance TypeInstantiable (DTableExpr DASTData)
instance TypeInstantiable (DField DASTData)
instance TypeInstantiable (DConstructor DASTData)
instance TypeInstantiable (DConst DASTData)