File: CtoHaskellMap.hs

package info (click to toggle)
haskell-haskell-gi 0.26.12-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 800 kB
  • sloc: haskell: 8,617; ansic: 74; makefile: 4
file content (179 lines) | stat: -rw-r--r-- 8,663 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
-- | 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
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid ((<>))
#endif
import Data.Text (Text)

import Data.GI.CodeGen.GtkDoc (CRef(..), docName)
import Data.GI.CodeGen.API (API(..), Name(..), Callback(..),
                            Constant(..), Flags(..),
                            Enumeration(..), EnumerationMember(..),
                            Interface(..), Object(..),
                            Function(..), Method(..), Struct(..), Union(..),
                            Signal(..), Property(..))
import Data.GI.CodeGen.ModulePath (dotModulePath)
import Data.GI.CodeGen.SymbolNaming (moduleLocation, lowerName, upperName,
                                     signalHaskellName, haddockSignalAnchor,
                                     haddockAttrAnchor, hyphensToCamelCase)
import Data.GI.CodeGen.Util (ucFirst, lcFirst)

-- | Link to an identifier, module, etc.
data Hyperlink = ValueIdentifier Text
               -- ^ An identifier at the value level: functions, data
               -- constructors, ...
               | TypeIdentifier Text
               -- ^ An identifier at the type level.
               | ModuleLink Text
               -- ^ Link to a module.
               | ModuleLinkWithAnchor (Maybe Text) Text Text
               -- ^ Link to an anchor inside a given module, with an
               -- optional label.
  deriving (Show, Eq)

-- | 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 = [(CTypeRef "gboolean", TypeIdentifier "P.Bool"),
                    (ConstantRef "TRUE", ValueIdentifier "P.True"),
                    (ConstantRef "FALSE", ValueIdentifier "P.False"),
                    (CTypeRef "GError", TypeIdentifier "GError"),
                    (CTypeRef "GType", TypeIdentifier "GType"),
                    (CTypeRef "GVariant", TypeIdentifier "GVariant"),
                    (ConstantRef "NULL", ValueIdentifier "P.Nothing")]

-- | Obtain the fully qualified symbol pointing to a value.
fullyQualifiedValue :: Name -> API -> Text -> Hyperlink
fullyQualifiedValue n api symbol =
  ValueIdentifier $ dotModulePath (moduleLocation n api) <> "." <> symbol

-- | Obtain the fully qualified symbol pointing to a type.
fullyQualifiedType :: Name -> API -> Text -> Hyperlink
fullyQualifiedType n api symbol =
  TypeIdentifier $ dotModulePath (moduleLocation 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), qualified),
                 (CTypeRef (constantCType c), qualified),
                 (TypeRef (docName n), qualified)]
  where qualified = fullyQualifiedValue n (APIConst c) $ name n

-- | Extract the C name of a function.
funcRefs :: Name -> Function -> [(CRef, Hyperlink)]
funcRefs n f = [(OldFunctionRef (fnSymbol f), qualified),
                (FunctionRef (docName n), qualified)]
  where qualified = fullyQualifiedValue 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 = (CTypeRef (enumCType e), qualified)
                   : (TypeRef (docName n), qualified)
                   : map memberToRef (enumMembers e)
  where qualified = fullyQualifiedType n api $ upperName n
        memberToRef :: EnumerationMember -> (CRef, Hyperlink)
        memberToRef em = (ConstantRef (enumMemberCId em),
                          fullyQualifiedValue n api $ upperName $
                          n {name = name n <> "_" <> enumMemberName em})

-- | Refs to the methods for a given owner.
methodRefs :: Name -> API -> [Method] -> [(CRef, Hyperlink)]
methodRefs n api methods = concatMap methodRef methods
  where methodRef :: Method -> [(CRef, Hyperlink)]
        methodRef Method{methodSymbol = symbol, methodName = mn} =
          -- Method name namespaced by the owner.
          let mn' = mn {name = name n <> "_" <> name mn}
              qualified = fullyQualifiedValue n api $ lowerName mn'
          in [(OldFunctionRef symbol, qualified),
              (MethodRef (docName n) (name mn), qualified)]

-- | Refs to the signals for a given owner.
signalRefs :: Name -> API -> Maybe Text -> [Signal] -> [(CRef, Hyperlink)]
signalRefs n@(Name _ owner) api maybeCName signals = concatMap signalRef signals
  where signalRef :: Signal -> [(CRef, Hyperlink)]
        signalRef (Signal {sigName = sn}) =
          let mod = dotModulePath (moduleLocation n api)
              sn' = signalHaskellName sn
              ownerCName = case maybeCName of
                Just cname -> cname
                Nothing -> let Name ns owner = n
                           in ucFirst ns <> owner
              label = Just (owner <> "::" <> sn')
              link = ModuleLinkWithAnchor label mod (haddockSignalAnchor <> sn')
          in [(OldSignalRef ownerCName sn, link),
              (SignalRef (docName n) sn, link)]

-- | Refs to the properties for a given owner.
propRefs :: Name -> API -> Maybe Text -> [Property] -> [(CRef, Hyperlink)]
propRefs n@(Name _ owner) api maybeCName props = concatMap propertyRef props
  where propertyRef :: Property -> [(CRef, Hyperlink)]
        propertyRef (Property {propName = pn}) =
          let mod = dotModulePath (moduleLocation n api)
              hn = lcFirst . hyphensToCamelCase $ pn
              ownerCName = case maybeCName of
                Just cname -> cname
                Nothing -> let Name ns owner = n
                           in ucFirst ns <> owner
              label = Just (owner <> ":" <> hn)
              link = ModuleLinkWithAnchor label mod (haddockAttrAnchor <> hn)
          in [(OldPropertyRef ownerCName pn, link),
              (PropertyRef (docName n) pn, link)]

-- | 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) = [(CTypeRef ctype, qualified),
                                 (TypeRef (docName n), qualified)]
  where qualified = fullyQualifiedType n api (upperName n)

-- | 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)
                 <> signalRefs n (APIInterface i) (ifCType i) (ifSignals 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)
                 <> signalRefs n (APIObject o) (objCType o) (objSignals o)
                 <> propRefs n (APIObject o) (objCType o) (objProperties o)