% % (c) The Foo Project, University of Glasgow, 1998 % % @(#) $Docid: Jun. 8th 2001 21:45 Sigbjorn Finne $ % @(#) $Contactid: sof@galconn.com $ % \begin{code}
module MarshallMonad
       ( Mm
       , runMm
       , getMethodName
       , addCode
       , addToEnv
       , lookupName
       
       , MarshallInfo(..)
       , proxyMarshallInfo
       , stubMarshallInfo
       , structMarshallInfo
       
       ) where

import AbstractH ( Expr(..), Pat(..) )
import qualified Env
import BasicTypes
import LibUtils ( prelReturn )

data Mm a = Mm (Maybe String -> NameEnv -> (a, Cont, NameEnv))

type NameEnv = Env.Env String String
type Cont = Expr -> Expr
\end{code} \begin{code}
runMm :: Maybe String -> [String] -> Expr -> Mm a -> Expr
runMm methName orig_names hole (Mm act) =
  case act methName env of
    (_, econt, _) -> peepHoleTop (econt hole)
  where
   env = Env.addListToEnv (Env.newEnv) (zip orig_names orig_names)

peepHoleTop :: Expr -> Expr
peepHoleTop e = 
  case e of
    Apply f [a] -> Apply f [(peepHole a)]  -- catch 'unsafePerformIO action'
    x	        -> peepHole x

peepHole :: Expr -> Expr
peepHole e = 
  case e of
    Let bndrs e1 -> Let bndrs (peepHole e1)
    Bind (Apply (Var x) [Var y]) (PatVar z) e2
      | x == prelReturn && qName y == qName z -> peepHole e2
    Bind_ e1 e2  -> Bind_ (peepHole e1) (peepHole e2)
    Bind e1 p e2 -> 
	let
	  p_e1 = peepHole e1
	  p_e2 = peepHole e2
	  p_e  = Bind p_e1 p p_e2
	in
	case p of
	  PatVar x ->
	    case p_e1 of
	       Return (Var y) | qName x == qName y -> p_e2
	       _ -> 
		 case p_e2 of
		   Return (Var y) | qName x == qName y -> p_e1
		   _ -> p_e
	  _ -> p_e
    _ -> e

{- UNUSED
doMm :: [String] -> Expr -> Mm a -> (a, Expr)
doMm orig_names hole (Mm act) =
  case act Nothing env of
    (v, econt, _) -> (v, econt hole)
  where
   env = Env.addListToEnv (Env.newEnv) (zip orig_names orig_names)
-}

thenMm :: Mm a -> (a -> Mm b) -> Mm b
thenMm (Mm act) cont = 
  Mm ( \ env s ->
        case (act env s) of
	  (v,cont1, s') -> 
	    let (Mm b) = cont v in
	    case b env s' of
	     (x, cont2, s'') -> 
	         (x, cont1.cont2, s''))

returnMm :: a -> Mm a
returnMm v = Mm ( \ _ s -> (v,id,s))

instance Monad Mm where
  (>>=)   = thenMm
  return  = returnMm

getMethodName :: Mm (Maybe String)
getMethodName = Mm (\ nm env -> (nm, id, env))

addCode :: (Expr -> Expr) -> Mm ()
addCode cont1 = Mm ( \ _ s -> ((), cont1, s))

lookupName :: String -> Mm (Maybe String)
lookupName nm = Mm ( \ _ env ->
		      case (Env.lookupEnv env nm) of
			  Just n  ->  (Just n, id, env)
			  Nothing ->  (Nothing, id, env))

addToEnv :: String -> String -> Mm ()
addToEnv src_nm new_nm = 
  Mm (\ _ env -> 
        ((), id, Env.addToEnv env src_nm new_nm))
\end{code} Marshalling IDL types isn't merely type-directed, it also needs to take into account the context, are we generating proxy or stub marshallers, for a struct etc. The @MarshallInfo@ encapsulates the context and is passed to the functions which implements the marshalling rules. \begin{code}
data MarshallInfo
 = MarshallInfo
      { forProxy  :: Bool
      , forStruct :: Bool
      , forInOut  :: Bool
      , forRef    :: Bool
      , doFree    :: Bool
      }

proxyMarshallInfo :: MarshallInfo
proxyMarshallInfo =
   MarshallInfo
      { forProxy  = True
      , forStruct = False
      , forInOut  = False
      , forRef    = False
      , doFree    = False
      }

stubMarshallInfo :: MarshallInfo
stubMarshallInfo =
   MarshallInfo
      { forProxy  = False
      , forStruct = False
      , forInOut  = False
      , forRef    = False
      , doFree    = False
      }

structMarshallInfo :: MarshallInfo
structMarshallInfo =
   MarshallInfo
      { forProxy  = False
      , forStruct = True
      , forInOut  = False
      , forRef    = True
      , doFree    = False
      }
\end{code}