summaryrefslogtreecommitdiff
path: root/src/Language/Fiddle/GenericTree.hs
blob: cbaf447ef73ac19ccfedff8e5b6f9cdb9f5264a8 (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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module Language.Fiddle.GenericTree where

import Control.Monad.Identity (Identity)
import Data.Aeson.Encoding (text)
import Data.Aeson.Types as Aeson
import Data.Foldable (Foldable (toList))
import Data.Proxy
import qualified Data.Text
import Data.Typeable
import qualified Data.Vector
import GHC.Generics
import GHC.TypeLits (KnownSymbol, symbolVal)
import Language.Fiddle.Ast
import Language.Fiddle.Internal.UnitInterface
import Language.Fiddle.Types

type Context stage =
  ( Show (NumberType stage),
    Typeable stage,
    ToJSON (NumberType stage),
    ToJSON (RegisterOffset stage),
    ToJSON (ImportInterface stage),
    ToJSON (FiddleUnitInterface stage),
    ToJSON (QualificationMetadata stage ()),
    ToJSON (QualificationMetadata stage ExportedPackageDecl),
    ToJSON (QualificationMetadata stage ExportedLocationDecl),
    ToJSON (QualificationMetadata stage ExportedBitsDecl),
    ToJSON (QualificationMetadata stage ExportedTypeDecl),
    ToJSON (QualificationMetadata stage ExportedObjectDecl)
  )

class FunctorShow f where
  showf :: (Show a) => f a -> String

instance (Show l) => FunctorShow (Either l) where
  showf = show

instance FunctorShow Maybe where
  showf = show

instance FunctorShow Identity where
  showf = show

data GenericSyntaxTree f a where
  {- GenericSyntaxtTree with a name and children. -}
  SyntaxTreeObject ::
    forall t f a.
    (Typeable t, Typeable f, Typeable a) =>
    String ->
    [GenericSyntaxTree f a] ->
    a ->
    t f a ->
    GenericSyntaxTree f a
  SyntaxTreeList :: [GenericSyntaxTree f a] -> GenericSyntaxTree f a
  SyntaxTreeDeferred :: f (GenericSyntaxTree f a) -> GenericSyntaxTree f a
  SyntaxTreeValue :: Value -> GenericSyntaxTree f a

alterGenericSyntaxTree ::
  (Functor f) =>
  (GenericSyntaxTree f a -> Maybe (GenericSyntaxTree f a)) ->
  GenericSyntaxTree f a ->
  GenericSyntaxTree f a
alterGenericSyntaxTree fn genericTree
  | (Just newGenericTree) <- fn genericTree = newGenericTree
  | otherwise =
      case genericTree of
        SyntaxTreeObject str members a tree ->
          SyntaxTreeObject
            str
            (map (alterGenericSyntaxTree fn) members)
            a
            tree
        SyntaxTreeList members ->
          SyntaxTreeList $ map (alterGenericSyntaxTree fn) members
        SyntaxTreeDeferred sub ->
          SyntaxTreeDeferred $ fmap (alterGenericSyntaxTree fn) sub
        v -> v

instance ToJSON Comment where
  toJSON (NormalComment str) = object ["normal" .= str]
  toJSON (DocComment str) = object ["doc" .= str]

instance (ToJSON a) => ToJSON (Commented a) where
  toJSON (Commented comment a) =
    object ["comment" .= comment, "annot" .= a]

instance (Foldable f) => ToJSON (GenericSyntaxTree f (Maybe Value)) where
  toJSON = \case
    (SyntaxTreeObject typ membs Nothing _) ->
      object ["_con" .= typ, "_members" .= membs]
    (SyntaxTreeObject typ membs (Just a) _) ->
      object ["_con" .= typ, "_members" .= membs, "_annot" .= a]
    (SyntaxTreeList l) ->
      Array $ Data.Vector.fromList $ map toJSON l
    (SyntaxTreeDeferred fdef) ->
      toJSON (SyntaxTreeList $ Data.Foldable.toList fdef)
    (SyntaxTreeValue s) -> toJSON s

  toEncoding = \case
    (SyntaxTreeObject typ membs (Just a) t) ->
      pairs $ "_type" .= show (typeOf t) <> "_con" .= typ <> "_members" .= membs <> "_annot" .= a
    (SyntaxTreeObject typ membs Nothing t) ->
      pairs $ "_type" .= show (typeOf t) <> "_con" .= typ <> "_members" .= membs
    (SyntaxTreeList l) ->
      foldable $ map toJSON l
    (SyntaxTreeDeferred fdef) ->
      toEncoding (SyntaxTreeList $ Data.Foldable.toList fdef)
    (SyntaxTreeValue v) -> toEncoding v

class ToGenericSyntaxTreeValue f v where
  toGenericSyntaxTreeValue :: forall a. v -> Maybe (GenericSyntaxTree f a)
  default toGenericSyntaxTreeValue ::
    forall a. (ToJSON v) => v -> Maybe (GenericSyntaxTree f a)
  toGenericSyntaxTreeValue = Just . SyntaxTreeValue . toJSON

instance ToGenericSyntaxTreeValue f Data.Text.Text where
  toGenericSyntaxTreeValue = Just . SyntaxTreeValue . String

instance (ToJSON s) => ToGenericSyntaxTreeValue f s where
  toGenericSyntaxTreeValue = Just . SyntaxTreeValue . toJSON

-- Witnesses exist just for type level meta programming, don't return anything
-- if we don't need it.
instance ToGenericSyntaxTreeValue f (Witness b) where
  toGenericSyntaxTreeValue _ = Nothing

type GenericContext t f a = (Traversable f, ToGenericSyntaxTree t, Typeable t, Typeable f, Typeable a)

class ToGenericSyntaxTree (t :: SynTree) where
  toGenericSyntaxTree :: (Traversable f, Typeable f, Typeable t, Typeable a) => t f a -> GenericSyntaxTree f a
  default toGenericSyntaxTree ::
    (GenericContext t f a, Generic (t f a), (GToGenericSyntaxTree (Rep (t f a)) f a)) =>
    t f a ->
    GenericSyntaxTree f a
  toGenericSyntaxTree t = gToGenericSyntaxTree t (from t)

class GToGenericSyntaxTree r f a where
  gToGenericSyntaxTree :: (Typeable t, Typeable f, Typeable a) => t f a -> r x -> GenericSyntaxTree f a

class GToMemberList r f a where
  gToMemberList :: Int -> r x -> [GenericSyntaxTree f a]

instance (ToGenericSyntaxTreeValue f v) => GToMemberList (Rec0 v) f a where
  gToMemberList _ = toList . toGenericSyntaxTreeValue . unK1

instance
  (GenericContext r f a) =>
  GToGenericSyntaxTree (Rec0 (f (r f a))) f a
  where
  gToGenericSyntaxTree _ k1 = SyntaxTreeDeferred (toGenericSyntaxTree <$> unK1 k1)

-- instance
--   GToGenericSyntaxTree (Rec0 (f x)) f a
--   where
--   gToGenericSyntaxTree _ k1 = SyntaxTreeList []

instance
  (GenericContext r f a, Traversable f1) =>
  GToGenericSyntaxTree (Rec0 (f1 (r f a))) f a
  where
  gToGenericSyntaxTree _ k1 =
    SyntaxTreeList (Data.Foldable.toList $ toGenericSyntaxTree <$> unK1 k1)

instance
  (GToMemberList r f a, GToMemberList l f a) =>
  GToMemberList (l :*: r) f a
  where
  gToMemberList n (l :*: r) = l1 ++ gToMemberList (length l1) r
    where
      l1 = gToMemberList n l

instance (GenericContext t f a) => GToMemberList (Rec0 (t f a)) f a where
  gToMemberList _ a = [toGenericSyntaxTree (unK1 a)]


instance
  (GenericContext t f a, Foldable l) =>
  GToMemberList (Rec0 (l (t f a))) f a
  where
  gToMemberList _ as = toGenericSyntaxTree <$> Data.Foldable.toList (unK1 as)

instance GToMemberList (Rec0 a) f a where
  gToMemberList _ _ = []

instance (GToMemberList r f a) => GToMemberList (M1 i c r) f a where
  gToMemberList n (M1 r) = gToMemberList n r

instance (GenericContext r f a) => GToGenericSyntaxTree (Rec0 (r f a)) f a where
  gToGenericSyntaxTree _ k1 = toGenericSyntaxTree $ unK1 k1

instance
  (GToMemberList r f a, KnownSymbol name, GAnnot a r) =>
  (GToGenericSyntaxTree (C1 ('MetaCons name _f _b) r)) f a
  where
  gToGenericSyntaxTree t c =
    SyntaxTreeObject (symbolVal (nameProxy c)) (gToMemberList 0 (unM1 c)) (gannot c) t
    where
      nameProxy :: C1 ('MetaCons name _f _b) r x -> Proxy name
      nameProxy _ = Proxy

instance
  (GToGenericSyntaxTree l f a, GToGenericSyntaxTree r f a) =>
  (GToGenericSyntaxTree (l :+: r) f a)
  where
  gToGenericSyntaxTree t (L1 l) = gToGenericSyntaxTree t l
  gToGenericSyntaxTree t (R1 r) = gToGenericSyntaxTree t r

instance (GToGenericSyntaxTree r f a) => (GToGenericSyntaxTree (M1 i c r) f a) where
  gToGenericSyntaxTree t (M1 r) = gToGenericSyntaxTree t r

-- deriving instance (ToGenericSyntaxTree (Test stage))

deriving instance (ToGenericSyntaxTree Identifier)

deriving instance (ToGenericSyntaxTree Name)

deriving instance (ToGenericSyntaxTree BodyType)

deriving instance (ToGenericSyntaxTree Directive)

deriving instance (ToGenericSyntaxTree DirectiveBody)

deriving instance (ToGenericSyntaxTree DirectiveElement)

deriving instance (ToGenericSyntaxTree DirectiveExpression)

deriving instance (ToGenericSyntaxTree ImportList)

deriving instance (Context stage) => (ToGenericSyntaxTree (ImportStatement stage))

deriving instance
  (Context stage, ToGenericSyntaxTree (t stage), Typeable t) =>
  (ToGenericSyntaxTree (Directed t stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (FiddleUnit stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (FiddleDecl stage))

deriving instance (Context stage) => ToGenericSyntaxTree (ObjType stage)

deriving instance (Context stage) => (ToGenericSyntaxTree (ObjTypeBody stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (ObjTypeDecl stage))

instance (ToGenericSyntaxTreeValue f ModifierKeyword) where
  toGenericSyntaxTreeValue kw = Just $ SyntaxTreeValue $ String (Data.Text.pack $ show kw)

instance (Functor f, ToJSON a) => (ToGenericSyntaxTreeValue f (f a)) where
  toGenericSyntaxTreeValue mv =
     Just $ SyntaxTreeDeferred $ SyntaxTreeValue . toJSON <$> mv

deriving instance (ToGenericSyntaxTree Modifier)

deriving instance (Context stage) => (ToGenericSyntaxTree (DeferredRegisterBody stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (RegisterBody stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (RegisterBitsDecl stage))

deriving instance (Context stage) => ToGenericSyntaxTree (RegisterBitsTypeRef stage)

deriving instance (Context stage) => (ToGenericSyntaxTree (AnonymousBitsType stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (BitType stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (EnumBody stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (EnumConstantDecl stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (PackageBody stage))

deriving instance (Context stage) => (ToGenericSyntaxTree (Expression stage))