------------------------------------------------------------------------------
-- | 
-- Maintainer	: Ralf Laemmel, Joost Visser
-- Stability	: experimental
-- Portability	: portable
--
-- This module is part of 'StrategyLib', a library of functional strategy
-- combinators, including combinators for generic traversal. This module
-- provides algorithms to collect names and their types.

------------------------------------------------------------------------------ 

module Data.Generics.Strafunski.StrategyLib.NameTheme where

import Data.List
import Data.Generics.Strafunski.StrategyLib.StrategyPrelude
import Data.Generics.Strafunski.StrategyLib.OverloadingTheme
import Data.Generics.Strafunski.StrategyLib.FlowTheme
import Data.Generics.Strafunski.StrategyLib.TraversalTheme
import Control.Monad.Identity hiding (fail)


------------------------------------------------------------------------------ 
-- * Free name analysis

-- | Generic free name analysis algorithm (without types)
freeNames :: (Eq name, Term t)
          => TU [(name,tpe)] Identity	-- ^ Identify declarations
          -> TU [name] Identity		-- ^ Identify references
          -> t				-- ^ Input term
          -> [name]			-- ^ Free names
freeNames declared referenced =
   runIdentity .
   applyTU (all_recTU (op2TU combine)
                      (op2TU (,) declared referenced))
  where
   combine (decs,refs) recs =
    (refs `union` recs) \\ (map fst decs)

-- | Generic free name analysis algorithm with types
freeTypedNames :: (Eq name, Term t)
               => TU [(name,tpe)] Identity -- ^ Identify declarations
               -> TU [name] Identity	   -- ^ Identify references
               -> [(name,tpe)]		   -- ^ Derived declarations
               -> t			   -- ^ Input term
               -> [(name,tpe)]	   	   -- ^ Free names with types
freeTypedNames declared referenced types t =
   filter (\e -> elem (fst e) names) types
  where
    names = freeNames declared referenced t


------------------------------------------------------------------------------ 
-- * Bound name analysis

-- | Accumulate declarations for focus 
boundTypedNames :: (Term f, Term t, Eq name)
                => TU [(name,tpe)] Identity	-- Identify declarations
                -> (f -> Maybe f)		-- Get focus
                -> t				-- Input term
                -> Maybe ([(name,tpe)],f)	-- Derived declarations
boundTypedNames declared unwrap =
   applyTU (once_pe (adhocTU failTU . stop) bind [])
  where
    stop inh =
      (maybe Nothing (Just . (,) inh)) .
      unwrap
    bind inh =
      msubstTU (Just . runIdentity) declared `passTU` \decs ->
      constTU (unionBy byName decs inh)
    byName = \a -> \a' -> fst a == fst a'

------------------------------------------------------------------------------