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 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 x SelectThis = return x
match (VInt a) (IntSel b) = if a==b then return VUnit else failedMatch
match v@(VInt _) _ = typeError "unexpected Int" v
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 v@(VBool _) _ = typeError "unexpected Bool" v
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)
= case Set.toList s of
[e] -> match e b
_ -> 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 val@(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 match val next else failedMatch
HeadSel next
-> if null l then failedMatch else match (head l) next
HeadNSel len next -> do
e <- saveTake len l
match (VList e) next
PrefixSel offset len next -> do
e <- saveDrop offset l >>= saveTake len
match (VList e) next
TailSel next
-> if not $ null l then match (VList $ tail l) next else failedMatch
SliceSel offsetL 0 next -> do
e <- saveDrop offsetL l
match (VList e) next
SliceSel offsetL offsetR next -> do
e <- saveDrop offsetL l
let len = length e
if len >= offsetR
then match (VList $ take (lenoffsetR) e) next
else failedMatch
SuffixSel offset len next -> do
let s = length l
if s >= offset + len
then match (VList $ take len $ drop (s offset len) l) next
else failedMatch
other -> typeError ("matchList : not excpecting a List :" ++ show other) val
match t@(VTuple b) (TupleLengthSel len next)
= if length b == len then match t next else typeError "tuple wrong arity" t
match v (TupleLengthSel _ _) = typeError "expecting tuple" v
match (VTuple b) (TupleIthSel i next) = match (b !! i) next
match v (TupleIthSel _ _) = 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 catch-all case of pattern-matcher :" ++ show (v,p))
Nothing $ Just v
saveDrop :: Int -> [a] -> Maybe [a]
saveDrop 0 l = Just l
saveDrop _ [] = Nothing
saveDrop n (_:r) = saveDrop (n1) r
saveTake :: Int -> [a] -> Maybe [a]
saveTake 0 _ = Just []
saveTake _ [] = Nothing
saveTake n (h:t) = do
l <- saveTake (n1) t
Just $ h: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 (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
_ -> throwInternalError "PatternMatcher : unexpected Pattern"
(Just $ srcLoc pat) $ Nothing