{-# LANGUAGE CPP               #-}
{-# LANGUAGE LambdaCase        #-}
{-# LANGUAGE OverloadedStrings #-}
{- |
Module      : HsLua.CLI
Copyright   : Copyright © 2017-2024 Albert Krewinkel
License     : MIT
Maintainer  : Albert Krewinkel <tarleb@hslua.org>

Embeddable Lua interpreter interface.
-}
module HsLua.CLI
  ( -- * Run scripts as program
    runStandalone
  , Settings (..)
  , EnvBehavior (..)
  ) where

import Control.Monad (unless, void, when, zipWithM_)
import Data.Bifunctor (first)
import Data.ByteString (ByteString)
import Data.Foldable (foldl')
import Data.Maybe (listToMaybe)
import Data.Text (Text)
import Foreign.C.String (withCString)
import HsLua.Core (LuaE, LuaError)
import HsLua.REPL (Config (..), defaultConfig, repl, setup)
import System.Console.GetOpt
import System.Environment (lookupEnv)
import qualified Lua.Constants as Lua
import qualified Lua.Primary as Lua
import qualified HsLua.Core as Lua
import qualified HsLua.Marshalling as Lua
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified HsLua.Core.Utf8 as UTF8

#ifndef _WINDOWS
import System.Posix.IO (stdOutput)
import System.Posix.Terminal (queryTerminal)
#endif

-- | Whether the program is connected to a terminal
istty :: IO Bool
#ifdef _WINDOWS
istty = pure True
#else
istty :: IO Bool
istty = Fd -> IO Bool
queryTerminal Fd
stdOutput
#endif

-- | Settings for the Lua command line interface.
--
-- If env vars should be ignored, and the interpreter invokes
-- @openlibs@, then the registry key @LUA_NOENV@ should be set to @true@
-- before that function is invoked. E.g.:
--
-- > runner envBehavior action = run $ do
-- >   when (envBehavior == IgnoreEnvVars) $ do
-- >     pushboolean True
-- >     setfield registryindex "LUA_NOENV"
-- >   openlibs
-- >   action
--
data Settings e = Settings
  { forall e. Settings e -> Text
settingsVersionInfo :: Text
    -- ^ Additional version info to present to the user. The current
    -- Lua version will always be printed.
  , forall e. Settings e -> EnvBehavior -> LuaE e () -> IO ()
settingsRunner      :: EnvBehavior -> LuaE e () -> IO ()
    -- ^ The Lua interpreter to be used; the first argument indicates
    -- whether environment variables should be consulted or ignored.
  , forall e. Settings e -> Maybe String
settingsHistory     :: Maybe FilePath
  }

-- | Whether environment variables should be consulted or ignored.
data EnvBehavior = IgnoreEnvVars | ConsultEnvVars
  deriving (EnvBehavior -> EnvBehavior -> Bool
(EnvBehavior -> EnvBehavior -> Bool)
-> (EnvBehavior -> EnvBehavior -> Bool) -> Eq EnvBehavior
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EnvBehavior -> EnvBehavior -> Bool
== :: EnvBehavior -> EnvBehavior -> Bool
$c/= :: EnvBehavior -> EnvBehavior -> Bool
/= :: EnvBehavior -> EnvBehavior -> Bool
Eq, Int -> EnvBehavior -> ShowS
[EnvBehavior] -> ShowS
EnvBehavior -> String
(Int -> EnvBehavior -> ShowS)
-> (EnvBehavior -> String)
-> ([EnvBehavior] -> ShowS)
-> Show EnvBehavior
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EnvBehavior -> ShowS
showsPrec :: Int -> EnvBehavior -> ShowS
$cshow :: EnvBehavior -> String
show :: EnvBehavior -> String
$cshowList :: [EnvBehavior] -> ShowS
showList :: [EnvBehavior] -> ShowS
Show)

-- | Get the Lua interpreter options from the command line. Throws an
-- error with usage instructions if parsing fails.
getOptions :: String -> [String] -> IO Options
getOptions :: String -> [String] -> IO Options
getOptions String
progName [String]
rawArgs = do
  let ([Options -> Options]
actions, [String]
args, [String]
errs) = ArgOrder (Options -> Options)
-> [OptDescr (Options -> Options)]
-> [String]
-> ([Options -> Options], [String], [String])
forall a.
ArgOrder a -> [OptDescr a] -> [String] -> ([a], [String], [String])
getOpt ArgOrder (Options -> Options)
forall a. ArgOrder a
RequireOrder [OptDescr (Options -> Options)]
luaOptions [String]
rawArgs
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
errs) (IO () -> IO ()) -> (String -> IO ()) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IOError -> IO ()
forall a. IOError -> IO a
ioError (IOError -> IO ()) -> (String -> IOError) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IOError
userError (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
    let usageHead :: String
usageHead = String
"Usage: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
progName String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" [options] [script [args]]"
    in [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String]
errs String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [OptDescr (Options -> Options)] -> String
forall a. String -> [OptDescr a] -> String
usageInfo String
usageHead [OptDescr (Options -> Options)]
luaOptions

  let (Maybe String
mscript, [String]
arg) = ([String] -> Maybe String)
-> ([String], [String]) -> (Maybe String, [String])
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first [String] -> Maybe String
forall a. [a] -> Maybe a
listToMaybe (([String], [String]) -> (Maybe String, [String]))
-> ([String], [String]) -> (Maybe String, [String])
forall a b. (a -> b) -> a -> b
$ Int -> [String] -> ([String], [String])
forall a. Int -> [a] -> ([a], [a])
splitAt Int
1 [String]
args
  let opts :: Options
opts = (Options -> (Options -> Options) -> Options)
-> Options -> [Options -> Options] -> Options
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (((Options -> Options) -> Options -> Options)
-> Options -> (Options -> Options) -> Options
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Options -> Options) -> Options -> Options
forall a b. (a -> b) -> a -> b
($)) Options
defaultLuaOpts [Options -> Options]
actions
  Options -> IO Options
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Options
opts
    { optScript = mscript
    , optScriptArgs = arg
    , optProgName = progName
    , optAllArgs = rawArgs
    }

-- | Print version information to the terminal.
showVersion :: LuaError e => Text -> LuaE e ()
showVersion :: forall e. LuaError e => Text -> LuaE e ()
showVersion Text
extraInfo = do
  Type
_ <- Name -> LuaE e Type
forall e. LuaError e => Name -> LuaE e Type
Lua.getglobal Name
"_VERSION"
  Text
versionString <- Peek e Text -> LuaE e Text
forall e a. LuaError e => Peek e a -> LuaE e a
Lua.forcePeek (Peek e Text -> LuaE e Text) -> Peek e Text -> LuaE e Text
forall a b. (a -> b) -> a -> b
$ Peeker e Text
forall e. Peeker e Text
Lua.peekText StackIndex
Lua.top Peek e Text -> LuaE e () -> Peek e Text
forall e a b. Peek e a -> LuaE e b -> Peek e a
`Lua.lastly` Int -> LuaE e ()
forall e. Int -> LuaE e ()
Lua.pop Int
1
  IO () -> LuaE e ()
forall a. IO a -> LuaE e a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
Lua.liftIO (IO () -> LuaE e ()) -> (Text -> IO ()) -> Text -> LuaE e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> IO ()
T.putStrLn (Text -> LuaE e ()) -> Text -> LuaE e ()
forall a b. (a -> b) -> a -> b
$ Text
versionString Text -> Text -> Text
`T.append` Text
extraInfo

-- | Runs code given on the command line
runCode :: LuaError e => LuaCode -> LuaE e ()
runCode :: forall e. LuaError e => LuaCode -> LuaE e ()
runCode = \case
  ExecuteCode ByteString
stat -> do
    Status
status <- ByteString -> LuaE e Status
forall e. ByteString -> LuaE e Status
Lua.dostringTrace ByteString
stat
    Bool -> LuaE e () -> LuaE e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Status
status Status -> Status -> Bool
forall a. Eq a => a -> a -> Bool
/= Status
Lua.OK)
      LuaE e ()
forall e a. LuaError e => LuaE e a
Lua.throwErrorAsException
  RequireModule Name
g Name
mod' -> do
    Type
_ <- Name -> LuaE e Type
forall e. LuaError e => Name -> LuaE e Type
Lua.getglobal Name
"require"
    Name -> LuaE e ()
forall e. Name -> LuaE e ()
Lua.pushName Name
mod'
    Status
status <- NumArgs -> NumResults -> LuaE e Status
forall e. NumArgs -> NumResults -> LuaE e Status
Lua.pcallTrace NumArgs
1 NumResults
1
    if Status
status Status -> Status -> Bool
forall a. Eq a => a -> a -> Bool
== Status
Lua.OK
      then Name -> LuaE e ()
forall e. LuaError e => Name -> LuaE e ()
Lua.setglobal Name
g
      else LuaE e ()
forall e a. LuaError e => LuaE e a
Lua.throwErrorAsException

--
-- Standalone
--

-- | Uses the first command line argument as the name of a script file
-- and tries to run that script in Lua. Falls back to stdin if no file
-- is given. Any remaining args are passed to Lua via the global table
-- @arg@.
runStandalone :: LuaError e
              => Settings e   -- ^ interpreter configuration
              -> String       -- ^ program name (for error messages)
              -> [String]     -- ^ command line arguments
              -> IO ()
runStandalone :: forall e. LuaError e => Settings e -> String -> [String] -> IO ()
runStandalone Settings e
settings String
progName [String]
args = do
  Options
opts <- String -> [String] -> IO Options
getOptions String
progName [String]
args
  let envVarOpt :: EnvBehavior
envVarOpt = if Options -> Bool
optNoEnv Options
opts
                  then EnvBehavior
IgnoreEnvVars
                  else EnvBehavior
ConsultEnvVars
  Settings e -> EnvBehavior -> LuaE e () -> IO ()
forall e. Settings e -> EnvBehavior -> LuaE e () -> IO ()
settingsRunner Settings e
settings EnvBehavior
envVarOpt (LuaE e () -> IO ()) -> LuaE e () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    -- print version info
    Bool -> LuaE e () -> LuaE e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Options -> Bool
optVersion Options
opts) (Text -> LuaE e ()
forall e. LuaError e => Text -> LuaE e ()
showVersion (Text -> LuaE e ()) -> Text -> LuaE e ()
forall a b. (a -> b) -> a -> b
$ Settings e -> Text
forall e. Settings e -> Text
settingsVersionInfo Settings e
settings)

    -- push `arg` table
    case Options -> Maybe String
optScript Options
opts of
      Just String
_script -> do
        let setField :: Integer -> String -> LuaE e ()
setField Integer
i String
x = String -> LuaE e ()
forall e. String -> LuaE e ()
Lua.pushString String
x LuaE e () -> LuaE e () -> LuaE e ()
forall a b. LuaE e a -> LuaE e b -> LuaE e b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> StackIndex -> Integer -> LuaE e ()
forall e. LuaError e => StackIndex -> Integer -> LuaE e ()
Lua.rawseti (CInt -> StackIndex
Lua.nth CInt
2) Integer
i
        let nprogargs :: Int
nprogargs = [String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Options -> [String]
optAllArgs Options
opts) Int -> Int -> Int
forall a. Num a => a -> a -> a
- [String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Options -> [String]
optScriptArgs Options
opts)
        let arg :: [String]
arg = Options -> String
optProgName Options
opts String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Options -> [String]
optAllArgs Options
opts
        LuaE e ()
forall e. LuaE e ()
Lua.newtable
        (Integer -> String -> LuaE e ())
-> [Integer] -> [String] -> LuaE e ()
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> m c) -> [a] -> [b] -> m ()
zipWithM_ Integer -> String -> LuaE e ()
forall {e}. LuaError e => Integer -> String -> LuaE e ()
setField [-(Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nprogargs)..] [String]
arg
      Maybe String
