module CSPM.Interpreter.PatternMatcher
(
match
,tryMatchStrict
,tryMatchLazy
,boundNames
)
where
import Language.CSPM.AST as AST hiding (Bindings)
import CSPM.Interpreter.Types as Types
import CSPM.Interpreter.Bindings
import Data.Maybe
import qualified Data.Set as Set
import Control.Exception
import Data.Array.IArray as Array
import qualified Data.List as List
failedMatch :: Maybe Value
failedMatch = Nothing
typeError :: String -> Value -> Maybe Value
typeError x v = throwTypingError ("error in pattern-match : "++ x) Nothing $ Just v
match :: Value -> Selector -> Maybe Value
match (VInt a) (IntSel b) = if a==b then return VUnit else failedMatch
match v (IntSel _) = typeError "expecting Int" v
match (VBool True) TrueSel = return VUnit
match (VBool False) TrueSel = failedMatch
match v TrueSel = typeError "expecting Bool" v
match (VBool True) FalseSel = failedMatch
match (VBool False) FalseSel = return VUnit
match v FalseSel = typeError "expecting Bool" v
match x SelectThis = return x
match (VChannel ch) (ConstrSel ident)
= if AST.uniqueIdentId ident == chanId ch then return VUnit else failedMatch
match (VConstructor (Types.Constructor i _ _)) (ConstrSel ident)
= if AST.uniqueIdentId ident == i then return VUnit else failedMatch
match v (ConstrSel c) = typeError ("expecting constructor " ++ show c) v
match (VSet s) (SingleSetSel b)
= if not $ Set.null s then match (Set.findMin s) b else failedMatch
match v (SingleSetSel _) = typeError "expecting a set" v
match (VSet s) EmptySetSel
= if Set.null s then return VUnit else failedMatch
match v EmptySetSel = typeError "expecting a set" v
match (VList l) p = case p of
ListIthSel i next -> match (l !! i) next
ListLengthSel 0 _next
-> if null l then return VUnit else failedMatch
ListLengthSel len next
-> if length l == len then matchList len l next else failedMatch
_ -> matchList (length l) l p
match t@(VTuple b) (TupleLengthSel len next)
= if length b == len then match t next else typeError "tuple wrong arity" t
match v (TupleLengthSel _ n) = typeError "expecting tuple" v
match (VTuple b) (TupleIthSel i next) = match (b !! i) next
match v (TupleIthSel _ n) = typeError "expecting tuple" v
match (VDotTuple l) (DotSel i next) = match (l !! i) next
match v (DotSel _ _) = typeError "expecting dot-tuple" v
match v p
= throwInternalError ("hit catchall case of pattern-matcher :" ++ show (v,p))
Nothing $ Just v
matchList :: Int -> [Value] -> Selector -> Maybe Value
matchList s !l !sel = case sel of
SelectThis -> return $ VList l
HeadSel next
-> if null l then failedMatch else match (head l) next
HeadNSel len next
-> if s >= len
then matchList len (take len l) next
else failedMatch
PrefixSel offset len next
-> if s >= offset + len
then matchList len (take len $ drop offset l) next
else failedMatch
TailSel next
-> if not $ null l then matchList (s1) (tail l) next else failedMatch
SliceSel offsetL offsetR next
-> if s >= offsetL + offsetR
then
let
newLen = s offsetL offsetR
in matchList newLen (take newLen $ drop offsetL l) next
else failedMatch
SuffixSel offset len next
-> if s >= offset + len
then
let
offsetLeft = s offset len
in matchList len (take len $ drop offsetLeft l) next
else failedMatch
ListLengthSel len next
-> if s == len then matchList s l next else failedMatch
ListIthSel i next -> match (l !! i) next
other -> throwTypingError ("matchList : not excpecting a List :" ++ show other)
Nothing (Just $ VList l)
tryMatchStrict :: Bindings -> LPattern -> Value -> Maybe Bindings
tryMatchStrict !binds p !val = case unLabel p of
VarPat ident -> Just $ bindIdent ident val binds
Selector sel ident -> case match val sel of
Nothing -> Nothing
Just valPart -> case ident of
Nothing -> Just binds
Just i -> Just $ bindIdent i valPart binds
Selectors selectorL identArray -> do
values <- matchGroup val selectorL
let
addBind b i = case identArray Array.! i of
Just n -> bindIdent n (values Array.! i) b
Nothing -> b
return $ List.foldl' addBind binds $ Array.indices identArray
_ -> throwInternalError "PatternMatcher : unsupported Pattern in strict match"
(Just $ srcLoc p) Nothing
tryMatchLazy :: Bindings -> LPattern -> Value -> Bindings
tryMatchLazy binds p@(unLabel -> VarPat ident) val
= bindIdent ident val binds
tryMatchLazy binds p@(unLabel -> Selector sel ident) val
= case ident of
Just i -> bindIdent i valPart binds
Nothing -> binds
where
valPart = case match val sel of
Just v -> v
Nothing -> throwPatternMatchError "pattern-match failure" (Just $ srcLoc p) $ Just val
tryMatchLazy binds sel@(unLabel -> Selectors selectorss identArray) val
= List.foldl' addBind binds $ Array.indices identArray
where
values = case matchGroup val selectorss of
Just x -> x
Nothing -> throwPatternMatchError "pattern-match failure"
(Just $ srcLoc sel) $ Just val
addBind b i = case identArray Array.! i of
Just n -> bindIdent n (values Array.! i) b
Nothing -> b
tryMatchLazy _ p v
= throwInternalError "PatternMatcher : unsupported Pattern in lazyMatch"
(Just $ srcLoc p) $ Just v
matchGroup :: Value -> Array Int Selector -> Maybe (Array Int Value)
matchGroup val sel = do
l <- mapM (match val) $ Array.elems sel
return $ Array.listArray (Array.bounds sel) l
boundNames :: LPattern -> [LIdent]
boundNames pat = case unLabel pat of
VarPat i -> [i]
Selector _ Nothing -> []
Selector _ (Just i) -> [i]
x@(Selectors {}) -> catMaybes $ Array.elems $ idents x