Skip to content

Commit 8b85714

Browse files
authored
Merge pull request #87 from iconnect/adinapoli/issue-84
Generate `shrink` implementations in quickCheckTool
2 parents 2bf817a + 3cf8f17 commit 8b85714

9 files changed

Lines changed: 214 additions & 52 deletions

File tree

api-tools.cabal

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Library
119119
-Wall
120120
-fwarn-tabs
121121

122-
Default-Language: Haskell2010
122+
Default-Language: GHC2021
123123

124124

125125
Executable migration-tool
@@ -138,7 +138,7 @@ Executable migration-tool
138138
-Wall
139139
-fwarn-tabs
140140

141-
Default-Language: Haskell2010
141+
Default-Language: GHC2021
142142

143143

144144
Executable perf-test
@@ -159,7 +159,7 @@ Executable perf-test
159159
-fwarn-tabs
160160
-rtsopts
161161

162-
Default-Language: Haskell2010
162+
Default-Language: GHC2021
163163

164164

165165
Test-Suite test-api-tools
@@ -200,7 +200,7 @@ Test-Suite test-api-tools
200200
GHC-Options:
201201
-Wall
202202

203-
Default-Language: Haskell2010
203+
Default-Language: GHC2021
204204

205205
Benchmark bench-time
206206
Hs-Source-Dirs: bench
@@ -219,4 +219,4 @@ Benchmark bench-time
219219
GHC-Options:
220220
-Wall
221221

222-
Default-Language: Haskell2010
222+
Default-Language: GHC2021