Nothing -> do
        (String -> LuaE e ()) -> [String] -> LuaE e ()
forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
Lua.pushList String -> LuaE e ()
forall e. String -> LuaE e ()
Lua.pushString (Options -> [String]
optAllArgs Options
opts)
        String -> LuaE e ()
forall e. String -> LuaE e ()
Lua.pushString (Options -> String
optProgName Options
opts)
        StackIndex -> Integer -> LuaE e ()
forall e. LuaError e => StackIndex -> Integer -> LuaE e ()
Lua.rawseti (CInt -> StackIndex
Lua.nth CInt
2) Integer
0
    Name -> LuaE e ()
forall e. LuaError e => Name -> LuaE e ()
Lua.setglobal Name
"arg"

    Bool -> LuaE e () -> LuaE e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Options -> Bool
optWarnings Options
opts) (LuaE e () -> LuaE e ()) -> LuaE e () -> LuaE e ()
forall a b. (a -> b) -> a -> b
$ do
      State
l <- LuaE e State
forall e. LuaE e State
Lua.state
      -- turn warnings on
      IO () -> LuaE e ()
forall a. IO a -> LuaE e a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
Lua.liftIO (IO () -> LuaE e ()) -> IO () -> LuaE e ()
forall a b. (a -> b) -> a -> b
$ String -> (CString -> IO ()) -> IO ()
forall a. String -> (CString -> IO a) -> IO a
withCString String
"@on" ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \CString
w -> State -> CString -> LuaBool -> IO ()
Lua.lua_warning State
l CString
w LuaBool
Lua.FALSE

    -- Run init code.
    Bool -> LuaE e () -> LuaE e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Options -> Bool
