packages feed

cuddle-0.5.0.0: src/Codec/CBOR/Cuddle/CDDL/CTree.hs

{-# LANGUAGE DataKinds #-}

module Codec.CBOR.Cuddle.CDDL.CTree where

import Codec.CBOR.Cuddle.CDDL (
  Name,
  OccurrenceIndicator,
  RangeBound,
  Value,
 )
import Codec.CBOR.Cuddle.CDDL.CtlOp
import Codec.CBOR.Cuddle.CDDL.Postlude (PTerm)
import Data.Hashable (Hashable)
import Data.List.NonEmpty qualified as NE
import Data.Map.Strict qualified as Map
import Data.Word (Word64)
import GHC.Generics (Generic)

--------------------------------------------------------------------------------

-- * Resolved CDDL Tree

--
-- This is a simplified representation of CDDL. It is technically more general -
-- that is, the structure can represent invalid CDDL - but is in that way easier
-- to manipulate.
--------------------------------------------------------------------------------

-- | CDDL Tree, parametrised over a functor
--
--   We principally use this functor to represent references - thus, every 'f a'
--   may be either an a or a reference to another CTree.
data CTree f
  = Literal Value
  | Postlude PTerm
  | Map [Node f]
  | Array [Node f]
  | Choice (NE.NonEmpty (Node f))
  | Group [Node f]
  | KV {key :: Node f, value :: Node f, cut :: Bool}
  | Occur {item :: Node f, occurs :: OccurrenceIndicator}
  | Range {from :: Node f, to :: Node f, inclusive :: RangeBound}
  | Control {op :: CtlOp, target :: Node f, controller :: Node f}
  | Enum (Node f)
  | Unwrap (Node f)
  | Tag Word64 (Node f)
  deriving (Generic)

-- | Traverse the CTree, carrying out the given operation at each node
traverseCTree :: Monad m => (Node f -> m (Node g)) -> CTree f -> m (CTree g)
traverseCTree _ (Literal a) = pure $ Literal a
traverseCTree _ (Postlude a) = pure $ Postlude a
traverseCTree atNode (Map xs) = Map <$> traverse atNode xs
traverseCTree atNode (Array xs) = Array <$> traverse atNode xs
traverseCTree atNode (Group xs) = Group <$> traverse atNode xs
traverseCTree atNode (Choice xs) = Choice <$> traverse atNode xs
traverseCTree atNode (KV k v c) = do
  k' <- atNode k
  v' <- atNode v
  pure $ KV k' v' c
traverseCTree atNode (Occur i occ) = flip Occur occ <$> atNode i
traverseCTree atNode (Range f t inc) = do
  f' <- atNode f
  t' <- atNode t
  pure $ Range f' t' inc
traverseCTree atNode (Control o t c) = do
  t' <- atNode t
  c' <- atNode c
  pure $ Control o t' c'
traverseCTree atNode (Enum ref) = Enum <$> atNode ref
traverseCTree atNode (Unwrap ref) = Unwrap <$> atNode ref
traverseCTree atNode (Tag i ref) = Tag i <$> atNode ref

type Node f = f (CTree f)

newtype CTreeRoot' poly f
  = CTreeRoot
      (Map.Map Name (poly (Node f)))
  deriving (Generic)

type CTreeRoot f = CTreeRoot' (ParametrisedWith [Name]) f

data ParametrisedWith w a
  = Unparametrised {underlying :: a}
  | Parametrised
      { underlying :: a
      , params :: w
      }
  deriving (Eq, Functor, Generic, Foldable, Traversable, Show)

instance (Hashable w, Hashable a) => Hashable (ParametrisedWith w a)