Newer
Older
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
180
181
182
183
184
185
186
187
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE LambdaCase #-}
-- | A module for typing of c expressions.
module CType where
import Control.Monad
import qualified Data.List as List
import qualified Data.List.NonEmpty as NonEmpty
import Data.Maybe
import GHC.Stack
import qualified Language.C as C
data Params
= VoidParams
| Params ![Maybe Type] !Bool
deriving (Show, Eq)
data FunType = FunType
{ funTypeReturn :: !Voidable
, funTypeParams :: !Params
}
deriving (Show, Eq)
data StructType = StructType
{ structTypeTag :: !C.CStructTag
, structTypeName :: !(Maybe C.Ident)
, structTypeFields :: ![(C.Ident, Maybe Type)]
}
deriving (Show, Eq)
data Type
= TNum
| TStruct !StructType
| TPointer !Voidable
| TFun !FunType
deriving (Show, Eq)
isNum, isStruct, isPointer, isFun :: Type -> Bool
isNum = \case TNum -> True; _ow -> False
isStruct = \case TStruct _ -> True; _ow -> False
isPointer = \case TPointer _ -> True; _ow -> False
isFun = \case TFun _ -> True; _ow -> False
data Voidable
= Void
| NonVoid !Type
deriving (Show, Eq)
fromVoid :: a -> (Type -> a) -> Voidable -> a
fromVoid a fn = \case
Void -> a
NonVoid t -> fn t
{-# INLINE fromVoid #-}
nonVoid :: (HasCallStack) => Voidable -> Type
nonVoid = fromVoid (error "expected non void type") id
{-# INLINE nonVoid #-}
type TypeDefLookup = (C.Ident -> Maybe Type)
type StructLookup = (C.Ident -> Maybe StructType)
typeOf
:: (HasCallStack)
=> StructLookup
-> TypeDefLookup
-> [C.CDeclarationSpecifier C.NodeInfo]
-> C.CDeclarator C.NodeInfo
-> Voidable
typeOf structLookup typeDefLookup spec (C.CDeclr _ dd _ _ _) =
foldr applyDD (baseTypeOf structLookup typeDefLookup spec) dd
where
applyDD :: C.CDerivedDeclarator C.NodeInfo -> Voidable -> Voidable
applyDD = \case
C.CPtrDeclr _ _ -> NonVoid . TPointer
C.CArrDeclr{} -> NonVoid . TPointer
C.CFunDeclr params _ ni -> \c ->
case params of
C.CFunParamsNew params' varadic -> do
NonVoid $ TFun (FunType c (findParams varadic params'))
b -> notSupportedYet b ni
findParams :: Bool -> [C.CDeclaration C.NodeInfo] -> Params
findParams varadic = \case
[C.CDecl [C.CTypeSpec (C.CVoidType _)] [] _] -> VoidParams
rst -> flip Params varadic $ flip map rst \case
C.CDecl spec' [] _ ->
Just . nonVoid $ baseTypeOf structLookup typeDefLookup spec'
C.CDecl spec' [C.CDeclarationItem decl _ _] _ ->
Just . nonVoid $ typeOf structLookup typeDefLookup spec' decl
a -> notSupportedYet' a
typeSpecs :: [C.CDeclarationSpecifier a] -> [C.CTypeSpecifier a]
typeSpecs = mapMaybe \case
C.CTypeSpec ts -> Just ts
_ow -> Nothing
baseTypeOf
:: (HasCallStack)
=> StructLookup
-> TypeDefLookup
-> [C.CDeclarationSpecifier C.NodeInfo]
-> Voidable
baseTypeOf structLookup typeDefLookup =
maybe
(error "no type in type-specs")
( \case
(t, []) -> NonEmpty.head t
(t, rs) -> error ("more than one type in type-specs: " <> show (t : rs))
)
. List.uncons
. NonEmpty.group
. map \case
C.CVoidType _ -> Void
C.CCharType _ -> NonVoid TNum
C.CShortType _ -> NonVoid TNum
C.CIntType _ -> NonVoid TNum
C.CFloatType _ -> NonVoid TNum
C.CDoubleType _ -> NonVoid TNum
C.CSignedType _ -> NonVoid TNum
C.CUnsigType _ -> NonVoid TNum
C.CBoolType _ -> NonVoid TNum
C.CLongType _ -> NonVoid TNum
C.CInt128Type _ -> NonVoid TNum
C.CFloatNType{} -> NonVoid TNum
C.CSUType c _ -> NonVoid (TStruct $ structTypeOf structLookup typeDefLookup c)
C.CEnumType _ _ -> NonVoid TNum
C.CTypeDef idx _ ->
case typeDefLookup idx of
Just t -> NonVoid t
Nothing -> error ("could not find typedef: " <> show (C.identToString idx))
a -> notSupportedYet (void a) a
. typeSpecs
structTypeOf
:: (HasCallStack)
=> StructLookup
-> TypeDefLookup
-> C.CStructureUnion C.NodeInfo
-> StructType
structTypeOf structLookup typeDefLookup (C.CStruct t mi md _ _) =
case mi of
Just ix ->
case md of
Just p -> do
let p' = concatMap (namesAndTypeOf structLookup typeDefLookup) p
case structLookup ix of
Just s
| structTypeFields s == p' -> s
| otherwise -> error "what?"
Nothing ->
StructType
{ structTypeTag = t
, structTypeName = mi
, structTypeFields = p'
}
Nothing ->
case structLookup ix of
Just s -> s
Nothing -> error "what!?"
Nothing -> do
let p' = maybe (error "what??") (concatMap (namesAndTypeOf structLookup typeDefLookup)) md
StructType
{ structTypeTag = t
, structTypeName = mi
, structTypeFields = p'
}
namesAndTypeOf
:: (HasCallStack)
=> StructLookup
-> TypeDefLookup
-> C.CDeclaration C.NodeInfo
-> [(C.Ident, Maybe Type)]
namesAndTypeOf structLookup typeDefLookup = \case
C.CDecl spec items ni ->
flip map items \case
C.CDeclarationItem decl@(C.CDeclr (Just ix) _ _ _ _) _ _ ->
(ix, Just . nonVoid $ typeOf structLookup typeDefLookup spec decl)
a -> notSupportedYet (void a) ni
a -> notSupportedYet' a
notSupportedYet :: (HasCallStack, Show a, C.Pos n) => a -> n -> b
notSupportedYet a ni = error (show a <> " at " <> show (C.posOf ni))
notSupportedYet' :: (HasCallStack, Show (a ()), Functor a, C.Pos (a C.NodeInfo)) => a C.NodeInfo -> b
notSupportedYet' a = notSupportedYet (void a) a