module Patterns (
Pattern(..),
Refs, emptyRef, union, newRef, reverseLookupRef, lookupRef, hasRecursion,
nullable, unescapable
) where
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import Expr
data Pattern
= Empty
| ZAny
| Node (Expr Bool) Pattern
| Or Pattern Pattern
| And Pattern Pattern
| Not Pattern
| Concat Pattern Pattern
| Interleave Pattern Pattern
| ZeroOrMore Pattern
| Optional Pattern
| Contains Pattern
| Reference String
deriving (Eq, Ord, Show)
nullable :: Refs -> Pattern -> Bool
nullable _ Empty = True
nullable _ ZAny = True
nullable _ Node{} = False
nullable refs (Or l r) = nullable refs l || nullable refs r
nullable refs (And l r) = nullable refs l && nullable refs r
nullable refs (Not p) = not $ nullable refs p
nullable refs (Concat l r) = nullable refs l && nullable refs r
nullable refs (Interleave l r) = nullable refs l && nullable refs r
nullable _ (ZeroOrMore _) = True
nullable _ (Optional _) = True
nullable refs (Contains p) = nullable refs p
nullable refs (Reference name) = nullable refs $ lookupRef refs name
unescapable :: Pattern -> Bool
unescapable ZAny = True
unescapable (Not ZAny) = True
unescapable _ = False
newtype Refs = Refs (M.Map String Pattern)
deriving (Show, Eq)
lookupRef :: Refs -> String -> Pattern
lookupRef (Refs m) name = m M.! name
reverseLookupRef :: Pattern -> Refs -> Maybe String
reverseLookupRef p (Refs m) = case M.keys $ M.filter (== p) m of
[] -> Nothing
(k:_) -> Just k
newRef :: String -> Pattern -> Refs
newRef key value = Refs $ M.singleton key value
emptyRef :: Refs
emptyRef = Refs M.empty
union :: Refs -> Refs -> Refs
union (Refs m1) (Refs m2) = Refs $ M.union m1 m2
hasRecursion :: Refs -> Bool
hasRecursion refs = hasRec refs (S.singleton "main") (lookupRef refs "main")
hasRec :: Refs -> S.Set String -> Pattern -> Bool
hasRec _ _ Empty = False
hasRec _ _ ZAny = False
hasRec _ _ Node{} = False
hasRec refs set (Or l r) = hasRec refs set l || hasRec refs set r
hasRec refs set (And l r) = hasRec refs set l || hasRec refs set r
hasRec refs set (Not p) = hasRec refs set p
hasRec refs set (Concat l r) = hasRec refs set l || (nullable refs l && hasRec refs set r)
hasRec refs set (Interleave l r) = hasRec refs set l || hasRec refs set r
hasRec _ _ (ZeroOrMore _) = False
hasRec refs set (Optional p) = hasRec refs set p
hasRec refs set (Contains p) = hasRec refs set p
hasRec refs set (Reference name) = S.member name set || hasRec refs (S.insert name set) (lookupRef refs name)