Retrie/Universe.hs (113 lines of code) (raw):
-- Copyright (c) Facebook, Inc. and its affiliates.
--
-- This source code is licensed under the MIT license found in the
-- LICENSE file in the root directory of this source tree.
--
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Retrie.Universe
( Universe
, printU
, Matchable(..)
, UMap(..)
) where
import Control.Monad
import Data.Data
import Retrie.AlphaEnv
import Retrie.ExactPrint
import Retrie.GHC
import Retrie.PatternMap.Class
import Retrie.PatternMap.Instances
import Retrie.Quantifiers
import Retrie.Substitution
-- | A sum type to collect all possible top-level rewritable types.
data Universe
= ULHsExpr (LHsExpr GhcPs)
| ULStmt (LStmt GhcPs (LHsExpr GhcPs))
| ULType (LHsType GhcPs)
| ULPat (LPat GhcPs)
deriving (Data)
-- | Exactprint an annotated 'Universe'.
printU :: Annotated Universe -> String
printU u = exactPrintU (astA u)
`debug` ("printU:" ++ showAst (astA u))
-- | Primitive exactprint for 'Universe'.
exactPrintU :: Universe -> String
exactPrintU (ULHsExpr e) = exactPrint e
exactPrintU (ULStmt s) = exactPrint s
exactPrintU (ULType t) = exactPrint t
exactPrintU (ULPat p) = exactPrint p
-------------------------------------------------------------------------------
-- | Class of types which can be injected into the 'Universe' type.
class Matchable ast where
-- | Inject an AST into 'Universe'
inject :: ast -> Universe
-- | Project an AST from a 'Universe'.
-- Can fail if universe contains the wrong type.
project :: Universe -> ast
-- | Get the original location of the AST.
getOrigin :: ast -> SrcSpan
instance Matchable Universe where
inject = id
project = id
getOrigin (ULHsExpr e) = getOrigin e
getOrigin (ULStmt s) = getOrigin s
getOrigin (ULType t) = getOrigin t
getOrigin (ULPat p) = getOrigin p
instance Matchable (LocatedA (HsExpr GhcPs)) where
inject = ULHsExpr
project (ULHsExpr x) = x
project _ = error "project LHsExpr"
getOrigin e = getLocA e
instance Matchable (LocatedA (Stmt GhcPs (LocatedA (HsExpr GhcPs)))) where
inject = ULStmt
project (ULStmt x) = x
project _ = error "project LStmt"
getOrigin e = getLocA e
instance Matchable (LocatedA (HsType GhcPs)) where
inject = ULType
project (ULType t) = t
project _ = error "project ULType"
getOrigin e = getLocA e
instance Matchable (LocatedA (Pat GhcPs)) where
inject = ULPat
project (ULPat p) = p
project _ = error "project ULPat"
getOrigin = getLocA
-------------------------------------------------------------------------------
-- | The pattern map for 'Universe'.
data UMap a = UMap
{ umExpr :: EMap a
, umStmt :: SMap a
, umType :: TyMap a
, umPat :: PatMap a
}
deriving (Functor)
instance PatternMap UMap where
type Key UMap = Universe
mEmpty :: UMap a
mEmpty = UMap mEmpty mEmpty mEmpty mEmpty
mUnion :: UMap a -> UMap a -> UMap a
mUnion m1 m2 = UMap
(unionOn umExpr m1 m2)
(unionOn umStmt m1 m2)
(unionOn umType m1 m2)
(unionOn umPat m1 m2)
mAlter :: AlphaEnv -> Quantifiers -> Universe -> A a -> UMap a -> UMap a
mAlter env vs u f m = go u
where
go (ULHsExpr e) = m { umExpr = mAlter env vs e f (umExpr m) }
go (ULStmt s) = m { umStmt = mAlter env vs s f (umStmt m) }
go (ULType t) = m { umType = mAlter env vs t f (umType m) }
go (ULPat p) = m { umPat = mAlter env vs (cLPat p) f (umPat m) }
mMatch :: MatchEnv -> Universe -> (Substitution, UMap a) -> [(Substitution, a)]
mMatch env = go
where
go (ULHsExpr e) = mapFor umExpr >=> mMatch env e
go (ULStmt s) = mapFor umStmt >=> mMatch env s
go (ULType t) = mapFor umType >=> mMatch env t
go (ULPat p) = mapFor umPat >=> mMatch env (cLPat p)