module Language.Haskell.TH.Syntax(
Quasi(..), Lift(..),
Q, runQ,
report, recover, reify,
currentModule, runIO,
Name(..), mkName, newName, nameBase, nameModule,
showName, showName', NameIs(..),
Dec(..), Exp(..), Con(..), Type(..), Cxt, Match(..),
Clause(..), Body(..), Guard(..), Stmt(..), Range(..),
Lit(..), Pat(..), FieldExp, FieldPat,
Strict(..), Foreign(..), Callconv(..), Safety(..),
StrictType, VarStrictType, FunDep(..),
Info(..),
Fixity(..), FixityDirection(..), defaultFixity, maxPrecedence,
returnQ, bindQ, sequenceQ,
NameFlavour(..), NameSpace (..),
mkNameG_v, mkNameG_d, mkNameG_tc, Uniq, mkNameL, mkNameU,
tupleTypeName, tupleDataName,
OccName, mkOccName, occString,
ModName, mkModName, modString,
PkgName, mkPkgName, pkgString
) where
import Data.PackedString
import GHC.Base ( Int(..), Int#, (<#), (==#) )
import Data.Generics (Data(..), Typeable, mkConstr, mkDataType)
import qualified Data.Generics as Generics
import Data.IORef
import GHC.IOBase ( unsafePerformIO )
import Control.Monad (liftM)
import System.IO ( hPutStrLn, stderr )
import Data.Char ( isAlpha )
class (Monad m, Functor m) => Quasi m where
qNewName :: String -> m Name
qReport :: Bool -> String -> m ()
qRecover :: m a -> m a -> m a
qReify :: Name -> m Info
qCurrentModule :: m String
qRunIO :: IO a -> m a
instance Quasi IO where
qNewName s = do { n <- readIORef counter
; writeIORef counter (n+1)
; return (mkNameU s n) }
qReport True msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
qReport False msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
qReify v = badIO "reify"
qCurrentModule = badIO "currentModule"
qRecover a b = badIO "recover"
qRunIO m = m
badIO :: String -> IO a
badIO op = do { qReport True ("Can't do `" ++ op ++ "' in the IO monad")
; fail "Template Haskell failure" }
counter :: IORef Int
counter = unsafePerformIO (newIORef 0)
newtype Q a = Q { unQ :: forall m. Quasi m => m a }
runQ :: Quasi m => Q a -> m a
runQ (Q m) = m
instance Monad Q where
return x = Q (return x)
Q m >>= k = Q (m >>= \x -> unQ (k x))
Q m >> Q n = Q (m >> n)
fail s = report True s >> Q (fail "Q monad failure")
instance Functor Q where
fmap f (Q x) = Q (fmap f x)
newName :: String -> Q Name
newName s = Q (qNewName s)
report :: Bool -> String -> Q ()
report b s = Q (qReport b s)
recover :: Q a -> Q a -> Q a
recover (Q r) (Q m) = Q (qRecover r m)
reify :: Name -> Q Info
reify v = Q (qReify v)
currentModule :: Q String
currentModule = Q qCurrentModule
runIO :: IO a -> Q a
runIO m = Q (qRunIO m)
instance Quasi Q where
qNewName = newName
qReport = report
qRecover = recover
qReify = reify
qCurrentModule = currentModule
qRunIO = runIO
returnQ :: a -> Q a
returnQ = return
bindQ :: Q a -> (a -> Q b) -> Q b
bindQ = (>>=)
sequenceQ :: [Q a] -> Q [a]
sequenceQ = sequence
class Lift t where
lift :: t -> Q Exp
instance Lift Integer where
lift x = return (LitE (IntegerL x))
instance Lift Int where
lift x= return (LitE (IntegerL (fromIntegral x)))
instance Lift Char where
lift x = return (LitE (CharL x))
instance Lift Bool where
lift True = return (ConE trueName)
lift False = return (ConE falseName)
instance Lift a => Lift (Maybe a) where
lift Nothing = return (ConE nothingName)
lift (Just x) = liftM (ConE justName `AppE`) (lift x)
instance (Lift a, Lift b) => Lift (Either a b) where
lift (Left x) = liftM (ConE leftName `AppE`) (lift x)
lift (Right y) = liftM (ConE rightName `AppE`) (lift y)
instance Lift a => Lift [a] where
lift xs = do { xs' <- mapM lift xs; return (ListE xs') }
instance (Lift a, Lift b) => Lift (a, b) where
lift (a, b)
= liftM TupE $ sequence [lift a, lift b]
instance (Lift a, Lift b, Lift c) => Lift (a, b, c) where
lift (a, b, c)
= liftM TupE $ sequence [lift a, lift b, lift c]
instance (Lift a, Lift b, Lift c, Lift d) => Lift (a, b, c, d) where
lift (a, b, c, d)
= liftM TupE $ sequence [lift a, lift b, lift c, lift d]
instance (Lift a, Lift b, Lift c, Lift d, Lift e)
=> Lift (a, b, c, d, e) where
lift (a, b, c, d, e)
= liftM TupE $ sequence [lift a, lift b, lift c, lift d, lift e]
instance (Lift a, Lift b, Lift c, Lift d, Lift e, Lift f)
=> Lift (a, b, c, d, e, f) where
lift (a, b, c, d, e, f)
= liftM TupE $ sequence [lift a, lift b, lift c, lift d, lift e, lift f]
instance (Lift a, Lift b, Lift c, Lift d, Lift e, Lift f, Lift g)
=> Lift (a, b, c, d, e, f, g) where
lift (a, b, c, d, e, f, g)
= liftM TupE $ sequence [lift a, lift b, lift c, lift d, lift e, lift f, lift g]
trueName, falseName :: Name
trueName = mkNameG DataName "base" "GHC.Base" "True"
falseName = mkNameG DataName "base" "GHC.Base" "False"
nothingName, justName :: Name
nothingName = mkNameG DataName "base" "Data.Maybe" "Nothing"
justName = mkNameG DataName "base" "Data.Maybe" "Just"
leftName, rightName :: Name
leftName = mkNameG DataName "base" "Data.Either" "Left"
rightName = mkNameG DataName "base" "Data.Either" "Right"
type ModName = PackedString
mkModName :: String -> ModName
mkModName s = packString s
modString :: ModName -> String
modString m = unpackPS m
type PkgName = PackedString
mkPkgName :: String -> PkgName
mkPkgName s = packString s
pkgString :: PkgName -> String
pkgString m = unpackPS m
type OccName = PackedString
mkOccName :: String -> OccName
mkOccName s = packString s
occString :: OccName -> String
occString occ = unpackPS occ
data Name = Name OccName NameFlavour deriving (Typeable, Data)
data NameFlavour
= NameS
| NameQ ModName
| NameU Int#
| NameL Int#
| NameG NameSpace PkgName ModName
deriving ( Typeable )
instance Data NameFlavour where
gunfold = error "gunfold"
toConstr NameS = con_NameS
toConstr (NameQ _) = con_NameQ
toConstr (NameU _) = con_NameU
toConstr (NameL _) = con_NameL
toConstr (NameG _ _ _) = con_NameG
dataTypeOf _ = ty_NameFlavour
con_NameS = mkConstr ty_NameFlavour "NameS" [] Generics.Prefix
con_NameQ = mkConstr ty_NameFlavour "NameQ" [] Generics.Prefix
con_NameU = mkConstr ty_NameFlavour "NameU" [] Generics.Prefix
con_NameL = mkConstr ty_NameFlavour "NameL" [] Generics.Prefix
con_NameG = mkConstr ty_NameFlavour "NameG" [] Generics.Prefix
ty_NameFlavour = mkDataType "Language.Haskell.TH.Syntax.NameFlavour"
[con_NameS, con_NameQ, con_NameU,
con_NameL, con_NameG]
data NameSpace = VarName
| DataName
| TcClsName
deriving( Eq, Ord, Data, Typeable )
type Uniq = Int
nameBase :: Name -> String
nameBase (Name occ _) = occString occ
nameModule :: Name -> Maybe String
nameModule (Name _ (NameQ m)) = Just (modString m)
nameModule (Name _ (NameG _ _ m)) = Just (modString m)
nameModule other_name = Nothing
mkName :: String -> Name
mkName str
= split [] (reverse str)
where
split occ [] = Name (mkOccName occ) NameS
split occ ('.':rev) | not (null occ),
not (null rev), head rev /= '.'
= Name (mkOccName occ) (NameQ (mkModName (reverse rev)))
split occ (c:rev) = split (c:occ) rev
mkNameU :: String -> Uniq -> Name
mkNameU s (I# u) = Name (mkOccName s) (NameU u)
mkNameL :: String -> Uniq -> Name
mkNameL s (I# u) = Name (mkOccName s) (NameL u)
mkNameG :: NameSpace -> String -> String -> String -> Name
mkNameG ns pkg mod occ
= Name (mkOccName occ) (NameG ns (mkPkgName pkg) (mkModName mod))
mkNameG_v, mkNameG_tc, mkNameG_d :: String -> String -> String -> Name
mkNameG_v = mkNameG VarName
mkNameG_tc = mkNameG TcClsName
mkNameG_d = mkNameG DataName
instance Eq Name where
v1 == v2 = cmpEq (v1 `compare` v2)
instance Ord Name where
(Name o1 f1) `compare` (Name o2 f2) = (f1 `compare` f2) `thenCmp`
(o1 `compare` o2)
instance Eq NameFlavour where
f1 == f2 = cmpEq (f1 `compare` f2)
instance Ord NameFlavour where
NameS `compare` NameS = EQ
NameS `compare` other = LT
(NameQ _) `compare` NameS = GT
(NameQ m1) `compare` (NameQ m2) = m1 `compare` m2
(NameQ _) `compare` other = LT
(NameU _) `compare` NameS = GT
(NameU _) `compare` (NameQ _) = GT
(NameU u1) `compare` (NameU u2) | u1 <# u2 = LT
| u1 ==# u2 = EQ
| otherwise = GT
(NameU _) `compare` other = LT
(NameL _) `compare` NameS = GT
(NameL _) `compare` (NameQ _) = GT
(NameL _) `compare` (NameU _) = GT
(NameL u1) `compare` (NameL u2) | u1 <# u2 = LT
| u1 ==# u2 = EQ
| otherwise = GT
(NameL _) `compare` other = LT
(NameG ns1 p1 m1) `compare` (NameG ns2 p2 m2) = (ns1 `compare` ns2) `thenCmp`
(p1 `compare` p2) `thenCmp`
(m1 `compare` m2)
(NameG _ _ _) `compare` other = GT
data NameIs = Alone | Applied | Infix
showName :: Name -> String
showName = showName' Alone
showName' :: NameIs -> Name -> String
showName' ni nm
= case ni of
Alone -> nms
Applied
| pnam -> nms
| otherwise -> "(" ++ nms ++ ")"
Infix
| pnam -> "`" ++ nms ++ "`"
| otherwise -> nms
where
nms = case nm of
Name occ NameS -> occString occ
Name occ (NameQ m) -> modString m ++ "." ++ occString occ
Name occ (NameG ns p m) -> modString m ++ "." ++ occString occ
Name occ (NameU u) -> occString occ ++ "_" ++ show (I# u)
Name occ (NameL u) -> occString occ ++ "_" ++ show (I# u)
pnam = classify nms
classify "" = False
classify (x:xs) | isAlpha x || (x `elem` "_[]()") =
case dropWhile (/='.') xs of
(_:xs') -> classify xs'
[] -> True
| otherwise = False
instance Show Name where
show = showName
tupleDataName :: Int -> Name
tupleTypeName :: Int -> Name
tupleDataName 0 = mk_tup_name 0 DataName
tupleDataName 1 = error "tupleDataName 1"
tupleDataName n = mk_tup_name (n1) DataName
tupleTypeName 0 = mk_tup_name 0 TcClsName
tupleTypeName 1 = error "tupleTypeName 1"
tupleTypeName n = mk_tup_name (n1) TcClsName
mk_tup_name n_commas space
= Name occ (NameG space (mkPkgName "base") tup_mod)
where
occ = mkOccName ('(' : replicate n_commas ',' ++ ")")
tup_mod = mkModName "Data.Tuple"
data Info
= ClassI Dec
| ClassOpI
Name
Type
Name
Fixity
| TyConI Dec
| PrimTyConI
Name
Int
Bool
| DataConI
Name
Type
Name
Fixity
| VarI
Name
Type
(Maybe Dec)
Fixity
| TyVarI
Name
Type
deriving( Show, Data, Typeable )
data Fixity = Fixity Int FixityDirection
deriving( Eq, Show, Data, Typeable )
data FixityDirection = InfixL | InfixR | InfixN
deriving( Eq, Show, Data, Typeable )
maxPrecedence :: Int
maxPrecedence = (9::Int)
defaultFixity :: Fixity
defaultFixity = Fixity maxPrecedence InfixL
data Lit = CharL Char
| StringL String
| IntegerL Integer
| RationalL Rational
| IntPrimL Integer
| FloatPrimL Rational
| DoublePrimL Rational
deriving( Show, Eq, Data, Typeable )
data Pat
= LitP Lit
| VarP Name
| TupP [Pat]
| ConP Name [Pat]
| InfixP Pat Name Pat
| TildeP Pat
| AsP Name Pat
| WildP
| RecP Name [FieldPat]
| ListP [ Pat ]
| SigP Pat Type
deriving( Show, Eq, Data, Typeable )
type FieldPat = (Name,Pat)
data Match = Match Pat Body [Dec]
deriving( Show, Eq, Data, Typeable )
data Clause = Clause [Pat] Body [Dec]
deriving( Show, Eq, Data, Typeable )
data Exp
= VarE Name
| ConE Name
| LitE Lit
| AppE Exp Exp
| InfixE (Maybe Exp) Exp (Maybe Exp)
| LamE [Pat] Exp
| TupE [Exp]
| CondE Exp Exp Exp
| LetE [Dec] Exp
| CaseE Exp [Match]
| DoE [Stmt]
| CompE [Stmt]
| ArithSeqE Range
| ListE [ Exp ]
| SigE Exp Type
| RecConE Name [FieldExp]
| RecUpdE Exp [FieldExp]
deriving( Show, Eq, Data, Typeable )
type FieldExp = (Name,Exp)
data Body
= GuardedB [(Guard,Exp)]
| NormalB Exp
deriving( Show, Eq, Data, Typeable )
data Guard
= NormalG Exp
| PatG [Stmt]
deriving( Show, Eq, Data, Typeable )
data Stmt
= BindS Pat Exp
| LetS [ Dec ]
| NoBindS Exp
| ParS [[Stmt]]
deriving( Show, Eq, Data, Typeable )
data Range = FromR Exp | FromThenR Exp Exp
| FromToR Exp Exp | FromThenToR Exp Exp Exp
deriving( Show, Eq, Data, Typeable )
data Dec
= FunD Name [Clause]
| ValD Pat Body [Dec]
| DataD Cxt Name [Name]
[Con] [Name]
| NewtypeD Cxt Name [Name]
Con [Name]
| TySynD Name [Name] Type
| ClassD Cxt Name [Name] [FunDep] [Dec]
| InstanceD Cxt Type [Dec]
| SigD Name Type
| ForeignD Foreign
deriving( Show, Eq, Data, Typeable )
data FunDep = FunDep [Name] [Name]
deriving( Show, Eq, Data, Typeable )
data Foreign = ImportF Callconv Safety String Name Type
| ExportF Callconv String Name Type
deriving( Show, Eq, Data, Typeable )
data Callconv = CCall | StdCall
deriving( Show, Eq, Data, Typeable )
data Safety = Unsafe | Safe | Threadsafe
deriving( Show, Eq, Data, Typeable )
type Cxt = [Type]
data Strict = IsStrict | NotStrict
deriving( Show, Eq, Data, Typeable )
data Con = NormalC Name [StrictType]
| RecC Name [VarStrictType]
| InfixC StrictType Name StrictType
| ForallC [Name] Cxt Con
deriving( Show, Eq, Data, Typeable )
type StrictType = (Strict, Type)
type VarStrictType = (Name, Strict, Type)
data Type = ForallT [Name] Cxt Type
| VarT Name
| ConT Name
| TupleT Int
| ArrowT
| ListT
| AppT Type Type
deriving( Show, Eq, Data, Typeable )
cmpEq :: Ordering -> Bool
cmpEq EQ = True
cmpEq _ = False
thenCmp :: Ordering -> Ordering -> Ordering
thenCmp EQ o2 = o2
thenCmp o1 o2 = o1