egison-2.0.0: hs-src/Interpreter/egisoni.hs
module Main where
import Paths_egison
import Language.Egison.Core -- Egison Interpreter
import Language.Egison.Types -- Egison data types
import Language.Egison.Variables -- Egison variable operations
--import Control.Monad (when)
import Control.Monad.Error
import System.IO
import System.Environment
import System.Console.Haskeline
main :: IO ()
main = do args <- getArgs
if null args then do showBanner
runRepl
else runOne $ args
-- REPL Section
flushStr :: String -> IO ()
flushStr str = putStr str >> hFlush stdout
-- |Execute a single egison file from the command line
runOne :: [String] -> IO ()
runOne args = do
env <- primitiveBindings
-- Load standard library
_ <- loadLibraries env
result <- runIOThrows $ liftM show $ evalTopExpr env $ Load (args !! 0)
case result of
Just errMsg -> putStrLn errMsg
_ -> do
-- Call into (main) if it exists...
alreadyDefined <- liftIO $ isBound env ("main", [])
when alreadyDefined (do
mainResult <- runIOThrows $ liftM show $ evalMain env $ args
case mainResult of
Just errMsg -> putStrLn errMsg
_ -> return ())
-- |Load standard libraries into the given environment
loadLibraries :: Env -> IO ()
loadLibraries env = do
-- Load standard library
_ <- evalString env $ "(load \"lib/core/base.egi\")"
_ <- evalString env $ "(load \"lib/core/number.egi\")"
_ <- evalString env $ "(load \"lib/core/collection.egi\")"
return ()
-- |Start the REPL (interactive interpreter)
runRepl :: IO ()
runRepl = do
env <- primitiveBindings
_ <- loadLibraries env
runInputT defaultSettings (loop env "> " "")
where
loop :: Env -> String -> String -> InputT IO ()
loop env prompt input0 = do
minput <- getInputLine prompt
case minput of
Nothing -> liftIO showByebyeMessage
Just "" -> if input0 == ""
then loop env "> " ""
else loop env " " (input0 ++ "\n")
Just input ->
let newInput = input0 ++ input in
if (countParens newInput)
then do result <- liftIO (evalString env newInput)
if (length result) > 0
then do outputStrLn result
loop env "> " ""
else loop env "> " ""
else loop env " " newInput
countParens :: String -> Bool
countParens str = let countOpen = length $ filter ((==) '(') str in
let countClose = length $ filter ((==) ')') str in
(countOpen > 0) && (countOpen <= countClose)
-- End REPL Section
-- Begin Util section, of generic functions
{- Remove leading/trailing white space from a string; based on corresponding Python function
Code taken from: http://gimbo.org.uk/blog/2007/04/20/splitting-a-string-in-haskell/ -}
strip :: String -> String
strip s = dropWhile ws $ reverse $ dropWhile ws $ reverse s
where ws = (`elem` [' ', '\n', '\t', '\r'])
-- End Util