multiarg-0.6.0.0: System/Console/MultiArg/SimpleParser.hs
-- | A simple command line parser that can parse options that take an
-- optional argument, one or two arguments, or a variable number of
-- arguments. For sample code that uses this parser, see
-- "System.Console.MultiArg.SampleParser".
module System.Console.MultiArg.SimpleParser (
-- * Interspersion control
Intersperse (Intersperse, StopOptions)
-- * Option specifications
, C.OptSpec (OptSpec, longOpts, shortOpts, argSpec)
, C.ArgSpec (NoArg, OptionalArg, OneArg, TwoArg, VariableArg)
-- * Exceptions
, Ex.Exceptional (Exception, Success)
, P.Error (Error)
, P.Message (Expected, StrMsg, Replaced, UnknownError)
-- * Get command line arguments
, G.getArgs
-- * The parser
, parse
) where
import qualified System.Console.MultiArg.Prim as P
import qualified System.Console.MultiArg.GetArgs as G
import qualified System.Console.MultiArg.Combinator as C
import qualified Control.Monad.Exception.Synchronous as Ex
import Control.Applicative ( many, (<|>), optional,
(<$), (<*>), (<*), (<$>))
import Data.Maybe (catMaybes)
-- | What to do after encountering the first non-option,
-- non-option-argument word on the command line? In either case, no
-- more options are parsed after a stopper.
data Intersperse =
Intersperse
-- ^ Additional options are allowed on the command line after
-- encountering the first positional argument. For example, if @a@
-- and @b@ are options, in the command line @-a posarg -b@, @b@ will
-- be parsed as an option. If @b@ is /not/ an option and the same
-- command line is entered, then @-b@ will result in an error
-- because @-b@ starts with a hyphen and therefore \"looks like\" an
-- option.
| StopOptions
-- ^ No additional options will be parsed after encountering the
-- first positional argument. For example, if @a@ and @b@ are
-- options, in the command line @-a posarg -b@, @b@ will be parsed
-- as a positional argument rather than as an option.
-- | Parse a command line.
parse ::
Intersperse
-- ^ What to do after encountering the first positional argument
-> [C.OptSpec a]
-- ^ All possible options
-> (String -> a)
-- ^ How to handle positional arguments. This function is applied to
-- the appropriate string every time the parser encounters a
-- positional argument.
-> [String]
-- ^ The command line to parse. This function correctly handles
-- Unicode strings; however, because 'System.Environment.getArgs'
-- does not always correctly handle Unicode strings, consult the
-- documentation in 'System.Console.MultiArg.GetArgs' and consider
-- using the functions in there if there is any chance that you will
-- be parsing command lines that have non-ASCII strings.
-> Ex.Exceptional P.Error [a]
parse i os p as =
let optParser = C.parseOption os
parser = case i of
Intersperse -> parseIntersperse optParser p
StopOptions -> parseStopOpts optParser p
in P.parse as parser
parseOptsNoIntersperse :: P.Parser a -> P.Parser [a]
parseOptsNoIntersperse p = P.manyTill p e where
e = P.end <|> nonOpt
nonOpt = P.lookAhead next
next = (() <$ P.nonOptionPosArg) <|> P.stopper
parseStopOpts :: P.Parser a -> (String -> a) -> P.Parser [a]
parseStopOpts optParser p =
(\opts args -> opts ++ map p args)
<$> parseOptsNoIntersperse optParser
<* optional P.stopper
<*> many P.nextArg
-- | @parseIntersperse o p@ parses options and positional arguments,
-- where o is a parser that parses options, and p is a function that,
-- when applied to a string, returns the appropriate type.
parseIntersperse :: P.Parser a -> (String -> a) -> P.Parser [a]
parseIntersperse optParser p =
let pa = (Just . p) <$> P.nonOptionPosArg
po = Just <$> optParser
ps = Nothing <$ P.stopper
parser = po <|> ps <|> pa
in catMaybes <$> P.manyTill parser P.end