Skip to content

Commit ca2e628

Browse files
committed
Added comment parsing
Pretty printer improvements Made test output colorful and added streaming Added top level comments Added tree-diff
1 parent 66af460 commit ca2e628

File tree

16 files changed

+408
-130
lines changed

16 files changed

+408
-130
lines changed

cabal.project

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
packages:
2+
.
3+
4+
test-show-details: streaming

cuddle.cabal

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ extra-doc-files: CHANGELOG.md
1717
-- extra-source-files:
1818

1919
common warnings
20-
ghc-options: -Wall
20+
ghc-options: -Wall -Werror
2121

2222
common ghc2021
2323
-- These options are all on by default in GHC2021, so once we drop GHC8 we
@@ -68,6 +68,7 @@ library
6868
, cborg
6969
, containers
7070
, data-default-class
71+
, foldable1-classes-compat
7172
, generic-optics
7273
, hashable
7374
, megaparsec
@@ -80,6 +81,7 @@ library
8081
, random <1.3
8182
, scientific
8283
, text
84+
, tree-diff
8385

8486
hs-source-dirs: src
8587
default-language: Haskell2010
@@ -141,3 +143,4 @@ test-suite cuddle-test
141143
, prettyprinter
142144
, QuickCheck
143145
, text
146+
, tree-diff

example/cddl-files/basic_assign.cddl

+17
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,20 @@ set<a> = [ * a]
3333
set2<a> = set<a>
3434

