module Data.GI.CodeGen.OverloadedMethods
( genMethodList
, genMethodInfo
, genUnsupportedMethodInfo
) where
import Control.Monad (forM, forM_, when)
import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as T
import Data.GI.CodeGen.API
import Data.GI.CodeGen.Callable (callableSignature, Signature(..),
ForeignSymbol(..), fixupCallerAllocates)
import Data.GI.CodeGen.Code
import Data.GI.CodeGen.SymbolNaming (lowerName, upperName, qualifiedSymbol)
import Data.GI.CodeGen.Util (ucFirst)
methodInfoName :: Name -> Method -> CodeGen Text
methodInfoName n method =
let infoName = upperName n <> (ucFirst . lowerName . methodName) method
<> "MethodInfo"
in qualifiedSymbol infoName n
genMethodResolver :: Text -> CodeGen ()
genMethodResolver n = do
group $ do
line $ "instance (info ~ Resolve" <> n <> "Method t " <> n <> ", "
<> "O.MethodInfo info " <> n <> " p) => O.IsLabelProxy t ("
<> n <> " -> p) where"
indent $ line $ "fromLabelProxy _ = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)"
group $ do
line $ "#if MIN_VERSION_base(4,9,0)"
line $ "instance (info ~ Resolve" <> n <> "Method t " <> n <> ", "
<> "O.MethodInfo info " <> n <> " p) => O.IsLabel t ("
<> n <> " -> p) where"
line $ "#if MIN_VERSION_base(4,10,0)"
indent $ line $ "fromLabel = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)"
line $ "#else"
indent $ line $ "fromLabel _ = O.overloadedMethod (O.MethodProxy :: O.MethodProxy info)"
line $ "#endif"
line $ "#endif"
genMethodList :: Name -> [(Name, Method)] -> CodeGen ()
genMethodList n methods = do
let name = upperName n
let filteredMethods = filter isOrdinaryMethod methods
gets = filter isGet filteredMethods
sets = filter isSet filteredMethods
others = filter (\m -> not (isSet m || isGet m)) filteredMethods
orderedMethods = others ++ gets ++ sets
infos <- forM orderedMethods $ \(owner, method) ->
do mi <- methodInfoName owner method
return ((lowerName . methodName) method, mi)
group $ do
let resolver = "Resolve" <> name <> "Method"
line $ "type family " <> resolver <> " (t :: Symbol) (o :: *) :: * where"
indent $ forM_ infos $ \(label, info) -> do
line $ resolver <> " \"" <> label <> "\" o = " <> info
indent $ line $ resolver <> " l o = O.MethodResolutionFailed l o"
genMethodResolver name
where isOrdinaryMethod :: (Name, Method) -> Bool
isOrdinaryMethod (_, m) = methodType m == OrdinaryMethod
isGet :: (Name, Method) -> Bool
isGet (_, m) = "get_" `T.isPrefixOf` (name . methodName) m
isSet :: (Name, Method) -> Bool
isSet (_, m) = "set_" `T.isPrefixOf` (name . methodName) m
genMethodInfo :: Name -> Method -> ExcCodeGen ()
genMethodInfo n m =
when (methodType m == OrdinaryMethod) $
group $ do
infoName <- methodInfoName n m
let callable = fixupCallerAllocates (methodCallable m)
sig <- callableSignature callable (KnownForeignSymbol undefined)
bline $ "data " <> infoName
when (null (signatureArgTypes sig)) $
error $ "Internal error: too few parameters! " ++ show m
let (obj:otherTypes) = map snd (signatureArgTypes sig)
sigConstraint = "signature ~ (" <> T.intercalate " -> "
(otherTypes ++ [signatureReturnType sig]) <> ")"
line $ "instance (" <> T.intercalate ", " (sigConstraint :
signatureConstraints sig)
<> ") => O.MethodInfo " <> infoName <> " " <> obj <> " signature where"
let mn = methodName m
mangled = lowerName (mn {name = name n <> "_" <> name mn})
indent $ line $ "overloadedMethod _ = " <> mangled
export (NamedSubsection MethodSection $ lowerName mn) infoName
genUnsupportedMethodInfo :: Name -> Method -> CodeGen ()
genUnsupportedMethodInfo n m = do
infoName <- methodInfoName n m
line $ "-- XXX: Dummy instance, since code generation failed.\n"
<> "-- Please file a bug at http://github.com/haskell-gi/haskell-gi."
bline $ "data " <> infoName
line $ "instance (p ~ (), o ~ O.MethodResolutionFailed \""
<> lowerName (methodName m) <> "\" " <> name n
<> ") => O.MethodInfo " <> infoName <> " o p where"
indent $ line $ "overloadedMethod _ = undefined"
export ToplevelSection infoName