{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Agda.Syntax.Abstract.Pattern where
import Prelude hiding (null)
import Control.Arrow ((***), second)
import Control.Monad ((>=>))
import Control.Monad.Identity
import Control.Applicative (liftA2)
import Data.Foldable (Foldable, foldMap)
import Data.Traversable (Traversable, traverse)
import Data.Maybe
import Data.Monoid
import Agda.Syntax.Abstract as A
import Agda.Syntax.Common
import Agda.Syntax.Concrete (FieldAssignment')
import qualified Agda.Syntax.Concrete as C
import Agda.Syntax.Concrete.Pattern (IsWithP(..))
import Agda.Syntax.Info
import Agda.Syntax.Position
import Agda.Utils.Functor
import Agda.Utils.List
import Agda.Utils.Null
import Agda.Utils.Impossible
type NAP = NamedArg Pattern
class MapNamedArgPattern a where
mapNamedArgPattern :: (NAP -> NAP) -> a -> a
default mapNamedArgPattern
:: (Functor f, MapNamedArgPattern a', a ~ f a') => (NAP -> NAP) -> a -> a
mapNamedArgPattern = fmap . mapNamedArgPattern
instance MapNamedArgPattern NAP where
mapNamedArgPattern f p =
case namedArg p of
VarP{} -> f p
WildP{} -> f p
DotP{} -> f p
EqualP{} -> f p
LitP{} -> f p
AbsurdP{} -> f p
ProjP{} -> f p
ConP i qs ps -> f $ setNamedArg p $ ConP i qs $ mapNamedArgPattern f ps
DefP i qs ps -> f $ setNamedArg p $ DefP i qs $ mapNamedArgPattern f ps
PatternSynP i x ps -> f $ setNamedArg p $ PatternSynP i x $ mapNamedArgPattern f ps
RecP i fs -> f $ setNamedArg p $ RecP i $ map (fmap namedArg) $ mapNamedArgPattern f $ map (fmap (setNamedArg p)) fs
AsP i x p0 -> f $ updateNamedArg (AsP i x) $ mapNamedArgPattern f $ setNamedArg p p0
WithP i p0 -> f $ updateNamedArg (WithP i) $ mapNamedArgPattern f $ setNamedArg p p0
instance MapNamedArgPattern a => MapNamedArgPattern [a] where
instance MapNamedArgPattern a => MapNamedArgPattern (FieldAssignment' a) where
instance MapNamedArgPattern a => MapNamedArgPattern (Maybe a) where
instance (MapNamedArgPattern a, MapNamedArgPattern b) => MapNamedArgPattern (a,b) where
mapNamedArgPattern f (a, b) = (mapNamedArgPattern f a, mapNamedArgPattern f b)
class APatternLike a p | p -> a where
foldrAPattern
:: Monoid m
=> (Pattern' a -> m -> m)
-> p -> m
default foldrAPattern
:: (Monoid m, Foldable f, APatternLike a b, f b ~ p)
=> (Pattern' a -> m -> m) -> p -> m
foldrAPattern = foldMap . foldrAPattern
traverseAPatternM
:: Monad m
=> (Pattern' a -> m (Pattern' a))
-> (Pattern' a -> m (Pattern' a))
-> p -> m p
default traverseAPatternM
:: (Traversable f, APatternLike a q, f q ~ p, Monad m)
=> (Pattern' a -> m (Pattern' a))
-> (Pattern' a -> m (Pattern' a))
-> p -> m p
traverseAPatternM pre post = traverse $ traverseAPatternM pre post
foldAPattern :: (APatternLike a p, Monoid m) => (Pattern' a -> m) -> p -> m
foldAPattern f = foldrAPattern $ \ p m -> f p `mappend` m
preTraverseAPatternM
:: (APatternLike a b, Monad m )
=> (Pattern' a -> m (Pattern' a))
-> b -> m b
preTraverseAPatternM pre p = traverseAPatternM pre return p
postTraverseAPatternM
:: (APatternLike a b, Monad m)
=> (Pattern' a -> m (Pattern' a))
-> b -> m b
postTraverseAPatternM post p = traverseAPatternM return post p
mapAPattern :: APatternLike a p => (Pattern' a -> Pattern' a) -> p -> p
mapAPattern f = runIdentity . postTraverseAPatternM (Identity . f)
instance APatternLike a (Pattern' a) where
foldrAPattern f p = f p $
case p of
AsP _ _ p -> foldrAPattern f p
ConP _ _ ps -> foldrAPattern f ps
DefP _ _ ps -> foldrAPattern f ps
RecP _ ps -> foldrAPattern f ps
PatternSynP _ _ ps -> foldrAPattern f ps
WithP _ p -> foldrAPattern f p
VarP _ -> mempty
ProjP _ _ _ -> mempty
WildP _ -> mempty
DotP _ _ -> mempty
AbsurdP _ -> mempty
LitP _ -> mempty
EqualP _ _ -> mempty
traverseAPatternM pre post = pre >=> recurse >=> post
where
recurse p = case p of
A.VarP{} -> return p
A.WildP{} -> return p
A.DotP{} -> return p
A.LitP{} -> return p
A.AbsurdP{} -> return p
A.ProjP{} -> return p
A.EqualP{} -> return p
A.ConP i ds ps -> A.ConP i ds <$> traverseAPatternM pre post ps
A.DefP i q ps -> A.DefP i q <$> traverseAPatternM pre post ps
A.AsP i x p -> A.AsP i x <$> traverseAPatternM pre post p
A.RecP i ps -> A.RecP i <$> traverseAPatternM pre post ps
A.PatternSynP i x ps -> A.PatternSynP i x <$> traverseAPatternM pre post ps
A.WithP i p -> A.WithP i <$> traverseAPatternM pre post p
instance APatternLike a b => APatternLike a (Arg b) where
instance APatternLike a b => APatternLike a (Named n b) where
instance APatternLike a b => APatternLike a [b] where
instance APatternLike a b => APatternLike a (Maybe b) where
instance APatternLike a b => APatternLike a (FieldAssignment' b) where
instance (APatternLike a b, APatternLike a c) => APatternLike a (b,c) where
foldrAPattern f (p, p') =
foldrAPattern f p `mappend` foldrAPattern f p'
traverseAPatternM pre post (p, p') =
liftA2 (,)
(traverseAPatternM pre post p)
(traverseAPatternM pre post p')
patternVars :: forall a p. APatternLike a p => p -> [A.Name]
patternVars p = foldAPattern f p `appEndo` []
where
f :: Pattern' a -> Endo [A.Name]
f = \case
A.VarP x -> Endo (unBind x :)
A.AsP _ x _ -> Endo (unBind x :)
A.LitP {} -> mempty
A.ConP {} -> mempty
A.RecP {} -> mempty
A.DefP {} -> mempty
A.ProjP {} -> mempty
A.WildP {} -> mempty
A.DotP {} -> mempty
A.AbsurdP {} -> mempty
A.EqualP {} -> mempty
A.PatternSynP {} -> mempty
A.WithP _ _ -> mempty
containsAPattern :: APatternLike a p => (Pattern' a -> Bool) -> p -> Bool
containsAPattern f = getAny . foldAPattern (Any . f)
containsAbsurdPattern :: APatternLike a p => p -> Bool
containsAbsurdPattern = containsAPattern $ \case
A.PatternSynP{} -> __IMPOSSIBLE__
A.AbsurdP{} -> True
_ -> False
containsAsPattern :: APatternLike a p => p -> Bool
containsAsPattern = containsAPattern $ \case
A.PatternSynP{} -> __IMPOSSIBLE__
A.AsP{} -> True
_ -> False
checkPatternLinearity :: (Monad m, APatternLike a p)
=> p -> ([C.Name] -> m ()) -> m ()
checkPatternLinearity ps err =
unlessNull (duplicates $ map nameConcrete $ patternVars ps) $ \ys -> err ys
substPattern :: [(Name, Pattern)] -> Pattern -> Pattern
substPattern s = substPattern' (substExpr $ map (second patternToExpr) s) s
substPattern'
:: (e -> e)
-> [(Name, Pattern' e)]
-> Pattern' e
-> Pattern' e
substPattern' subE s = mapAPattern $ \ p -> case p of
VarP x -> fromMaybe p $ lookup (A.unBind x) s
DotP i e -> DotP i $ subE e
EqualP i es -> EqualP i $ map (subE *** subE) es
ConP _ _ _ -> p
RecP _ _ -> p
ProjP _ _ _ -> p
WildP _ -> p
AbsurdP _ -> p
LitP _ -> p
DefP _ _ _ -> p
AsP _ _ _ -> p
PatternSynP _ _ _ -> p
WithP _ _ -> p
instance IsWithP (Pattern' e) where
isWithP = \case
WithP _ p -> Just p
_ -> Nothing
splitOffTrailingWithPatterns :: A.Patterns -> (A.Patterns, A.Patterns)
splitOffTrailingWithPatterns = spanEnd (isJust . isWithP)
trailingWithPatterns :: Patterns -> Patterns
trailingWithPatterns = snd . splitOffTrailingWithPatterns
data LHSPatternView e
= LHSAppP (NAPs e)
| LHSProjP ProjOrigin AmbiguousQName (NamedArg (Pattern' e))
| LHSWithP [Pattern' e]
deriving (Show)
lhsPatternView :: IsProjP e => NAPs e -> Maybe (LHSPatternView e, NAPs e)
lhsPatternView [] = Nothing
lhsPatternView (p0 : ps) =
case namedArg p0 of
ProjP _i o d -> Just (LHSProjP o d p0, ps)
WithP _i p -> Just (LHSWithP (p : map namedArg ps1), ps2)
where
(ps1, ps2) = spanJust isWithP ps
_ -> Just (LHSAppP (p0 : ps1), ps2)
where
(ps1, ps2) = span (\ p -> isNothing (isProjP p) && isNothing (isWithP p)) ps
class LHSToSpine a b where
lhsToSpine :: a -> b
spineToLhs :: b -> a
instance LHSToSpine Clause SpineClause where
lhsToSpine = fmap lhsToSpine
spineToLhs = fmap spineToLhs
instance LHSToSpine a b => LHSToSpine [a] [b] where
lhsToSpine = map lhsToSpine
spineToLhs = map spineToLhs
instance LHSToSpine LHS SpineLHS where
lhsToSpine (LHS i core) = SpineLHS i f ps
where QNamed f ps = lhsCoreToSpine core
spineToLhs (SpineLHS i f ps) = LHS i (spineToLhsCore $ QNamed f ps)
lhsCoreToSpine :: LHSCore' e -> A.QNamed [NamedArg (Pattern' e)]
lhsCoreToSpine = \case
LHSHead f ps -> QNamed f ps
LHSProj d h ps -> lhsCoreToSpine (namedArg h) <&> (++ (p : ps))
where p = updateNamedArg (const $ ProjP empty ProjPrefix d) h
LHSWith h wps ps -> lhsCoreToSpine h <&> (++ map (defaultNamedArg . mkWithP) wps ++ ps)
where mkWithP p = WithP (PatRange $ getRange p) p
spineToLhsCore :: IsProjP e => QNamed [NamedArg (Pattern' e)] -> LHSCore' e
spineToLhsCore (QNamed f ps) = lhsCoreAddSpine (LHSHead f []) ps
lhsCoreApp :: LHSCore' e -> [NamedArg (Pattern' e)] -> LHSCore' e
lhsCoreApp core ps = core { lhsPats = lhsPats core ++ ps }
lhsCoreWith :: LHSCore' e -> [Pattern' e] -> LHSCore' e
lhsCoreWith (LHSWith core wps []) wps' = LHSWith core (wps ++ wps') []
lhsCoreWith core wps' = LHSWith core wps' []
lhsCoreAddChunk :: IsProjP e => LHSCore' e -> LHSPatternView e -> LHSCore' e
lhsCoreAddChunk core = \case
LHSAppP ps -> lhsCoreApp core ps
LHSWithP wps -> lhsCoreWith core wps
LHSProjP ProjPrefix d np -> LHSProj d (setNamedArg np core) []
LHSProjP _ _ np -> lhsCoreApp core [np]
lhsCoreAddSpine :: IsProjP e => LHSCore' e -> [NamedArg (Pattern' e)] -> LHSCore' e
lhsCoreAddSpine core ps =
case lhsPatternView ps of
Nothing -> core
Just (v, ps') -> lhsCoreAddChunk core chunk `lhsCoreAddSpine` ps'
where
chunk = case v of
LHSProjP ProjPrefix _ _
-> v
LHSProjP _ d np | let nh = C.numHoles d, nh > 0, nh <= 1 + length ps'
-> LHSProjP ProjPrefix d np
_ -> v
lhsCoreAllPatterns :: LHSCore' e -> [Pattern' e]
lhsCoreAllPatterns = map namedArg . qnamed . lhsCoreToSpine
lhsCoreToPattern :: LHSCore -> Pattern
lhsCoreToPattern lc =
case lc of
LHSHead f aps -> DefP noInfo (unambiguous f) aps
LHSProj d lhscore aps -> DefP noInfo d $
fmap (fmap lhsCoreToPattern) lhscore : aps
LHSWith h wps aps -> case lhsCoreToPattern h of
DefP r q ps -> DefP r q $ ps ++ map (\ p -> defaultNamedArg $ WithP (PatRange $ getRange p) p) wps ++ aps
_ -> __IMPOSSIBLE__
where noInfo = empty
mapLHSHead :: (QName -> [NamedArg Pattern] -> LHSCore) -> LHSCore -> LHSCore
mapLHSHead f = \case
LHSHead x ps -> f x ps
LHSProj d h ps -> LHSProj d (fmap (fmap (mapLHSHead f)) h) ps
LHSWith h wps ps -> LHSWith (mapLHSHead f h) wps ps