summaryrefslogtreecommitdiff
path: root/src/Language/Fiddle/Internal
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-09-25 23:14:30 -0600
committerJosh Rahm <joshuarahm@gmail.com>2024-09-25 23:14:30 -0600
commit3a59cfb59b3339e13bdc9dfd1696ae2c554fcd9a (patch)
tree22ca47a8dec86c561e26f1ca07b4eb0a94d39bdd /src/Language/Fiddle/Internal
parent9b6a5f836680c95ce65390ba24a4c1390306fa75 (diff)
downloadfiddle-3a59cfb59b3339e13bdc9dfd1696ae2c554fcd9a.tar.gz
fiddle-3a59cfb59b3339e13bdc9dfd1696ae2c554fcd9a.tar.bz2
fiddle-3a59cfb59b3339e13bdc9dfd1696ae2c554fcd9a.zip
Don't allow duplicate types.
Diffstat (limited to 'src/Language/Fiddle/Internal')
-rw-r--r--src/Language/Fiddle/Internal/Scopes.hs34
1 files changed, 20 insertions, 14 deletions
diff --git a/src/Language/Fiddle/Internal/Scopes.hs b/src/Language/Fiddle/Internal/Scopes.hs
index 280945d..302eab2 100644
--- a/src/Language/Fiddle/Internal/Scopes.hs
+++ b/src/Language/Fiddle/Internal/Scopes.hs
@@ -43,20 +43,26 @@ instance Semigroup (ScopePath k) where
instance Monoid (ScopePath k) where
mempty = ScopePath mempty mempty
--- | 'insertScope' inserts a value 'v' into the scope at the specified
--- key path ('NonEmpty k'). If the key path does not exist, it is created.
-insertScope :: (Ord k) => NonEmpty k -> t -> Scope k t -> Scope k t
-insertScope (s :| []) v (Scope ss sv) = Scope ss (Map.insert s v sv)
-insertScope (s :| (a : as)) v (Scope ss sv) =
- Scope
- ( Map.alter
- ( \case
- (fromMaybe mempty -> mp) -> Just (insertScope (a :| as) v mp)
- )
- s
- ss
- )
- sv
+-- | 'upsertScope' attempts to insert a value 'v' into the 'Scope' at the given
+-- key path ('NonEmpty k'). If the key path already exists, the value at the
+-- final key is replaced, and the original value is returned in the result.
+-- If the key path does not exist, it is created. The function returns a tuple
+-- containing the previous value (if any) and the updated scope.
+--
+-- This function effectively performs an "insert-or-update" operation, allowing
+-- you to upsert values into nested scopes while tracking any existing value
+-- that was replaced.
+upsertScope :: (Ord k) => NonEmpty k -> t -> Scope k t -> (Maybe t, Scope k t)
+upsertScope (s :| []) v (Scope ss sv) =
+ Scope ss <$> Map.insertLookupWithKey (\_ n _ -> n) s v sv
+upsertScope (s :| (a : as)) v (Scope ss sv) =
+ let subscope = fromMaybe mempty (Map.lookup s ss)
+ (replaced, subscope') = upsertScope (a :| as) v subscope
+ in (replaced, Scope (Map.insert s subscope' ss) sv)
+
+-- insertScope :: (Ord k) => NonEmpty k -> t -> Scope k t -> Scope k t
+-- insertScope a b = snd . upsertScope a b
+
-- | 'lookupScope' performs a lookup of a value in the scope using a key path
-- ('NonEmpty k'). It traverses through sub-scopes as defined by the path.