module System.Console.ArgParser.Params (
StdArgParam (..)
, ArgSrc (..)
, FlagFormat (..)
, ArgParser (..)
, Optionality (..)
, Key
, FlagParam (..)
, Descr (..)
, MetaVar (..)
) where
import Data.Char (toUpper)
import Data.List
import qualified Data.Map as M
import Data.Maybe
import System.Console.ArgParser.BaseType
import System.Console.ArgParser.Parser
type Key = String
data FlagFormat =
Short |
Long
deleteMany :: [String] -> Flags -> Flags
deleteMany keys flags = foldl (flip M.delete) flags keys
type FlagParser = String -> Flags -> (Maybe Args, Flags)
takeFlag :: FlagParser
takeFlag key flags = (args, rest) where
args = case mapMaybe lookupflag prefixes of
[] -> Nothing
grpargs -> Just $ concat grpargs
lookupflag _key = M.lookup _key flags
rest = deleteMany prefixes flags
prefixes = drop 1 $ inits key
takeLongFlag :: FlagParser
takeLongFlag key flags = (args, rest) where
args = M.lookup key flags
rest = M.delete key flags
takeValidFlag :: FlagFormat -> FlagParser
takeValidFlag fmt = case fmt of
Short -> takeFlag
Long -> takeLongFlag
data FlagParam a =
FlagParam FlagFormat Key (Bool -> a)
fullFlagformat :: FlagFormat -> String -> String
fullFlagformat fmt key = case fmt of
Short -> shortfmt ++ ", " ++ longfmt
Long -> longfmt
where
shortfmt = shortflagformat key
longfmt = longflagformat key
longflagformat :: String -> String
longflagformat = ("--" ++)
shortflagformat :: String -> String
shortflagformat key = '-' : first where
first = take 1 key
shortestFlagFmt :: FlagFormat -> String -> String
shortestFlagFmt fmt = case fmt of
Short -> shortflagformat
Long -> longflagformat
instance ParamSpec FlagParam where
getParser (FlagParam fmt key parse) = Parser rawparse where
rawparse (pos, flags) = case margs of
Just [] -> (Right $ parse True, (pos, rest))
Just args' -> (Right $ parse True, (pos ++ args', rest))
Nothing -> (Right $ parse False, (pos, rest))
where
(margs, rest) = takeValidFlag fmt key flags
getParamDescr (FlagParam fmt key _) = [ParamDescr
(const $ "[" ++ shortestFlagFmt fmt key ++ "]")
"optional arguments"
(const $ fullFlagformat fmt key)
""
(map toUpper key)]
infixl 2 `Descr`
data Descr spec a = Descr
{ getdvalue :: spec a
, getuserdescr :: String
}
instance ParamSpec spec => ParamSpec (Descr spec) where
getParser = getParser . getdvalue
getParamDescr (Descr inner descr) =
map (\d -> d { argDescr = descr }) (getParamDescr inner)
infixl 2 `MetaVar`
data MetaVar spec a = MetaVar
{ getmvvalue :: spec a
, getusermvar :: String
}
instance ParamSpec spec => ParamSpec (MetaVar spec) where
getParser = getParser . getmvvalue
getParamDescr (MetaVar inner metavar) =
map (\d -> d { argMetaVar = metavar }) (getParamDescr inner)
data ArgSrc = Flag | Pos
data Optionality a = Mandatory | Optional a
data ArgParser a =
SingleArgParser (Arg -> ParseResult a) |
MulipleArgParser (Args -> ParseResult a)
runFlagParse
:: ArgParser a
-> Args
-> ParseResult a
runFlagParse parser args = case parser of
SingleArgParser f -> case args of
[] -> Left "missing arg"
[val] -> f val
_ -> Left "too many args"
MulipleArgParser f -> f args
runPosParse
:: ArgParser a
-> Args
-> (ParseResult a, Args)
runPosParse parser args = case parser of
SingleArgParser f -> case args of
[] -> (Left "missing arg", [])
val:rest -> (f val, rest)
MulipleArgParser f -> (f args, [])
getValFormat :: ArgParser a -> String -> String
getValFormat parser metavar = case parser of
SingleArgParser _ -> metavar
MulipleArgParser _ -> "[" ++ metavar ++ "...]"
data StdArgParam a =
StdArgParam (Optionality a) ArgSrc Key (ArgParser a)
instance ParamSpec StdArgParam where
getParser (StdArgParam opt src key parse) = Parser rawparse where
rawparse = choosesrc flagparse posparse src
flagparse (pos, flags) = (logkey key res, (pos, rest)) where
(margs, rest) = takeFlag key flags
res = case margs of
Nothing -> defaultOrError "missing flag"
Just args -> runFlagParse parse args
posparse (pos, flags) = case (pos, parse) of
([], SingleArgParser _) ->
(logkey key $ defaultOrError "missing arg", (pos, flags))
(args, _) -> let (res, rest) = runPosParse parse args
in (res, (rest, flags))
defaultOrError = missing opt
getParamDescr (StdArgParam opt src key parser) =
[ParamDescr
(wrap opt . usage) (category opt) format "" _metavar]
where
getflagformat flagfmt = choosesrc
((++ " ") . flagfmt)
(const "")
getinputfmt flagfmt metavar = flag ++ value where
flag = getflagformat flagfmt src key
value = getValFormat parser metavar
usage = getinputfmt shortflagformat
format = case src of
Flag -> getinputfmt (fullFlagformat Short)
Pos -> id
wrap Mandatory msg = msg
wrap _ msg = "[" ++ msg ++ "]"
_metavar = choosesrc (map toUpper key) key src
choosesrc :: a -> a -> ArgSrc -> a
choosesrc flag pos src = case src of
Flag -> flag
Pos -> pos
missing :: Optionality a -> String -> ParseResult a
missing opt msg = case opt of
Mandatory -> Left msg
Optional val -> Right val
category :: Optionality a -> String
category opt = case opt of
Mandatory -> "mandatory arguments"
_ -> "optional arguments"
logkey :: String -> ParseResult a -> ParseResult a
logkey key result = case result of
Left err -> Left $ "fail to parse '" ++ key ++ "' : " ++ err
val -> val