blob: 5e7063e991e5cae0233873a48b2591100419b04a (
plain) (
blame)
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Language.Fiddle.Compiler.Expansion (expandAst, expansionPhase) where
import Control.Monad.Identity (Identity (..))
import Control.Monad.State (get, modify, put)
import qualified Data.Char as Char
import Data.List (intercalate)
import Data.List.NonEmpty (NonEmpty, (<|))
import qualified Data.List.NonEmpty as NonEmpty
import Data.Text (Text)
import qualified Data.Text as Text
import Language.Fiddle.Ast
import Language.Fiddle.Compiler
import Language.Fiddle.Compiler.Qualification ()
import Language.Fiddle.Internal.UnitNumbers
import Language.Fiddle.Types
type M = Compile State
type Annot = Commented SourceSpan
type CurrentStage = ImportsResolved
type Path = [Text]
expandAst :: FiddleUnit CurrentStage I Annot -> Compile () (FiddleUnit Expanded I Annot)
expandAst = fmap snd . subCompile (State [] []) . advanceStage mempty
expansionPhase :: CompilationPhase CurrentStage Expanded
expansionPhase = CompilationPhase (pure ()) (\_ _ -> return ([], Just ())) (\_ _ -> expandAst)
-- Shorthand for Identity
type I = Identity
newtype Linkage = Linkage (NonEmpty Text) deriving (Show)
data State
= State
-- Anonymous object type bodies that need to be re-linked
![(Linkage, ObjTypeBody Expanded I Annot)]
-- Anonymous enum bodies that need to be re-linked
![(Linkage, AnonymousBitsType Expanded I Annot)]
instance CompilationStage CurrentStage where
type StageAfter CurrentStage = Expanded
type StageMonad CurrentStage = M
type StageState CurrentStage = Path
type StageFunctor CurrentStage = Identity
type StageAnnotation CurrentStage = Annot
deriving instance AdvanceStage CurrentStage ObjTypeBody
deriving instance AdvanceStage CurrentStage DeferredRegisterBody
deriving instance AdvanceStage CurrentStage RegisterBody
deriving instance AdvanceStage CurrentStage AnonymousBitsType
deriving instance AdvanceStage CurrentStage ImportStatement
deriving instance AdvanceStage CurrentStage BitType
deriving instance AdvanceStage CurrentStage EnumBody
deriving instance AdvanceStage CurrentStage (ConstExpression u)
deriving instance AdvanceStage CurrentStage EnumConstantDecl
deriving instance (AdvanceStage CurrentStage t) => AdvanceStage CurrentStage (Directed t)
instance AdvanceStage CurrentStage RegisterBitsDecl where
modifyState t =
return
. case t of
DefinedBits {definedBitsIdent = i} -> pushId i
_ -> id
instance AdvanceStage CurrentStage PackageBody where
advanceStage p (PackageBody decls a) =
PackageBody <$> reconfigureFiddleDecls p decls <*> pure a
instance AdvanceStage CurrentStage ObjTypeDecl where
modifyState t =
return
. case t of
TypeSubStructure {subStructureName = (Just n)} -> pushId n
RegisterDecl {regIdent = (Perhaps (Just n))} -> pushId n
_ -> id
instance AdvanceStage CurrentStage FiddleDecl where
modifyState t =
return
. case t of
-- PackageDecl {packageName = n} -> pushName n
BitsDecl {bitsName = n} -> pushName n
ObjTypeDecl {objTypeIdent = i} -> pushName i
ObjectDecl {objectIdent = i} -> pushId i
_ -> id
instance AdvanceStage CurrentStage FiddleUnit where
advanceStage path (FiddleUnit v decls a) =
FiddleUnit v <$> reconfigureFiddleDecls path decls <*> pure a
instance AdvanceStage CurrentStage (Expression u) where
advanceStage _ = \case
(Var i a) -> return $ Var i a
(LitNum (LeftV t) a) ->
LitNum . RightV <$> parseNum (unCommented a) t <*> pure a
instance AdvanceStage CurrentStage RegisterBitsTypeRef where
advanceStage path = \case
RegisterBitsArray typeref expr annot ->
RegisterBitsArray
<$> advanceStage path typeref
<*> advanceStage path expr
<*> pure annot
RegisterBitsReference q name annot ->
return $ RegisterBitsReference q name annot
RegisterBitsJustBits expr annot ->
RegisterBitsJustBits
<$> advanceStage path expr
<*> pure annot
RegisterBitsAnonymousType _ anonType annot -> do
name <-
internAnonymousBitsType path
=<< advanceStage path anonType
return $ RegisterBitsReference (Identity Vacant) name annot
instance AdvanceStage CurrentStage ObjType where
advanceStage path = \case
(AnonymousObjType _ (Identity body) annot) -> do
body' <- advanceStage path body
name <- internObjType path body'
return (ReferencedObjType (Identity Vacant) name annot)
(ReferencedObjType q name annot) ->
return $ ReferencedObjType q name annot
(ArrayObjType objType expr a) ->
ArrayObjType
<$> advanceStage path objType
<*> advanceStage path expr
<*> pure a
parseNum :: SourceSpan -> Text -> Compile s (N u)
parseNum span txt = fmap NumberWithUnit $
fromMayberOrFail span "Unable to parse number" $
case Text.unpack (Text.take 2 txt) of
"0b" -> toNumWithRadix (Text.drop 2 txt) 2
"0x" -> toNumWithRadix (Text.drop 2 txt) 16
('0' : _) -> toNumWithRadix (Text.tail txt) 8
_ -> toNumWithRadix txt 10
where
removeUnders :: Text -> Text
removeUnders = Text.replace (Text.pack "_") Text.empty
toNumWithRadix :: Text -> Int -> Maybe Int
toNumWithRadix (removeUnders -> txt) (fromIntegral -> radix) =
Text.foldl
( \mAcc x ->
mAcc >>= (\acc -> (acc * radix +) <$> digitToInt x radix)
)
(Just 0)
txt
digitToInt :: Char -> Int -> Maybe Int
digitToInt (Char.toLower -> ch) radix =
let a
| Char.isDigit ch = Just (Char.ord ch - Char.ord '0')
| ch >= 'a' && ch <= 'f' = Just $ (Char.ord ch - Char.ord 'a') + 10
| otherwise = Nothing
in a
>>= ( \a' ->
if a' >= fromIntegral radix
then Nothing
else Just (fromIntegral a')
)
reconfigureFiddleDecls ::
Path ->
[Directed FiddleDecl CurrentStage I Annot] ->
M [Directed FiddleDecl Expanded I Annot]
reconfigureFiddleDecls p decls = do
lastState <- get
put (State [] [])
decls <- mapM (mapDirectedM $ advanceStage p) decls
(State anonymousObjTypes anonymousBitsTypes) <- get
put lastState
return $
map (asDirected . resolveAnonymousObjType) anonymousObjTypes
++ map (asDirected . resolveAnonymousBitsType) anonymousBitsTypes
++ decls
where
resolveAnonymousObjType (Linkage linkage, objTypeBody) =
ObjTypeDecl
(Identity Vacant)
(Name (fmap (\t -> Identifier t (annot objTypeBody)) (NonEmpty.reverse linkage)) (annot objTypeBody))
(pure objTypeBody)
(annot objTypeBody)
resolveAnonymousBitsType (Linkage linkage, AnonymousEnumBody expr body a) =
BitsDecl
(Identity Vacant)
(Name (fmap (\t -> Identifier t a) (NonEmpty.reverse linkage)) a)
(EnumBitType expr body a)
a
identToName :: Identifier I a -> Name I a
identToName ident = Name (NonEmpty.singleton ident) (annot ident)
internObjType :: Path -> ObjTypeBody Expanded I Annot -> M (Name I Annot)
internObjType [] _ = compilationFailure
internObjType (NonEmpty.fromList -> path) body =
do
modify $ \(State objTypeBodies a) ->
State ((Linkage path, body) : objTypeBodies) a
let a = annot body
in return (Name (fmap (\t -> Identifier t a) (NonEmpty.reverse path)) a)
internAnonymousBitsType ::
Path ->
AnonymousBitsType Expanded I Annot ->
M (Name I Annot)
internAnonymousBitsType [] _ = compilationFailure
internAnonymousBitsType (NonEmpty.fromList -> path) anonymousBitsType =
do
modify $ \(State a anonymousBitsTypes) ->
State a ((Linkage path, anonymousBitsType) : anonymousBitsTypes)
let a = annot anonymousBitsType
in return (Name (fmap (\t -> Identifier t a) (NonEmpty.reverse path)) a)
pushId :: Identifier f a -> Path -> Path
pushId (Identifier str _) lst = str : lst
pushName :: Name f a -> Path -> Path
pushName (Name idents _) path = foldl (flip pushId) path idents
|