1+ {-# LANGUAGE CPP #-}
12module Composite.TH
23 ( withProxies
34 , withLensesAndProxies
@@ -18,6 +19,9 @@ import Language.Haskell.TH
1819 ( Q , newName , mkName , nameBase
1920 , Body (NormalB ), cxt , Dec (PragmaD , SigD , ValD ), Exp (VarE ), Inline (Inlinable ), Name , Pat (VarP ), Phases (AllPhases ), Pragma (InlineP ), RuleMatch (FunLike )
2021 , Type (AppT , ConT , ForallT , VarT ), TyVarBndr (PlainTV , KindedTV ), varT
22+ #if MIN_VERSION_template_haskell(2,17,0)
23+ , Specificity (SpecifiedSpec )
24+ #endif
2125 )
2226import Language.Haskell.TH.Lens (_TySynD )
2327
@@ -141,31 +145,62 @@ withPrismsAndProxies = withBoilerplate False True
141145withOpticsAndProxies :: Q [Dec ] -> Q [Dec ]
142146withOpticsAndProxies = withBoilerplate True True
143147
148+ #if MIN_VERSION_template_haskell(2,17,0)
149+ tyUnitToSpec :: Specificity -> TyVarBndr () -> TyVarBndr Specificity
150+ tyUnitToSpec x (PlainTV n () ) = PlainTV n x
151+ tyUnitToSpec x (KindedTV n () k) = KindedTV n x k
152+
153+ fieldDecUnitToSpec :: Specificity -> FieldDec () -> FieldDec Specificity
154+ fieldDecUnitToSpec x (FieldDec n b t v) = FieldDec n (map (tyUnitToSpec x) b) t v
155+
156+ data FieldDec a = FieldDec
157+ #else
144158data FieldDec = FieldDec
159+ #endif
145160 { fieldName :: Name
161+ #if MIN_VERSION_template_haskell(2,17,0)
162+ , fieldBinders :: [TyVarBndr a ]
163+ #else
146164 , fieldBinders :: [TyVarBndr ]
165+ #endif
147166 , fieldTypeApplied :: Type
148167 , fieldValueType :: Type
149168 }
169+
150170-- | TH splice which implements 'withLensesAndProxies', 'withPrismsAndProxies', and 'withOpticsAndProxies'
151171withBoilerplate :: Bool -> Bool -> Q [Dec ] -> Q [Dec ]
152172withBoilerplate generateLenses generatePrisms qDecs = do
153173 decs <- qDecs
154174
155175 let fieldDecs = catMaybes . map fieldDecMay . toListOf (each . _TySynD) $ decs
156-
176+ #if MIN_VERSION_template_haskell(2,17,0)
177+ let sFieldDecs = map (fieldDecUnitToSpec SpecifiedSpec ) fieldDecs
178+ #endif
157179 proxyDecs <- traverse proxyDecFor fieldDecs
158- lensDecs <- if generateLenses then traverse lensDecFor fieldDecs else pure []
180+ #if MIN_VERSION_template_haskell(2,17,0)
181+ lensDecs <- if generateLenses then traverse lensDecFor sFieldDecs else pure []
182+ prismDecs <- if generatePrisms then traverse prismDecFor sFieldDecs else pure []
183+ #else
184+ lensDecs <- if generateLenses then traverse lensDecFor fieldDecs else pure []
159185 prismDecs <- if generatePrisms then traverse prismDecFor fieldDecs else pure []
160-
186+ #endif
161187 pure $ decs <> concat proxyDecs <> concat lensDecs <> concat prismDecs
162188
189+ #if MIN_VERSION_template_haskell(2,17,0)
190+ fieldDecMay :: (Name , [TyVarBndr () ], Type ) -> Maybe (FieldDec () )
191+ #else
163192fieldDecMay :: (Name , [TyVarBndr ], Type ) -> Maybe FieldDec
193+ #endif
164194fieldDecMay (fieldName, fieldBinders, ty) = case ty of
165195 AppT (AppT (ConT n) _) fieldValueType | n == ''(:->) ->
166196 let fieldTypeApplied = foldl' AppT (ConT fieldName) (map binderTy fieldBinders)
167- binderTy (PlainTV n') = VarT n'
197+ #if MIN_VERSION_template_haskell(2,17,0)
198+ binderTy (PlainTV n' _ ) = VarT n'
199+ binderTy (KindedTV n' _ _) = VarT n'
200+ #else
201+ binderTy (PlainTV n' ) = VarT n'
168202 binderTy (KindedTV n' _) = VarT n'
203+ #endif
169204 in Just $ FieldDec {.. }
170205 _ ->
171206 Nothing
@@ -175,7 +210,11 @@ lensNameFor = mkName . over _head toLower . nameBase
175210prismNameFor = mkName . (" _" ++ ) . nameBase
176211proxyNameFor = mkName . (++ " _" ) . over _head toLower . nameBase
177212
213+ #if MIN_VERSION_template_haskell(2,17,0)
214+ proxyDecFor :: FieldDec () -> Q [Dec ]
215+ #else
178216proxyDecFor :: FieldDec -> Q [Dec ]
217+ #endif
179218proxyDecFor (FieldDec { fieldName, fieldTypeApplied }) = do
180219 let proxyName = proxyNameFor fieldName
181220
@@ -187,7 +226,11 @@ proxyDecFor (FieldDec { fieldName, fieldTypeApplied }) = do
187226 , ValD (VarP proxyName) (NormalB proxyVal) []
188227 ]
189228
229+ #if MIN_VERSION_template_haskell(2,17,0)
230+ lensDecFor :: FieldDec Specificity -> Q [Dec ]
231+ #else
190232lensDecFor :: FieldDec -> Q [Dec ]
233+ #endif
191234lensDecFor (FieldDec {.. }) = do
192235 f <- newName " f"
193236 rs <- newName " rs"
@@ -197,7 +240,11 @@ lensDecFor (FieldDec {..}) = do
197240 proxyName = proxyNameFor fieldName
198241 lensName = lensNameFor fieldName
199242 proxyVal = VarE proxyName
243+ #if MIN_VERSION_template_haskell(2,17,0)
244+ lensBinders = fieldBinders ++ [PlainTV f SpecifiedSpec , PlainTV rs SpecifiedSpec ]
245+ #else
200246 lensBinders = fieldBinders ++ [PlainTV f, PlainTV rs]
247+ #endif
201248
202249 lensContext <- cxt [ [t | Functor $fTy |], [t | $(pure fieldTypeApplied) ∈ $rsTy |] ]
203250 lensType <- [t | ($(pure fieldValueType) -> $fTy $(pure fieldValueType)) -> (Record $rsTy -> $fTy (Record $rsTy)) |]
@@ -209,15 +256,23 @@ lensDecFor (FieldDec {..}) = do
209256 , ValD (VarP lensName) (NormalB rlensVal) []
210257 ]
211258
259+ #if MIN_VERSION_template_haskell(2,17,0)
260+ prismDecFor :: FieldDec Specificity -> Q [Dec ]
261+ #else
212262prismDecFor :: FieldDec -> Q [Dec ]
263+ #endif
213264prismDecFor (FieldDec {.. }) = do
214265 rs <- newName " rs"
215266
216267 let rsTy = varT rs
217268 proxyName = proxyNameFor fieldName
218269 prismName = prismNameFor fieldName
219270 proxyVal = VarE proxyName
271+ #if MIN_VERSION_template_haskell(2,17,0)
272+ prismBinders = fieldBinders ++ [PlainTV rs SpecifiedSpec ]
273+ #else
220274 prismBinders = fieldBinders ++ [PlainTV rs]
275+ #endif
221276
222277 prismContext <- cxt [ [t | RecApplicative $rsTy |], [t | $(pure fieldTypeApplied) ∈ $rsTy |] ]
223278 prismType <- [t | Prism' (Field $rsTy) $(pure fieldValueType) |]
0 commit comments