ghc-session-0.1.0.1: src/Language/Haskell/Session/Hint/Eval.hs
---------------------------------------------------------------------------
-- Copyright (C) Flowbox, Inc - All Rights Reserved
-- Flowbox Team <contact@flowbox.io>, 2014
-- Proprietary and confidential
-- Unauthorized copying of this file, via any medium is strictly prohibited
---------------------------------------------------------------------------
{-# LANGUAGE MagicHash #-}
module Language.Haskell.Session.Hint.Eval (
interpret
) 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 = interpret'' expr typeStr where
typeStr = show $ Typeable.typeOf wit
interpret'' :: (GHC.GhcMonad m, Typeable a) => String -> String -> m a
interpret'' 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