packages feed

egison-2.4.5: hs-src/Interpreter/egisoni.hs

module Main where
import Language.Egison.Core      -- Egison Interpreter
import Language.Egison.Parser
import Language.Egison.Types     -- Egison data types
import Language.Egison.Variables -- Egison variable operations
import System.Console.GetOpt
import Control.Monad.Error
import System.IO
import System.Environment
import System.Console.Haskeline
import System.Exit (ExitCode (..), exitWith, exitFailure)
import Text.Regex.Posix

main :: IO ()
main = do
  args <- getArgs
  let (actions, nonOpts, _) = getOpt Permute options args
  let opts = foldl (flip id) defaultOptions actions
  case opts of
    Options {optShowHelp = True} -> printHelp
    Options {optShowVersion = True} -> printVersionNumber
    Options {optPrompt = prompt, optShowBanner = bannerFlag} ->
      if null nonOpts
        then do if bannerFlag
                   then showBanner
                   else return ()
                runRepl prompt
                if bannerFlag
                  then showByebyeMessage
                  else return ()
        else do runOne $ nonOpts

data Options = Options {
    optShowVersion :: Bool,
    optShowHelp :: Bool,
    optShowBanner :: Bool,
    optPrompt :: String
    }

showUsage :: IO ()
showUsage = do
  putStrLn "egisonc: no input files"
  
defaultOptions :: Options
defaultOptions = Options {
    optShowVersion = False,
    optShowHelp = False,
    optShowBanner = True,
    optPrompt = "> "
    }

options :: [OptDescr (Options -> Options)]
options = [
  Option ['v', 'V'] ["version"]
    (NoArg (\opts -> opts {optShowVersion = True}))
    "show version number",
  Option ['h', '?'] ["help"]
    (NoArg (\opts -> opts {optShowHelp = True}))
    "show usage information",
  Option [] ["no-banner"]
    (NoArg (\opts -> opts {optShowBanner = False}))
    "show usage information",
  Option ['p'] ["prompt"]
    (ReqArg (\prompt opts -> opts {optPrompt = prompt})
            "String")
    "output file to write"
  ]

printVersionNumber :: IO ()
printVersionNumber = do
  putStrLn egisonVersion
  exitWith ExitSuccess

printHelp :: IO ()
printHelp = do
  putStrLn "Usage: egisonc [options] file"
  putStrLn ""
  putStrLn "Options:"
  putStrLn "  --help                Display this information"
  putStrLn "  --version             Display egison version information"
  putStrLn "  --no-banner           Don't show banner"
  putStrLn "  --prompt string       Set prompt of the interpreter"
  putStrLn ""
  exitWith ExitSuccess

-- 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 ())

-- |Start the REPL (interactive interpreter)
runRepl :: String -> IO ()
runRepl prompt = do
    env <- primitiveBindings
    _ <- loadLibraries env
    runInputT defaultSettings (loop env prompt "")
    where
        loop :: Env -> String -> String -> InputT IO ()
        loop env prompt2 input0 = do
            minput <- getInputLine prompt2
            case minput of
                Nothing -> return ()
                Just "" -> if input0 == ""
                             then loop env prompt2 ""
                             else loop env (take (length prompt) (repeat ' ')) (input0 ++ "\n")
                Just input -> do
                  let newInput = input0 ++ input
                  let eTopExpr = readTopExpr newInput
                  case eTopExpr of
                    Left e -> do
                      if show e =~ "unexpected end of input" -- Is this really OK?
                        then loop env (take (length prompt) (repeat ' ')) $ newInput ++ "\n"
                        else do liftIO $ putStrLn $ show e
                                loop env prompt ""
                    Right _ -> do
                      result <- liftIO (evalString env newInput)
                      if (length result) > 0
                        then do outputStrLn result
                                loop env prompt ""
                        else loop env prompt ""