Skip to content

Commit 5976f89

Browse files
authored
Merge pull request #43 from input-output-hk/nc/ref-range
Support references in ranges
2 parents 20f226f + e6d124a commit 5976f89

File tree

5 files changed

+69
-30
lines changed

5 files changed

+69
-30
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,12 @@
2929
control over the order that items are presented in the CDDL, at the cost
3030
of making it somewhat harder to re-use items (they need to be returned from
3131
the monad).
32+
33+
## O.3.5.0 -- 2024-11-25
34+
35+
* Add support for constraints on references and generic references.
36+
* Add support for using references as range bounds. Note that this breaks
37+
backwards compatibility - because the range arguments are now more generic,
38+
additional hints are required to type literal numerics correctly. Typically
39+
this is most easily fixed by adding a call `int` for any numeric literals in
40+
ranges. An example is shown in `example/Conway.hs`

cuddle.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 3.4
22
name: cuddle
3-
version: 0.3.4.0
3+
version: 0.3.5.0
44
synopsis: CDDL Generator and test utilities
55

66
-- description:

example/Conway.hs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ language =
647647
/ int 2 -- Plutus v3
648648

649649
potential_languages :: Rule
650-
potential_languages = "potential_languages" =:= 0 ... 255
650+
potential_languages = "potential_languages" =:= int 0 ... int 255
651651

652652
-- The format for costmdls is flexible enough to allow adding Plutus built-ins and language
653653
-- versions in the future.
@@ -767,16 +767,16 @@ asset_name :: Rule
767767
asset_name = "asset_name" =:= VBytes `sized` (0 :: Word64, 32 :: Word64)
768768

769769
negInt64 :: Rule
770-
negInt64 = "negInt64" =:= (-9223372036854775808) ... (-1)
770+
negInt64 = "negInt64" =:= int (-9223372036854775808) ... int (-1)
771771

772772
posInt64 :: Rule
773-
posInt64 = "posInt64" =:= 1 ... 9223372036854775807
773+
posInt64 = "posInt64" =:= int 1 ... int 9223372036854775807
774774

775775
nonZeroInt64 :: Rule
776776
nonZeroInt64 = "nonZeroInt64" =:= negInt64 / posInt64 -- this is the same as the current int64 definition but without zero
777777

778778
positive_coin :: Rule
779-
positive_coin = "positive_coin" =:= 1 ... 18446744073709551615
779+
positive_coin = "positive_coin" =:= int 1 ... int 18446744073709551615
780780

781781
value :: Rule
782782
value = "value" =:= coin / sarr [a coin, a (multiasset positive_coin)]
@@ -785,7 +785,7 @@ mint :: Rule
785785
mint = "mint" =:= multiasset nonZeroInt64
786786

787787
int64 :: Rule
788-
int64 = "int64" =:= (-9223372036854775808) ... 9223372036854775807
788+
int64 = "int64" =:= int (-9223372036854775808) ... int 9223372036854775807
789789

790790
network_id :: Rule
791791
network_id = "network_id" =:= int 0 / int 1
@@ -900,7 +900,7 @@ nonempty_oset :: (IsType0 t0) => t0 -> GRuleCall
900900
nonempty_oset = nonempty_set
901901

902902
positive_int :: Rule
903-
positive_int = "positive_int" =:= 1 ... 18446744073709551615
903+
positive_int = "positive_int" =:= int 1 ... int 18446744073709551615
904904

905905
unit_interval :: Rule
906906
unit_interval = "unit_interval" =:= tag 30 (arr [1, 2])

src/Codec/CBOR/Cuddle/Huddle.hs

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ instance Num ArrayEntry where
234234
fromInteger i =
235235
ArrayEntry
236236
Nothing
237-
(NoChoice . T2Literal . Unranged $ LInt (fromIntegral i))
237+
(NoChoice . T2Range . Unranged $ LInt (fromIntegral i))
238238
def
239239
Nothing
240240
(+) = error "Cannot treat ArrayEntry as a number"
@@ -265,7 +265,7 @@ instance IsList Group where
265265

266266
data Type2
267267
= T2Constrained Constrained
268-
| T2Literal Ranged
268+
| T2Range Ranged
269269
| T2Map Map
270270
| T2Array Array
271271
| T2Tagged (Tagged Type0)
@@ -280,7 +280,7 @@ data Type2
280280
type Type0 = Choice Type2
281281

