packages feed

berp-0.0.1: src/Berp/Interpreter/Repl.hs

-----------------------------------------------------------------------------
-- |
-- Module      : Berp.Interpreter.Repl
-- Copyright   : (c) 2010 Bernie Pope
-- License     : BSD-style
-- Maintainer  : florbitous@gmail.com
-- Stability   : experimental
-- Portability : ghc
--
-- The Read Eval Print Loop (REPL) of the interpreter.
--
-----------------------------------------------------------------------------

module Berp.Interpreter.Repl (repl) where

import MonadUtils
import HscTypes (liftGhcT)
import Control.Monad.Trans (lift)
import GHC
   ( defaultErrorHandler, getSessionDynFlags, setSessionDynFlags
   , findModule, mkModuleName, setContext, SingleStep (RunToCompletion)
   , runStmt, gcatch, RunResult (..))
import Control.Monad (when)
import Control.Exception.Extensible (SomeException (..))
import GHC.Paths (libdir)
import DynFlags (defaultDynFlags)
import System.IO (hSetBuffering, stdout, BufferMode (..))
import Language.Python.Version3.Parser (parseStmt)
-- import Language.Python.Common.PrettyParseError 
import Language.Python.Common.Pretty (prettyText)
import Language.Python.Common.AST (StatementSpan)
import Language.Haskell.Exts.Pretty 
   ( prettyPrintStyleMode, defaultMode, style, Style (..), PPHsMode (..)
   , Mode (..), PPLayout (PPSemiColon))
import Language.Haskell.Exts.Build (app, qualStmt) 
import Language.Haskell.Exts.Syntax (Stmt) 
import Berp.Version (version)
import Berp.Compile.Compile (compile)
import Berp.Compile.PrimName as Prim (interpretStmt, init)
import Berp.Compile.PySyntaxUtils (InterpreterStmt (..))
import Berp.Interpreter.Monad (Repl, runRepl)
import Berp.Interpreter.Input (getInputLines)
 
repl :: IO ()
repl = do
    hSetBuffering stdout NoBuffering
    greeting
    defaultErrorHandler defaultDynFlags $ do
      runRepl (Just libdir) $ do
         dflags <- getSessionDynFlags
         setSessionDynFlags dflags
         -- target <- guessTarget "test_main.hs" Nothing
         -- setTargets [target]
         -- load LoadAllTargets
         -- prel_mod <- findModule (mkModuleName "Prelude") Nothing
         berp_base_mod <- findModule (mkModuleName "Berp.Base") Nothing
         -- setContext [] [prel_mod, berp_base_mod]
         setContext [] [berp_base_mod]
         replLoop

greeting :: IO ()
greeting = putStrLn $ "Berp version " ++ version ++ ", type control-d to exit."

replLoop :: Repl ()
replLoop = do
   maybeInput <- getInputLines
   case maybeInput of 
      Nothing -> return () 
      Just input -> do
         when (not $ null input) $ do
            pyStmts <- liftIO $ parseAndCheckErrors (input ++ "\n")
            when (not $ null pyStmts) $ do
               stmts <- liftGhcT $ lift $ compile $ InterpreterStmt pyStmts
               let finalStmt = qualStmt (app Prim.interpretStmt Prim.init)
               let stmtStrs = map oneLinePrinter (stmts ++ [finalStmt])
               -- liftIO $ mapM_ putStrLn stmtStrs
               mapM_ runAndCatch stmtStrs
         replLoop

runAndCatch :: String -> Repl ()
runAndCatch stmt = do 
   gcatch (runStmt stmt RunToCompletion >>= printRunResult) catcher
   where
   catcher :: SomeException -> Repl ()
   catcher e = liftIO $ print e 

printRunResult :: RunResult -> Repl ()
printRunResult (RunException e) = liftIO $ putStrLn ("Exception " ++ show e)
printRunResult _other = return () 

oneLinePrinter :: Stmt -> String
oneLinePrinter = 
   prettyPrintStyleMode newStyle newMode
   where
   newStyle = style { mode = OneLineMode } 
   newMode = defaultMode { layout = PPSemiColon }

parseAndCheckErrors :: String -> IO [StatementSpan]
parseAndCheckErrors fileContents =
   case parseStmt fileContents "<stdin>" of
      Left e -> (putStrLn $ prettyText e) >> return [] 
      Right (pyStmt, _comments) -> return pyStmt