packages feed

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