% % (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 -- :: CgM String , setDllName -- :: String -> CgM a -> CgM a -- decl name is the name of the IDL unit (i.e., -- module/interface etc.) being translated. -- , getDeclName -- :: (String -> CgM a) -> CgM a , withDeclName -- :: String -> CgM a -> CgM a , withIfaceDeclName -- :: String -> CgM a -> CgM a , needStubs -- :: Bool -> CgM () , hasPrims -- :: CgM () , setInterfaceFlag -- :: IfaceType -> CgM a -> CgM a , getInterfaceFlag -- :: CgM IfaceType , setSourceIfaceFlag -- :: Bool -> CgM a -> CgM a , getSourceIfaceFlag -- :: CgM Bool , setClientFlag -- :: Bool -> CgM a -> CgM a , getClientFlag -- :: CgM Bool , getIfaceName -- :: CgM String , setIfaceName -- :: String -> CgM a -> CgM a , inDispInterface -- :: CgM a -> CgM a , isInDispInterface -- :: CgM Bool , setIfaceAttributes -- :: [Attribute] -> CgM a -> CgM a , getIfaceAttributes -- :: CgM [Attribute] , getIfaceInherit -- :: CgM [QualName] , withIfaceInherit -- :: [QualNam] -> CgM a -> CgM a , IsoEnv , getIsoEnv -- :: CgM IsoEnv , setIsoEnv -- :: IsoEnv -> CgM () , getIEnumFlag -- :: CgM Bool , setIEnumFlag -- :: Bool -> CgM a -> CgM a , addDynStub -- :: String -> String -> CgM () , lookupDynStub -- :: String -> Maybe String , addExport -- :: HIEEntity -> CgM () , addVitalExport -- :: HIEEntity -> CgM () , addExportWithComment -- :: HIEEntity -> String -> CgM () , exportDecl -- :: (String, HDecl) -> CgM HDecl , addExplicitImports -- :: [(Bool,String)] -> CgM () , hoistInClass -- :: String -> (String -> CgM a) -> CgM a , getMethodNumber -- :: Maybe Int -> CgM Int , setMethodNumber -- :: Int -> CgM () , incMethodNumber -- :: CgM () ) 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, -- True => generating client stubs. if_source :: Bool, -- True => processing outgoing interface if_ienum :: Bool, -- True => processing IEnum interface 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 -- client | ComIDispatch Bool -- client, True => [dual] deriving Eq type IsoEnv = Env String [(Bool, Result, [Param])] data CgState = CgState { exp_list :: [(HIEEntity, Bool, Maybe String)], -- export list imp_list :: [(String,Bool,[HIEEntity])], dyn_env :: Env String{-'signature' string of a type-} (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 -- 'convenient' interface that combines the result of -- looking up whether 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}