{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module FFICXX.Generate.Code.HsFrontEnd where
import Control.Monad.Reader
import Data.Either (lefts,rights)
import Data.List
import Data.Monoid ((<>))
import Language.Haskell.Exts.Build (app,letE,name,pApp)
import Language.Haskell.Exts.Syntax (Decl(..),ExportSpec(..),ImportDecl(..))
import System.FilePath ((<.>))
import FFICXX.Generate.Code.Primitive (CFunSig(..),HsFunSig(..)
,accessorSignature
,classConstraints
,convertCpp2HS
,extractArgRetTypes
,functionSignature
,hsFuncXformer
)
import FFICXX.Generate.Name (accessorName
,aliasedFuncName
,hsClassName
,hscAccessorName
,hscFuncName
,hsFuncName
,hsFrontNameForTopLevelFunction
,typeclassName)
import FFICXX.Generate.Dependency (class_allparents
,extractClassDepForTopLevelFunction
,getClassModuleBase,getTClassModuleBase
,argumentDependency,returnDependency
)
import FFICXX.Generate.Type.Class
import FFICXX.Generate.Type.Annotate
import FFICXX.Generate.Type.Module
import FFICXX.Generate.Util
import FFICXX.Generate.Util.HaskellSrcExts
genHsFrontDecl :: Class -> Reader AnnotateMap (Decl ())
genHsFrontDecl c = do
let cdecl = mkClass (classConstraints c) (typeclassName c) [mkTBind "a"] body
sigdecl f = mkFunSig (hsFuncName c f) (functionSignature c f)
body = map (clsDecl . sigdecl) . virtualFuncs . class_funcs $ c
return cdecl
genHsFrontInst :: Class -> Class -> [Decl ()]
genHsFrontInst parent child
| (not.isAbstractClass) child =
let idecl = mkInstance cxEmpty (typeclassName parent) [convertCpp2HS (Just child) SelfType] body
defn f = mkBind1 (hsFuncName child f) [] rhs Nothing
where rhs = app (mkVar (hsFuncXformer f)) (mkVar (hscFuncName child f))
body = map (insDecl . defn) . virtualFuncs . class_funcs $ parent
in [idecl]
| otherwise = []
genHsFrontInstNew :: Class
-> Reader AnnotateMap [Decl ()]
genHsFrontInstNew c = do
let fs = filter isNewFunc (class_funcs c)
return . flip concatMap fs $ \f ->
let
rhs = app (mkVar (hsFuncXformer f)) (mkVar (hscFuncName c f))
in mkFun (aliasedFuncName c f) (functionSignature c f) [] rhs Nothing
genHsFrontInstNonVirtual :: Class -> [Decl ()]
genHsFrontInstNonVirtual c =
flip concatMap nonvirtualFuncs $ \f ->
let rhs = app (mkVar (hsFuncXformer f)) (mkVar (hscFuncName c f))
in mkFun (aliasedFuncName c f) (functionSignature c f) [] rhs Nothing
where nonvirtualFuncs = nonVirtualNotNewFuncs (class_funcs c)
genHsFrontInstStatic :: Class -> [Decl ()]
genHsFrontInstStatic c =
flip concatMap (staticFuncs (class_funcs c)) $ \f ->
let rhs = app (mkVar (hsFuncXformer f)) (mkVar (hscFuncName c f))
in mkFun (aliasedFuncName c f) (functionSignature c f) [] rhs Nothing
genHsFrontInstVariables :: Class -> [Decl ()]
genHsFrontInstVariables c =
flip concatMap (class_vars c) $ \v ->
let rhs accessor =
app (mkVar (case accessor of Getter -> "xform0"; _ -> "xform1"))
(mkVar (hscAccessorName c v accessor))
in mkFun (accessorName c v Getter) (accessorSignature c v Getter) [] (rhs Getter) Nothing
<> mkFun (accessorName c v Setter) (accessorSignature c v Setter) [] (rhs Setter) Nothing
hsClassRawType :: Class -> [Decl ()]
hsClassRawType c =
[ mkData rawname [] [] Nothing
, mkNewtype highname [] [qualConDecl Nothing Nothing (conDecl highname [tyapp tyPtr rawtype])] mderiv
, mkInstance cxEmpty "FPtr" [hightype]
[ insType (tyapp (tycon "Raw") hightype) rawtype
, insDecl (mkBind1 "get_fptr" [pApp (name highname) [mkPVar "ptr"]] (mkVar "ptr") Nothing)
, insDecl (mkBind1 "cast_fptr_to_obj" [] (con highname) Nothing)
]
]
where (highname,rawname) = hsClassName c
hightype = tycon highname
rawtype = tycon rawname
mderiv = Just (mkDeriving [i_eq,i_ord,i_show])
where i_eq = irule Nothing Nothing (ihcon (unqual "Eq"))
i_ord = irule Nothing Nothing (ihcon (unqual "Ord"))
i_show = irule Nothing Nothing (ihcon (unqual "Show"))
genHsFrontUpcastClass :: Class -> [Decl ()]
genHsFrontUpcastClass c = mkFun ("upcast"<>highname) typ [mkPVar "h"] rhs Nothing
where (highname,rawname) = hsClassName c
hightype = tycon highname
rawtype = tycon rawname
iname = typeclassName c
a_bind = unkindedVar (name "a")
a_tvar = mkTVar "a"
typ = tyForall (Just [a_bind])
(Just (cxTuple [classA (unqual "FPtr") [a_tvar], classA (unqual iname) [a_tvar]]))
(tyfun a_tvar hightype)
rhs = letE [ pbind (mkPVar "fh") (app (mkVar "get_fptr") (mkVar "h")) Nothing
, pbind (mkPVarSig "fh2" (tyapp tyPtr rawtype))
(app (mkVar "castPtr") (mkVar "fh")) Nothing
]
(mkVar "cast_fptr_to_obj" `app` mkVar "fh2")
genHsFrontDowncastClass :: Class -> [Decl ()]
genHsFrontDowncastClass c = mkFun ("downcast"<>highname) typ [mkPVar "h"] rhs Nothing
where (highname,_rawname) = hsClassName c
hightype = tycon highname
iname = typeclassName c
a_bind = unkindedVar (name "a")
a_tvar = mkTVar "a"
typ = tyForall (Just [a_bind])
(Just (cxTuple [classA (unqual "FPtr") [a_tvar], classA (unqual iname) [a_tvar]]))
(tyfun hightype a_tvar)
rhs = letE [ pbind (mkPVar "fh") (app (mkVar "get_fptr") (mkVar "h")) Nothing
, pbind (mkPVar "fh2") (app (mkVar "castPtr") (mkVar "fh")) Nothing
]
(mkVar "cast_fptr_to_obj" `app` mkVar "fh2")
genTopLevelFuncDef :: TopLevelFunction -> [Decl ()]
genTopLevelFuncDef f@TopLevelFunction {..} =
let fname = hsFrontNameForTopLevelFunction f
HsFunSig typs assts =
extractArgRetTypes
Nothing
False
(CFunSig toplevelfunc_args toplevelfunc_ret)
sig = tyForall Nothing (Just (cxTuple assts)) (foldr1 tyfun typs)
xformerstr = let len = length toplevelfunc_args in if len > 0 then "xform" <> show (len-1) else "xformnull"
cfname = "c_" <> toLowers fname
rhs = app (mkVar xformerstr) (mkVar cfname)
in mkFun fname sig [] rhs Nothing
genTopLevelFuncDef v@TopLevelVariable {..} =
let fname = hsFrontNameForTopLevelFunction v
cfname = "c_" <> toLowers fname
rtyp = convertCpp2HS Nothing toplevelvar_ret
sig = tyapp (tycon "IO") rtyp
rhs = app (mkVar "xformnull") (mkVar cfname)
in mkFun fname sig [] rhs Nothing
genExport :: Class -> [ExportSpec ()]
genExport c =
let espec n = if null . (filter isVirtualFunc) $ (class_funcs c)
then eabs nonamespace (unqual n)
else ethingall (unqual n)
in if isAbstractClass c
then [ espec (typeclassName c) ]
else [ ethingall (unqual ((fst.hsClassName) c))
, espec (typeclassName c)
, evar (unqual ("upcast" <> (fst.hsClassName) c))
, evar (unqual ("downcast" <> (fst.hsClassName) c)) ]
<> genExportConstructorAndNonvirtual c
<> genExportStatic c
genExportConstructorAndNonvirtual :: Class -> [ExportSpec ()]
genExportConstructorAndNonvirtual c = map (evar . unqual) fns
where fs = class_funcs c
fns = map (aliasedFuncName c) (constructorFuncs fs
<> nonVirtualNotNewFuncs fs)
genExportStatic :: Class -> [ExportSpec ()]
genExportStatic c = map (evar . unqual) fns
where fs = class_funcs c
fns = map (aliasedFuncName c) (staticFuncs fs)
genExtraImport :: ClassModule -> [ImportDecl ()]
genExtraImport cm = map mkImport (cmExtraImport cm)
genImportInModule :: [Class] -> [ImportDecl ()]
genImportInModule = concatMap (\x -> map (\y -> mkImport (getClassModuleBase x<.>y)) ["RawType","Interface","Implementation"])
genImportInInterface :: ClassModule -> [ImportDecl ()]
genImportInInterface m =
let modlstraw = cmImportedModulesRaw m
modlstparent = cmImportedModulesHighNonSource m
modlsthigh = cmImportedModulesHighSource m
in [mkImport (cmModule m <.> "RawType")]
<> flip map modlstraw
(\case
Left t -> mkImport (getTClassModuleBase t <.> "Template")
Right c -> mkImport (getClassModuleBase c <.>"RawType")
)
<> flip map modlstparent
(\case
Left t -> mkImport (getTClassModuleBase t <.> "Template")
Right c -> mkImport (getClassModuleBase c <.>"Interface")
)
<> flip map modlsthigh
(\case
Left t ->
mkImport (getTClassModuleBase t <.> "Template")
Right c -> mkImportSrc (getClassModuleBase c<.>"Interface")
)
genImportInCast :: ClassModule -> [ImportDecl ()]
genImportInCast m = [ mkImport (cmModule m <.> "RawType")
, mkImport (cmModule m <.> "Interface") ]
genImportInImplementation :: ClassModule -> [ImportDecl ()]
genImportInImplementation m =
let modlstraw' = cmImportedModulesForFFI m
modlsthigh = nub $ map Right $ concatMap class_allparents (cmClass m)
modlstraw = filter (not.(flip elem modlsthigh)) modlstraw'
in [ mkImport (cmModule m <.> "RawType")
, mkImport (cmModule m <.> "FFI")
, mkImport (cmModule m <.> "Interface")
, mkImport (cmModule m <.> "Cast") ]
<> concatMap (\case Left t -> [mkImport (getTClassModuleBase t <.> "Template")]; Right c -> map (\y -> mkImport (getClassModuleBase c<.>y)) ["RawType","Cast","Interface"]) modlstraw
<> concatMap (\case Left t -> [mkImport (getTClassModuleBase t <.> "Template")]; Right c -> map (\y -> mkImport (getClassModuleBase c<.>y)) ["RawType","Cast","Interface"]) modlsthigh
genImportForTopLevelFunction :: TopLevelFunction -> [ImportDecl ()]
genImportForTopLevelFunction f =
let dep4func = extractClassDepForTopLevelFunction f
ecs = returnDependency dep4func ++ argumentDependency dep4func
cmods = nub $ map getClassModuleBase $ rights ecs
tmods = nub $ map getTClassModuleBase $ lefts ecs
in concatMap (\x -> map (\y -> mkImport (x<.>y)) ["RawType","Cast","Interface"]) cmods
<> concatMap (\x -> map (\y -> mkImport (x<.>y)) ["Template"]) tmods
genImportInTopLevel ::
String
-> ([ClassModule],[TemplateClassModule])
-> TopLevelImportHeader
-> [ImportDecl ()]
genImportInTopLevel modname (mods,tmods) tih =
let tfns = tihFuncs tih
in map (mkImport . cmModule) mods
++ if null tfns
then []
else map mkImport [ "Foreign.C", "Foreign.Ptr", "FFICXX.Runtime.Cast" ]
++ map (\c -> mkImport (modname <.> (fst.hsClassName.cihClass) c <.> "RawType")) (tihClassDep tih)
++ map (\m -> mkImport (tcmModule m <.> "Template")) tmods
++ concatMap genImportForTopLevelFunction tfns