-- | Sets of lookahead symbols.
module Data.Cfg.LookaheadSet (
    LookaheadSet,
    mkLookaheadSet,
    fromList,
    toSet,
    (<>),	-- reexport
    -- * Set operations
    empty,
    singleton,
    unions
    ) where

import Data.Cfg.Augment(AugT(..))
import Data.Monoid(Monoid(..), (<>))
import qualified Data.Set as S

-- | Set of lookahead symbols providing different 'Monoid' semantics
-- than 'Data.Set.Set'.	 ('mappend' implements concatenation, not set
-- union.)
newtype LookaheadSet t = LookaheadSet {
    toSet :: S.Set (AugT t)
	-- ^ Converts the 'LookaheadSet' to a regular 'Data.Set.Set'
    }
    deriving (Eq, Ord, Show)

instance Ord t => Monoid (LookaheadSet t) where
    mempty = LookaheadSet $ S.singleton EOF
    l@(LookaheadSet s) `mappend` LookaheadSet s'
	= if EOF `S.member` s
	      then LookaheadSet $ S.delete EOF s `S.union` s'
	      else l

-- | Creates a 'LookaheadSet'
mkLookaheadSet :: (Ord t)
	       => Bool	-- ^ true iff it has 'EOF'
	       -> [t]	-- ^ terminal symbols
	       -> LookaheadSet t
mkLookaheadSet hasEOF = LookaheadSet . S.fromList . f . map AugT
    where
    f = if hasEOF then (EOF:) else id

-- | Creates a 'LookaheadSet' from a list of augmented terminals.
fromList :: Ord t => [AugT t] -> LookaheadSet t
fromList = LookaheadSet . S.fromList

-- | The empty lookahead set.
empty :: LookaheadSet t
empty = LookaheadSet S.empty

-- | Creates a singleton lookahead set.
singleton :: AugT t -> LookaheadSet t
singleton = LookaheadSet . S.singleton

-- | Returns the union of all the lookahead sets.
unions :: Ord t => [LookaheadSet t] -> LookaheadSet t
unions = LookaheadSet . S.unions . map toSet