1
1
{-# LANGUAGE OverloadedLabels #-}
2
2
{-# LANGUAGE OverloadedStrings #-}
3
3
4
- module LambdaBuffers.Compiler.TypeClassCheck (detectSuperclassCycles , detectSuperclassCycles' ) where
4
+ module LambdaBuffers.Compiler.TypeClassCheck (detectSuperclassCycles , detectSuperclassCycles' , runDeriveCheck , validateTypeClasses ) where
5
5
6
6
import Control.Lens.Combinators (view )
7
7
import Control.Lens.Operators ((^.) )
8
+ import Control.Monad (void )
8
9
import Data.Generics.Labels ()
9
10
import Data.List (foldl' )
11
+ import Data.Map (traverseWithKey )
10
12
import Data.Map qualified as M
13
+ import Data.Set qualified as S
11
14
import Data.Text (Text )
15
+ import LambdaBuffers.Compiler.ProtoCompat qualified as P
12
16
import LambdaBuffers.Compiler.ProtoCompat.Types (
13
17
ClassDef (),
14
18
ForeignClassRef (ForeignClassRef ),
15
19
LocalClassRef (LocalClassRef ),
16
20
TyClassRef (ForeignCI , LocalCI ),
17
21
)
22
+ import LambdaBuffers.Compiler.TypeClassCheck.Pretty (spaced , (<//>) )
23
+ import LambdaBuffers.Compiler.TypeClassCheck.Utils (
24
+ Instance ,
25
+ ModuleBuilder (mbInstances ),
26
+ TypeClassError (FailedToSolveConstraints ),
27
+ checkInstance ,
28
+ mkBuilders ,
29
+ )
30
+ import LambdaBuffers.Compiler.TypeClassCheck.Validate (checkDerive )
18
31
import Prettyprinter (
19
32
Doc ,
20
33
Pretty (pretty ),
@@ -23,6 +36,7 @@ import Prettyprinter (
23
36
line ,
24
37
punctuate ,
25
38
vcat ,
39
+ (<+>) ,
26
40
)
27
41
28
42
data ClassInfo = ClassInfo { ciName :: Text , ciSupers :: [Text ]}
@@ -65,3 +79,39 @@ detectSuperclassCycles cds = case detectSuperclassCycles' cds of
65
79
where
66
80
format :: [Text ] -> Doc a
67
81
format = hcat . punctuate " => " . map pretty
82
+
83
+ runDeriveCheck :: P. ModuleName -> ModuleBuilder -> Either TypeClassError ()
84
+ runDeriveCheck mn mb = mconcat <$> traverse go (S. toList $ mbInstances mb)
85
+ where
86
+ go :: Instance -> Either TypeClassError ()
87
+ go i =
88
+ checkInstance i
89
+ >> checkDerive mn mb i
90
+ >>= \ case
91
+ [] -> pure ()
92
+ xs -> Left $ FailedToSolveConstraints mn xs i
93
+
94
+ -- ModuleBuilder is suitable codegen input,
95
+ -- and is (relatively) computationally expensive to
96
+ -- construct, so we return it here if successful.
97
+ validateTypeClasses' :: P. CompilerInput -> Either TypeClassError (M. Map P. ModuleName ModuleBuilder )
98
+ validateTypeClasses' ci = do
99
+ -- detectSuperclassCycles ci
100
+ moduleBuilders <- mkBuilders ci
101
+ void $ traverseWithKey runDeriveCheck moduleBuilders
102
+ pure moduleBuilders
103
+
104
+ -- maybe use Control.Exception? Tho if we're not gonna catch it i guess this is fine
105
+ validateTypeClasses :: P. CompilerInput -> IO (M. Map P. ModuleName ModuleBuilder )
106
+ validateTypeClasses ci = case validateTypeClasses' ci of
107
+ Left err -> print (spaced $ pretty err) >> error " \n Compilation aborted due to TypeClass Error"
108
+ Right mbs -> print (prettyBuilders mbs) >> pure mbs
109
+
110
+ prettyBuilders :: forall a . M. Map P. ModuleName ModuleBuilder -> Doc a
111
+ prettyBuilders = spaced . vcat . punctuate line . map (uncurry go) . M. toList
112
+ where
113
+ go :: P. ModuleName -> ModuleBuilder -> Doc a
114
+ go mn mb =
115
+ " MODULE"
116
+ <+> pretty mn
117
+ <//> indent 2 (pretty mb)
0 commit comments