optNoEnv Options
opts) (LuaE e () -> LuaE e ()) -> LuaE e () -> LuaE e ()
forall a b. (a -> b) -> a -> b
$ do
      Maybe String
init' <- IO (Maybe String) -> LuaE e (Maybe String)
forall a. IO a -> LuaE e a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
Lua.liftIO (IO (Maybe String) -> LuaE e (Maybe String))
-> IO (Maybe String) -> LuaE e (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> IO (Maybe String)
lookupEnv String
"LUA_INIT"
      (case Maybe String
init' of
         Just (Char
'@' : String
filename) -> Maybe String -> LuaE e Status
forall e. Maybe String -> LuaE e Status
Lua.dofileTrace (String -> Maybe String
forall a. a -> Maybe a
Just String
filename)
         Just String
cmd              -> ByteString -> LuaE e Status
forall e. ByteString -> LuaE e Status
Lua.dostring (String -> ByteString
UTF8.fromString String
cmd)
         Maybe String
Nothing               -> Status -> LuaE e Status
forall a. a -> LuaE e a
forall (m :: * -> *) a. Monad m => a -> m a
return Status
Lua.OK)
        LuaE e Status -> (Status -> LuaE e ()) -> LuaE e ()
forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Status
Lua.OK -> () -> LuaE e ()
forall a. a -> LuaE e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
        Status
_      -> LuaE e ()
forall e a. LuaError e => LuaE e a
Lua.throwErrorAsException

    -- run code statements and module loading instructions
    (LuaCode -> LuaE e ()) -> [LuaCode] -> LuaE e ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ LuaCode -> LuaE e ()
forall e. LuaError e => LuaCode -> LuaE e ()
runCode ([LuaCode] -> [LuaCode]
forall a. [a] -> [a]
reverse ([LuaCode] -> [LuaCode]) -> [LuaCode] -> [LuaCode]
forall a b. (a -> b) -> a -> b
$ Options -> [LuaCode]
optExecute Options
opts)

    let nargs :: NumArgs
nargs = Int -> NumArgs
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> NumArgs) -> ([String] -> Int) -> [String] -> NumArgs
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([String] -> NumArgs) -> [String] -> NumArgs
forall a b. (a -> b) -> a -> b
$ Options -> [String]
optScriptArgs Options
opts
    let startREPL :: LuaE e ()
