Skip to content

Commit

Permalink
Add runStmt for executing IO statements and binding new names
Browse files Browse the repository at this point in the history
  • Loading branch information
HeinrichApfelmus authored and gelisam committed Sep 6, 2017
1 parent 555ed6c commit f10e357
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 2 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Daniel Wagner
Evan Laforge
Fernando Benavides
Gwern Branwen
Heinrich Apfelmus
Jean Philippe Bernardy
Jens Petersen
Mark Wright
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### Upcoming release

* Add `runStmt` for executing statements in the `IO` monad and binding new names.

### 0.7.0

* Support for GHC 8.2
Expand Down
7 changes: 7 additions & 0 deletions examples/example.hs
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,10 @@ testHint =
say "Here we evaluate an expression of type string, that when evaluated (again) leads to a string"
res <- interpret "head $ map show [\"Worked!\", \"Didn't work\"]" infer >>= flip interpret infer
say res
emptyLine
say "We can also execute statements in the IO monad and bind new names, e.g."
let stmts = ["x <- return 42", "print x"]
forM_ stmts $ \s -> do
say $ " " ++ s
runStmt s
emptyLine
30 changes: 29 additions & 1 deletion src/Hint/Eval.hs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
module Hint.Eval (
interpret, as, infer,
unsafeInterpret,
eval, parens
eval, runStmt,
parens
) where

import qualified GHC.Exts (unsafeCoerce#)

import Control.Exception

import Data.Typeable hiding (typeOf)
import qualified Data.Typeable (typeOf)

Expand Down Expand Up @@ -55,6 +58,31 @@ eval expr = do in_scope_show <- supportShow
let show_expr = unwords [in_scope_show, parens expr]
unsafeInterpret show_expr in_scope_String

-- | Evaluate a statement in the 'IO' monad, possibly binding new names.
--
-- Example:
--
-- > runStmt "x <- return 42"
-- > runStmt "print x"
runStmt :: (MonadInterpreter m) => String -> m ()
runStmt = mayFail . runGhc1 go
where
#if __GLASGOW_HASKELL__ >= 800
go statements = do
result <- GHC.execStmt statements GHC.execOptions
return $ case result of
GHC.ExecComplete { GHC.execResult = Right _ } -> Just ()
GHC.ExecComplete { GHC.execResult = Left e } -> throw e
_ -> Nothing
#else
go statements = do
result <- GHC.runStmt statements GHC.RunToCompletion
return $ case result of
GHC.RunOk _ -> Just ()
GHC.RunException e -> throw e
_ -> Nothing
#endif

-- | 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
Expand Down
2 changes: 1 addition & 1 deletion src/Language/Haskell/Interpreter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module Language.Haskell.Interpreter(
-- ** Type inference
typeOf, typeChecks, kindOf, normalizeType,
-- ** Evaluation
interpret, as, infer, eval,
interpret, as, infer, eval, runStmt,
-- * Error handling
InterpreterError(..), GhcError(..), MultipleInstancesNotAllowed(..),
-- * Miscellaneous
Expand Down

0 comments on commit f10e357

Please sign in to comment.