@@ -94,15 +94,16 @@ import Data.ByteString (ByteString)
9494import Data.Default.Class (Default (.. ))
9595import Data.Generics.Product (field , getField )
9696import Data.List.NonEmpty qualified as NE
97- import Data.Map.Strict qualified as HaskMap
97+ import Data.Map.Ordered.Strict (OMap )
98+ import Data.Map.Ordered.Strict qualified as OMap
9899import Data.String (IsString (fromString ))
99100import Data.Text qualified as T
100101import Data.Tuple.Optics (Field2 (.. ))
101102import Data.Void (Void )
102103import Data.Word (Word64 )
103104import GHC.Exts (IsList (Item , fromList , toList ))
104105import GHC.Generics (Generic )
105- import Optics.Core (view , (%~) , (&) , (.~) )
106+ import Optics.Core (view , (%~) , (&) , (.~) , (^.) )
106107import Prelude hiding ((/) )
107108
108109data Named a = Named
@@ -131,12 +132,40 @@ data HuddleItem
131132data Huddle = Huddle
132133 { -- | Root elements
133134 roots :: [Rule ],
134- items :: [ HuddleItem ]
135+ items :: OMap T. Text HuddleItem
135136 }
136137 deriving (Generic , Show )
137138
139+ -- | This semigroup instance:
140+ -- - Takes takes the roots from the RHS unless they are empty, in which case
141+ -- it takes the roots from the LHS
142+ -- - Uses the RHS to override items on the LHS where they share a name.
143+ -- The value from the RHS is taken, but the index from the LHS is used.
144+ --
145+ -- Note that this allows replacing items in the middle of a tree without
146+ -- updating higher-level items which make use of them - that is, we do not
147+ -- need to "close over" higher-level terms, since by the time they have been
148+ -- built into a huddle structure, the references have been converted to keys.
149+ instance Semigroup Huddle where
150+ h1 <> h2 =
151+ Huddle
152+ { roots = case roots h2 of
153+ [] -> roots h1
154+ xs -> xs,
155+ items = OMap. unionWithL (\ _ _ v2 -> v2) (items h1) (items h2)
156+ }
157+
158+ -- | This instance is mostly used for testing
159+ instance IsList Huddle where
160+ type Item Huddle = Rule
161+ fromList [] = Huddle mempty OMap. empty
162+ fromList (x : xs) =
163+ (field @ " items" %~ (OMap. |> (x ^. field @ " name" , HIRule x))) $ fromList xs
164+
165+ toList = const []
166+
138167instance Default Huddle where
139- def = Huddle [] []
168+ def = Huddle [] OMap. empty
140169
141170data Choice a
142171 = NoChoice a
@@ -505,6 +534,13 @@ instance IsType0 GRef where
505534instance (IsType0 a ) => IsType0 (Tagged a ) where
506535 toType0 = NoChoice . T2Tagged . fmap toType0
507536
537+ instance IsType0 HuddleItem where
538+ toType0 (HIRule r) = toType0 r
539+ toType0 (HIGroup g) = toType0 g
540+ toType0 (HIGRule g) =
541+ error $
542+ " Attempt to reference generic rule from HuddleItem not supported: " <> show g
543+
508544class CanQuantify a where
509545 -- | Apply a lower bound
510546 (<+) :: Word64 -> a -> a
@@ -829,17 +865,17 @@ collectFrom topRs =
829865 toHuddle $
830866 execState
831867 (traverse goRule topRs)
832- HaskMap . empty
868+ OMap . empty
833869 where
834870 toHuddle items =
835871 Huddle
836872 { roots = topRs,
837- items = view _2 <$> HaskMap. toList items
873+ items = items
838874 }
839875 goRule r@ (Named n t0 _) = do
840876 items <- get
841- when (HaskMap . notMember n items) $ do
842- modify (HaskMap. insert n ( HIRule r))
877+ when (OMap . notMember n items) $ do
878+ modify (OMap. |> (n, HIRule r))
843879 goT0 t0
844880 goChoice f (NoChoice x) = f x
845881 goChoice f (ChoiceOf x xs) = f x >> goChoice f xs
@@ -850,13 +886,13 @@ collectFrom topRs =
850886 goT2 (T2Ref n) = goRule n
851887 goT2 (T2Group r@ (Named n g _)) = do
852888 items <- get
853- when (HaskMap . notMember n items) $ do
854- modify (HaskMap. insert n ( HIGroup r))
889+ when (OMap . notMember n items) $ do
890+ modify (OMap. |> (n, HIGroup r))
855891 goGroup g
856892 goT2 (T2Generic r@ (Named n g _)) = do
857893 items <- get
858- when (HaskMap . notMember n items) $ do
859- modify (HaskMap. insert n ( HIGRule $ fmap callToDef r))
894+ when (OMap . notMember n items) $ do
895+ modify (OMap. |> (n, HIGRule $ fmap callToDef r))
860896 goT0 (body g)
861897 -- Note that the parameters here may be different, so this doesn't live
862898 -- under the guard
@@ -890,7 +926,7 @@ toCDDL' mkPseudoRoot hdl =
890926 then (toTopLevelPseudoRoot (roots hdl) NE. <| )
891927 else id
892928 )
893- $ fmap toCDDLItem (NE. fromList $ items hdl)
929+ $ fmap toCDDLItem (NE. fromList $ fmap (view _2) $ toList $ items hdl)
894930 where
895931 toCDDLItem (HIRule r) = toCDDLRule r
896932 toCDDLItem (HIGroup g) = toCDDLGroup g
0 commit comments