startREPL = do
          Config -> LuaE e ()
forall e. Config -> LuaE e ()
setup Config
defaultConfig
            { replHistory = settingsHistory settings
            , replInfo = replInfo defaultConfig `T.append`
                         settingsVersionInfo settings
            }
          LuaE e NumResults -> LuaE e ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void LuaE e NumResults
forall e. LuaError e => LuaE e NumResults
repl
    let handleScriptResult :: Status -> LuaE e ()
handleScriptResult = \case
          Status
Lua.OK -> do
            (String -> LuaE e ()) -> [String] -> LuaE e ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ String -> LuaE e ()
forall e. String -> LuaE e ()
Lua.pushString (Options -> [String]
optScriptArgs Options
opts)
            Status
status <- NumArgs -> NumResults -> LuaE e Status
forall e. NumArgs -> NumResults -> LuaE e Status
Lua.pcallTrace NumArgs
nargs NumResults
Lua.multret
            Bool -> LuaE e () -> LuaE e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Status
status Status -> Status -> Bool
forall a. Eq a => a -> a -> Bool
/= Status
Lua.OK)
              LuaE e ()
forall e a. LuaError e => LuaE e a
Lua.throwErrorAsException
            Bool -> LuaE e () -> LuaE e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Options -> Bool
optInteractive Options
opts)
              LuaE e ()
