@@ -50,26 +50,77 @@ gen_sn_ab = mkTool $ \ ts (an, sn) -> case snFilter sn of
5050 Nothing | snType sn == BTint -> mk_instance ts an sn [e | QC.arbitraryBoundedIntegral |] (shrinkNewtype ts an sn)
5151 | otherwise -> mk_instance ts an sn [e | arbitrary |] (shrinkNewtype ts an sn)
5252 Just (FtrIntg ir) ->
53- mk_instance ts an sn [e | arbitraryIntRange ir |] (shrinkNewtype ts an sn)
53+ mk_instance ts an sn [e | arbitraryIntRange ir |] (shrinkIntRange ir ts an sn)
5454 Just (FtrUTC ur) ->
55- mk_instance ts an sn [e | arbitraryUTCRange ur |] (shrinkNewtype ts an sn)
55+ mk_instance ts an sn [e | arbitraryUTCRange ur |] (shrinkUTCRange ur ts an sn)
5656 Just (FtrStrg _) -> return []
5757 where
5858 mk_instance ts an sn arb =
5959 mkArbitraryInstance ts (nodeRepT an) [e | fmap $(nodeNewtypeConE ts an sn) $arb |]
6060
61- -- shrinking a newtype means calling shrink and repack the newtype.
62- -- Example:
63- -- shrink = \x -> case x of { Foo y -> map Foo (shrink y) }
64- shrinkNewtype ts an sn = do
65- x <- newName " x"
66- y <- newName " y"
67- lamE [varP x] $
68- caseE (varE x) [
69- match (nodeNewtypeConP ts an sn [varP y])
70- (normalB [| map $ (nodeNewtypeConE ts an sn) (QC. shrink $ (varE y)) | ])
71- []
72- ]
61+ -- shrinking a newtype means calling shrink and repack the newtype.
62+ -- Example:
63+ -- shrink = \x -> case x of { Foo y -> map Foo (shrink y) }
64+ shrinkNewtype :: ToolSettings -> APINode -> SpecNewtype -> Q Exp
65+ shrinkNewtype ts an sn = do
66+ x <- newName " x"
67+ y <- newName " y"
68+ lamE [varP x] $
69+ caseE (varE x) [
70+ match (nodeNewtypeConP ts an sn [varP y])
71+ (normalB [| map $ (nodeNewtypeConE ts an sn) (QC. shrink $ (varE y)) | ])
72+ []
73+ ]
74+
75+ -- | Attempts to shrink an input 'APINode' within the given 'IntRange', i.e. if the 'IntRange'
76+ -- specifies an 'ir_lo', then we shrink such that the resulting shrunk values still satisfies
77+ -- the min constrain of the range (i.e. we never generate values /smaller/ than 'ir_lo').
78+ --
79+ -- A few observations/remarks:
80+ --
81+ -- * If the 'ir_lo' is 'Nothing', then this because just 'shrinkNewtype', because we don't
82+ -- really care about 'ir_hi' as shrinking by default won't generate value higher than the
83+ -- value being shrunk (it would be a nonsense);
84+ --
85+ -- * We can generate code that typechecks only if we have a 'BTint', otherwise we don't shrink.
86+ shrinkIntRange :: IntRange -> ToolSettings -> APINode -> SpecNewtype -> ExpQ
87+ shrinkIntRange ir ts an sn = case ir_lo ir of
88+ Nothing -> shrinkNewtype ts an sn
89+ Just lowerBound -> do
90+ x <- newName " x"
91+ y <- newName " y"
92+ lamE [varP x] $
93+ caseE (varE x) [
94+ match (nodeNewtypeConP ts an sn [varP y])
95+ (normalB $ do
96+ if snType sn == BTint
97+ then [| map $ (nodeNewtypeConE ts an sn) $ filter (>= lowerBound) $ (QC. shrink $ (varE y)) | ]
98+ else noShrink
99+ ) []
100+ ]
101+
102+ noShrink :: ExpQ
103+ noShrink = [e | \_ -> [] |]
104+
105+ -- | Attempts to shrink an input 'APINode' within the given 'UTCRange', i.e. if the 'UTCRange'
106+ -- specifies an 'ur_lo', then we shrink such that the resulting shrunk values still satisfies
107+ -- the min constrain of the range (i.e. we never generate values /smaller/ than 'ur_lo').
108+ -- Same proviso as for 'shrinkIntRange', it makes sense to apply the filter only for 'BTutc'.
109+ shrinkUTCRange :: UTCRange -> ToolSettings -> APINode -> SpecNewtype -> ExpQ
110+ shrinkUTCRange ur ts an sn = case ur_lo ur of
111+ Nothing -> shrinkNewtype ts an sn
112+ Just lowerBound -> do
113+ x <- newName " x"
114+ y <- newName " y"
115+ lamE [varP x] $
116+ caseE (varE x) [
117+ match (nodeNewtypeConP ts an sn [varP y])
118+ (normalB $ do
119+ if snType sn == BTutc
120+ then [| map $ (nodeNewtypeConE ts an sn) $ filter (>= $ (liftUTC lowerBound)) $ (QC. shrink $ (varE y)) | ]
121+ else noShrink
122+ ) []
123+ ]
73124
74125-- | Generate an 'Arbitrary' instance for a record:
75126--
0 commit comments