content: -- Copyright (c) Facebook, Inc. and its affiliates.
  --
  -- This source code is licensed under the MIT license found in the
  -- LICENSE file in the root directory of this source tree.
  --
  {-# LANGUAGE CPP #-}
  module Retrie.Substitution
    ( Substitution
    , HoleVal(..)
    , emptySubst
    , extendSubst
    , lookupSubst
    , deleteSubst
    , foldSubst
    ) where
  
  import Retrie.ExactPrint
  import Retrie.GHC
  
  -- | A 'Substitution' is essentially a map from variable name to 'HoleVal'.
  newtype Substitution = Substitution (UniqFM FastString (FastString, HoleVal))
  -- See Note [Why not RdrNames?] for explanation of use of FastString
  
  instance Show Substitution where
    show (Substitution m) = show (nonDetEltsUFM m)
  
  -- | Sum type of possible substitution values.
  data HoleVal
    = HoleExpr AnnotatedHsExpr -- ^ 'HsExpr'
    | HolePat AnnotatedPat -- ^ 'Pat'
    | HoleType AnnotatedHsType -- ^ 'HsType'
    | HoleRdr RdrName -- ^ Alpha-renamed binder.
  
  instance Show HoleVal where
    show (HoleExpr e) = "HoleExpr " ++ printA e
    show (HolePat p) = "HolePat " ++ printA p
    show (HoleType t) = "HoleType " ++ printA t
    show (HoleRdr r) = "HoleRdr " ++ unpackFS (rdrFS r)
  
  -- | The empty substitution.
  emptySubst :: Substitution
  emptySubst = Substitution emptyUFM
  
  -- | Lookup a value in the substitution.
  lookupSubst :: FastString -> Substitution -> Maybe HoleVal
  lookupSubst k (Substitution m) = snd <$> lookupUFM m k
  
  -- | Extend the substitution. If the key already exists, its value is replaced.
  extendSubst :: Substitution -> FastString -> HoleVal -> Substitution
  extendSubst (Substitution m) k v = Substitution (addToUFM m k (k,v))
  
  -- | Delete from the substitution.
  deleteSubst :: Substitution -> [FastString] -> Substitution
  deleteSubst (Substitution m) ks = Substitution (delListFromUFM m ks)
  
  -- | Fold over the substitution.
  foldSubst :: ((FastString, HoleVal) -> a -> a) -> a -> Substitution -> a
  #if __GLASGOW_HASKELL__ < 908
  foldSubst f x (Substitution m) = foldUFM f x m
  #else
  foldSubst f x (Substitution m) = nonDetFoldUFM f x m
  #endif
  