3535
coin_bag = set2<coin>
36+
37+
big_group = (
38+
"hello",
39+
32,
40+
8* 4,
41+
& group,
42+
uint,
43+
unit_interval<uint>,
44+
5 ...10,
45+
h'11aaff3351bc'
46+
)
47+
48+
test = ~ aaaa .. "j" /
49+
# /
50+
{xco, lhXH // // } .cborseq # /
51+
& (* kkhw // // ) /
52+
"b"

example/cddl-files/conway.cddl

+1-2
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,7 @@ constr<a> =
546546
/ #6.124([* a])
547547
/ #6.125([* a])
548548
/ #6.126([* a])
549-
/ #6.127([* a])
550-
; similarly for tag range: 6.1280 .. 6.1400 inclusive
549+
/ #6.127([* a]) ; similarly for tag range: 6.1280 .. 6.1400 inclusive
551550
/ #6.102([uint, [* a]])
552551

553552
redeemers =

example/cddl-files/pretty.cddl

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
a = [ 2*30 2 : uint
2+
, ? 33 : bytes
3+
, 4444 : set<uint>
4+
, * 55 => uint
5+
]
6+
7+
b = [1,uint,(3,4)]
8+
9+
c = { x
10+
, y ; hello
11+
}

src/Codec/CBOR/Cuddle/CDDL.hs

+78-9
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,63 @@
1+
{-# LANGUAGE DeriveAnyClass #-}
2+
{-# LANGUAGE DerivingStrategies #-}
3+
14
-- | This module defined the data structure of CDDL as specified in
25
-- https://datatracker.ietf.org/doc/rfc8610/
3-
module Codec.CBOR.Cuddle.CDDL where
6+
module Codec.CBOR.Cuddle.CDDL (
7+
CDDL (..),
8+
TopLevel (..),
9+
Name (..),
10+
WithComments (..),
11+
Comment (..),
12+
Rule (..),
13+
TypeOrGroup (..),
14+
Assign (..),
15+
GenericArg (..),
16+
GenericParam (..),
17+
Type0 (..),
18+
Type1 (..),
19+
Type2 (..),
20+
TyOp (..),
21+
RangeBound (..),
22+
OccurrenceIndicator (..),
23+
Group (..),
24+
GroupEntry (..),
25+
MemberKey (..),
26+
Value (..),
27+
GrpChoice,
28+
sortCDDL,
29+
comment,
30+
stripComment,
31+
noComment,
32+
unwrap,
33+
groupEntryOccurrenceIndicator,
34+
) where
435

536
import Codec.CBOR.Cuddle.CDDL.CtlOp (CtlOp)
637
import Data.ByteString qualified as B
738
import Data.Hashable (Hashable)
39+
import Data.List.NonEmpty (NonEmpty)
840
import Data.List.NonEmpty qualified as NE
941
import Data.Text qualified as T
42+
import Data.TreeDiff (ToExpr)
1043
import Data.Word (Word64, Word8)
1144
import GHC.Generics (Generic)
1245

13-
newtype CDDL = CDDL (NE.NonEmpty (WithComments Rule))
46+
newtype CDDL = CDDL (NE.NonEmpty TopLevel)
1447
deriving (Eq, Generic, Show)
1548

49+
data TopLevel
50+
= TopLevelRule (Maybe Comment) Rule (Maybe Comment)
51+
| TopLevelComment Comment
52+
deriving (Eq, Ord, Generic, Show)
53+
1654
-- | Sort the CDDL Rules on the basis of their names
1755
sortCDDL :: CDDL -> CDDL
1856
sortCDDL (CDDL xs) = CDDL $ NE.sort xs
1957

2058
data WithComments a = WithComments a (Maybe Comment)
2159
deriving (Eq, Show, Generic)
60+
deriving anyclass (ToExpr)
2261

2362
instance Ord a => Ord (WithComments a) where
2463
compare (WithComments a1 _) (WithComments a2 _) = compare a1 a2
@@ -54,6 +93,7 @@ noComment a = WithComments a Nothing
5493
-- encoding, but names used as "barewords" in member keys do.
5594
newtype Name = Name T.Text
5695
deriving (Eq, Generic, Ord, Show)
96+
deriving anyclass (ToExpr)
5797

5898
instance Hashable Name
5999

@@ -72,6 +112,7 @@ instance Hashable Name
72112
-- side the first entry in the choice being created.)
73113
data Assign = AssignEq | AssignExt
74114
deriving (Eq, Generic, Show)
115+
deriving anyclass (ToExpr)
75116

76117
-- |
77118
-- Generics
@@ -90,10 +131,14 @@ data Assign = AssignEq | AssignExt
90131
-- Generic rules can be used for establishing names for both types and
91132
-- groups.
92133
newtype GenericParam = GenericParam (NE.NonEmpty Name)
93-
deriving (Eq, Generic, Show, Semigroup)
134+
deriving (Eq, Generic, Show)
135+
deriving newtype (Semigroup)
136+
deriving anyclass (ToExpr)
94137

95138
newtype GenericArg = GenericArg (NE.NonEmpty Type1)
96-
deriving (Eq, Generic, Show, Semigroup)
139+
deriving (Eq, Generic, Show)
140+
deriving newtype (Semigroup)
141+
deriving anyclass (ToExpr)
97142

98143
-- |
99144
-- rule = typename [genericparm] S assignt S type
@@ -120,6 +165,7 @@ newtype GenericArg = GenericArg (NE.NonEmpty Type1)
120165
-- definitions before a determination can be made.)
121166
data Rule = Rule Name (Maybe GenericParam) Assign TypeOrGroup
122167
deriving (Eq, Generic, Show)
168+
deriving anyclass (ToExpr)
123169

124170
instance Ord Rule where
125171
compare (Rule n1 _ _ _) (Rule n2 _ _ _) = compare n1 n2
@@ -132,14 +178,17 @@ instance Ord Rule where
132178
-- included for ".." and excluded for "...".
133179
data RangeBound = ClOpen | Closed
134180
deriving (Eq, Generic, Show)
181+
deriving anyclass (ToExpr)
135182

136183
instance Hashable RangeBound
137184

138185
data TyOp = RangeOp RangeBound | CtrlOp CtlOp
139186
deriving (Eq, Generic, Show)
187+
deriving anyclass (ToExpr)
140188

141189
data TypeOrGroup = TOGType Type0 | TOGGroup GroupEntry
142190
deriving (Eq, Generic, Show)
191+
deriving anyclass (ToExpr)
143192

144193
{-- |
145194
The group that is used to define a map or an array can often be reused in the
@@ -191,7 +240,7 @@ data TypeOrGroup = TOGType Type0 | TOGGroup GroupEntry
191240
which suggested the thread-like "~" character.)
192241
-}
193242
unwrap :: TypeOrGroup -> Maybe Group
194-
unwrap (TOGType (Type0 ((Type1 t2 Nothing) NE.:| []))) = case t2 of
243+
unwrap (TOGType (Type0 (Type1 t2 Nothing NE.:| []))) = case t2 of
195244
T2Map g -> Just g
196245
T2Array g -> Just g
197246
_ -> Nothing
@@ -202,12 +251,15 @@ unwrap _ = Nothing
202251
-- choice matches a data item if the data item matches any one of the
203252
-- types given in the choice.
204253
newtype Type0 = Type0 (NE.NonEmpty Type1)
205-
deriving (Eq, Generic, Show, Semigroup)
254+
deriving (Eq, Generic, Show)
255+
deriving newtype (Semigroup)
256+
deriving anyclass (ToExpr)
206257

207258
-- |
208259
-- Two types can be combined with a range operator (see below)
209260
data Type1 = Type1 Type2 (Maybe (TyOp, Type2))
210261
deriving (Eq, Generic, Show)
262+
deriving anyclass (ToExpr)
211263

212264
data Type2
213265
= -- | A type can be just a single value (such as 1 or "icecream" or
@@ -244,6 +296,7 @@ data Type2
244296
| -- | Any data item
245297
T2Any
246298
deriving (Eq, Generic, Show)
299+
deriving anyclass (ToExpr)
247300

248301
-- |
249302
-- An optional _occurrence_ indicator can be given in front of a group
@@ -265,14 +318,17 @@ data OccurrenceIndicator
265318
| OIOneOrMore
266319
| OIBounded (Maybe Word64) (Maybe Word64)
267320
deriving (Eq, Generic, Show)
321+
deriving anyclass (ToExpr)
268322

269323
instance Hashable OccurrenceIndicator
270324

271325
-- |
272326
-- A group matches any sequence of key/value pairs that matches any of
273327
-- the choices given (again using PEG semantics).
274328
newtype Group = Group (NE.NonEmpty GrpChoice)
275-
deriving (Eq, Generic, Show, Semigroup)
329+
deriving (Eq, Generic, Show)
330+
deriving newtype (Semigroup)
331+
deriving anyclass (ToExpr)
276332

277333
type GrpChoice = [WithComments GroupEntry]
278334

@@ -288,6 +344,12 @@ data GroupEntry
288344
| GERef (Maybe OccurrenceIndicator) Name (Maybe GenericArg)
289345
| GEGroup (Maybe OccurrenceIndicator) Group
290346
deriving (Eq, Generic, Show)
347+
deriving anyclass (ToExpr)
348+
349+
groupEntryOccurrenceIndicator :: GroupEntry -> Maybe OccurrenceIndicator
350+
groupEntryOccurrenceIndicator (GEType oi _ _) = oi
351+
groupEntryOccurrenceIndicator (GERef oi _ _) = oi
352+
groupEntryOccurrenceIndicator (GEGroup oi _) = oi
291353

292354
-- |
293355
-- Key types can be given by a type expression, a bareword (which stands
@@ -302,6 +364,7 @@ data MemberKey
302364
| MKBareword Name
303365
| MKValue Value
304366
deriving (Eq, Generic, Show)
367+
deriving anyclass (ToExpr)
305368

306369
data Value
307370
= VUInt Word64
@@ -313,8 +376,14 @@ data Value
313376
| VText T.Text
314377
| VBytes B.ByteString
315378
deriving (Eq, Generic, Show)
379+
deriving anyclass (ToExpr)
316380

317381
instance Hashable Value
318382

319-
newtype Comment = Comment T.Text
320-
deriving (Eq, Generic, Show)
383+
newtype Comment = Comment {unComment :: NonEmpty T.Text}
384+
deriving (Eq, Ord, Generic, Show)
385+
deriving newtype (Semigroup)
386+
deriving anyclass (ToExpr)
387+
388+
comment :: T.Text -> Comment
389+
comment t = Comment $ t NE.:| []

src/Codec/CBOR/Cuddle/CDDL/CtlOp.hs

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
{-# LANGUAGE DeriveAnyClass #-}
2+
{-# LANGUAGE DerivingStrategies #-}
3+
14
module Codec.CBOR.Cuddle.CDDL.CtlOp where
25

36
import Data.Hashable (Hashable)
7+
import Data.TreeDiff (ToExpr)
48
import GHC.Generics (Generic)
59

610
-- | A _control_ allows relating a _target_ type with a _controller_ type
@@ -31,5 +35,6 @@ data CtlOp
3135
| Ne
3236
| Default
3337
deriving (Eq, Generic, Show)
38+
deriving anyclass (ToExpr)
3439

3540
instance Hashable CtlOp

src/Codec/CBOR/Cuddle/CDDL/Prelude.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ module Codec.CBOR.Cuddle.CDDL.Prelude (prependPrelude) where
44

55
import Codec.CBOR.Cuddle.CDDL (CDDL (..))
66
import Codec.CBOR.Cuddle.Parser (pCDDL)
7-
import Text.Megaparsec (parse)
7+
import Text.Megaparsec (errorBundlePretty, parse)
88

99
-- TODO switch to quasiquotes
1010
cddlPrelude :: CDDL
1111
cddlPrelude =
12-
either (error . show) id $
12+
either (error . errorBundlePretty) id $
1313
parse
1414
pCDDL
1515
"<HARDCODED>"

src/Codec/CBOR/Cuddle/CDDL/Resolve.hs

+4-1
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@ parameters (Unparametrised _) = mempty
8282
parameters (Parametrised _ ps) = ps
8383

8484
asMap :: CDDL -> CDDLMap
85-
asMap (CDDL rules) = foldl' assignOrExtend Map.empty (stripComment <$> rules)
85+
asMap (CDDL rules) = foldl' go Map.empty rules
8686
where
87+
go x (TopLevelComment _) = x
88+
go x (TopLevelRule _ r _) = assignOrExtend x r
89+
8790
assignOrExtend :: CDDLMap -> Rule -> CDDLMap
8891
assignOrExtend m (Rule n gps assign tog) = case assign of
8992
-- Equals assignment

0 commit comments

Comments
 (0)