startREPL
          Status
_      -> LuaE e ()
forall e a. LuaError e => LuaE e a
Lua.throwErrorAsException
    Bool
tty <- IO Bool -> LuaE e Bool
forall a. IO a -> LuaE e a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
Lua.liftIO IO Bool
istty
    case Options -> Maybe String
optScript Options
opts of
      Just String
"-" ->  -- load from stdin
        Maybe String -> LuaE e Status
forall e. Maybe String -> LuaE e Status
Lua.loadfile Maybe String
forall a. Maybe a
Nothing LuaE e Status -> (Status -> LuaE e ()) -> LuaE e ()
forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Status -> LuaE e ()
handleScriptResult
      Just String
script ->
        Maybe String -> LuaE e Status
forall e. Maybe String -> LuaE e Status
Lua.loadfile (String -> Maybe String
forall a. a -> Maybe a
Just String
script) LuaE e Status -> (Status -> LuaE e ()) -> LuaE e ()
forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Status -> LuaE e ()
handleScriptResult
      Maybe String
_ | Options -> Bool
optInteractive Options
opts -> do
        LuaE e ()
startREPL
      Maybe String
_ | Options -> Bool
optVersion Options
opts Bool -> Bool -> Bool
|| Bool -> Bool
not ([LuaCode] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Options -> [LuaCode]
optExecute Options
opts)) ->
        () -> LuaE e ()
forall a. a -> LuaE e a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
      Maybe String
_ | Bool
tty -> do
        LuaE e ()
startREPL
      Maybe String
_ -> do
        -- load script from stdin
        Maybe String -> LuaE e Status
forall e. Maybe String -> LuaE e Status
Lua.loadfile Maybe String
forall a. Maybe a
Nothing LuaE e Status -> (Status -> LuaE e ()) -> LuaE e ()
forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Status -> LuaE e ()
handleScriptResult

-- | Code to execute on startup.
data LuaCode =
    ExecuteCode ByteString
  | RequireModule Lua.Name Lua.Name

-- | Lua runner command line options.
data Options = Options
  { Options -> Bool
optNoEnv       :: Bool          -- ^ Ignore environment variables
  , Options -> Bool
optInteractive :: Bool          -- ^ Interactive
  , Options -> Bool
optVersion     :: Bool          -- ^ Show version info
  , Options -> Bool
optWarnings    :: Bool          -- ^ Whether warnings are enabled
  , Options -> [LuaCode]
optExecute     :: [LuaCode]     -- ^ code to execute, in reverse order
  , Options -> String
optProgName    :: String        -- ^ program name
  , Options -> [String]
optAllArgs     :: [String]      -- ^ all arguments
  , Options -> Maybe String
optScript      :: Maybe String  -- ^ script name, if any
  , Options -> [String]
optScriptArgs  :: [String]      -- ^ arguments passed to the script
  }

