{-# LANGUAGE MagicHash #-} module Language.Haskell.Session.Hint.Eval ( interpret, interpretTyped, ) where import Data.Typeable (Typeable) import qualified Data.Typeable as Typeable import qualified GHC import qualified GHC.Exts as Exts import qualified Language.Haskell.Session.Hint.Util as Util interpret :: (GHC.GhcMonad m, Typeable a) => String -> m a interpret expr = interpret' expr wit where wit :: a wit = undefined -- | Evaluates an expression, given a witness for its monomorphic type. interpret' :: (GHC.GhcMonad m, Typeable a) => String -> a -> m a interpret' expr wit = interpretTyped expr typeStr where typeStr = show $ Typeable.typeOf wit interpretTyped :: GHC.GhcMonad m => String -> String -> m a interpretTyped expr typeStr = do let typedExpr = concat [parens expr, " :: ", typeStr] exprVal <- GHC.compileExpr typedExpr return (Exts.unsafeCoerce# exprVal :: a) -- | Conceptually, @parens s = \"(\" ++ s ++ \")\"@, where s is any valid haskell -- expression. In practice, it is harder than this. -- Observe that if @s@ ends with a trailing comment, then @parens s@ would -- be a malformed expression. The straightforward solution for this is to -- put the closing parenthesis in a different line. However, now we are -- messing with the layout rules and we don't know where @s@ is going to -- be used! -- Solution: @parens s = \"(let {foo =\n\" ++ s ++ \"\\n ;} in foo)\"@ where @foo@ does not occur in @s@ parens :: String -> String parens s = concat ["(let {", foo, " =\n", s, "\n", " ;} in ", foo, ")"] where foo = Util.safeBndFor s