src/Data/API/API/Gen.hs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
{-# LANGUAGE TemplateHaskell #-}
21
{-# LANGUAGE OverloadedStrings #-}
3-
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4-
{-# LANGUAGE DeriveDataTypeable #-}
2+
{-# LANGUAGE TemplateHaskell #-}
53

64
-- | This module contains datatypes generated from the DSL description
75
-- of the api-tools API; they thus correspond to the types in

src/Data/API/TH.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
module Data.API.TH
77
( applicativeE
88
, optionalInstanceD
9+
, optionalStandaloneDerivD
910
, funSigD
1011
, simpleD
1112
, simpleSigD
@@ -56,6 +57,17 @@ optionalInstanceD stgs c tqs dqs = do
5657
where
5758
msg ts = "instance " ++ pprint c ++ " " ++ pprint ts ++ " already exists, so it was not generated"
5859

60+
-- | Adds a "deriving instance" standalone declaration for a class, if such an instance does
61+
-- not already exist.
62+
optionalStandaloneDerivD :: ToolSettings -> Name -> [TypeQ] -> Q [Dec]
63+
optionalStandaloneDerivD stgs c tqs = do
64+
ts <- sequence tqs
65+
exists <- isInstance c ts
66+
if exists then do when (warnOnOmittedInstance stgs) $ reportWarning $ msg ts
67+
return []
68+
else pure [StandaloneDerivD Nothing [] (foldl AppT (ConT c) ts)]
69+
where
70+
msg ts = "instance " ++ pprint c ++ " " ++ pprint ts ++ " already exists, so it was not generated"
5971

6072
-- | Construct a TH function with a type signature
6173
funSigD :: Name -> TypeQ -> [ClauseQ] -> Q [Dec]

src/Data/API/Tools.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module Data.API.Tools
2020
, defaultToolSettings
2121
, warnOnOmittedInstance
2222
, newtypeSmartConstructors
23+
, defaultDerivedClasses
2324

2425
-- * Individual tools
2526
, enumTool
@@ -56,15 +57,14 @@ import Data.API.Types
5657
import qualified Data.Monoid as Monoid
5758
import Language.Haskell.TH
5859

59-
6060
-- | Generate the datatypes corresponding to an API.
6161
generate :: API -> Q [Dec]
6262
generate = generateWith defaultToolSettings
6363

6464
-- | Generate the datatypes corresponding to an API, allowing the
6565
-- 'ToolSettings' to be overriden.
6666
generateWith :: ToolSettings -> API -> Q [Dec]
67-
generateWith ts api = generateAPIToolsWith ts api [datatypesTool]
67+
generateWith ts api = generateAPIToolsWith ts api [datatypesTool ts]
6868

6969
-- | Apply a list of tools to an 'API', generating TH declarations.
7070
-- See the individual tool descriptions for details. Note that

src/Data/API/Tools/Combinators.hs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@ module Data.API.Tools.Combinators
2222
, warnOnOmittedInstance
2323
, newtypeSmartConstructors
2424
, defaultToolSettings
25+
, defaultDerivedClasses
2526
) where
2627

2728
import Data.API.Types
2829

2930
import Control.Applicative
3031
import Data.Monoid
3132
import Data.Semigroup as Sem
33+
import Data.String
34+
import Data.Typeable
3235
import Language.Haskell.TH
3336
import Prelude
3437

@@ -43,15 +46,41 @@ data ToolSettings = ToolSettings
4346
, newtypeSmartConstructors :: Bool
4447
-- ^ Rename the constructors of filtered newtypes and generate
4548
-- smart constructors that enforce the invariants
49+
, defaultDerivedClasses :: APINode -> [Name]
50+
-- ^ The classes which are derived automatically for datatypes created by 'datatypesTool'.
4651
}
4752

4853
-- | Default settings designed to be overridden.
4954
defaultToolSettings :: ToolSettings
5055
defaultToolSettings = ToolSettings
5156
{ warnOnOmittedInstance = False
5257
, newtypeSmartConstructors = False
58+
, defaultDerivedClasses = default_derived_classes
5359
}
5460

61+
-- | Default names of classes for which to derive instances, depending
62+
-- on the type of API node.
63+
default_derived_classes :: APINode -> [Name]
64+
default_derived_classes an = case anSpec an of
65+
SpNewtype sn -> case snType sn of
66+
BTstring -> ''IsString : derive_leaf_nms
67+
BTbinary -> derive_leaf_nms
68+
BTbool -> derive_leaf_nms
69+
BTint -> derive_leaf_nms
70+
BTutc -> derive_leaf_nms
71+
SpRecord _ -> derive_node_nms
72+
SpUnion _ -> derive_node_nms
73+
SpEnum _ -> derive_leaf_nms ++ [''Bounded, ''Enum]
74+
SpSynonym _ -> []
75+
76+
derive_leaf_nms :: [Name]
77+
derive_leaf_nms = [''Show,''Eq,''Ord,''Typeable]
78+
79+
derive_node_nms :: [Name]
80+
derive_node_nms = [''Show,''Eq,''Typeable]
81+
82+
83+
5584
-- | A @'Tool' a@ is something that can generate TH declarations from
5685
-- a value of type @a@. Tools can be combined using the 'Monoid'
5786
-- instance.

src/Data/API/Tools/Datatypes.hs

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22
module Data.API.Tools.Datatypes
33
( datatypesTool
44
, datatypesTool'
5-
, defaultDerivedClasses
65
, type_nm
76
, rep_type_nm
87
, nodeT
98
, nodeRepT
109
, nodeConE
1110
, nodeConP
1211
, nodeNewtypeConE
12+
, nodeNewtypeConP
1313
, nodeFieldE
1414
, nodeFieldP
1515
, nodeAltConE
1616
, nodeAltConP
1717
, newtypeProjectionE
18+
, pref_field_nm
1819
) where
1920

2021
import Data.API.TH
@@ -30,15 +31,14 @@ import Data.Maybe
3031
import Data.String
3132
import qualified Data.Text as T
3233
import Data.Time
33-
import Data.Typeable
3434
import Language.Haskell.TH
3535
import Text.Regex
3636
import Prelude
3737

3838

3939
-- | Tool to generate datatypes and type synonyms corresponding to an API
40-
datatypesTool :: APITool
41-
datatypesTool = datatypesTool' defaultDerivedClasses
40+
datatypesTool :: ToolSettings -> APITool
41+
datatypesTool = datatypesTool' . defaultDerivedClasses
4242

4343
-- | Tool to generate datatypes and type synonyms corresponding to an
4444
-- API, where the function specifies the derived classes for each datatype.
@@ -163,28 +163,6 @@ basic_type bt =
163163
BTutc -> ConT ''UTCTime
164164

165165

166-
-- | Default names of classes for which to derive instances, depending
167-
-- on the type of API node.
168-
defaultDerivedClasses :: APINode -> [Name]
169-
defaultDerivedClasses an = case anSpec an of
170-
SpNewtype sn -> case snType sn of
171-
BTstring -> ''IsString : derive_leaf_nms
172-
BTbinary -> derive_leaf_nms
173-
BTbool -> derive_leaf_nms
174-
BTint -> derive_leaf_nms
175-
BTutc -> derive_leaf_nms
176-
SpRecord _ -> derive_node_nms
177-
SpUnion _ -> derive_node_nms
178-
SpEnum _ -> derive_leaf_nms ++ [''Bounded, ''Enum]
179-
SpSynonym _ -> []
180-
181-
derive_leaf_nms :: [Name]
182-
derive_leaf_nms = [''Show,''Eq,''Ord,''Typeable]
183-
184-
derive_node_nms :: [Name]
185-
derive_node_nms = [''Show,''Eq,''Typeable]
186-
187-
188166
-- | Name of the type corresponding to the API node, e.g. @JobId@
189167
type_nm :: APINode -> Name
190168
type_nm an = mkName $ T.unpack $ _TypeName $ anName an
@@ -252,6 +230,9 @@ nodeConP an = conP (rep_type_nm an)
252230
nodeNewtypeConE :: ToolSettings -> APINode -> SpecNewtype -> ExpQ
253231
nodeNewtypeConE ts an sn = conE $ newtype_con_nm (newtypeSmartConstructors ts && isJust (snFilter sn)) an
254232

233+
nodeNewtypeConP :: ToolSettings -> APINode -> SpecNewtype -> [Q Pat] -> PatQ
234+
nodeNewtypeConP ts an sn ps = conP (newtype_con_nm (newtypeSmartConstructors ts && isJust (snFilter sn)) an) ps
235+
255236
-- | A record field in an API node, as an expression
256237
nodeFieldE :: APINode -> FieldName -> ExpQ
257238
nodeFieldE an fnm = varE $ pref_field_nm an fnm

0 commit comments

Comments
 (0)