module Mueval.ArgsParse (Options (..), interpreterOpts) where

import Control.Monad (liftM)
import System.Console.GetOpt

import Mueval.Context (defaultModules, defaultPackages)

-- | See the results of --help for information on what each option means.
data Options = Options
    { Options -> Int
timeLimit :: Int
    , Options -> Maybe [String]
modules :: Maybe [String]
    , Options -> String
expression :: String
    , Options -> String
loadFile :: String
    , Options -> String
user :: String
    , Options -> Bool
printType :: Bool
    , Options -> Bool
typeOnly :: Bool
    , Options -> Bool
extensions :: Bool
    , Options -> [String]
namedExtensions :: [String]
    , Options -> Bool
noImports :: Bool
    , Options -> Bool
rLimits :: Bool
    , Options -> Bool
packageTrust :: Bool
    , Options -> [String]
trustedPackages :: [String]
    , Options -> Bool
help :: Bool
    }
    deriving (Int -> Options -> ShowS
[Options] -> ShowS
Options -> String
(Int -> Options -> ShowS)
-> (Options -> String) -> ([Options] -> ShowS) -> Show Options
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Options -> ShowS
showsPrec :: Int -> Options -> ShowS
$cshow :: Options -> String
show :: Options -> String
$cshowList :: [Options] -> ShowS
showList :: [Options] -> ShowS
Show)

defaultOptions :: Options
defaultOptions :: Options
defaultOptions =
    Options
        { expression :: String
expression = String
""
        , modules :: Maybe [String]
modules = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [String]
defaultModules
        , timeLimit :: Int
timeLimit = Int
5
        , user :: String
user = String
""
        , loadFile :: String
loadFile = String
""
        , printType :: Bool
printType = Bool
False
        , typeOnly :: Bool
typeOnly = Bool
False
        , extensions :: Bool
extensions = Bool
False
        , namedExtensions :: [String]
namedExtensions = []
        , noImports :: Bool
noImports = Bool
False
        , rLimits :: Bool
rLimits = Bool
False
        , packageTrust :: Bool
packageTrust = Bool
False
        , trustedPackages :: [String]
trustedPackages = [String]
defaultPackages
        , help :: Bool
help = Bool
False
        }

options :: [OptDescr (Options -> Options)]
options :: [OptDescr (Options -> Options)]
options =
    [ String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"p"
        [String
"password"]
        ((String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
u Options
opts -> Options
opts{user = u}) String
"PASSWORD")
        String
"The password for the mubot account. If this is set, mueval will attempt to setuid to the mubot user. This is optional, as it requires the mubot user to be set up properly. (Currently a null-op.)"
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"t"
        [String
"time-limit"]
        ((String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
t Options
opts -> Options
opts{timeLimit = read t :: Int}) String
"TIME")
        String
"Time limit for compilation and evaluation"
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"l"
        [String
"load-file"]
        ((String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
e Options
opts -> Options
opts{loadFile = e}) String
"FILE")
        String
"A local file for Mueval to load, providing definitions. Contents are trusted! Do not put anything dubious in it!"
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"m"
        [String
"module"]
        ((String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
m Options
opts -> Options
opts{modules = liftM (m :) (modules opts)}) String
"MODULE")
        String
"A module we should import functions from for evaluation. (Can be given multiple times.)"
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"n"
        [String
"no-imports"]
        ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg (\Options
opts -> Options
opts{noImports = True}))
        String
"Whether to import any default modules, such as Prelude; this is useful if you are loading a file which, say, redefines Prelude operators. This can be subverted by using --load-file."
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"E"
        [String
"Extensions"]
        ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg (\Options
opts -> Options
opts{extensions = True}))
        String
"Whether to enable the Glasgow extensions to Haskell '98. Defaults to false, but enabling is useful for QuickCheck."
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"X"
        [String
"extension"]
        ((String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
e Options
opts -> Options
opts{namedExtensions = e : namedExtensions opts}) String
"EXTENSION")
        String
"Pass additional flags enabling extensions just like you would to ghc. Example: -XViewPatterns"
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"e"
        [String
"expression"]
        ((String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
e Options
opts -> Options
opts{expression = e}) String
"EXPRESSION")
        String
"The expression to be evaluated."
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"i"
        [String
"inferred-type"]
        ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg (\Options
opts -> Options
opts{printType = True}))
        String
"Whether to enable printing of inferred type and the expression (as Mueval sees it). Defaults to false."
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"T"
        [String
"type-only"]
        ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg (\Options
opts -> Options
opts{typeOnly = True}))
        String
"Only print the expression and type, don't evaluate the expression. Defaults to false."
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"r"
        [String
"resource-limits"]
        ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg (\Options
opts -> Options
opts{rLimits = True}))
        String
"Enable resource limits (using POSIX rlimits). Mueval does not by default since rlimits are broken on many systems."
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"S"
        [String
"package-trust"]
        ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg (\Options
opts -> Options
opts{packageTrust = True, namedExtensions = "Safe" : namedExtensions opts}))
        String
"Enable Safe-Haskell package trust system"
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"s"
        [String
"trust"]
        ((String -> Options -> Options)
-> String -> ArgDescr (Options -> Options)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
e Options
opts -> Options
opts{trustedPackages = e : trustedPackages opts}) String
"PACKAGE")
        String
"Specify a package to be trusted by Safe Haskell (ignored unless -S also present)"
    , String
-> [String]
-> ArgDescr (Options -> Options)
-> String
-> OptDescr (Options -> Options)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option
        String
"h"
        [String
"help"]
        ((Options -> Options) -> ArgDescr (Options -> Options)
forall a. a -> ArgDescr a
NoArg (\Options
opts -> Options
opts{help = True}))
        String
"Prints out usage info."
    ]

interpreterOpts :: [String] -> Either (Bool, String) Options
interpreterOpts :: [String] -> Either (Bool, String) Options
interpreterOpts [String]
argv
    | Options -> Bool
help Options
opts = (Bool, String) -> Either (Bool, String) Options
forall a b. a -> Either a b
Left (Bool
True, String
msg)
    | Bool -> Bool
not ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
ers) = (Bool, String) -> Either (Bool, String) Options
forall a b. a -> Either a b
Left (Bool
False, [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String]
ers String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
msg)
    | Bool
otherwise = Options -> Either (Bool, String) Options
forall a b. b -> Either a b
Right Options
opts
  where
    ([Options -> Options]
o, [String]
_, [String]
ers) = 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
Permute [OptDescr (Options -> Options)]
options [String]
argv
    msg :: String
msg = String -> [OptDescr (Options -> Options)] -> String
forall a. String -> [OptDescr a] -> String
usageInfo String
header [OptDescr (Options -> Options)]
options
    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. a -> a
id) Options
defaultOptions [Options -> Options]
o

header :: String
header :: String
header = String
"Usage: mueval [OPTION...] --expression EXPRESSION..."