aterm-utils-0.2.0.0: src/ATerm/Matching.hs
{-# LANGUAGE PatternGuards #-}
module ATerm.Matching
( -- * Types
Binding(..)
-- * Combinators
, exactlyS
, exactlyI
, exactlyL
, exactlyA
, exactlyNamed
, contains
, containsL
, containsA
, containsChildren
, bindT
, bindL
, bindI
, bindS
, bindA
) where
import ATerm.AbstractSyntax
import qualified ATerm.Utilities as U
import Control.Monad -- For MonadPlus
-- | Binding type gives you back the parts of the ATerm that
-- that match.
data Binding = BoundTerm Int -- ^ The index into the ATermTable of the matching ATerm
| BoundList [Int] -- ^ The list of indexes into the ATermTable that match
| BoundInt Integer -- ^ The matching Integer
| BoundStr String -- ^ The matching String
| BoundAppl Int -- ^ The index into the ATermTable for the ShAAppl term
deriving (Eq, Read, Show, Ord)
-- | Turns anything with an Eq instance into a
-- matcher by using (==). No binding is generated.
exactly :: (MonadPlus m, Eq a) => a -> a -> m ()
exactly a b = guard (a == b) >> return ()
-- * ATermMatcher Combinators
---------------------------------------------------------------------
-- ** Exact matchers, no binding generated when they match
---------------------------------------------------------------------
-- | Matches exactly the string 's' within the ATerm
exactlyS :: MonadPlus m => String -> ATermTable -> m ()
exactlyS s t = case getATerm t of
ShAAppl s' [] _ -> exactly s s'
_ -> mzero
-- | Matches exactly the integer 'i' within the ATerm
exactlyI :: MonadPlus m => Integer -> ATermTable -> m ()
exactlyI i t = case getATerm t of
ShAInt i' _ -> exactly i i'
_ -> mzero
-- | Matches exactly the list 'xs' within the ATerm
exactlyL :: MonadPlus m => [ATermTable -> m a] -> ATermTable -> m [a]
exactlyL ms t = case getATerm t of
ShAList ls _ -> do
guard (length ms == length ls)
sequence (zipWith (\m i -> m (getATermByIndex1 i t)) ms ls)
_ -> mzero
-- | Matches the string exactly
exactlyA :: MonadPlus m => String -> [ATermTable -> m a] -> ATermTable -> m [a]
exactlyA s ms t = case getATerm t of
ShAAppl s' ls _ -> do
exactly s s'
guard (length ms == length ls)
sequence (zipWith (\m i -> U.app m t i) ms ls)
_ -> mzero
-- | Looks for an Appl with name 's' and any children
exactlyNamed :: MonadPlus m => String -> ATermTable -> m ()
exactlyNamed s t = case getATerm t of
ShAAppl s' _ _ -> exactly s s'
_ -> mzero
---------------------------------------------------------------------
-- ** Partial matchers, ie., they just specify part of the structure
---------------------------------------------------------------------
containsChildren :: Monad m
=> m (ATermTable -> b) -> m Int -> ATermTable -> m b
containsChildren ms is t = do
i <- is
m <- ms
return (m (getATermByIndex1 i t))
-- | Matches a partial specification against the children. The
-- matching is maximised so that if the pattern occurs more than
-- once it is matched each time it appears.
contains :: [ATermTable -> a] -> ATermTable -> [a]
contains ms t = case getATerm t of
ShAAppl _ ls _ -> containsChildren ms ls t
ShAList ls _ -> containsChildren ms ls t
_ -> mzero
-- | Matches a partial specification of a sub aterm List. The
-- matching is maximised so that if the pattern occurs more than
-- once it is matched each time it appears.
containsL :: [ATermTable -> a] -> ATermTable -> [a]
containsL ms t = case getATerm t of
ShAList ls _ -> containsChildren ms ls t
_ -> mzero
-- | Matches a partial specification of an Appl. The matching is
-- maximised so that if the pattern occurs more than once it is match
-- each time it appears.
containsA :: String -> [ATermTable -> a] -> ATermTable -> [a]
containsA s ams t = case getATerm t of
ShAAppl s' ls _ -> do
exactly s s'
containsChildren ams ls t
_ -> mzero
---------------------------------------------------------------------
-- ** Wildcard matchers, these create bindings when they match
---------------------------------------------------------------------
-- | Matches any ATerm and generates a binding to that term
bindT :: MonadPlus m => ATermTable -> m Binding
bindT t = return (BoundTerm (getTopIndex t))
-- | Matches any list and generates a binding to that list
bindL :: MonadPlus m => ATermTable -> m Binding
bindL t = case getATerm t of
ShAList ls _ -> return (BoundList ls)
_ -> mzero
-- | Matches any integer and generates a binding to that integer
bindI :: MonadPlus m => ATermTable -> m Binding
bindI t = case getATerm t of
ShAInt i _ -> return (BoundInt i)
_ -> mzero
-- | Matches any string and generates a binding to that string
-- Strings have the form (Appl somestring [] []).
-- Not to be confused with matching the the string part of an Appl.
bindS :: MonadPlus m => ATermTable -> m Binding
bindS t = case getATerm t of
ShAAppl s [] [] -> return (BoundStr s)
_ -> mzero
-- | Matches any Appl and generates a binding to that Appl
bindA :: MonadPlus m => ATermTable -> m Binding
bindA t = case getATerm t of
ShAAppl _ _ _ -> return (BoundAppl (getTopIndex t))
_ -> mzero