% % (c) The Foo Project, University of Glasgow, 1998 % % @(#) $Docid: Jun. 9th 2003 16:33 Sigbjorn Finne $ % @(#) $Contactid: sof@galois.com $ % \begin{code} module MarshallUtils ( mkHVar , adjustField , prefixHTy , appHTy , infoHeader , helpStringComment , toHaskellIfaceTy , findParamDependents , findFieldDependents , removeDependees , removeDependents , removeDependers ) where import BasicTypes import CoreUtils import CoreIDL import Attribute import qualified AbstractH as Haskell import AbsHUtils ( var, prefix, prefixApp, mkVarName, comment, andDecl, andDecls, emptyDecl, tyQCon, tyVar, mkTyCon, tyQConst, ctxtTyApp, ctxtClass ) import PpCore ( ppDecl, showCore, setDebug ) import PpAbstractH ( ppType, showAbstractH ) import LibUtils import Literal import List ( intersperse ) import Utils ( notNull ) import Opts ( optShowIDLInComments, optIgnoreHelpstring, optCorba, optHaskellToC, optJNI, optSubtypedInterfacePointers ) \end{code} \begin{code} mkHVar :: Id -> Haskell.Expr mkHVar i = var (mkHaskellVarName (idName i)) \end{code} Fields and parameters with pointer types that are represented as lists in Haskell land, are turned into raw([ptr]) pointers prior to marshalling. Why? Because the marshalling of these pointers has already been performed by the dependency marshalling. (Since [ptr] marshalling is the identity operation at the moment, we could equally well remove the dependent fields/params from the marshalling lists.) \begin{code} adjustField :: Bool -> [(Id,[Dependent])] -> Field -> Maybe Field adjustField forMarshalling dep_list f -- isSwitchDependee dep_list (fieldId f) = Nothing | isDepender dep_list i && not (isArrayTy ty) = if (forMarshalling && not (isIfaceTy ty)) || isSwitchDepender dep_list i then Just (f{fieldType=mkPtrPointer ty}) else Just (f{fieldType=Pointer Ptr True Void}) | otherwise = if not forMarshalling && isArrayTy ty && isDepender dep_list i then Just (f{fieldType=Pointer Ptr True Void}) else Just f where i = fieldId f ty = fieldType f \end{code} \begin{code} prefixHTy :: String -> Haskell.Type -> QualName prefixHTy pre ty = case ty of Haskell.TyVar _ tv -> prefix pre tv Haskell.TyCon tc -> prefix pre tc Haskell.TyApply f _ -> prefixHTy pre f Haskell.TyList _ -> mkVarName (pre ++ list) _ -> error ("prefixHTy: unexpected type" ++ showAbstractH (ppType ty)) appHTy :: String -> Haskell.Type -> QualName appHTy pre ty = case ty of Haskell.TyVar _ tv -> prefixApp pre tv Haskell.TyCon tc -> prefixApp pre tc Haskell.TyApply f _ -> appHTy pre f Haskell.TyList _ -> mkVarName (pre ++ list) _ -> error ("prefixHTy: unexpected type" ++ showAbstractH (ppType ty)) \end{code} Prefixing \begin{code} infoHeader :: Decl -> Haskell.HDecl infoHeader d = case d of Interface i _ _ _ -> header "interface" (idOrigName i) `andDecl` idlDecls `andDecl` line CoClass i _ -> header "coclass" (idOrigName i) `andDecl` coIdlDecls `andDecl` line DispInterface i _ _ _ -> header "dispinterface" (idOrigName i) `andDecl` idlDecls `andDecl` line _ -> emptyDecl where header pre nm = line `andDecl` comment "" `andDecl` comment (pre++' ':nm) `andDecl` comment "" ifaces = case d of CoClass _ ds -> map toStr ds _ -> error "MarshallUtils.infoHeader: Expected a coclass." toStr dcl = let i = coClassId dcl attrs = idAttributes i if_source | attrs `hasAttributeWithName` "source" = ("[source]" ++) | otherwise = id in if_source (idOrigName i) coIdlDecls | optShowIDLInComments = idlDecls | otherwise = comment (" implements: " ++ unwords (intersperse "," ifaces)) idlDecls | optShowIDLInComments = andDecls (map comment (lines (showCore (setDebug False $ ppDecl d)))) | otherwise = emptyDecl line = comment "--------------------------------------------------" \end{code} \begin{code} helpStringComment :: Id -> Haskell.HDecl helpStringComment i | optIgnoreHelpstring = emptyDecl | otherwise = case findAttribute "helpstring" (idAttributes i) of Just (Attribute _ (ParamLit (StringLit hs):_)) -> comment hs _ -> emptyDecl \end{code} The T-translation of interface types is provided as a separate function, as its needed by both MarshallType.toHaskellBaseTy and MarshallCore.toHaskellTy \begin{code} toHaskellIfaceTy :: Type -> Haskell.Type toHaskellIfaceTy (Iface nm mo _ attrs _ _) -- dear, oh dear: special treatment of IUnknown and IDispatch just to make -- AutoPrim.idl generate right looking code. | optCorba = tyQCon mo nm [iface_ptr_ty_arg] | optHaskellToC && nm `notElem` ["IUnknown", "IDispatch"] = case findAttribute "ty_args" attrs of Just (Attribute _ [ParamLit (StringLit s)]) -> tyQCon mo (mkHaskellTyConName nm) (map tyVar (words s)) _ -> tyQConst mo (mkHaskellTyConName nm) | optJNI && attrs `hasAttributeWithName` "jni_iface_ty" = let i = tyVar "a" in mkTyCon jObject [ ctxtTyApp (ctxtClass (mkQualName mo nm) [mkTyCon jObject [i]]) i ] | optSubtypedInterfacePointers = tyQCon mo (mkHaskellTyConName nm) [iface_ptr_ty_arg] | otherwise = tyQConst mo (mkHaskellTyConName nm) where iface_ptr_ty_arg = tyVar "a" toHaskellIfaceTy _ = error "toHaskellIfaceTy: not an interface type" \end{code} Given a parameter dependency list, figure out which parameters should be represented as a Haskell list. [This code is somewhat simplistic, as being a dependent doesn't necessarily mean that a pair of parameters to an IDL method should be coalesced into a Haskell list.] \begin{code} findParamDependents :: Bool -> [Param] -> ( [Param], DependInfo ) findParamDependents isOut ps = (removeDependees deps ps, deps) where deps = filter (notNull.snd) $ -- 12/98: strengthened - deps list now -- only contain the real dependent args. (if isOut then (\ ls -> zipWith notVoidPtr ps ls) else id) $ findDependents (map paramId ps) notVoidPtr _ t@(_,[]) = t notVoidPtr p t@(x,_) | isVoidPointerTy (paramType p) = (x,[]) | otherwise = t findFieldDependents :: [Field] -> DependInfo findFieldDependents fs = deps where deps = filter (notNull.snd) $ -- 12/98: strengthened - deps list now -- only contain the real dependent args. (\ ls -> zipWith notVoidPtr fs ls) $ findDependents (map fieldId fs) notVoidPtr _ t@(_,[]) = t notVoidPtr f t@(x,_) | isVoidPointerTy (fieldType f) = (x,[]) | otherwise = t removeDependees :: DependInfo -> [Param] -> [Param] removeDependees ls ps = filter (not.(isDependee ls).paramId) ps removeDependents :: DependInfo -> [Param] -> [Param] removeDependents ls ps = filter (not.(isHParamDep ls)) ps removeDependers :: DependInfo -> [Param] -> [Param] removeDependers ls ps = filter (\ x -> not (isDependee ls (paramId x)) && not (isHParamDep ls x)) ps -- local utility fun, used by the two previous defs. only. isHParamDep :: DependInfo -> Param -> Bool isHParamDep ls p = isDepender ls (paramId p) \end{code}