%
% Copyright (C) 1997 Thomas Nordin and Alastair Reid
%
\begin{code}
module FillIn
( ProtoProc, ppProtoProc, fillinProc
, Consts, genConsts, genConsts2
) where
#if !defined(__HASKELL98__)
#define mplus (++)
#define isAlphaNum isAlphanum
#endif
import Char (isLower, isAlphaNum)
import Decl (Sig, Call, CCode, Fail, Result)
import Proc (Proc, ppProc)
import Name (Name)
import Type (Type(..), typeArgs, typeResult)
import DIS (DIS(..), DISEnv, apply, freeVarsOfDIS, expandDIS ,simplify)
import NameSupply
import ListUtils (prefix)
import Casm (BaseTy(..))
import Pretty
import PrettyUtils( indent, joinedBy, ppAssign, vcatMap )
import Maybe( fromMaybe )
import Char ( toLower )
import List( intersperse )
#if defined(__HASKELL98__)
import Monad (MonadPlus(mplus))
#endif
-- #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 202
-- import PrelBase(maybe) -- workaround for GHC 2.02
-- #endif
\end{code}
%************************************************************************
%* *
\subsection{The interface}
%* *
%************************************************************************
Note that we expand the DIS before we generate the ccode.
\begin{code}
type ProtoProc = (Sig, Maybe Call, Maybe CCode, Fail, Maybe Result)
\end{code}
\begin{code}
fillinProc :: DISEnv -> [String] -> ProtoProc -> Proc
fillinProc env prefixes (sig@(nm, ty), mbcall, mbccode, fs, mbres)
= ((mangleName prefixes nm, ty), call, ccode, fs, res)
where
(call', res') = expandType env ty
xp = expandDIS env
call = map xp $ fromMaybe call' mbcall
res = xp $ fromMaybe res' mbres
ccode = fromMaybe (expandCCode nm call res) mbccode
\end{code}
%************************************************************************
%* *
\subsection{Generating constants}
%* *
%************************************************************************
Exactly as described in the paper:
\begin{code}
type Consts = (Type, [(Name, Name)])
genConsts :: DISEnv -> Consts -> [ProtoProc]
genConsts env (ty, cs)
= [ ( (hname, ty), Nothing, Just ["res1="++cname], [], Nothing)
| (hname, cname) <- cs
]
where
dis0 = fst $ initNS (typeToDIS env ty) (nameSupply "res")
dis1 = expandDIS env dis0
\end{code}
\begin{code}
genConsts2 :: DISEnv -> [String] -> Consts -> Int -> (Proc, Doc)
genConsts2 env prefixes (ty, cs) i
= ( ( (hname, intTy `Arrow` ty)
, [Apply (BaseDIS Int) [Declare "int" (Var "i")]]
, [render body]
, []
, resdis
)
, vcatMap text [ mangleName prefixes c ++ " = " ++ hname ++ " " ++ show i
| ((c,_),i) <- zip cs [0..] ]
)
where
hname = "consts_" ++ show i
intTy = TypeVar "Int"
resdis = expandDIS env $ fst $ initNS (typeToDIS env ty) (nameSupply "res")
Apply (BaseDIS k) [Declare cty (Var res)] = simplify resdis
body = text "static" <+> text cty <+> text "consts[] = {"
$$ indent (map (text.snd) cs `joinedBy` \ x y -> x <> comma $$ y)
$$ text "};"
$$ ppAssign res (text "consts[i]") <> semi
\end{code}
%************************************************************************
%* *
\subsection{Generating DISs from Types}
%* *
%************************************************************************
@expandType@ turns a type into a DIS. It is used when auto-expanding
missing @%call@ and @%result@ statements.
\begin{code}
expandType :: DISEnv -> Type -> ([DIS], DIS)
expandType env ty = (call, res)
where
ty_args = typeArgs ty
ty_res = typeResult ty
call = fst $ initNS (mapM (typeToDIS env) ty_args) (nameSupply "arg")
res = fst $ initNS (typeToDIS env ty_res) (nameSupply "res")
typeToDIS :: DISEnv -> Type -> NSM DIS
typeToDIS env (TypeTuple ts) =
do ds <- mapM (typeToDIS env) ts
return (apply Tuple ds)
typeToDIS env (TypeList t) =
do ptr <- getNewName
len <- getNewName
return (apply (Var ("listLen" ++ show t)) [Var ptr, Var len])
typeToDIS env (TypeVar typeName) =
do ns <- getNewNames arity
return (apply (Var disName) (map Var ns))
where
arity :: Int
arity = maybe 1 (length . fst) x
disName :: Name
disName = lowerName typeName
x :: Maybe ([Name], DIS)
x = lookup disName env
typeToDIS env (TypeApply (TypeVar f) args) =
do ds <- mapM (typeToDIS env) args
ns <- getNewNames (max 0 (arity - length ds))
return (apply (Var disName) (ds ++ map Var ns))
where
arity :: Int
arity = maybe 1 (length . fst) x
disName :: Name
disName = lowerName f
x :: Maybe ([Name], DIS)
x = lookup disName env
\end{code}
%************************************************************************
%* *
\subsection{Filling in CCode lines}
%* *
%************************************************************************
NB: The DISs should have been expanded before we call this puppy.
\begin{code}
expandCCode :: String -> [DIS] -> DIS -> [String]
expandCCode name ds rs =
[ lhs ++ name ++ "(" ++ concat (intersperse ", " args) ++ ");" ]
where
args = concatMap leafVarsOfDIS ds
res = leafVarsOfDIS rs
lhs | null res = ""
| otherwise = head res ++ " = "
-- like freeVarsOfDIS but omits "functions"
leafVarsOfDIS :: DIS -> [Name]
leafVarsOfDIS = free
where
free (Apply d ds) = concatMap free ds
free (Var nm) = [nm]
free (Exp e) = let vs = noDups (varsInExp e)
in vs
free _ = []
varsInExp [] = []
varsInExp ('%':c:cs)
| isLower c = nm: varsInExp rest
| c=='%' = varsInExp cs
where (cs1, rest) = span isAlphaNum cs
nm = c:cs1
varsInExp (c:cs) = varsInExp cs
noDups = noDups' []
where noDups' a [] = a
noDups' a (x:xs)
| x `elem` a = noDups' a xs
| otherwise = noDups' (x:a) xs
\end{code}
%************************************************************************
%* *
\subsection{Name Mangling}
%* *
%************************************************************************
Convert a Type name to a DIS name
\begin{code}
lowerName :: Name -> Name
lowerName [] = []
lowerName (c:cs) = toLower c : cs
\end{code}
Convert C name to Haskell name by stripping prefixes and
converting first letter to lowercase.
\begin{code}
mangleName :: [String] -> String -> String
mangleName ps n = lowerName (stripPrefixes ps n)
stripPrefixes :: [String] -> String -> String
stripPrefixes ps n = fromMaybe n $ foldr mplus Nothing
[ prefix p n | p <- ps ]
\end{code}
%************************************************************************
%* *
\subsection{Pretty printing}
%* *
%************************************************************************
A gruesome hack to print it...
\begin{code}
ppProtoProc :: ProtoProc -> Doc
ppProtoProc (sig@(nm, ty), mbcall, mbccode, fs, mbres)
= ppProc (sig, call, ccode, fs, res)
where
call = fromMaybe [Var ""] mbcall
res = fromMaybe (Var "") mbres
ccode = fromMaybe [] mbccode
\end{code}
|