-- | Construct a map from C identifiers to the corresponding Haskell -- elements in the bindings. module Data.GI.CodeGen.CtoHaskellMap ( cToHaskellMap , Hyperlink(..) ) where import qualified Data.Map as M import Data.Monoid ((<>)) import Data.Text (Text) import qualified Data.Text as T import Data.String (IsString(..)) import Data.GI.CodeGen.GtkDoc (CRef(..)) import Data.GI.CodeGen.API (API(..), Name(..), Callback(..), Constant(..), Flags(..), Enumeration(..), EnumerationMember(..), Interface(..), Object(..), Function(..), Method(..), Struct(..), Union(..)) import Data.GI.CodeGen.ModulePath (ModulePath, dotModulePath, (/.)) import Data.GI.CodeGen.SymbolNaming (submoduleLocation, lowerName, upperName) import Data.GI.CodeGen.Util (ucFirst) -- | Link to an identifier, module, etc. data Hyperlink = IdentifierLink Text | ModuleLink Text | ModuleLinkWithAnchor Text Text deriving (Show, Eq) -- Just for convenience instance IsString Hyperlink where fromString = IdentifierLink . T.pack -- | Given a set of APIs, build a `Map` that given a Text -- corresponding to a certain C identifier returns the corresponding -- Haskell element in the bindings. For instance, `gtk_widget_show` -- will get mapped to `GI.Gtk.Objects.Widget.show`. cToHaskellMap :: [(Name, API)] -> M.Map CRef Hyperlink cToHaskellMap apis = M.union (M.fromList builtins) (M.fromList $ concatMap extractRefs apis) where extractRefs :: (Name, API) -> [(CRef, Hyperlink)] extractRefs (n, APIConst c) = constRefs n c extractRefs (n, APIFunction f) = funcRefs n f extractRefs (n, api@(APIEnum e)) = enumRefs api n e extractRefs (n, api@(APIFlags (Flags e))) = enumRefs api n e extractRefs (n, APICallback c) = callbackRefs n c extractRefs (n, APIStruct s) = structRefs n s extractRefs (n, APIUnion u) = unionRefs n u extractRefs (n, APIInterface i) = ifaceRefs n i extractRefs (n, APIObject o) = objectRefs n o builtins :: [(CRef, Hyperlink)] builtins = [(TypeRef "gboolean", "Bool"), (ConstantRef "TRUE", "True"), (ConstantRef "FALSE", "False"), (TypeRef "GError", "GError"), (TypeRef "GType", "GType"), (TypeRef "GVariant", "GVariant"), (ConstantRef "NULL", "Nothing")] -- | Obtain the absolute location of the module where the given `API` -- lives. location :: Name -> API -> ModulePath location n api = ("GI" /. ucFirst (namespace n)) <> submoduleLocation n api -- | Obtain the fully qualified symbol. fullyQualified :: Name -> API -> Text -> Hyperlink fullyQualified n api symbol = IdentifierLink $ dotModulePath (location n api) <> "." <> symbol -- | Extract the C name of a constant. These are often referred to as -- types, so we allow that too. constRefs :: Name -> Constant -> [(CRef, Hyperlink)] constRefs n c = [(ConstantRef (constantCType c), fullyQualified n (APIConst c) $ name n), (TypeRef (constantCType c), fullyQualified n (APIConst c) $ name n)] -- | Extract the C name of a function. funcRefs :: Name -> Function -> [(CRef, Hyperlink)] funcRefs n f = [(FunctionRef (fnSymbol f), fullyQualified n (APIFunction f) $ lowerName n)] -- | Extract the C names of the fields in an enumeration/flags, and -- the name of the type itself. enumRefs :: API -> Name -> Enumeration -> [(CRef, Hyperlink)] enumRefs api n e = (TypeRef (enumCType e), fullyQualified n api $ upperName n) : map memberToRef (enumMembers e) where memberToRef :: EnumerationMember -> (CRef, Hyperlink) memberToRef em = (ConstantRef (enumMemberCId em), fullyQualified n api $ upperName $ n {name = name n <> "_" <> enumMemberName em}) -- | Given an optional C type and the API constructor construct the -- list of associated refs. maybeCType :: Name -> API -> Maybe Text -> [(CRef, Hyperlink)] maybeCType _ _ Nothing = [] maybeCType n api (Just ctype) = [(TypeRef ctype, fullyQualified n api (upperName n))] -- | Refs to the methods for a given owner. methodRefs :: Name -> API -> [Method] -> [(CRef, Hyperlink)] methodRefs n api methods = map methodRef methods where methodRef :: Method -> (CRef, Hyperlink) methodRef m@(Method {methodName = mn}) = -- Method name namespaced by the owner. let mn' = mn {name = name n <> "_" <> name mn} in (FunctionRef (methodSymbol m), fullyQualified n api $ lowerName mn') -- | Extract the C name of a callback. callbackRefs :: Name -> Callback -> [(CRef, Hyperlink)] callbackRefs n cb = maybeCType n (APICallback cb) (cbCType cb) -- | Extract the C references in a struct. structRefs :: Name -> Struct -> [(CRef, Hyperlink)] structRefs n s = maybeCType n (APIStruct s) (structCType s) <> methodRefs n (APIStruct s) (structMethods s) -- | Extract the C references in a union. unionRefs :: Name -> Union -> [(CRef, Hyperlink)] unionRefs n u = maybeCType n (APIUnion u) (unionCType u) <> methodRefs n (APIUnion u) (unionMethods u) -- | Extract the C references in an interface. ifaceRefs :: Name -> Interface -> [(CRef, Hyperlink)] ifaceRefs n i = maybeCType n (APIInterface i) (ifCType i) <> methodRefs n (APIInterface i) (ifMethods i) -- | Extract the C references in an object. objectRefs :: Name -> Object -> [(CRef, Hyperlink)] objectRefs n o = maybeCType n (APIObject o) (objCType o) <> methodRefs n (APIObject o) (objMethods o)