2012-12-26 22:07:09 +00:00
|
|
|
|
2012-11-23 04:15:59 +00:00
|
|
|
module Parse.Patterns (patternTerm, patternExpr, makeLambda, flattenPatterns) where
|
2012-06-10 04:21:16 +00:00
|
|
|
|
|
|
|
import Ast
|
2012-12-25 08:39:18 +00:00
|
|
|
import Context
|
2012-10-10 21:39:59 +00:00
|
|
|
import Control.Applicative ((<$>),(<*>))
|
2012-06-10 04:21:16 +00:00
|
|
|
import Control.Monad
|
2012-11-25 04:49:56 +00:00
|
|
|
import Control.Monad.State
|
2012-12-25 08:39:18 +00:00
|
|
|
import Data.Char (isUpper)
|
2012-12-26 22:07:09 +00:00
|
|
|
import Guid
|
2012-11-25 04:49:56 +00:00
|
|
|
import Text.Parsec hiding (newline,spaces,State)
|
|
|
|
import Text.Parsec.Indent
|
2012-11-23 04:15:59 +00:00
|
|
|
import Parse.Library
|
2012-06-10 04:21:16 +00:00
|
|
|
|
2012-11-25 04:49:56 +00:00
|
|
|
patternBasic :: IParser Pattern
|
2012-06-10 04:21:16 +00:00
|
|
|
patternBasic =
|
|
|
|
choice [ char '_' >> return PAnything
|
|
|
|
, do x@(c:_) <- var
|
2012-10-10 21:39:59 +00:00
|
|
|
return $ if isUpper c then PData x [] else PVar x
|
2012-06-10 04:21:16 +00:00
|
|
|
]
|
|
|
|
|
2012-12-26 22:07:09 +00:00
|
|
|
patternRecord :: IParser Pattern
|
|
|
|
patternRecord = PRecord <$> brackets (commaSep1 lowVar)
|
|
|
|
|
2012-11-25 04:49:56 +00:00
|
|
|
patternTuple :: IParser Pattern
|
2012-06-10 04:21:16 +00:00
|
|
|
patternTuple = do ps <- parens (commaSep patternExpr)
|
|
|
|
return $ case ps of { [p] -> p; _ -> ptuple ps }
|
|
|
|
|
2012-11-25 04:49:56 +00:00
|
|
|
patternList :: IParser Pattern
|
2012-06-10 04:21:16 +00:00
|
|
|
patternList = plist <$> braces (commaSep patternExpr)
|
|
|
|
|
2012-11-25 04:49:56 +00:00
|
|
|
patternTerm :: IParser Pattern
|
2012-12-26 22:07:09 +00:00
|
|
|
patternTerm = choice [ patternRecord, patternTuple, patternList, patternBasic ]
|
|
|
|
<?> "pattern"
|
2012-06-10 04:21:16 +00:00
|
|
|
|
2012-11-25 04:49:56 +00:00
|
|
|
patternConstructor :: IParser Pattern
|
2012-10-10 21:39:59 +00:00
|
|
|
patternConstructor = PData <$> capVar <*> spacePrefix patternTerm
|
|
|
|
|
2012-11-25 04:49:56 +00:00
|
|
|
patternExpr :: IParser Pattern
|
2012-10-10 21:39:59 +00:00
|
|
|
patternExpr = foldr1 pcons <$> consSep1 (patternConstructor <|> patternTerm) <?> "pattern"
|
2012-06-10 05:08:55 +00:00
|
|
|
|
2012-12-26 22:07:09 +00:00
|
|
|
makeLambda :: [Pattern] -> CExpr -> GuidCounter CExpr
|
|
|
|
makeLambda pats body = go (reverse pats) body
|
|
|
|
where go [] body = return body
|
|
|
|
go (p:ps) body@(C t s _) = do
|
|
|
|
(x,e) <- extract p body
|
|
|
|
go ps (C t s $ Lambda x e)
|
|
|
|
|
|
|
|
extract :: Pattern -> CExpr -> GuidCounter (String, CExpr)
|
|
|
|
extract pattern body@(C t s _) =
|
|
|
|
let ctx = C t s in
|
|
|
|
let fn x e = (x,e) in
|
|
|
|
case pattern of
|
|
|
|
PAnything -> return $ fn "_" body
|
|
|
|
PVar x -> return $ fn x body
|
|
|
|
PData name ps -> do
|
|
|
|
x <- guid
|
2013-01-06 00:27:36 +00:00
|
|
|
let a = '_' : show x
|
2012-12-26 22:07:09 +00:00
|
|
|
return . fn a . ctx $ Case (ctx (Var a)) [(pattern, body)]
|
|
|
|
PRecord fs -> do
|
|
|
|
x <- guid
|
2013-01-06 00:27:36 +00:00
|
|
|
let a = '_' : show x
|
2012-12-26 22:07:09 +00:00
|
|
|
toDef f = FnDef f [] (ctx $ Access (ctx $ Var a) f)
|
|
|
|
return . fn a . ctx $ Let (map toDef fs) body
|
|
|
|
|
|
|
|
extracts :: [Pattern] -> CExpr -> GuidCounter ([String], CExpr)
|
|
|
|
extracts ps body = go [] (reverse ps) body
|
|
|
|
where go args [] body = return (args, body)
|
|
|
|
go args (p:ps) body = do (x,e) <- extract p body
|
|
|
|
go (x:args) ps e
|
|
|
|
|
|
|
|
flattenPatterns :: [Pattern] -> CExpr -> GuidCounter (IParser [Def])
|
|
|
|
flattenPatterns patterns exp@(C t s _) =
|
|
|
|
let ctx = C t s in
|
|
|
|
case patterns of
|
|
|
|
PVar f : args -> do
|
|
|
|
(as,e) <- extracts args exp
|
|
|
|
return . return $
|
|
|
|
if isOp (head f) then let [a,b] = as in [ OpDef f a b e ]
|
|
|
|
else [ FnDef f as e ]
|
|
|
|
|
|
|
|
[p] -> return `liftM` matchSingle p exp p
|
|
|
|
|
|
|
|
_ -> return . fail $ "Pattern (" ++ unwords (map show patterns) ++
|
|
|
|
") cannot be used on the left-hand side of an assign statement."
|
|
|
|
|
|
|
|
matchSingle :: Pattern -> CExpr -> Pattern -> GuidCounter [Def]
|
|
|
|
matchSingle pat exp@(C t s _) p =
|
|
|
|
let ctx = C t s in
|
|
|
|
case p of
|
|
|
|
PData _ ps -> do x <- guid
|
2013-01-06 00:27:36 +00:00
|
|
|
let v = '_' : show x
|
2012-12-26 22:07:09 +00:00
|
|
|
dss <- mapM (matchSingle p . ctx $ Var v) ps
|
|
|
|
return (FnDef v [] exp : concat dss)
|
|
|
|
|
|
|
|
PVar x ->
|
|
|
|
return [ FnDef x [] (ctx $ Case exp [(pat, ctx $ Var x)]) ]
|
|
|
|
|
2012-12-28 11:24:00 +00:00
|
|
|
PRecord fs -> do
|
2013-01-06 00:27:36 +00:00
|
|
|
a <- (\x -> '_' : show x) `liftM` guid
|
2012-12-28 11:24:00 +00:00
|
|
|
let toDef f = FnDef f [] (ctx $ Access (ctx $ Var a) f)
|
|
|
|
return (FnDef a [] exp : map toDef fs)
|
|
|
|
|
2012-12-26 22:07:09 +00:00
|
|
|
PAnything -> return []
|