282282
instance Num Type0 where
283-
fromInteger i = NoChoice . T2Literal . Unranged $ LInt (fromIntegral i)
283+
fromInteger i = NoChoice . T2Range . Unranged $ LInt (fromIntegral i)
284284
(+) = error "Cannot treat Type0 as a number"
285285
(*) = error "Cannot treat Type0 as a number"
286286
abs = error "Cannot treat Type0 as a number"
@@ -512,20 +512,36 @@ le v bound =
512512

513513
-- Ranges
514514

515+
data RangeBound =
516+
RangeBoundLiteral Literal
517+
| RangeBoundRef (Named Type0)
518+
deriving Show
519+
520+
class IsRangeBound a where
521+
toRangeBound :: a -> RangeBound
522+
523+
instance IsRangeBound Literal where
524+
toRangeBound = RangeBoundLiteral
525+
526+
instance IsRangeBound Integer where
527+
toRangeBound = RangeBoundLiteral . inferInteger
528+
529+
instance IsRangeBound (Named Type0) where
530+
toRangeBound = RangeBoundRef
531+
515532
data Ranged where
516533
Ranged ::
517-
{ lb :: Literal,
518-
ub :: Literal,
534+
{ lb :: RangeBound,
535+
ub :: RangeBound,
519536
bounds :: C.RangeBound
520537
} ->
521538
Ranged
522539
Unranged :: Literal -> Ranged
523540
deriving (Show)
524541

525-
-- | Establish a closed range bound. Currently specialised to Int for type
526-
-- inference purposes.
527-
(...) :: Integer -> Integer -> Ranged
528-
l ... u = Ranged (inferInteger l) (inferInteger u) C.Closed
542+
-- | Establish a closed range bound.
543+
(...) :: (IsRangeBound a, IsRangeBound b) => a -> b -> Ranged
544+
l ... u = Ranged (toRangeBound l) (toRangeBound u) C.Closed
529545

530546
infixl 9 ...
531547

@@ -558,27 +574,27 @@ instance IsType0 ArrayChoice where
558574
toType0 = NoChoice . T2Array . NoChoice
559575

560576
instance IsType0 Ranged where
561-
toType0 = NoChoice . T2Literal
577+
toType0 = NoChoice . T2Range
562578

563579
instance IsType0 Literal where
564-
toType0 = NoChoice . T2Literal . Unranged
580+
toType0 = NoChoice . T2Range . Unranged
565581

566582
-- We also allow going directly from primitive types to Type2
567583
instance IsType0 Integer where
568-
toType0 = NoChoice . T2Literal . Unranged . inferInteger
584+
toType0 = NoChoice . T2Range . Unranged . inferInteger
569585

570586
instance IsType0 T.Text where
571587
toType0 :: T.Text -> Type0
572-
toType0 = NoChoice . T2Literal . Unranged . LText
588+
toType0 = NoChoice . T2Range . Unranged . LText
573589

574590
instance IsType0 ByteString where
575-
toType0 = NoChoice . T2Literal . Unranged . LBytes
591+
toType0 = NoChoice . T2Range . Unranged . LBytes
576592

577593
instance IsType0 Float where
578-
toType0 = NoChoice . T2Literal . Unranged . LFloat
594+
toType0 = NoChoice . T2Range . Unranged . LFloat
579595

580596
instance IsType0 Double where
581-
toType0 = NoChoice . T2Literal . Unranged . LDouble
597+
toType0 = NoChoice . T2Range . Unranged . LDouble
582598

583599
instance IsType0 (Value a) where
584600
toType0 = NoChoice . T2Constrained . unconstrained
@@ -722,7 +738,7 @@ instance IsChoosable GRef Type2 where
722738
toChoice = toChoice . T2GenericRef
723739

724740
instance IsChoosable ByteString Type2 where
725-
toChoice = toChoice . T2Literal . Unranged . LBytes
741+
toChoice = toChoice . T2Range . Unranged . LBytes
726742

727743
instance IsChoosable Constrained Type2 where
728744
toChoice = toChoice . T2Constrained
@@ -731,7 +747,7 @@ instance (IsType0 a) => IsChoosable (Tagged a) Type2 where
731747
toChoice = toChoice . T2Tagged . fmap toType0
732748

733749
instance IsChoosable Literal Type2 where
734-
toChoice = toChoice . T2Literal . Unranged
750+
toChoice = toChoice . T2Range . Unranged
735751

736752
instance IsChoosable (Value a) Type2 where
737753
toChoice = toChoice . T2Constrained . unconstrained
@@ -944,6 +960,7 @@ collectFrom topRs =
944960
goChoice f (NoChoice x) = f x
945961
goChoice f (ChoiceOf x xs) = f x >> goChoice f xs
946962
goT0 = goChoice goT2
963+
goT2 (T2Range r) = goRanged r
947964
goT2 (T2Map m) = goChoice (mapM_ goMapEntry . unMapChoice) m
948965
goT2 (T2Array m) = goChoice (mapM_ goArrayEntry . unArrayChoice) m
949966
goT2 (T2Tagged (Tagged _ t0)) = goT0 t0
@@ -975,7 +992,11 @@ collectFrom topRs =
975992
goKey (TypeKey k) = goT2 k
976993
goKey _ = pure ()
977994
goGroup (Group g) = mapM_ goT0 g
978-
995+
goRanged (Unranged _) = pure ()
996+
goRanged (Ranged lb ub _) = goRangeBound lb >> goRangeBound ub
997+
goRangeBound (RangeBoundLiteral _) = pure ()
998+
goRangeBound (RangeBoundRef r) = goRule r
999+
9791000
--------------------------------------------------------------------------------
9801001
-- Conversion to CDDL
9811002
--------------------------------------------------------------------------------
@@ -1052,7 +1073,7 @@ toCDDL' mkPseudoRoot hdl =
10521073
T2Constrained (Constrained x constr _) ->
10531074
-- TODO Need to handle choices at the top level
10541075
applyConstraint constr (C.T2Name (toCDDLConstrainable x) Nothing)
1055-
T2Literal l -> toCDDLRanged l
1076+
T2Range l -> toCDDLRanged l
10561077
T2Map m ->
10571078
C.Type1
10581079
(C.T2Map $ mapToCDDLGroup m)
@@ -1112,8 +1133,12 @@ toCDDL' mkPseudoRoot hdl =
11121133
C.Type1 (C.T2Value $ toCDDLValue x) Nothing
11131134
toCDDLRanged (Ranged lb ub rop) =
11141135
C.Type1
1115-
(C.T2Value $ toCDDLValue lb)
1116-
(Just (C.RangeOp rop, C.T2Value $ toCDDLValue ub))
1136+
(toCDDLRangeBound lb)
1137+
(Just (C.RangeOp rop, toCDDLRangeBound ub))
1138+
1139+
toCDDLRangeBound :: RangeBound -> C.Type2
1140+
toCDDLRangeBound (RangeBoundLiteral l) = C.T2Value $ toCDDLValue l
1141+
toCDDLRangeBound (RangeBoundRef (Named n _ _)) = C.T2Name (C.Name n) Nothing
11171142

11181143
toCDDLGroup :: Named Group -> C.WithComments C.Rule
11191144
toCDDLGroup (Named n (Group t0s) c) =

test/Test/Codec/CBOR/Cuddle/Huddle.hs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,15 @@ genericSpec =
114114

115115
constraintSpec :: Spec
116116
constraintSpec =
117-
describe "Constraints" $
117+
describe "Constraints" $ do
118118
it "Size can take a Word" $
119119
toSortedCDDL (collectFrom ["sz" =:= VUInt `sized` (2 :: Word)])
120120
`shouldMatchParseCDDL` "sz = uint .size 2"
121+
122+
it "Range bound can take a reference" $
123+
let b = "b" =:= (16 :: Integer) in
124+
toSortedCDDL (collectFrom ["b" =:= (16 :: Integer), "c" =:= int 0 ... b])
125+
`shouldMatchParseCDDL` "b = 16\n c = 0 .. b"
121126
--------------------------------------------------------------------------------
122127
-- Helper functions
123128
--------------------------------------------------------------------------------

0 commit comments

Comments
 (0)