module Language.CSPM.PatternCompiler
(
compilePattern
)
where
import Language.CSPM.AST as AST
import Control.Monad
import Data.Generics.Schemes (everywhere')
import Data.Generics.Aliases (mkT)
import Data.Array.IArray
compilePattern :: LModule -> LModule
compilePattern ast
= Data.Generics.Schemes.everywhere' (Data.Generics.Aliases.mkT compPat) ast
where
compPat :: LPattern -> LPattern
compPat x@(unLabel -> VarPat {}) = x
compPat pat = case cp id pat of
[(i,s)] -> setNode pat $ Selector s i
x -> setNode pat $ Selectors {
selectors = listToArr $ map snd x
,idents = listToArr $ map fst x
}
listToArr :: [a] -> Array Int a
listToArr l = array (0,length l 1) $ zip [0..] l
cp :: (Selector -> Selector ) -> LPattern -> [(Maybe LIdent,Selector)]
cp path pat = case unLabel pat of
IntPat i -> return (Nothing, path $ IntSel i)
TruePat -> return (Nothing, path TrueSel )
FalsePat -> return (Nothing, path FalseSel )
WildCard -> return (Nothing, path SelectThis )
VarPat x -> return (Just x , path SelectThis )
ConstrPat x -> return (Nothing, path $ ConstrSel $ unUIdent $ unLabel x)
Also l -> concatMap (cp path) l
Append l -> do
let (prefix,suffix,variable) = analyzeAppendPattern l
msum [ concatMap (mkListPrefixPat path) prefix
, mkListVariablePat path variable
, concatMap (mkListSuffixPat path) suffix ]
DotPat l -> msum $ map
(\(x,i) -> cp (path . DotSel i) x)
(zip l [0..])
SingleSetPat p -> cp (path . SingleSetSel) p
EmptySetPat -> return (Nothing, path EmptySetSel)
ListEnumPat [] -> return (Nothing, path $ ListLengthSel 0 $ SelectThis )
ListEnumPat l -> do
let len = length l
msum $ map
(\(x,i) -> cp (path . ListLengthSel len . ListIthSel i) x)
(zip l [0..])
TuplePat [] -> return (Nothing, path $ TupleLengthSel 0 $ SelectThis )
TuplePat l -> do
let len = length l
msum $ map
(\(x,i) -> cp (path . TupleLengthSel len . TupleIthSel i) x)
(zip l [0..])
Selector {} -> error "PatternCompiler.hs : didn't expect Selector"
Selectors {} -> error "PatternCompiler.hs : didn't expect Selectors"
mkListPrefixPat
:: (Selector -> Selector )
-> (Offset,Len,LPattern)
-> [(Maybe LIdent,Selector)]
mkListPrefixPat path l = case l of
(0,1,pat) -> let (unLabel -> ListEnumPat [r]) = pat
in cp (path . HeadSel) r
(0,n,pat) -> cp (path . HeadNSel n) pat
(o,s,pat) -> cp (path . PrefixSel o s) pat
mkListSuffixPat
:: (Selector -> Selector )
-> (Offset,Len,LPattern)
-> [(Maybe LIdent,Selector)]
mkListSuffixPat path (o,l,pat)
= cp (path . SuffixSel o l) pat
mkListVariablePat
:: (Selector -> Selector )
-> Maybe (Offset,Offset,LPattern)
-> [(Maybe LIdent,Selector)]
mkListVariablePat _path Nothing = []
mkListVariablePat path (Just (l,r,pat)) = cp (path . SliceSel l r) pat
type Offset = Int
type Len = Int
analyzeAppendPattern ::
[LPattern] ->
([(Offset,Len,LPattern)]
,[(Offset,Len,LPattern)]
,Maybe (Offset,Offset,LPattern)
)
analyzeAppendPattern pl
= let
taggedPatList = zip pl $ map lengthOfListPattern pl
prefixPat = computePrefixPattern taggedPatList
suffixPat = computeSuffixPattern taggedPatList
lenPrefix = sum $ map (\(_,l,_)-> l) prefixPat
lenSuffix = sum $ map (\(_,l,_)-> l) suffixPat
varPat = case filter (\(_,len) -> len == Nothing) taggedPatList of
[] -> Nothing
[(pat,_)] -> Just (lenPrefix,lenSuffix,pat)
l -> error $ "PatternCompiler.hs : alsopattern contains multiple "
++ "variable length pattern "
++ show l
in
(prefixPat,suffixPat,varPat)
where
lengthOfListPattern :: LPattern -> Maybe Len
lengthOfListPattern p = case unLabel p of
ListEnumPat l -> return $ length l
Append patl -> do
l <- mapM lengthOfListPattern patl
return $ sum l
VarPat _ -> Nothing
Also patl -> do
let l = map lengthOfListPattern patl
error "PatternCompiler.hs: lengthOfListPat : also pattern: todo"
_ -> error $ "PatternCompiler.hs: lengthOfListPat : no list pattern "
++ show p
computePrefixPattern :: [(LPattern,Maybe Len)] -> [(Offset,Len,LPattern)]
computePrefixPattern l = worker 0 l where
worker _ [] = []
worker _ ((_ ,Nothing ) : _) = []
worker offset ((pat,Just len): rest)
= (offset,len,pat) : worker (offset+len) rest
computeSuffixPattern :: [(LPattern,Maybe Len)] -> [(Offset,Len,LPattern)]
computeSuffixPattern = computePrefixPattern . reverse