-- | Generate names while desugaring.
module Fay.Compiler.Desugar.Name
  ( withScopedTmpName
  , unscopedTmpNames
  ) where

import           Fay.Compiler.Prelude

import           Fay.Compiler.Desugar.Types

import           Control.Monad.Reader            (asks, local)
import           Language.Haskell.Exts (Name (..))

-- | Generate a temporary, SCOPED name for testing conditions and
-- such. We don't have name tracking yet, so instead we use this.
withScopedTmpName :: (Data l, Typeable l) => l -> (Name l -> Desugar l a) -> Desugar l a
withScopedTmpName :: l -> (Name l -> Desugar l a) -> Desugar l a
withScopedTmpName l
l Name l -> Desugar l a
f = do
  String
prefix <- (DesugarReader l -> String) -> Desugar l String
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DesugarReader l -> String
forall l. DesugarReader l -> String
readerTmpNamePrefix
  Int
n <- (DesugarReader l -> Int) -> Desugar l Int
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks DesugarReader l -> Int
forall l. DesugarReader l -> Int
readerNameDepth
  (DesugarReader l -> DesugarReader l) -> Desugar l a -> Desugar l a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (\DesugarReader l
r -> DesugarReader l
r { readerNameDepth :: Int
readerNameDepth = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 }) (Desugar l a -> Desugar l a) -> Desugar l a -> Desugar l a
forall a b. (a -> b) -> a -> b
$
    Name l -> Desugar l a
f (Name l -> Desugar l a) -> Name l -> Desugar l a
forall a b. (a -> b) -> a -> b
$ l -> String -> Int -> Name l
forall l. l -> String -> Int -> Name l
tmpName l
l String
prefix Int
n

-- | Generates temporary names where the scope doesn't matter.
unscopedTmpNames :: l -> String -> [Name l]
unscopedTmpNames :: l -> String -> [Name l]
unscopedTmpNames l
l String
prefix = (Int -> Name l) -> [Int] -> [Name l]
forall a b. (a -> b) -> [a] -> [b]
map (l -> String -> Int -> Name l
forall l. l -> String -> Int -> Name l
tmpName l
l String
prefix) [Int
0..]

-- | Don't call this directly, use withScopedTmpName or unscopedTmpNames instead.
tmpName :: l -> String -> Int -> Name l
tmpName :: l -> String -> Int -> Name l
tmpName l
l String
prefix Int
n = l -> String -> Name l
forall l. l -> String -> Name l
Ident l
l (String -> Name l) -> String -> Name l
forall a b. (a -> b) -> a -> b
$ String
prefix String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
n