-%
+2%
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
\section[TcSplice]{Template Haskell splices}
\begin{code}
-module TcSplice( tcSpliceExpr, tcSpliceDecls ) where
+module TcSplice( tcSpliceExpr, tcSpliceDecls, tcBracket ) where
#include "HsVersions.h"
import HscMain ( compileExpr )
-import TcRnDriver ( importSupportingDecls )
+import TcRnDriver ( importSupportingDecls, tcTopSrcDecls )
-- These imports are the reason that TcSplice
-- is very high up the module hierarchy
-import CompManager ( sandboxIO )
- -- Ditto, but this one could be defined muchlower down
-
import qualified Language.Haskell.THSyntax as Meta
import HscTypes ( HscEnv(..), GhciMode(..), PersistentCompilerState(..), unQualInScope )
+import HsSyn ( HsBracket(..) )
import Convert ( convertToHsExpr, convertToHsDecls )
import RnExpr ( rnExpr )
import RdrHsSyn ( RdrNameHsExpr, RdrNameHsDecl )
import TcExpr ( tcMonoExpr )
import TcHsSyn ( TcExpr, TypecheckedHsExpr, mkHsLet, zonkTopExpr )
import TcSimplify ( tcSimplifyTop )
-import TcType ( TcType )
+import TcType ( TcType, openTypeKind, mkAppTy )
import TcEnv ( spliceOK, tcMetaTy )
import TcRnTypes ( TopEnv(..) )
+import TcMType ( newTyVarTy )
import Name ( Name )
import TcRnMonad
import TysWiredIn ( mkListTy )
-import PrelNames ( exprTyConName, declTyConName )
+import DsMeta ( exprTyConName, declTyConName, decTyConName, qTyConName )
import Outputable
import GHC.Base ( unsafeCoerce# ) -- Should have a better home in the module hierarchy
\end{code}
%************************************************************************
\begin{code}
+tcBracket :: HsBracket Name -> TcM TcType
+tcBracket (ExpBr expr)
+ = newTyVarTy openTypeKind `thenM` \ any_ty ->
+ tcMonoExpr expr any_ty `thenM_`
+ tcMetaTy exprTyConName
+ -- Result type is Expr (= Q Exp)
+
+tcBracket (DecBr decls)
+ = tcTopSrcDecls decls `thenM_`
+ tcMetaTy decTyConName `thenM` \ decl_ty ->
+ tcMetaTy qTyConName `thenM` \ q_ty ->
+ returnM (mkAppTy q_ty (mkListTy decl_ty))
+ -- Result type is Q [Dec]
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection{Splicing an expression}
+%* *
+%************************************************************************
+
+\begin{code}
tcSpliceExpr name expr res_ty
= getStage `thenM` \ level ->
case spliceOK level of {
expr2 = convertToHsExpr simple_expr
in
traceTc (text "Got result" <+> ppr expr2) `thenM_`
+
+ showSplice "expression"
+ zonked_q_expr (ppr expr2) `thenM_`
initRn SourceMode (rnExpr expr2) `thenM` \ (exp3, fvs) ->
importSupportingDecls fvs `thenM` \ env ->
\begin{code}
-- Always at top level
tcSpliceDecls expr
- = tcMetaTy declTyConName `thenM` \ meta_dec_ty ->
+ = tcMetaTy decTyConName `thenM` \ meta_dec_ty ->
+ tcMetaTy qTyConName `thenM` \ meta_q_ty ->
setStage topSpliceStage (
- getLIE (tcMonoExpr expr (mkListTy meta_dec_ty))
+ getLIE (tcMonoExpr expr (mkAppTy meta_q_ty (mkListTy meta_dec_ty)))
) `thenM` \ (expr', lie) ->
-- Solve the constraints
tcSimplifyTop lie `thenM` \ const_binds ->
decls :: [RdrNameHsDecl]
decls = convertToHsDecls simple_expr
in
+ traceTc (text "Got result" <+> vcat (map ppr decls)) `thenM_`
+ showSplice "declarations"
+ zonked_q_expr (vcat (map ppr decls)) `thenM_`
returnM decls
\end{code}
-> TcM Meta.Exp -- Of type Exp
runMetaE e = runMeta e
-runMetaD :: TypecheckedHsExpr -- Of type (Q [Dec]
+runMetaD :: TypecheckedHsExpr -- Of type Q [Dec]
-> TcM [Meta.Dec] -- Of type [Dec]
runMetaD e = runMeta e
-runMeta :: TypecheckedHsExpr -- Of type (Q t)
+-- Warning: if Q is anything other than IO, we need to change this
+tcRunQ :: Meta.Q a -> TcM a
+tcRunQ thing = ioToTcRn thing
+
+
+runMeta :: TypecheckedHsExpr -- Of type X
-> TcM t -- Of type t
-runMeta expr :: TcM t
+runMeta expr
= getTopEnv `thenM` \ top_env ->
getEps `thenM` \ eps ->
getNameCache `thenM` \ name_cache ->
print_unqual = unQualInScope rdr_env
in
- if (ghci_mode == OneShot) then
- failWithTc (ptext SLIT("You must use --make or --interactive to run splice expressions"))
- -- The reason for this is that the demand-linker doesn't have
- -- enough information available to link all the things that
- -- are needed when you try to run a splice
- else
- ioToTcRn (do {
- -- Warning: if Q is anything other than IO, we may need to wrap
- -- the expression 'expr' in a runQ before compiling it
- hval <- HscMain.compileExpr hsc_env pcs this_mod print_unqual expr
-
- -- hval :: HValue
- -- Need to coerce it to IO t
- ; sandboxIO (unsafeCoerce# hval :: IO t) }) `thenM` \ either_tval ->
+ ioToTcRn (HscMain.compileExpr hsc_env pcs this_mod
+ print_unqual expr) `thenM` \ hval ->
+
+ tryM (tcRunQ (unsafeCoerce# hval)) `thenM` \ either_tval ->
case either_tval of
- Left err -> failWithTc (vcat [text "Exception when running compiled-time code:",
- nest 4 (text (show err))])
- Right v -> returnM v
+ Left exn -> failWithTc (vcat [text "Exception when running compile-time code:",
+ nest 4 (vcat [text "Code:" <+> ppr expr,
+ text ("Exn: " ++ show exn)])])
+ Right v -> returnM v
\end{code}
%************************************************************************
\begin{code}
+showSplice :: String -> TypecheckedHsExpr -> SDoc -> TcM ()
+showSplice what before after
+ = getSrcLocM `thenM` \ loc ->
+ traceSplice (vcat [ppr loc <> colon <+> text "Splicing" <+> text what,
+ nest 2 (sep [nest 2 (ppr before),
+ text "======>",
+ nest 2 after])])
+
illegalSplice level
= ptext SLIT("Illegal splice at level") <+> ppr level