%
% (c) The Foo Project, University of Glasgow, 1998
%
% @(#) $Docid: Feb. 9th 2003 14:49 Sigbjorn Finne $
% @(#) $Contactid: sof@galois.com $
%
The code generator carries around information about
the abstract Haskell code that's being generated:
- the export list so far.
- the context we're in (e.g., are we processing
a COM method)
- etc.
\begin{code}
module CgMonad
(
CgM
, IfaceType(..)
, runCgM
, getDllName
, setDllName
, getDeclName
, withDeclName
, withIfaceDeclName
, needStubs
, hasPrims
, setInterfaceFlag
, getInterfaceFlag
, setSourceIfaceFlag
, getSourceIfaceFlag
, setClientFlag
, getClientFlag
, getIfaceName
, setIfaceName
, inDispInterface
, isInDispInterface
, setIfaceAttributes
, getIfaceAttributes
, getIfaceInherit
, withIfaceInherit
, IsoEnv
, getIsoEnv
, setIsoEnv
, getIEnumFlag
, setIEnumFlag
, addDynStub
, lookupDynStub
, addExport
, addVitalExport
, addExportWithComment
, exportDecl
, addExplicitImports
, hoistInClass
, getMethodNumber
, setMethodNumber
, incMethodNumber
) where
import Env
import AbstractH
import CoreIDL ( Result, Param, Id, Attribute )
import Opts ( optServer, optOneModulePerInterface )
import Maybe ( fromMaybe )
import BasicTypes ( QualName )
\end{code}
Information is carried both down and along:
\begin{code}
newtype CgM a = CgM ( CgDown -> CgState -> (a, CgState) )
data CgDown
= CgDown {
if_ty :: IfaceType,
if_client :: Bool,
if_source :: Bool,
if_ienum :: Bool,
if_disp :: Bool,
dll_nm :: String,
mod_nm :: String,
if_nm :: String,
if_attrs :: [Attribute],
if_inh :: [QualName],
iface_env :: Env String (Maybe Id)
}
data IfaceType
= StdFFI
| VTBLObject
| ComIDispatch Bool
deriving Eq
type IsoEnv = Env String [(Bool, Result, [Param])]
data CgState =
CgState {
exp_list :: [(HIEEntity, Bool, Maybe String)],
imp_list :: [(String,Bool,[HIEEntity])],
dyn_env :: Env String (Bool, String),
iso_env :: IsoEnv,
meth_no :: !Int,
need_stubs :: Bool,
has_prims :: Bool
}
runCgM :: Env String [(Result, [Param])]
-> Env String (Maybe Id)
-> CgM a
-> ( a
, [(HIEEntity, Bool, Maybe String)]
, [(String, Bool, [HIEEntity])]
, Bool
, Bool
)
runCgM isoEnv ifaceEnv (CgM act) =
case (act (CgDown iface_flg is_client is_source is_ienum
is_disp "" "" "" [] [] ifaceEnv)
(CgState [] [] newEnv iso_env' 0 False False)) of
(v,CgState expo imps _ _ _ flg1 flg2) -> (v, reverse expo, imps, flg1, flg2)
where
is_client = not optServer
is_ienum = False
is_source = False
is_disp = False
iface_flg = StdFFI
iso_env' = mapEnv (\ _ ls -> map (\ (as,bs) -> (True, as, bs)) ls) isoEnv
getDllName :: CgM String
getDllName = CgM (\ env st -> (dll_nm env, st))
setDllName :: String -> CgM a -> CgM a
setDllName dname (CgM a) = CgM (\ env st -> a (env{dll_nm=dname}) st)
getDeclName :: (String -> CgM a) -> CgM a
getDeclName cont = CgM (\ env st -> let (CgM a) = cont (mod_nm env) in a env st)
needStubs :: Bool -> CgM ()
needStubs flg = CgM (\ _ st -> ((), st{need_stubs=need_stubs st || flg}))
hasPrims :: CgM ()
hasPrims = CgM (\ _ st -> ((), st{has_prims=True}))
withDeclName :: String -> CgM a -> CgM a
withDeclName mname (CgM a) = CgM (\ env st -> a (env{mod_nm=mname}) st)
withIfaceDeclName :: String -> CgM a -> CgM a
withIfaceDeclName mname act
| not optOneModulePerInterface = act
| otherwise = withDeclName mname act
setInterfaceFlag :: IfaceType -> CgM a -> CgM a
setInterfaceFlag flg (CgM a) = CgM (\ env st -> a (env{if_ty=flg}) st)
setClientFlag :: Bool -> CgM a -> CgM a
setClientFlag flg (CgM a) = CgM (\ env st -> a (env{if_client=flg}) st)
getClientFlag :: CgM Bool
getClientFlag = CgM (\ env st -> (if_client env, st))
getInterfaceFlag :: CgM IfaceType
getInterfaceFlag = CgM (\ env st -> (if_ty env, st))
getIfaceName :: CgM String
getIfaceName = CgM (\ env st -> (if_nm env, st))
getIfaceAttributes :: CgM [Attribute]
getIfaceAttributes = CgM (\ env st -> (if_attrs env, st))
getIfaceInherit :: CgM [QualName]
getIfaceInherit = CgM (\ env st -> (if_inh env, st))
withIfaceInherit :: [QualName] -> CgM a -> CgM a
withIfaceInherit ls (CgM a) =
CgM (\ env st -> a (env{if_inh=ls}) st)
setIfaceName :: String -> CgM a -> CgM a
setIfaceName iface (CgM a) =
CgM (\ env st -> a (env{if_nm=iface}) st)
setIfaceAttributes :: [Attribute] -> CgM a -> CgM a
setIfaceAttributes as (CgM a) = CgM (\ env st -> a (env{if_attrs=as}) st)
getIsoEnv :: CgM IsoEnv
getIsoEnv = CgM (\ _ st -> (iso_env st, st))
setIsoEnv :: IsoEnv -> CgM ()
setIsoEnv env = CgM (\ _ st -> ((),st{iso_env=env}))
getIEnumFlag :: CgM Bool
getIEnumFlag = CgM (\ env st -> (if_ienum env, st))
setIEnumFlag :: Bool -> CgM a -> CgM a
setIEnumFlag i (CgM a) = CgM (\ env st -> a (env{if_ienum=i}) st)
getSourceIfaceFlag :: CgM Bool
getSourceIfaceFlag = CgM (\ env st -> (if_source env, st))
setSourceIfaceFlag :: Bool -> CgM a -> CgM a
setSourceIfaceFlag i (CgM a) = CgM (\ env st -> a (env{if_source=i}) st)
addExport :: HIEEntity -> CgM ()
addExport nm = CgM ( \ _ st -> ((), st{exp_list=(nm, False, Nothing):exp_list st}))
addVitalExport :: HIEEntity -> CgM ()
addVitalExport nm = CgM ( \ _ st -> ((), st{exp_list=(nm, True, Nothing):exp_list st}))
hoistInClass :: String -> (Maybe Id -> CgM a) -> CgM a
hoistInClass nm cont =
CgM (\ env st ->
let
(CgM a) = cont (fromMaybe Nothing (lookupEnv (iface_env env) nm))
in
a env st)
addExportWithComment :: HIEEntity -> String -> CgM ()
addExportWithComment nm comm =
CgM ( \ _ st -> ((), st{exp_list=(nm, False, Just comm):exp_list st}))
addExplicitImports :: [(Bool,String)] -> CgM ()
addExplicitImports imps = CgM ( \ _ st -> ((), st{imp_list= map (\ (x,y) -> (y,x,[])) imps ++imp_list st}))
exportDecl :: (String, HDecl) -> CgM HDecl
exportDecl (nm,d) = do
addExport (IEVal nm)
return d
getMethodNumber :: Maybe Int -> CgM Int
getMethodNumber (Just i) = return i
getMethodNumber Nothing = CgM (\ _ st -> (meth_no st, st))
incMethodNumber :: CgM ()
incMethodNumber = CgM (\ _ st -> ((), st{meth_no=1+meth_no st}))
setMethodNumber :: Int -> CgM ()
setMethodNumber n = CgM (\ _ st -> ((), st{meth_no=n}))
\end{code}
\begin{code}
inDispInterface :: CgM a -> CgM a
inDispInterface (CgM a) = CgM (\ env st -> a (env{if_disp=True}) st)
isInDispInterface :: CgM Bool
isInDispInterface = CgM (\ env st -> (if_disp env, st))
\end{code}
Within a Haskell module we share 'foreign export dynamic'
(or equivalent) stubs, if possible.
\begin{code}
addDynStub :: String -> String -> Bool -> CgM ()
addDynStub nm sig is_exp = CgM $ \ _ st ->
((),st{dyn_env=addToEnv (dyn_env st) sig (is_exp,nm)})
lookupDynStub :: String -> CgM (Maybe (Bool, String))
lookupDynStub sig = CgM $ \ _ st ->
(lookupEnv (dyn_env st) sig, st)
\end{code}
\begin{code}
instance Monad CgM where
(>>=) (CgM a) f =
CgM (\ env st ->
case a env st of
(v, st1) -> let CgM b = f v in b env st1)
return v = CgM (\ _ st -> (v, st))
\end{code}