defaultLuaOpts :: Options
defaultLuaOpts :: Options
defaultLuaOpts = Options
  { optNoEnv :: Bool
optNoEnv = Bool
False
  , optInteractive :: Bool
optInteractive = Bool
False
  , optVersion :: Bool
optVersion = Bool
False
  , optWarnings :: Bool
optWarnings = Bool
False
  , optExecute :: [LuaCode]
optExecute = [LuaCode]
forall a. Monoid a => a
mempty
  , optProgName :: String
optProgName = String
forall a. Monoid a => a
mempty
  , optAllArgs :: [String]
optAllArgs = [String]
forall a. Monoid a => a
mempty
  , optScript :: Maybe String
optScript = Maybe String
forall a. Maybe a
Nothing
  , optScriptArgs :: [String]
optScriptArgs = [String]
forall a. Monoid a => a
mempty
  }

-- | Lua command line options.
luaOptions :: [OptDescr (Options -> Options)]
luaOptions :: [OptDescr (Options -> Options)]
luaOptions =
  [ String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"e" []
    (((String -> Options -> Options)
 -> String -> ArgDescr (Options -> Options))
-> String
-> (String -> Options -> Options)
-> ArgDescr (Options -> Options)
forall a b c. (a -> b -> c) -> b -> a -> c
flip (String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg String
"stat" ((String -> Options -> Options) -> ArgDescr (Options -> Options))
-> (String -> Options -> Options) -> ArgDescr (Options -> Options)
forall a b. (a -> b) -> a -> b
$ \String
stat Options
opt ->
        let code :: LuaCode
code = ByteString -> LuaCode
ExecuteCode (ByteString -> LuaCode) -> ByteString -> LuaCode
forall a b. (a -> b) -> a -> b
$ String -> ByteString
UTF8.fromString String
stat
        in Options
opt{ optExecute = code:optExecute opt })
    String
"execute string 'stat'"

  , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"i" []
    ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg ((Options -> Options) -> ArgDescr (Options -> Options))
-> (Options -> Options) -> ArgDescr (Options -> Options)
forall a b. (a -> b) -> a -> b
$ \Options
opt -> Options
opt { optInteractive = True })
    String
"interactive mode -- currently not supported"

  , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"l" []
    (((String -> Options -> Options)
 -> String -> ArgDescr (Options -> Options))
-> String
-> (String -> Options -> Options)
-> ArgDescr (Options -> Options)
forall a b c. (a -> b -> c) -> b -> a -> c
flip (String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg String
"mod" ((String -> Options -> Options) -> ArgDescr (Options -> Options))
-> (String -> Options -> Options) -> ArgDescr (Options -> Options)
forall a b. (a -> b) -> a -> b
$ \String
mod' Options
opt ->
      let toName :: String -> Name
toName = ByteString -> Name
Lua.Name (ByteString -> Name) -> (String -> ByteString) -> String -> Name
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
UTF8.fromString
          code :: LuaCode
code = case (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'=') String
mod' of
            (String
glb, Char
'=':String
m)  -> Name -> Name -> LuaCode
RequireModule (String -> Name
toName String
glb) (String -> Name
toName String
m)
            (String
glb, String
_    )  -> Name -> Name -> LuaCode
RequireModule (String -> Name
toName String
glb) (String -> Name
toName String
glb)
      in Options
opt{ optExecute = code:optExecute opt })
    ([String] -> String
unlines
     [ String
"require library 'mod' into global 'mod';"
     , String
"if 'mod' has the pattern 'g=module', then"
     , String
"require library 'module' into global 'g'"
     ])

  , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"v" []
    ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg ((Options -> Options) -> ArgDescr (Options -> Options))
-> (Options -> Options) -> ArgDescr (Options -> Options)
forall a b. (a -> b) -> a -> b
$ \Options
opt -> Options
opt { optVersion = True })
    String
"show version information"

  , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"E" []
    ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg ((Options -> Options) -> ArgDescr (Options -> Options))
-> (Options -> Options) -> ArgDescr (Options -> Options)
forall a b. (a -> b) -> a -> b
$ \Options
opt -> Options
opt { optNoEnv = True })
    String
"ignore environment variables -- partially supported"

  , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"W" []
    ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg ((Options -> Options) -> ArgDescr (Options -> Options))
-> (Options -> Options) -> ArgDescr (Options -> Options)
forall a b. (a -> b) -> a -> b
$ \Options
opt -> Options
opt { optWarnings = True })
    String
"turn warnings on -- currently not supported"
  ]