cuddle-1.1.0.0: src/Codec/CBOR/Cuddle/Huddle/HuddleM.hs
{-# LANGUAGE DataKinds #-}
-- | Monad for declaring Huddle constructs
module Codec.CBOR.Cuddle.Huddle.HuddleM (
module Huddle,
(=:=),
(=:~),
(=::=),
binding,
setRootRules,
huddleDef,
huddleDef',
include,
unsafeIncludeFromHuddle,
)
where
import Codec.CBOR.Cuddle.CDDL (Name)
import Codec.CBOR.Cuddle.Huddle hiding (binding, (=:=), (=:~))
import Codec.CBOR.Cuddle.Huddle qualified as Huddle
import Control.Monad.State.Strict (State, modify, runState)
import Data.Default.Class (def)
import Data.Generics.Product (HasField (..))
import Data.Map.Ordered.Strict qualified as OMap
import Optics.Core (set, (%~), (^.))
type HuddleM = State Huddle
-- | Overridden version of assignment which also adds the rule to the state
(=:=) :: IsType0 a => Name -> a -> HuddleM Rule
n =:= b = let r = n Huddle.=:= b in include r
infixl 1 =:=
-- | Overridden version of group assignment which adds the rule to the state
(=:~) :: Name -> Group -> HuddleM GroupDef
n =:~ b = let r = n Huddle.=:~ b in include r
infixl 1 =:~
binding ::
forall t0.
IsType0 t0 =>
(GRef -> Rule) ->
HuddleM (t0 -> GRuleCall)
binding fRule = include (Huddle.binding fRule)
-- | Renamed version of Huddle's underlying '=:=' for use in generic bindings
(=::=) :: IsType0 a => Name -> a -> Rule
n =::= b = n Huddle.=:= b
infixl 1 =::=
setRootRules :: [Rule] -> HuddleM ()
setRootRules = modify . set (field @"roots")
huddleDef :: HuddleM a -> Huddle
huddleDef = snd . huddleDef'
huddleDef' :: HuddleM a -> (a, Huddle)
huddleDef' mh = runState mh def
class Includable a where
-- | Include a rule, group, or generic rule defined elsewhere
include :: a -> HuddleM a
instance Includable Rule where
include r@(Rule x _) =
modify (field @"items" %~ (OMap.|> (getName x, HIRule r)))
>> pure r
instance Includable GroupDef where
include r =
modify
( (field @"items")
%~ (OMap.|> (getName r, HIGroup r))
)
>> pure r
instance IsType0 t0 => Includable (t0 -> GRuleCall) where
include gr =
let fakeT0 = error "Attempting to unwrap fake value in generic call"
GRuleCall g extra = gr fakeT0
grDef = callToDef <$> g
n = getName grDef
in do
modify (field @"items" %~ (OMap.|> (n, HIGRule $ GRuleDef grDef extra)))
pure gr
instance Includable HuddleItem where
include x@(HIRule r) = include r >> pure x
include x@(HIGroup g) = include g >> pure x
include x@(HIGRule g) =
do
modify (field @"items" %~ (OMap.|> (getName g, x)))
pure x
unsafeIncludeFromHuddle ::
Huddle ->
Name ->
HuddleM HuddleItem
unsafeIncludeFromHuddle h name =
let items = h ^. field @"items"
in case OMap.lookup name items of
Just v -> include v
Nothing -> error $ show name <> " was not found in Huddle spec"