    -- | This module provides facilities for generating unique names.
    module Futhark.FreshNames
      ( VNameSource,
        blankNameSource,
        newNameSource,
        newName,
      )
    where

    import Language.Futhark.Core
    import Language.Haskell.TH.Syntax (Lift)

    -- | A name source is conceptually an infinite sequence of names with
    -- no repeating entries.  In practice, when asked for a name, the name
    -- source will return the name along with a new name source, which
    -- should then be used in place of the original.
    --
    -- The 'Ord' instance is based on how many names have been extracted
    -- from the name source.
    newtype VNameSource = VNameSource Int
      deriving ((forall (m :: * -> *). Quote m => VNameSource -> m Exp)
    -> (forall (m :: * -> *).
        Quote m =>
        VNameSource -> Code m VNameSource)
    -> Lift VNameSource
    forall t.
    (forall (m :: * -> *). Quote m => t -> m Exp)
    -> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
    forall (m :: * -> *). Quote m => VNameSource -> m Exp
    forall (m :: * -> *). Quote m => VNameSource -> Code m VNameSource
    $clift :: forall (m :: * -> *). Quote m => VNameSource -> m Exp
    lift :: forall (m :: * -> *). Quote m => VNameSource -> m Exp
    $cliftTyped :: forall (m :: * -> *). Quote m => VNameSource -> Code m VNameSource
    liftTyped :: forall (m :: * -> *). Quote m => VNameSource -> Code m VNameSource
    Lift, VNameSource -> VNameSource -> Bool
    (VNameSource -> VNameSource -> Bool)
    -> (VNameSource -> VNameSource -> Bool) -> Eq VNameSource
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: VNameSource -> VNameSource -> Bool
    == :: VNameSource -> VNameSource -> Bool
    $c/= :: VNameSource -> VNameSource -> Bool
    /= :: VNameSource -> VNameSource -> Bool
    Eq, Eq VNameSource
    Eq VNameSource =>
    (VNameSource -> VNameSource -> Ordering)
    -> (VNameSource -> VNameSource -> Bool)
    -> (VNameSource -> VNameSource -> Bool)
    -> (VNameSource -> VNameSource -> Bool)
    -> (VNameSource -> VNameSource -> Bool)
    -> (VNameSource -> VNameSource -> VNameSource)
    -> (VNameSource -> VNameSource -> VNameSource)
    -> Ord VNameSource
    VNameSource -> VNameSource -> Bool
    VNameSource -> VNameSource -> Ordering
    VNameSource -> VNameSource -> VNameSource
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: VNameSource -> VNameSource -> Ordering
    compare :: VNameSource -> VNameSource -> Ordering
    $c< :: VNameSource -> VNameSource -> Bool
    < :: VNameSource -> VNameSource -> Bool
    $c<= :: VNameSource -> VNameSource -> Bool
    <= :: VNameSource -> VNameSource -> Bool
    $c> :: VNameSource -> VNameSource -> Bool
    > :: VNameSource -> VNameSource -> Bool
    $c>= :: VNameSource -> VNameSource -> Bool
    >= :: VNameSource -> VNameSource -> Bool
    $cmax :: VNameSource -> VNameSource -> VNameSource
    max :: VNameSource -> VNameSource -> VNameSource
    $cmin :: VNameSource -> VNameSource -> VNameSource
    min :: VNameSource -> VNameSource -> VNameSource
    Ord)

    instance Semigroup VNameSource where
      VNameSource Int
    x <> :: VNameSource -> VNameSource -> VNameSource
    <> VNameSource Int
    y = Int -> VNameSource
    VNameSource (Int
    x Int -> Int -> Int
    forall a. Ord a => a -> a -> a
    `max` Int
    y)

    instance Monoid VNameSource where
      mempty :: VNameSource
    mempty = VNameSource
    blankNameSource

    -- | Produce a fresh name, using the given name as a template.
    newName :: VNameSource -> VName -> (VName, VNameSource)
    newName :: VNameSource -> VName -> (VName, VNameSource)
    newName (VNameSource Int
    i) VName
    k = Int
    i' Int -> (VName, VNameSource) -> (VName, VNameSource)
    forall a b. a -> b -> b
    `seq` (Name -> Int -> VName
    VName (VName -> Name
    baseName VName
    k) Int
    i, Int -> VNameSource
    VNameSource Int
    i')
      where
        i' :: Int
    i' = Int
    i Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + Int
    1

    -- | A blank name source.
    blankNameSource :: VNameSource
    blankNameSource :: VNameSource
    blankNameSource = Int -> VNameSource
    newNameSource Int
    0

    -- | A new name source that starts counting from the given number.
    newNameSource :: Int -> VNameSource
    newNameSource :: Int -> VNameSource
    newNameSource = Int -> VNameSource
    VNameSource