----------------------------------------------------------------------------- -- | -- Module : CSPM.Interpreter.PatternCompiler -- Copyright : (c) Fontaine 2008 - 2011 -- License : BSD3 -- -- Maintainer : fontaine@cs.uni-duesseldorf.de -- Stability : experimental -- Portability : GHC-only -- -- replace nested patterns with a set of linear Selectors -- todo : benchmark if it pays off to introduce -- helperbindings and only atomic bindings (unlikely) -- todo : add testcases {-# LANGUAGE ViewPatterns #-} module CSPM.Interpreter.PatternCompiler ( compilePattern ) where import Language.CSPM.Frontend (ModuleFromRenaming) import Language.CSPM.AST as AST import CSPM.Interpreter.Types (INT) import Control.Monad import Data.Generics.Schemes (everywhere') import Data.Generics.Aliases (mkT) import Data.Array.IArray -- | replace all pattern in the module with list of linear Selectors compilePattern :: ModuleFromRenaming -> Module INT compilePattern ast = castModule $ Data.Generics.Schemes.everywhere' (Data.Generics.Aliases.mkT compPat) ast where -- pattern that consist only of a variable match remain unchanged 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 { -- origPat = pat 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)] -- prefixpattern ,[(Offset,Len,LPattern)] -- suffixpattern ,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 {- compute the length of a list pattern Just Int -> fixed length pattern Nothing -> variable length pattern -} 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 WildCard -> Nothing Also patl -> do let l = map lengthOfListPattern patl -- todo: check that all length are equal: error "PatternCompiler.hs: lengthOfListPat : also pattern: todo" _ -> error $ "PatternCompiler.hs: lengthOfListPat : no list pattern " ++ show p {- PrefixPattern are fixed-length pattern with a fixed offset from the front return when the first variable length pattern occurs -} 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