% % (c) The Foo Project, University of Glasgow, 1998 % % @(#) $Docid: Feb. 2nd 2003 07:49 Sigbjorn Finne $ % @(#) $Contactid: sof@galois.com $ % Generating marshalling code for Haskell COM servers. \begin{code}
module MarshallJNI 
	( 
	  cgJNIMethod
	, cgJNIInterface
	, cgJNIClass
	, cgClassNameDecl
	) where

import CoreIDL hiding ( Expr(..), CaseLabel(..) )
import BasicTypes
import AbstractH hiding ( Type(..) )
import AbsHUtils
import CoreUtils
import MarshallCore
import Attribute
import Literal
import CgMonad
import LibUtils
import PpCore ( showCore, ppType )
import Opts
	( optOneModulePerInterface
        )

import Monad ( when )
import Maybe ( mapMaybe )
import Utils ( splitLast, snoc )

\end{code} \begin{code}
cgJNIMethod :: Id -> Result -> [Param] -> CgM HDecl
cgJNIMethod i res params = do
  iface <- getIfaceName
  as    <- getIfaceAttributes
  addExport (ieValue (idName i))
  return (mkJNIMethod i iface res params as)

mkJNIMethod :: Id -> String -> Result -> [Param] -> [Attribute] -> HDecl
mkJNIMethod i iface res params iface_attrs = m_decl
 where
  name        = idName i
  m_name      = name
  m_orig_name = idOrigName i
  attrs       = idAttributes i

  m_decl      = m_tysig `andDecl` m_def
  m_tysig     = mkTypeSig m_name param_tys (io res_ty)

  m_def       = funDef m_name m_pats m_rhs

  res_ty      = 
    let r_ty = toHaskellTy True (resultOrigType res) in
    if isCtor then
       groundTyVars r_ty
    else
       r_ty

  param_tys   = map (paramToHaskellType [] False False False) params `snoc` objParamTy

  isGetField  = attrs `hasAttributeWithName` "jni_get_field"
  isSetField  = attrs `hasAttributeWithName` "jni_set_field"
  isStatic    = attrs `hasAttributeWithName` "jni_static"
  isInterface = not (iface_attrs `hasAttributeWithName` "jni_class")
  isFinal     = attrs `hasAttributeWithName` "jni_final"
  isCtor      = attrs `hasAttributeWithName` "jni_ctor"

  isStaticGetField = isGetField && isStatic
  isStaticSetField = isSetField && isStatic

  objParamTy 
    | isStatic    = mkTyConst jniEnv
    | isCtor      = mkTyConst jniEnv
    | isInterface = let 
                       tyv = tyVar "a"
		       nm  = mkHaskellTyConName iface
		       qnm
		        | optOneModulePerInterface = mkQualName (Just nm) nm
			| otherwise		   = mkQualName Nothing nm
		    in
		    mkTyCon jObject
		       [ctxtTyApp (ctxtClass qnm [mkTyCon jObject [tyv]])
			          tyv]
    | otherwise   = tyQCon Nothing (mkHaskellTyConName iface) [obj_ty_arg]
   where  
    obj_ty_arg
     | isFinal   = tyUnit
     | otherwise = tyVar "a"

  m_rhs
    | isStaticGetField  = funApp getStaticField [ var cls_cls_name, meth_name, ty_spec ]
    | isStaticSetField  = funApp setStaticField [ var cls_cls_name, meth_name, ty_spec, tup m_args ]
    | isGetField        = funApp getField [ meth_name, ty_spec ]
    | isSetField        = funApp setField [ meth_name, ty_spec, tup m_args ]
    | isCtor      = funApp newObj    [ var cls_cls_name, ty_spec, tup m_args ]
    | isStatic    = funApp invokeStaticMethod invoke_static_args
    | isInterface = funApp invokeInterfaceMethod [ meth_name, ty_spec, tup m_args ]
    | otherwise   = funApp invokeMethod [ meth_name, ty_spec, tup m_args ]

  cls_cls_name = mkClassName (mkHaskellVarName iface)

  invoke_static_args = 
          [ var cls_cls_name
	  , meth_name
	  , ty_spec
	  , tup m_args
	  ]

  ty_spec
   | isGetField = stringLit (toTyDesc (resultType res))
   | otherwise  = stringLit (mkJavaTypeSpec params res)

  meth_name 
    | isGetField = stringLit stripped_m_name
    | isSetField = stringLit stripped_m_name
    | otherwise  = stringLit m_orig_name
   where
    (_:_:_:_:stripped_m_name) = m_orig_name

  m_args    = map (\ p -> var (idName (paramId p))) params
  m_pats    = map (patVar.idName.paramId) params

\end{code} \begin{code}
mkJavaTypeSpec :: [Param] -> Result -> String
mkJavaTypeSpec ps res = '(':concatMap tyParam ps ++ ')':tyRes res
 where
   tyParam p = toTyDesc (paramType p)
   tyRes  r  = toTyDesc (resultType r)

toTyDesc :: Type -> String
toTyDesc ty = 
   case ty of
       Integer Short _     -> "S"
       Integer Long  _     -> "I"
       Integer Natural  _  -> "I"
       Integer LongLong  _ -> "J"
       String{}            -> "Ljava/lang/String;"
       Name _ _ _ _ (Just t) _ -> toTyDesc t
       Name n _ _ _ _ _    -> 'L':trans n ++ ";"
       Iface _ _ n _ _ _ -> 'L':trans n ++ ";"
       Float Short -> "F"
       Float Long  -> "D"
       Bool        -> "Z"
       Octet       -> "B"
       Char _      -> "C"
       Void	   -> "V"
       Array t _   -> '[':toTyDesc t
       _	   -> error ("toTyDesc: unknown type " ++ showCore (ppType ty))

 where
  trans x = map dotToSlash x

  dotToSlash '.' = '/'
  dotToSlash x   = x
\end{code} \begin{code}
cgClassNameDecl :: Id -> (HDecl, Name)
cgClassNameDecl i = (cls_name_tysig `andDecl` cls_name_def, cls_cls_name)
 where
   name	          = idName i
   attrs	  = idAttributes i
   h_nm           = mkHaskellTyConName (snd (splitLast "." name))
   cls_cls_name   = mkClassName (mkHaskellVarName h_nm)
   cls_name_tysig = typeSig cls_cls_name (mkTyCon className [ty_arg])
   ty_arg
    | attrs `hasAttributeWithName` "jni_class" = mkTyCon (mkQualName Nothing h_nm) [tyUnit]
    | otherwise				       = tyUnit -- for an interface.

   cls_name_def   = funDef cls_cls_name [] cls_name_rhs
   cls_name_rhs   = funApp makeClassName [stringLit (idOrigName i)]

cgJNIInterface :: Id
	       -> Bool
	       -> CgM HDecl
cgJNIInterface i ignore_decls = do
   when (not ignore_decls) $ do
        addExport (ieClass (mkHaskellTyConName name))
        addExport (ieValue cls_cls_name)
   let
    ds 
     | ignore_decls = emptyDecl
     | otherwise    = class_decl `andDecl` cls_nm_decl

   return ds
 where
   class_decl = hClass ctxt cls_name [tvar] []

   name	      = idName i

   (cls_nm_decl, cls_cls_name) = cgClassNameDecl i

   cls_name   = mkClsName name

   mkClsName n = mkConName (mkHaskellTyConName n)

   tvar       = mkTyVar "a"
   attrs      = idAttributes i
   is         = 
    case (findAttribute "jni_implements" attrs) of
      Just (Attribute _ [ParamLit (StringLit s)]) -> words s
      _ -> []

   ctxt       = CtxtTuple (map (\ x -> CtxtClass (mkClsName x) [tyVar "a"]) is)

\end{code} \begin{code}
cgJNIClass :: Id
	   -> Bool
	   -> CgM HDecl
cgJNIClass i incl_type_defs 
 | incl_type_defs = return iface_inst_decls
 | otherwise      = do
   addExport (ieValue cls_cls_name)
   addExport (ieValue ctor_name)
   return (andDecls [cls_name,default_ctor, iface_inst_decls])
  where
   attrs = idAttributes i
   nm    = idOrigName i
   h_nm  = mkHaskellTyConName (snd (splitLast "." nm))

   (cls_name, cls_cls_name) = cgClassNameDecl i
   obj_ty_open    = tyCon (mkHaskellTyConName h_nm) [tyVar "a"]

   default_ctor   = ctor_tysig `andDecl` ctor_def
   ctor_tysig = typeSig ctor_name
		        (funTy (mkTyConst jniEnv)
			       (io (tyCon h_nm [tyUnit])))

   ctor_def   = funDef ctor_name [] ctor_rhs
   ctor_rhs   = funApp newObj [ var cls_cls_name
			      , stringLit "()V"
			      , tup []
			      ]
   ctor_name  = "new" ++ h_nm 

   iface_inst_decls = andDecls (map declInstance ifaces_implemented)

   ifaces_implemented = mapMaybe toNm (filterAttributes attrs ["jni_interface"])
     where
      toNm  (Attribute _ [ParamLit (StringLit s)]) = Just s
      toNm  _					   = Nothing

   declInstance n = hInstance Nothing (mkQConName hmod haskell_nm) obj_ty_open []
     where
      hmod 
        | optOneModulePerInterface = Just haskell_nm
	| otherwise                = Nothing

      haskell_nm = mkHaskellTyConName (snd (splitLast "." n))

\end{code}