module Data.Singletons.Syntax where
import Prelude hiding ( exp )
import Data.Monoid
import Data.Singletons.Util
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Desugar
import Language.Haskell.TH.Ppr
import Data.Map.Strict ( Map )
import qualified Data.Map.Strict as Map
import Data.Maybe
import Control.Monad
type VarPromotions = [(Name, Name)]
data DataDecl = DataDecl NewOrData Name [DTyVarBndr] [DCon] [Name]
data ClassDecl = ClassDecl DCxt Name [DTyVarBndr] ULetDecEnv
data InstDecl = InstDecl Name [DType] [(Name, ULetDecRHS)]
data PartitionedDecs =
PDecs { pd_let_decs :: [DLetDec]
, pd_class_decs :: [ClassDecl]
, pd_instance_decs :: [InstDecl]
, pd_data_decs :: [DataDecl]
}
instance Monoid PartitionedDecs where
mempty = PDecs [] [] [] []
mappend (PDecs a1 b1 c1 d1) (PDecs a2 b2 c2 d2) =
PDecs (a1 <> a2) (b1 <> b2) (c1 <> c2) (d1 <> d2)
partitionDecs :: Monad m => [DDec] -> m PartitionedDecs
partitionDecs = concatMapM partitionDec
partitionDec :: Monad m => DDec -> m PartitionedDecs
partitionDec (DLetDec letdec) = return $ mempty { pd_let_decs = [letdec] }
partitionDec (DDataD nd _cxt name tvbs cons derivings) =
return $ mempty { pd_data_decs = [DataDecl nd name tvbs cons derivings] }
partitionDec (DClassD cxt name tvbs _fds decs) = do
env <- concatMapM partitionClassDec decs
return $ mempty { pd_class_decs = [ClassDecl cxt name tvbs env] }
partitionDec (DInstanceD _cxt ty decs) = do
defns <- liftM catMaybes $ mapM partitionInstanceDec decs
(name, tys) <- split_app_tys [] ty
return $ mempty { pd_instance_decs = [InstDecl name tys defns] }
where
split_app_tys acc (DAppT t1 t2) = split_app_tys (t2:acc) t1
split_app_tys acc (DConT name) = return (name, acc)
split_app_tys acc (DSigT t _) = split_app_tys acc t
split_app_tys _ _ = fail $ "Illegal instance head: " ++ show ty
partitionDec (DRoleAnnotD {}) = return mempty
partitionDec (DPragmaD {}) = return mempty
partitionDec dec =
fail $ "Declaration cannot be promoted: " ++ pprint (decToTH dec)
partitionClassDec :: Monad m => DDec -> m ULetDecEnv
partitionClassDec (DLetDec (DSigD name ty)) = return $ typeBinding name ty
partitionClassDec (DLetDec (DValD (DVarPa name) exp)) =
return $ valueBinding name (UValue exp)
partitionClassDec (DLetDec (DFunD name clauses)) =
return $ valueBinding name (UFunction clauses)
partitionClassDec (DLetDec (DInfixD fixity name)) =
return $ infixDecl fixity name
partitionClassDec (DPragmaD {}) = return mempty
partitionClassDec _ =
fail "Only method declarations can be promoted within a class."
partitionInstanceDec :: Monad m => DDec -> m (Maybe (Name, ULetDecRHS))
partitionInstanceDec (DLetDec (DValD (DVarPa name) exp)) =
return $ Just (name, UValue exp)
partitionInstanceDec (DLetDec (DFunD name clauses)) =
return $ Just (name, UFunction clauses)
partitionInstanceDec (DPragmaD {}) = return Nothing
partitionInstanceDec _ =
fail "Only method bodies can be promoted within an instance."
data ADExp = ADVarE Name
| ADConE Name
| ADLitE Lit
| ADAppE ADExp ADExp
| ADLamE VarPromotions
DType
[Name] ADExp
| ADCaseE ADExp [ADMatch]
| ADLetE ALetDecEnv ADExp
| ADSigE ADExp DType
data ADMatch = ADMatch VarPromotions DType DPat ADExp
data ADClause = ADClause VarPromotions
[DPat] ADExp
data AnnotationFlag = Annotated | Unannotated
type Annotated = 'Annotated
type Unannotated = 'Unannotated
type family IfAnn (ann :: AnnotationFlag) (yes :: k) (no :: k) :: k
type instance IfAnn Annotated yes no = yes
type instance IfAnn Unannotated yes no = no
data ALetDecRHS = AFunction DType
Int
[ADClause]
| AValue DType
Int
ADExp
data ULetDecRHS = UFunction [DClause]
| UValue DExp
data LetDecEnv ann = LetDecEnv
{ lde_defns :: Map Name (IfAnn ann ALetDecRHS ULetDecRHS)
, lde_types :: Map Name DType
, lde_infix :: [(Fixity, Name)]
, lde_proms :: IfAnn ann (Map Name DType) ()
}
type ALetDecEnv = LetDecEnv Annotated
type ULetDecEnv = LetDecEnv Unannotated
instance Monoid ULetDecEnv where
mempty = LetDecEnv Map.empty Map.empty [] ()
mappend (LetDecEnv defns1 types1 infx1 _) (LetDecEnv defns2 types2 infx2 _) =
LetDecEnv (defns1 <> defns2) (types1 <> types2) (infx1 <> infx2) ()
valueBinding :: Name -> ULetDecRHS -> ULetDecEnv
valueBinding n v = emptyLetDecEnv { lde_defns = Map.singleton n v }
typeBinding :: Name -> DType -> ULetDecEnv
typeBinding n t = emptyLetDecEnv { lde_types = Map.singleton n t }
infixDecl :: Fixity -> Name -> ULetDecEnv
infixDecl f n = emptyLetDecEnv { lde_infix = [(f,n)] }
emptyLetDecEnv :: ULetDecEnv
emptyLetDecEnv = mempty
buildLetDecEnv :: DsMonad q => [DLetDec] -> q ULetDecEnv
buildLetDecEnv = go emptyLetDecEnv
where
go acc [] = return acc
go acc (DFunD name clauses : rest) =
go (valueBinding name (UFunction clauses) <> acc) rest
go acc (DValD (DVarPa name) exp : rest) =
go (valueBinding name (UValue exp) <> acc) rest
go acc (dec@(DValD {}) : rest) = do
flattened <- flattenDValD dec
go acc (flattened ++ rest)
go acc (DSigD name ty : rest) =
go (typeBinding name ty <> acc) rest
go acc (DInfixD f n : rest) =
go (infixDecl f n <> acc) rest