packages feed

multiarg 0.2.0.0 → 0.4.0.0

raw patch · 19 files changed

+1495/−2152 lines, 19 filesdep −textdep −transformersPVP ok

version bump matches the API change (PVP)

Dependencies removed: text, transformers

API changes (from Hackage documentation)

- System.Console.MultiArg.Combinator: longNoArg :: (Error e, Monad m) => LongOpt -> ParserT s e m LongOpt
- System.Console.MultiArg.Combinator: longOneArg :: (Error e, Monad m) => LongOpt -> ParserT s e m (LongOpt, Text)
- System.Console.MultiArg.Combinator: longOptionalArg :: (Error e, Monad m) => LongOpt -> ParserT s e m (LongOpt, Maybe Text)
- System.Console.MultiArg.Combinator: longTwoArg :: (Error e, Monad m) => LongOpt -> ParserT s e m (LongOpt, Text, Text)
- System.Console.MultiArg.Combinator: longVariableArg :: (Error e, Monad m) => LongOpt -> ParserT s e m (LongOpt, [Text])
- System.Console.MultiArg.Combinator: matchApproxLongOpt :: (Error e, Monad m) => LongOpt -> Set LongOpt -> ParserT s e m (Text, LongOpt, Maybe Text)
- System.Console.MultiArg.Combinator: matchNonGNUApproxLongOpt :: (Error e, Monad m) => LongOpt -> Set LongOpt -> ParserT s e m (Text, LongOpt)
- System.Console.MultiArg.Combinator: mixedNoArg :: (Error e, Monad m) => LongOpt -> [LongOpt] -> [ShortOpt] -> ParserT s e m (Either ShortOpt LongOpt)
- System.Console.MultiArg.Combinator: mixedOneArg :: (Error e, Monad m) => LongOpt -> [LongOpt] -> [ShortOpt] -> ParserT s e m (Either ShortOpt LongOpt, Text)
- System.Console.MultiArg.Combinator: mixedOptionalArg :: (Error e, Monad m) => LongOpt -> [LongOpt] -> [ShortOpt] -> ParserT s e m (Either ShortOpt LongOpt, Maybe Text)
- System.Console.MultiArg.Combinator: mixedTwoArg :: (Error e, Monad m) => LongOpt -> [LongOpt] -> [ShortOpt] -> ParserT s e m (Either ShortOpt LongOpt, Text, Text)
- System.Console.MultiArg.Combinator: mixedVariableArg :: (Error e, Monad m) => LongOpt -> [LongOpt] -> [ShortOpt] -> ParserT s e m (Either ShortOpt LongOpt, [Text])
- System.Console.MultiArg.Combinator: nonGNUexactLongOpt :: (Error e, Monad m) => LongOpt -> ParserT s e m LongOpt
- System.Console.MultiArg.Combinator: option :: (Error e, Monad m) => a -> ParserT s e m a -> ParserT s e m a
- System.Console.MultiArg.Combinator: optionMaybe :: (Error e, Monad m) => ParserT s e m a -> ParserT s e m (Maybe a)
- System.Console.MultiArg.Combinator: shortNoArg :: (Error e, Monad m) => ShortOpt -> ParserT s e m ShortOpt
- System.Console.MultiArg.Combinator: shortOneArg :: (Error e, Monad m) => ShortOpt -> ParserT s e m (ShortOpt, Text)
- System.Console.MultiArg.Combinator: shortOptionalArg :: (Error e, Monad m) => ShortOpt -> ParserT s e m (ShortOpt, Maybe Text)
- System.Console.MultiArg.Combinator: shortTwoArg :: (Error e, Monad m) => ShortOpt -> ParserT s e m (ShortOpt, Text, Text)
- System.Console.MultiArg.Combinator: shortVariableArg :: (Error e, Monad m) => ShortOpt -> ParserT s e m (ShortOpt, [Text])
- System.Console.MultiArg.Error: ExpApproxLong :: (Set LongOpt) -> Expecting
- System.Console.MultiArg.Error: ExpApproxWord :: (Set Text) -> Expecting
- System.Console.MultiArg.Error: ExpEnd :: Expecting
- System.Console.MultiArg.Error: ExpExactLong :: LongOpt -> Expecting
- System.Console.MultiArg.Error: ExpLongOptArg :: Expecting
- System.Console.MultiArg.Error: ExpMatchingApproxLong :: LongOpt -> (Set LongOpt) -> Expecting
- System.Console.MultiArg.Error: ExpNextArg :: Expecting
- System.Console.MultiArg.Error: ExpNonGNUExactLong :: LongOpt -> Expecting
- System.Console.MultiArg.Error: ExpNonGNUMatchingApproxLong :: LongOpt -> (Set LongOpt) -> Expecting
- System.Console.MultiArg.Error: ExpNonOptionPosArg :: Expecting
- System.Console.MultiArg.Error: ExpNonPendingShortOpt :: ShortOpt -> Expecting
- System.Console.MultiArg.Error: ExpNotFollowedBy :: Expecting
- System.Console.MultiArg.Error: ExpOptionOrPosArg :: Expecting
- System.Console.MultiArg.Error: ExpOtherFailure :: Expecting
- System.Console.MultiArg.Error: ExpPendingShortArg :: Expecting
- System.Console.MultiArg.Error: ExpPendingShortOpt :: ShortOpt -> Expecting
- System.Console.MultiArg.Error: ExpStopper :: Expecting
- System.Console.MultiArg.Error: ExpTextError :: Text -> Expecting
- System.Console.MultiArg.Error: SawAlreadyStopper :: Saw
- System.Console.MultiArg.Error: SawEmptyArg :: Saw
- System.Console.MultiArg.Error: SawFollowedBy :: Saw
- System.Console.MultiArg.Error: SawGNULongOptArg :: Text -> Saw
- System.Console.MultiArg.Error: SawLeadingDashArg :: Text -> Saw
- System.Console.MultiArg.Error: SawMatchingApproxLongWithArg :: Text -> Saw
- System.Console.MultiArg.Error: SawMoreInput :: Saw
- System.Console.MultiArg.Error: SawMultipleApproxMatches :: (Set Text) -> Text -> Saw
- System.Console.MultiArg.Error: SawMultipleMatches :: (Set LongOpt) -> Text -> Saw
- System.Console.MultiArg.Error: SawNewStopper :: Saw
- System.Console.MultiArg.Error: SawNoArgsLeft :: Saw
- System.Console.MultiArg.Error: SawNoMatches :: Text -> Saw
- System.Console.MultiArg.Error: SawNoOption :: Saw
- System.Console.MultiArg.Error: SawNoOptionOrPosArg :: Saw
- System.Console.MultiArg.Error: SawNoPendingShortArg :: Saw
- System.Console.MultiArg.Error: SawNoPendingShorts :: Saw
- System.Console.MultiArg.Error: SawNotLongArg :: Text -> Saw
- System.Console.MultiArg.Error: SawNotMatchingApproxLong :: Text -> LongOpt -> Saw
- System.Console.MultiArg.Error: SawNotShortArg :: Text -> Saw
- System.Console.MultiArg.Error: SawNotStopper :: Saw
- System.Console.MultiArg.Error: SawOtherFailure :: Saw
- System.Console.MultiArg.Error: SawSingleDashArg :: Saw
- System.Console.MultiArg.Error: SawStillPendingShorts :: TextNonEmpty -> Saw
- System.Console.MultiArg.Error: SawTextError :: Text -> Saw
- System.Console.MultiArg.Error: SawWrongLongArg :: Text -> Saw
- System.Console.MultiArg.Error: SawWrongPendingShort :: Char -> Saw
- System.Console.MultiArg.Error: SawWrongShortArg :: Char -> Saw
- System.Console.MultiArg.Error: SimpleError :: Expecting -> Saw -> SimpleError
- System.Console.MultiArg.Error: class Error e
- System.Console.MultiArg.Error: data Expecting
- System.Console.MultiArg.Error: data Saw
- System.Console.MultiArg.Error: data SimpleError
- System.Console.MultiArg.Error: instance Eq Expecting
- System.Console.MultiArg.Error: instance Eq Saw
- System.Console.MultiArg.Error: instance Eq SimpleError
- System.Console.MultiArg.Error: instance Error SimpleError
- System.Console.MultiArg.Error: instance Error Text
- System.Console.MultiArg.Error: instance Show Expecting
- System.Console.MultiArg.Error: instance Show Saw
- System.Console.MultiArg.Error: instance Show SimpleError
- System.Console.MultiArg.Error: parseErr :: Error e => Expecting -> Saw -> e
- System.Console.MultiArg.Error: printError :: SimpleError -> Text
- System.Console.MultiArg.Error: printExpecting :: Expecting -> Text
- System.Console.MultiArg.Error: printSaw :: Saw -> Text
- System.Console.MultiArg.Prim: (<?>) :: Monad m => ParserT s e m a -> e -> ParserT s e m a
- System.Console.MultiArg.Prim: data ParserT s e m a
- System.Console.MultiArg.Prim: feed :: Monad m => (a -> ParserT s e m a) -> (a -> ParserT s e m end) -> a -> ParserT s e m [a]
- System.Console.MultiArg.Prim: get :: Monad m => ParserT s e m s
- System.Console.MultiArg.Prim: instance (Error e, Monad m) => Monad (ParserT s e m)
- System.Console.MultiArg.Prim: instance (Monad m, Error e) => Alternative (ParserT s e m)
- System.Console.MultiArg.Prim: instance (Monad m, Error e) => MonadPlus (ParserT s e m)
- System.Console.MultiArg.Prim: instance (Monad m, Error e) => Monoid (ParserT s e m a)
- System.Console.MultiArg.Prim: instance (MonadIO m, Error e) => MonadIO (ParserT s e m)
- System.Console.MultiArg.Prim: instance Eq s => Eq (ParseSt s)
- System.Console.MultiArg.Prim: instance Monad m => Applicative (ParserT s e m)
- System.Console.MultiArg.Prim: instance Monad m => Functor (ParserT s e m)
- System.Console.MultiArg.Prim: instance MonadTrans (ParserT s e)
- System.Console.MultiArg.Prim: instance Show s => Show (ParseSt s)
- System.Console.MultiArg.Prim: modify :: Monad m => (s -> s) -> ParserT s e m ()
- System.Console.MultiArg.Prim: parseE :: [Text] -> ParserE e a -> Exceptional e a
- System.Console.MultiArg.Prim: parseSE :: s -> [Text] -> ParserSE s e a -> (Exceptional e a, s)
- System.Console.MultiArg.Prim: parseT :: Monad m => s -> [Text] -> ParserT s e m a -> m (Exceptional e a, s)
- System.Console.MultiArg.Prim: parserIO :: (MonadIO m, Error e) => IO a -> ParserT s e m a
- System.Console.MultiArg.Prim: parserLift :: Monad m => m a -> ParserT s e m a
- System.Console.MultiArg.Prim: put :: Monad m => s -> ParserT s e m ()
- System.Console.MultiArg.Prim: type Parser a = ParserT () SimpleError Identity a
- System.Console.MultiArg.Prim: type ParserE e a = ParserT () e Identity a
- System.Console.MultiArg.Prim: type ParserSE s e a = ParserT s e Identity a
- System.Console.MultiArg.SimpleParser: Option :: String -> Args -> Result
- System.Console.MultiArg.SimpleParser: PosArg :: String -> Result
- System.Console.MultiArg.SimpleParser: Stopper :: Result
- System.Console.MultiArg.SimpleParser: args :: Result -> Args
- System.Console.MultiArg.SimpleParser: data Args
- System.Console.MultiArg.SimpleParser: data Result
- System.Console.MultiArg.SimpleParser: data SimpleError
- System.Console.MultiArg.SimpleParser: instance Show Args
- System.Console.MultiArg.SimpleParser: instance Show OptSpec
- System.Console.MultiArg.SimpleParser: instance Show Result
- System.Console.MultiArg.SimpleParser: label :: Result -> String
- System.Console.MultiArg.SimpleParser: longOpt :: OptSpec -> String
- System.Console.MultiArg.SimpleParser: noArg :: Args
- System.Console.MultiArg.SimpleParser: oArg :: Args -> Maybe String
- System.Console.MultiArg.SimpleParser: oneArg :: Args
- System.Console.MultiArg.SimpleParser: optionalArg :: Args
- System.Console.MultiArg.SimpleParser: posArg :: Result -> String
- System.Console.MultiArg.SimpleParser: sArg1 :: Args -> String
- System.Console.MultiArg.SimpleParser: tArg1 :: Args -> String
- System.Console.MultiArg.SimpleParser: tArg2 :: Args -> String
- System.Console.MultiArg.SimpleParser: twoArg :: Args
- System.Console.MultiArg.SimpleParser: vArgs :: Args -> [String]
- System.Console.MultiArg.SimpleParser: variableArg :: Args
- System.Console.MultiArg.TextNonEmpty: TextNonEmpty :: Char -> Text -> TextNonEmpty
- System.Console.MultiArg.TextNonEmpty: data TextNonEmpty
- System.Console.MultiArg.TextNonEmpty: instance Eq TextNonEmpty
- System.Console.MultiArg.TextNonEmpty: instance Show TextNonEmpty
+ System.Console.MultiArg.Combinator: (<?>) :: Parser a -> String -> Parser a
+ System.Console.MultiArg.Combinator: NoArg :: a -> ArgSpec a
+ System.Console.MultiArg.Combinator: OneArg :: (String -> a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: OptSpec :: [String] -> [Char] -> ArgSpec a -> OptSpec a
+ System.Console.MultiArg.Combinator: OptionalArg :: (Maybe String -> a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: TwoArg :: (String -> String -> a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: VariableArg :: ([String] -> a) -> ArgSpec a
+ System.Console.MultiArg.Combinator: argSpec :: OptSpec a -> ArgSpec a
+ System.Console.MultiArg.Combinator: data ArgSpec a
+ System.Console.MultiArg.Combinator: data OptSpec a
+ System.Console.MultiArg.Combinator: longOpts :: OptSpec a -> [String]
+ System.Console.MultiArg.Combinator: parseOption :: [OptSpec a] -> Parser a
+ System.Console.MultiArg.Combinator: shortOpts :: OptSpec a -> [Char]
+ System.Console.MultiArg.Prim: (<??>) :: Parser a -> ([Message] -> [Message]) -> Parser a
+ System.Console.MultiArg.Prim: Error :: [Message] -> Location -> Error
+ System.Console.MultiArg.Prim: Expected :: String -> Message
+ System.Console.MultiArg.Prim: Replaced :: String -> Message
+ System.Console.MultiArg.Prim: StrMsg :: String -> Message
+ System.Console.MultiArg.Prim: UnknownError :: Message
+ System.Console.MultiArg.Prim: data Error
+ System.Console.MultiArg.Prim: data Message
+ System.Console.MultiArg.Prim: data Parser a
+ System.Console.MultiArg.Prim: instance Alternative Parser
+ System.Console.MultiArg.Prim: instance Applicative Parser
+ System.Console.MultiArg.Prim: instance Functor Parser
+ System.Console.MultiArg.Prim: instance Monad Parser
+ System.Console.MultiArg.Prim: instance MonadPlus Parser
+ System.Console.MultiArg.Prim: instance Monoid (Parser a)
+ System.Console.MultiArg.Prim: instance Show Error
+ System.Console.MultiArg.Prim: instance Show Message
+ System.Console.MultiArg.Prim: instance Show ParseSt
+ System.Console.MultiArg.Prim: resetStopper :: Parser ()
+ System.Console.MultiArg.Prim: type Location = String
+ System.Console.MultiArg.SampleParser: Bytes :: String -> Flag
+ System.Console.MultiArg.SampleParser: Filename :: String -> Flag
+ System.Console.MultiArg.SampleParser: Follow :: (Maybe String) -> Flag
+ System.Console.MultiArg.SampleParser: Help :: Flag
+ System.Console.MultiArg.SampleParser: Intersperse :: Intersperse
+ System.Console.MultiArg.SampleParser: Lines :: String -> Flag
+ System.Console.MultiArg.SampleParser: Pid :: String -> Flag
+ System.Console.MultiArg.SampleParser: Quiet :: Flag
+ System.Console.MultiArg.SampleParser: Retry :: Flag
+ System.Console.MultiArg.SampleParser: Sleep :: String -> Flag
+ System.Console.MultiArg.SampleParser: Stats :: String -> Flag
+ System.Console.MultiArg.SampleParser: StopOptions :: Intersperse
+ System.Console.MultiArg.SampleParser: Verbose :: Flag
+ System.Console.MultiArg.SampleParser: Version :: Flag
+ System.Console.MultiArg.SampleParser: data Flag
+ System.Console.MultiArg.SampleParser: data Intersperse
+ System.Console.MultiArg.SampleParser: instance Show Flag
+ System.Console.MultiArg.SimpleParser: Error :: [Message] -> Location -> Error
+ System.Console.MultiArg.SimpleParser: Exception :: e -> Exceptional e a
+ System.Console.MultiArg.SimpleParser: Expected :: String -> Message
+ System.Console.MultiArg.SimpleParser: Replaced :: String -> Message
+ System.Console.MultiArg.SimpleParser: StrMsg :: String -> Message
+ System.Console.MultiArg.SimpleParser: Success :: a -> Exceptional e a
+ System.Console.MultiArg.SimpleParser: UnknownError :: Message
+ System.Console.MultiArg.SimpleParser: data ArgSpec a
+ System.Console.MultiArg.SimpleParser: data Error
+ System.Console.MultiArg.SimpleParser: data Exceptional e a :: * -> * -> *
+ System.Console.MultiArg.SimpleParser: data Message
- System.Console.MultiArg.Combinator: matchApproxWord :: (Error e, Monad m) => Set Text -> ParserT s e m (Text, Text)
+ System.Console.MultiArg.Combinator: matchApproxWord :: Set String -> Parser (String, String)
- System.Console.MultiArg.Combinator: notFollowedBy :: (Error e, Monad m) => ParserT s e m a -> ParserT s e m ()
+ System.Console.MultiArg.Combinator: notFollowedBy :: Parser a -> Parser ()
- System.Console.MultiArg.Option: makeLongOpt :: Text -> LongOpt
+ System.Console.MultiArg.Option: makeLongOpt :: String -> Maybe LongOpt
- System.Console.MultiArg.Option: makeShortOpt :: Char -> ShortOpt
+ System.Console.MultiArg.Option: makeShortOpt :: Char -> Maybe ShortOpt
- System.Console.MultiArg.Option: unLongOpt :: LongOpt -> Text
+ System.Console.MultiArg.Option: unLongOpt :: LongOpt -> String
- System.Console.MultiArg.Prim: apply :: Monad m => ParserT s e m (a -> b) -> ParserT s e m a -> ParserT s e m b
+ System.Console.MultiArg.Prim: apply :: Parser (a -> b) -> Parser a -> Parser b
- System.Console.MultiArg.Prim: approxLongOpt :: (Error e, Monad m) => Set LongOpt -> ParserT s e m (Text, LongOpt, Maybe Text)
+ System.Console.MultiArg.Prim: approxLongOpt :: Set LongOpt -> Parser (String, LongOpt, Maybe String)
- System.Console.MultiArg.Prim: choice :: Monad m => ParserT s e m a -> ParserT s e m a -> ParserT s e m a
+ System.Console.MultiArg.Prim: choice :: Parser a -> Parser a -> Parser a
- System.Console.MultiArg.Prim: combine :: Monad m => ParserT s e m a -> (a -> ParserT s e m b) -> ParserT s e m b
+ System.Console.MultiArg.Prim: combine :: Parser a -> (a -> Parser b) -> Parser b
- System.Console.MultiArg.Prim: end :: (Error e, Monad m) => ParserT s e m ()
+ System.Console.MultiArg.Prim: end :: Parser ()
- System.Console.MultiArg.Prim: exactLongOpt :: (Error e, Monad m) => LongOpt -> ParserT s e m (LongOpt, Maybe Text)
+ System.Console.MultiArg.Prim: exactLongOpt :: LongOpt -> Parser (Maybe String)
- System.Console.MultiArg.Prim: genericThrow :: (Monad m, Error e) => ParserT s e m a
+ System.Console.MultiArg.Prim: genericThrow :: Parser a
- System.Console.MultiArg.Prim: good :: Monad m => a -> ParserT s e m a
+ System.Console.MultiArg.Prim: good :: a -> Parser a
- System.Console.MultiArg.Prim: lookAhead :: Monad m => ParserT s e m a -> ParserT s e m a
+ System.Console.MultiArg.Prim: lookAhead :: Parser a -> Parser a
- System.Console.MultiArg.Prim: manyTill :: Monad m => ParserT s e m a -> ParserT s e m end -> ParserT s e m [a]
+ System.Console.MultiArg.Prim: manyTill :: Parser a -> Parser end -> Parser [a]
- System.Console.MultiArg.Prim: nextArg :: (Error e, Monad m) => ParserT s e m Text
+ System.Console.MultiArg.Prim: nextArg :: Parser String
- System.Console.MultiArg.Prim: nonOptionPosArg :: (Error e, Monad m) => ParserT s e m Text
+ System.Console.MultiArg.Prim: nonOptionPosArg :: Parser String
- System.Console.MultiArg.Prim: nonPendingShortOpt :: (Error e, Monad m) => ShortOpt -> ParserT s e m ShortOpt
+ System.Console.MultiArg.Prim: nonPendingShortOpt :: ShortOpt -> Parser ()
- System.Console.MultiArg.Prim: parse :: [Text] -> Parser a -> Exceptional SimpleError a
+ System.Console.MultiArg.Prim: parse :: [String] -> Parser a -> Exceptional Error a
- System.Console.MultiArg.Prim: parserMap :: Monad m => (a -> b) -> ParserT s e m a -> ParserT s e m b
+ System.Console.MultiArg.Prim: parserMap :: (a -> b) -> Parser a -> Parser b
- System.Console.MultiArg.Prim: pendingShortOpt :: (Monad m, Error e) => ShortOpt -> ParserT s e m ShortOpt
+ System.Console.MultiArg.Prim: pendingShortOpt :: ShortOpt -> Parser ()
- System.Console.MultiArg.Prim: pendingShortOptArg :: (Error e, Monad m) => ParserT s e m Text
+ System.Console.MultiArg.Prim: pendingShortOptArg :: Parser String
- System.Console.MultiArg.Prim: several :: Monad m => ParserT s e m a -> ParserT s e m [a]
+ System.Console.MultiArg.Prim: several :: Parser a -> Parser [a]
- System.Console.MultiArg.Prim: stopper :: (Error e, Monad m) => ParserT s e m ()
+ System.Console.MultiArg.Prim: stopper :: Parser ()
- System.Console.MultiArg.Prim: throw :: Monad m => e -> ParserT s e m a
+ System.Console.MultiArg.Prim: throw :: Message -> Parser a
- System.Console.MultiArg.Prim: throwString :: (Error e, Monad m) => String -> ParserT s e m a
+ System.Console.MultiArg.Prim: throwString :: String -> Parser a
- System.Console.MultiArg.Prim: try :: Monad m => ParserT s e m a -> ParserT s e m a
+ System.Console.MultiArg.Prim: try :: Parser a -> Parser a
- System.Console.MultiArg.SampleParser: sampleMain :: IO ()
+ System.Console.MultiArg.SampleParser: sampleMain :: Intersperse -> IO ()
- System.Console.MultiArg.SampleParser: specs :: [OptSpec]
+ System.Console.MultiArg.SampleParser: specs :: [OptSpec Flag]
- System.Console.MultiArg.SimpleParser: NoArg :: Args
+ System.Console.MultiArg.SimpleParser: NoArg :: a -> ArgSpec a
- System.Console.MultiArg.SimpleParser: OneArg :: String -> Args
+ System.Console.MultiArg.SimpleParser: OneArg :: (String -> a) -> ArgSpec a
- System.Console.MultiArg.SimpleParser: OptSpec :: String -> [Char] -> [String] -> Args -> OptSpec
+ System.Console.MultiArg.SimpleParser: OptSpec :: [String] -> [Char] -> ArgSpec a -> OptSpec a
- System.Console.MultiArg.SimpleParser: OptionalArg :: Maybe String -> Args
+ System.Console.MultiArg.SimpleParser: OptionalArg :: (Maybe String -> a) -> ArgSpec a
- System.Console.MultiArg.SimpleParser: TwoArg :: String -> String -> Args
+ System.Console.MultiArg.SimpleParser: TwoArg :: (String -> String -> a) -> ArgSpec a
- System.Console.MultiArg.SimpleParser: VariableArg :: [String] -> Args
+ System.Console.MultiArg.SimpleParser: VariableArg :: ([String] -> a) -> ArgSpec a
- System.Console.MultiArg.SimpleParser: argSpec :: OptSpec -> Args
+ System.Console.MultiArg.SimpleParser: argSpec :: OptSpec a -> ArgSpec a
- System.Console.MultiArg.SimpleParser: data OptSpec
+ System.Console.MultiArg.SimpleParser: data OptSpec a
- System.Console.MultiArg.SimpleParser: longOpts :: OptSpec -> [String]
+ System.Console.MultiArg.SimpleParser: longOpts :: OptSpec a -> [String]
- System.Console.MultiArg.SimpleParser: parse :: Intersperse -> [OptSpec] -> [String] -> Either SimpleError [Result]
+ System.Console.MultiArg.SimpleParser: parse :: Intersperse -> [OptSpec a] -> (String -> a) -> [String] -> Exceptional Error [a]
- System.Console.MultiArg.SimpleParser: shortOpts :: OptSpec -> [Char]
+ System.Console.MultiArg.SimpleParser: shortOpts :: OptSpec a -> [Char]

Files

NEWS view
@@ -12,3 +12,21 @@   to carry out stateful parses without using a user state. Sometimes   this aids in composability--for instance, I use it when combining   parsers from different parts of the same program.++Release 0.4.0.0, June 30, 2012+Changes since release 0.2.0.0:++* Code written for version 0.2.* will not work at all with this+  version.++* Removed dependency on text library. multiarg now only deals with+  plain Strings. The memory usage concerns that originally led me to+  use Texts were unfounded.++* Dramatically simplified code for primitive parsers. No more custom+  error types, monad transformers, or user states. This sort of+  functionality is easily implemented in the parsers that you can+  build; baking it into the primitive parsers makes things needlessly+  complicated.++* Reworked included combinators in Combinator module.
+ System/Console/MultiArg.hs view
@@ -0,0 +1,151 @@+-- | A combinator library for building command-line parsers.++module System.Console.MultiArg (++  -- | To say this library is inspired by Parsec would probably insult the+  -- creators of Parsec, as this library could not possibly be as+  -- elegant or throughly considered as Parsec is. Nevertheless this+  -- library can be used in a similar style as Parsec, but is+  -- specialized for parsing command lines.+  --+  -- This parser was built because I could not find anything that would+  -- readily parse command lines where the options took more than one+  -- argument. For example, for the @tail@ command on GNU systems, the+  -- --lines option takes one argument to specify how many lines you+  -- want to see. Well, what if you want to build a program with an+  -- option that takes /two/ arguments, like @--foo bar baz@? I found no+  -- such library so I built this one. Nevertheless, using this library+  -- you can build parsers to parse a variety of command line+  -- vocabularies, from simple to complex.++  -- * Terminology+  +  -- | Some terms are used throughout multiarg:+  --+  -- [@word@] When you run your program from the Unix shell prompt,+  -- your shell is responsible for splitting the command line into+  -- words. Typically you separate words with spaces, although quoting+  -- can affect this. multiarg parses lists of words. Each word can+  -- consist of a single long option, a single long option and an+  -- accompanying option argument, a single short option, multiple+  -- short options, and even one or more multiple short options and an+  -- accompanying short option argument. Or, a word can be a+  -- positional argument or a stopper. All these are described below.+  --+  -- [@option@] Options allow a user to specify ways to tune the+  -- operation of a program. Typically options are indeed optional,+  -- although some programs do sport \"required options\" (a bit of an+  -- oxymoron). Options can be either short options or long+  -- options. Also, options can take arguments.+  --+  -- [@short option@] An option that is specified with a single hyphen+  -- and a single letter. For example, for the program @tail(1)@,+  -- possible short options include @n@ and @v@. With multiarg it is+  -- possible to easily parse short options that are specified in+  -- different words or in the same word. For example, if a user wants+  -- to run @tail@ with two options, he might type @tail -v -f@ or he+  -- might type @tail -vf@.+  --+  -- [@long option@] An option that is specified using two hyphens and+  -- what is usually a mnemonic word, though it could be as short as a+  -- single letter. For example, @tail(1)@ has long options including+  -- @follow@ and @verbose@. The user would specify these on the+  -- command line by typing @tail --follow --verbose@.+  --+  -- [@option argument@] Some options take additional arguments that+  -- are specific to the option and change what the option does. For+  -- instance, the @lines@ option to @tail(1)@ takes a single,+  -- optional argument, which is the number of lines to show. Option+  -- arguments can be optional or required, and a single option can+  -- take a mulitple, fixed number of arguments and it can take a+  -- variable number of arguments. Option arguments can be given in+  -- various ways. They can be specified in the same word as a long+  -- option by using an equals sign; they can also be specified in the+  -- same word as a short option simply by placing them in the same+  -- word, or they can be specified in the following word. For+  -- example, these different command lines all mean the same thing;+  -- @tail --verbose --lines=20@, @tail --verbose --lines 20@, @tail+  -- -vn 20@, @tail -v -n20@, @tail -vn20@, and @tail -v -n 20@, and+  -- numerous other combinations also have the same meaning.+  --+  -- [@GNU-style option argument@] A long option with an argument+  -- given with an equal sign, such as [@lines=20@].+  --+  -- [@positional argument@] A word on the command line that is not an+  -- option or an argument to an option. For instance, with @tail(1)@,+  -- you specify the files you want to see by using positional+  -- arguments. In the command @tail -n 10 myfile@, @myfile@ is a+  -- positional argument. For some programs, such as @git@ or @darcs@,+  -- a positional argument might be a \"command\" or a \"mode\", such+  -- as the @commit@ in @git commit@ or the @whatsnew@ in @darcs+  -- whatsnew@. multiarg has no primitive parsers that treat these+  -- positional arguments specially but it is trivial to build a+  -- parser for command lines such as this, too.+  --+  -- [@stopper@] A single word consisting solely of two hyphens,+  -- @--@. The user types this to indicate that all subsequent words+  -- on the command line are positional arguments, even if they begin+  -- with hyphens and therefore look like they might be options.+  --+  -- [@pending@] The user might specify more than one short option, or+  -- a short option and a short option argument, in a single word. For+  -- example, she might type @tail -vl20@. After parsing the @v@+  -- option, the Parser makes @l20@ into a \"pending\". The next+  -- parser can then treat @l20@ as an option argument to the @v@+  -- option (which is probably not what was wanted) or the next parser+  -- can parse @l@ as a short option. This would result in a+  -- \"pending\" of @20@. Then, the next parser can treat @20@ as an+  -- option argument. After that parse there will be no pendings.+  +  -- * Getting started++  -- |If your needs are simple to moderately complicated just look at the+  -- "System.Console.MultiArg.SimpleParser" module, which uses the+  -- underlying combinators to build a simple parser for you. That+  -- module is already exported from this module for easy usage. For+  -- maximum flexibility you will want to start with the+  -- "System.Console.MultiArg.Prim" module.+  --+  -- Using the parsers and combinators in+  -- "System.Console.MultiArg.Prim", you can easily build parsers that+  -- are quite complicated. The parsers can check for errors along the+  -- way, simplifying the sometimes complex task of ensuring that data+  -- a user supplied on the command line is good. You can easily build+  -- parsers for programs that take no options, take dozens of+  -- options, require that options be given in a particular order,+  -- require that some options be given, or bar some combinations of+  -- options. You might also require particular positional+  -- arguments. You can also easily parse command lines for programs+  -- that have multiple \"modes\", like @git@ or @darcs@. If you're+  -- doing this, of course first start by reading the documentation+  -- for "System.Console.MultiArg.Prim" and+  -- "System.Console.MultiArg.Combinator". You will also want to look+  -- at the source code for "System.Console.MultiArg.Combinator" and+  -- "System.Console.Multiarg.SimpleParser", as these show some ways+  -- to use the primitive parsers and combinators.++  -- * Non-features and shortcomings+  --+  -- | multiarg isn't perfect; no software is. multiarg does not+  -- automatically make online help for your command line+  -- parsers. Getting this right would be tricky given the nature of+  -- the code and I don't even want to bother trying, as I just write+  -- my own online help in a text editor.+  --+  -- multiarg partially embraces \"The Tao of Option Parsing\" that+  -- Python's Optik (<http://optik.sourceforge.net/>) follows. Read+  -- \"The Tao of Option Parsing\" here:+  --+  -- <http://optik.sourceforge.net/doc/1.5/tao.html>+  --+  -- multiarg's philosophy is similar to that of Optik, which+  -- means you won't be able to use multiarg to (easily) build a clone+  -- to the UNIX @find(1)@ command. (You could do it, but multiarg won't+  -- help you very much.)+  --+  -- multiarg can be complicated, although I'd like to believe this is+  -- because it addresses a complicated problem in a flexible way.++  module System.Console.MultiArg.SimpleParser ) where++import System.Console.MultiArg.SimpleParser
+ System/Console/MultiArg/Combinator.hs view
@@ -0,0 +1,284 @@+-- | Combinators that are useful for building command-line+-- parsers. These build off the functions in+-- "System.Console.MultiArg.Prim". Unlike those functions, these+-- functions have no access to the internals of the parser.+module System.Console.MultiArg.Combinator (+  -- * Parser combinators+  notFollowedBy,+  (<?>),+  +  -- * Combined long and short option parser+  OptSpec(OptSpec, longOpts, shortOpts, argSpec),+  ArgSpec(NoArg, OptionalArg, OneArg, TwoArg, VariableArg),+  parseOption,+  +  -- * Other words+  matchApproxWord ) where+  +import Data.List (isPrefixOf, intersperse)+import Data.Set ( Set )+import qualified Data.Set as Set+import Control.Applicative ((<*>), optional, (<$))++import System.Console.MultiArg.Prim+  ( Parser, throw, try, approxLongOpt,+    nextArg, pendingShortOptArg, nonOptionPosArg,+    pendingShortOpt, nonPendingShortOpt, nextArg,+    Message(Expected, Replaced), (<??>))+import System.Console.MultiArg.Option+  ( LongOpt, ShortOpt, unLongOpt,+    makeLongOpt, makeShortOpt, unShortOpt )+import Control.Applicative ((<|>), many)+import qualified Data.Map as M+import Data.Map ((!))+import Data.Monoid ( mconcat )+++-- | @notFollowedBy p@ succeeds only if parser p fails. If p fails,+-- notFollowedBy succeeds without consuming any input. If p succeeds+-- and consumes input, notFollowedBy fails and consumes input. If p+-- succeeds and does not consume any input, notFollowedBy fails and+-- does not consume any input.+notFollowedBy :: Parser a -> Parser ()+notFollowedBy p =+  () <$ ((try p >> fail "notFollowedBy failed")+         <|> return ())+++-- | Runs the parser given. If it succeeds, then returns the result of+-- the parser. If it fails and consumes input, returns the result of+-- the parser. If it fails without consuming any input, then removes+-- all previous errors, replacing them with a single error of type+-- Replaced containing the string given.+(<?>) :: Parser a -> String -> Parser a+(<?>) l e = l <??> (const [Replaced e])++infix 0 <?>++-- | Examines the possible words in Set. If there are no pendings,+-- then get the next word and see if it matches one of the words in+-- Set. If so, returns the word actually parsed and the matching word+-- from Set. If there is no match, fails without consuming any input.+matchApproxWord :: Set String -> Parser (String, String)+matchApproxWord s = try $ do+  a <- nextArg+  let p t = a `isPrefixOf` t+      matches = Set.filter p s+      err = throw $ Expected+            ("word matching one of: "+             ++ (concat . intersperse ", " $ Set.toList s))+  case Set.toList matches of+    [] -> err+    (x:[]) -> return (a, x)+    _ -> err+++unsafeShortOpt :: Char -> ShortOpt+unsafeShortOpt c = case makeShortOpt c of+  Nothing -> error $ "invalid short option: " ++ [c]+  Just o -> o++unsafeLongOpt :: String -> LongOpt+unsafeLongOpt c = case makeLongOpt c of+  Nothing -> error $ "invalid long option: " ++ c+  Just o -> o+++-- |Specifies options for the 'parseOption' function. Each OptSpec+-- represents one command-line option.+data OptSpec a = OptSpec {+  longOpts :: [String]+  -- ^ Each String is a single long option, such as @version@. When+  -- the user specifies long options on the command line, she must+  -- type two dashes; however, do not include the dashes when you+  -- specify the long option here. Strings you specify as long options+  -- cannot include a dash as either the first or the second+  -- character, and they cannot include an equal sign anywhere. If+  -- your long option does not meet these conditions, a runtime error+  -- will occur.++          +  , shortOpts :: [Char]+    -- ^ Each Char is a single short option, such as @v@. The+    -- character cannot be a dash; if it is, a runtime error will occur.+    +  , argSpec :: ArgSpec a+    -- ^ What to do each time one of the given long options or+    -- short options appears on the command line.+  }++-- | Specifies how many arguments each option takes. As with+-- 'System.Console.GetOpt.ArgDescr', there are (at least) two ways to+-- use this type. You can simply represent each possible option using+-- different data constructors in an algebraic data type. Or you can+-- have each ArgSpec yield a function that transforms a record. For an+-- example that uses an algebraic data type, see+-- "System.Console.MultiArg.SampleParser".+data ArgSpec a =+  NoArg a+  -- ^ This option takes no arguments++  | OptionalArg (Maybe String -> a)+    -- ^ This option takes an optional argument. As noted in \"The Tao+    -- of Option Parsing\", optional arguments can result in some+    -- ambiguity. (Read it here:+    -- <http://optik.sourceforge.net/doc/1.5/tao.html>) If option @a@+    -- takes an optional argument, and @b@ is also an option, what+    -- does @-ab@ mean? SimpleParser resolves this ambiguity by+    -- assuming that @b@ is an argument to @a@. If the user does not+    -- like this, she can specify @-a -b@ (in such an instance @-b@ is+    -- not parsed as an option to @-a@, because @-b@ begins with a+    -- hyphen and therefore \"looks like\" an option.) Certainly+    -- though, optional arguments lead to ambiguity, so if you don't+    -- like it, don't use them :)++  | OneArg (String -> a)+    -- ^ This option takes one argument. Here, if option @a@ takes one+    -- argument, @-a -b@ will be parsed with @-b@ being an argument to+    -- option @a@, even though @-b@ starts with a hyphen and therefore+    -- \"looks like\" an option.+    +  | TwoArg (String -> String -> a)+    -- ^ This option takes two arguments. Parsed similarly to 'OneArg'.++  | VariableArg ([String] -> a)+    -- ^ This option takes a variable number of arguments--zero or+    -- more. Option arguments continue until the command line contains+    -- a word that begins with a hyphen. For example, if option @a@+    -- takes a variable number of arguments, then @-a one two three+    -- -b@ will be parsed as @a@ taking three arguments, and @-a -b@+    -- will be parsed as @a@ taking no arguments. If the user enters+    -- @-a@ as the last option on the command line, then the only way+    -- to indicate the end of arguments for @a@ and the beginning of+    -- positional argments is with a stopper.+    ++-- | Parses a single command line option. Examines all the options+-- specified using multiple OptSpec and parses one option on the+-- command line accordingly. Fails without consuming any input if the+-- next word on the command line is not a recognized option. Allows+-- the user to specify the shortest unambiguous match for long+-- options; for example, the user could type @--verb@ for @--verbose@+-- and @--vers@ for @--version@.+--+-- For an example that uses this function, see+-- "System.Console.MultiArg.SimpleParser".+parseOption :: [OptSpec a] -> Parser a+parseOption os =+  let longs = longOptParser os+  in case mconcat ([shortOpt] <*> os) of+    Nothing -> longs+    Just shorts -> longs <|> shorts+  +longOptParser :: [OptSpec a] -> Parser a+longOptParser os = longOpt (longOptSet os) (longOptMap os)+      ++longOptSet :: [OptSpec a] -> Set LongOpt+longOptSet = Set.fromList . concatMap toOpts where+  toOpts = map unsafeLongOpt . longOpts++longOptMap :: [OptSpec a] -> M.Map LongOpt (ArgSpec a)+longOptMap = M.fromList . concatMap toPairs where+  toPairs (OptSpec los _ as) = map (toPair as) los where+    toPair a s = (unsafeLongOpt s, a)++longOpt ::+  Set LongOpt+  -> M.Map LongOpt (ArgSpec a)+  -> Parser a+longOpt set mp = do+  (_, lo, maybeArg) <- approxLongOpt set+  let spec = mp ! lo+  case spec of+    NoArg a -> case maybeArg of+      Nothing -> return a+      Just _ -> fail $ "option " ++ unLongOpt lo+                  ++ " does not take argument"+    OptionalArg f -> return (f maybeArg)+    OneArg f -> case maybeArg of+      Nothing -> do+        a1 <- nextArg+        return $ f a1+      Just a -> return $ f a+    TwoArg f -> case maybeArg of+      Nothing -> do+        a1 <- nextArg+        a2 <- nextArg+        return $ f a1 a2+      Just a1 -> do+        a2 <- nextArg+        return $ f a1 a2+    VariableArg f -> do+      as <- many nonOptionPosArg+      return . f $ case maybeArg of+        Nothing -> as+        Just a1 -> a1 : as+++shortOpt :: OptSpec a -> Maybe (Parser a)+shortOpt o = mconcat parsers where+  parsers = map mkParser . shortOpts $ o+  mkParser c =+    let opt = unsafeShortOpt c+    in Just $ case argSpec o of+      NoArg a -> a <$ nextShort opt+      OptionalArg f -> shortOptionalArg opt f+      OneArg f -> shortOneArg opt f+      TwoArg f -> shortTwoArg opt f+      VariableArg f -> shortVariableArg opt f++-- | Parses a short option without an argument, either pending or+-- non-pending. Fails with a single error message rather than two.+nextShort :: ShortOpt -> Parser ()+nextShort o = p <??> e where+  p = pendingShortOpt o <|> nonPendingShortOpt o+  err = Expected ("short option: " ++ [unShortOpt o])+  e ls = err : (drop 2 ls)++shortVariableArg :: ShortOpt -> ([String] -> a) -> Parser a+shortVariableArg opt f = do+  nextShort opt+  maybeSameWordArg <- optional pendingShortOptArg+  args <- many nonOptionPosArg+  case maybeSameWordArg of+    Nothing -> return (f args)+    Just arg1 -> return (f (arg1:args))+  ++shortTwoArg :: ShortOpt -> (String -> String -> a) -> Parser a+shortTwoArg opt f = do+  nextShort opt+  maybeSameWordArg <- optional pendingShortOptArg+  case maybeSameWordArg of+    Nothing -> do+      arg1 <- nextArg+      arg2 <- nextArg+      return (f arg1 arg2)+    Just arg1 -> do +      arg2 <- nextArg+      return (f arg1 arg2)+  ++shortOneArg :: ShortOpt -> (String -> a) -> Parser a+shortOneArg opt f = do+  nextShort opt+  maybeSameWordArg <- optional pendingShortOptArg+  case maybeSameWordArg of+    Nothing -> do+      arg <- nextArg+      return (f arg)+    Just a -> return (f a)+++shortOptionalArg :: ShortOpt -> (Maybe String -> a) -> Parser a+shortOptionalArg opt f = do+  nextShort opt+  maybeSameWordArg <- optional pendingShortOptArg+  case maybeSameWordArg of+    Nothing -> do+      maybeArg <- optional nonOptionPosArg+      case maybeArg of+        Nothing -> return (f Nothing)+        Just a -> return (f (Just a))+    Just a -> return (f (Just a))
+ System/Console/MultiArg/GetArgs.hs view
@@ -0,0 +1,68 @@+{-# LANGUAGE CPP #-}++-- | Get the arguments from the command line, ensuring they are+-- properly encoded into Unicode.+--+-- base 4.3.1.0 has a System.Environment.getArgs that does not return+-- a Unicode string. Instead, it simply puts each octet into a+-- different Char. Thus its getArgs is broken on UTF-8 and nearly any+-- non-ASCII encoding. As a workaround I use+-- System.Environment.UTF8. The downside of this is that it requires+-- that the command line be encoded in UTF8, regardless of what the+-- default system encoding is.+--+-- Unlike base 4.3.1.0, base 4.4.0.0 actually returns a proper Unicode+-- string when you call System.Environment.getArgs. (base 4.3.1.0+-- comes with ghc 7.0.4; base 4.4.0.0 comes with ghc 7.2.) The string+-- is encoded depending on the default system locale. The only problem+-- is that System.Environment.UTF8 apparently simply uses+-- System.Environment.getArgs and then assumes that the string it+-- returns has not been decoded. In other words,+-- System.Environment.UTF8 assumes that System.Environment.getArgs is+-- broken, and when System.Environment.getArgs was fixed in base+-- 4.4.0.0, it likely will break System.Environment.UTF8.+--+-- One obvious solution to this problem is to find some other way to+-- get the command line that will not break when base is updated. But+-- it was not easy to find such a thing. The other libraries I saw on+-- hackage (as of January 6, 2012) had problems, such as breakage on+-- ghc 7.2. There is a package that has a simple interface to the UNIX+-- setlocale(3) function, but I'm not sure that what it returns easily+-- and reliably maps to character encodings that you can use with,+-- say, iconv.+--+-- So by use of Cabal and preprocessor macors, the code uses+-- utf8-string if base is less than 4.4, and uses+-- System.Environment.getArgs if base is at least 4.4.+--+-- The GHC bug is here:+--+-- <http://hackage.haskell.org/trac/ghc/ticket/3309>++module System.Console.MultiArg.GetArgs ( getArgs, getProgName ) where++#if MIN_VERSION_base(4,4,0)+import qualified System.Environment as E ( getArgs, getProgName )+#else+import qualified System.Environment.UTF8 as E ( getArgs, getProgName )+#endif++-- | Gets the command-line arguments supplied by the program's+-- user. If the @base@ package is older than version 4.4, then this+-- function assumes the command line is encoded in UTF-8, which is+-- true for many newer Unix systems; however, many older systems may+-- use single-byte encodings like ISO-8859. In such cases, this+-- function will give erroneous results.+--+-- If the @base@ package is version 4.4.0 or newer, this function+-- simply uses the getArgs that comes with @base@. That getArgs+-- detects the system's default encoding and uses that, so it should+-- give accurate results on most systems.+getArgs :: IO [String]+getArgs = E.getArgs++-- | Gets the name of the program that the user invoked. See+-- documentation for 'getArgs' for important caveats that also apply+-- to this function.+getProgName :: IO String+getProgName = E.getProgName
+ System/Console/MultiArg/Option.hs view
@@ -0,0 +1,56 @@+-- | These types represent options. Option names cannot have a dash as+-- their first or second character, and long option names cannot have+-- an equals sign anywhere in the name.+module System.Console.MultiArg.Option (+  ShortOpt,+  unShortOpt,+  makeShortOpt,+  LongOpt,+  unLongOpt,+  makeLongOpt )+  where++import Data.List (find)++-- | Short options. Options that are preceded with a single dash on+-- the command line and consist of a single letter. That single letter+-- cannot be a dash. Any other Unicode character is good (including+-- pathological ones like newlines).+newtype ShortOpt = ShortOpt { unShortOpt :: Char } deriving (Show, Eq, Ord)++-- | Creates a short option. Returns Nothing if the character is not+-- valid for a short option.+makeShortOpt :: Char -> Maybe ShortOpt+makeShortOpt c = case c of+  '-' -> Nothing+  x -> Just $ ShortOpt x++-- | Long options. Options that are preceded with two dashes on the+-- command line and typically consist of an entire mnemonic word, such+-- as @lines@. However, anything that is at least one letter long is+-- fine for a long option name. The name must not have a dash as+-- either the first or second character and it must be at least one+-- character long. It cannot have an equal sign anywhere in its+-- name. Otherwise any Unicode character is good (including+-- pathological ones like newlines).+data LongOpt = LongOpt { unLongOpt :: String } deriving (Show, Eq, Ord)++-- | Makes a long option. Returns Nothing if the string is not a valid+-- long option.+makeLongOpt :: String -> Maybe LongOpt+makeLongOpt t = case isValidLongOptText t of+  True -> Just $ LongOpt t+  False -> Nothing++isValidLongOptText :: String -> Bool+isValidLongOptText s = case s of+  [] -> False+  x:xs ->+    if x == '-' || x == '='+    then False+    else case xs of+      [] -> True+      y:_ ->+        if y == '-' || y == '='+        then False+        else maybe True (const False) (find (== '=') xs)
+ System/Console/MultiArg/Prim.hs view
@@ -0,0 +1,741 @@+-- | Parser primitives. These are the only functions that have access+-- to the internals of the parser. Use these functions if you want to+-- build your own parser from scratch. If your needs are simpler, you+-- will want to look at "System.Console.MultiArg.SimpleParser" or+-- "System.Console.MultiArg.Combinator", which do a lot of grunt work+-- for you.+module System.Console.MultiArg.Prim (+    -- * Parser types+  Parser,+  +  -- * Running a parser+  +  -- | Each parser runner is applied to a list of Strings, which are the+  -- command line arguments to parse. +  parse,+  +  -- * Higher-level parser combinators+  parserMap,+  good,+  apply,+  choice,+  combine,+  lookAhead,+  +  -- ** Running parsers multiple times+  several,+  manyTill,++  -- ** Failure and errors+  throw,+  throwString,+  genericThrow,+  (<??>),+  try,+  +  -- * Parsers+  -- ** Short options and arguments+  pendingShortOpt,+  nonPendingShortOpt,+  pendingShortOptArg,  +  +  -- ** Long options and arguments+  exactLongOpt,+  approxLongOpt,++  -- ** Stoppers+  stopper,+  resetStopper,+  +  -- ** Positional (non-option) arguments+  nextArg,+  nonOptionPosArg,+  +  -- ** Miscellaneous+  end,+  +  -- * Errors+  Message(Expected, StrMsg, Replaced, UnknownError),+  Error(Error),+  Location++  ) where+++import System.Console.MultiArg.Option+  (ShortOpt,+    unShortOpt,+    LongOpt,+    unLongOpt, +    makeLongOpt )+import Control.Applicative ( Applicative, Alternative )+import qualified Control.Applicative+import Control.Monad.Exception.Synchronous+  (Exceptional(Success, Exception))+import qualified Data.Set as Set+import Data.Set ( Set )+import Control.Monad ( when, MonadPlus(mzero, mplus), guard )+import Data.Monoid ( Monoid ( mempty, mappend ) )+import qualified Data.List as L+import Data.List (isPrefixOf)++type Location = String++-- | An Error contains a list of Messages and a String indicating+-- where the error happened.+data Error = Error [Message] Location deriving Show++-- | Extract a Location from a ParseSt for use in error messages.+location :: ParseSt -> Location+location st = pending ++ next ++ stop where+  pending+    | null (pendingShort st) = ""+    | otherwise = "short option or short option argument: "+                  ++ pendingShort st ++ " "+  next = case remaining st of+    [] -> "no words remaining"+    x:_ -> "next word: " ++ x+  stop = if sawStopper st then " (stopper already seen)" else ""++-- | Error messages.+data Message =+  Expected String+  -- ^ The parser expected to see one thing, but it actually saw+  -- something else. The string indicates what was expected.+  | StrMsg String+    -- ^ The 'fromString' function was applied.+    +  | Replaced String+    -- ^ A previous list of error messages was replaced with this error message.+    +  | UnknownError+    -- ^ Any other error; used by 'genericThrow'.++  deriving Show++-- | Carries the internal state of the parser. The counter is a simple+-- way to determine whether the remaining list one ParseSt has been+-- modified from another. When parsers modify remaining, they+-- increment the counter.+data ParseSt = ParseSt { pendingShort :: String+                       , remaining :: [String]+                       , sawStopper :: Bool+                       , counter :: Int+                       , errors :: [Message]+                       } deriving Show++-- | Load up the ParseSt with an initial user state and a list of+-- commmand line arguments.+defaultState :: [String] -> ParseSt+defaultState ts = ParseSt { pendingShort = ""+                          , remaining = ts+                          , sawStopper = False+                          , counter = 0+                          , errors = [] }++-- | Carries the result of each parse.+data Result a = Bad | Good a++-- | Parsers. Internally the parser tracks what input remains to be+-- parsed, whether there are any pending short options, and whether a+-- stopper has been seen. A parser can return a value of any type.+--+-- The parser also includes the notion of failure. Any parser can+-- fail; a failed parser affects the behavior of combinators such as+-- combine.+data Parser a =+  Parser { runParser :: ParseSt -> (Result a, ParseSt) }++instance Functor Parser where+  fmap = parserMap++instance Applicative Parser where+  pure = good+  (<*>) = apply++instance Monoid (Parser a) where+  mempty = genericThrow+  mappend = choice++instance Alternative Parser where+  empty = genericThrow+  (<|>) = choice+  many = several++instance Monad Parser where+  (>>=) = combine+  return = good+  fail = throwString++instance MonadPlus Parser where+  mzero = genericThrow+  mplus = choice+++-- | Runs a parser. This is the only way to change a value of type+-- @Parser a@ into a value of type @a@ (that is, it is the only way to+-- \"get out of the Parser monad\" or to \"escape the Parser monad\".)+parse ::+  [String]+  -- ^ Command line arguments to parse. Presumably you got these from+  -- 'getArgs'. If there is any chance that you will be parsing+  -- Unicode strings, see the documentation in+  -- "System.Console.MultiArg.GetArgs" before you use+  -- 'System.Environment.getArgs'.+  +  -> Parser a+  -- ^ Parser to run+  +  -> Exceptional Error a+  -- ^ Success or failure. Any parser might fail; for example, the+  -- command line might not have any values left to parse. Use of the+  -- 'choice' combinator can lead to a list of failures. If multiple+  -- parsers are tried one after another using the 'choice' combinator,+  -- and each fails without consuming any input, then multiple Error+  -- will result, one for each failure.++parse ts p =+  let (result, st') = runParser p (defaultState ts)+  in case result of+    Good g -> Success g+    Bad ->+      let e = Error (errors st') (location st')+      in Exception e+++-- | Combines two parsers into a single parser. The second parser can+-- optionally depend upon the result from the first parser.+--+-- This applies the first parser. If the first parser succeeds,+-- combine then takes the result from the first parser, applies the+-- function given to the result from the first parser, and then+-- applies the resulting parser.+--+-- If the first parser fails, combine will not apply the second+-- function but instead will bypass the second parser.+--+-- This provides the implementation for '>>=' in+-- 'Control.Monad.Monad'.+combine :: Parser a -> (a -> Parser b) -> Parser b+combine a k = Parser $ \s ->+  let (r, s') = runParser a s+  in case r of+    Bad -> (Bad, s')+    Good g -> runParser (k g) s'+++-- | @lookAhead p@ runs parser p. If p succeeds, lookAhead p succeeds+-- without consuming any input. If p fails without consuming any+-- input, so does lookAhead. If p fails and consumes input, lookAhead+-- also fails and consumes input. If this is undesirable, combine with+-- "try".+lookAhead :: Parser a -> Parser a+lookAhead a = Parser $ \s ->+  let (r, s') = runParser a s+  in case r of+    Good g -> (Good g, s)+    Bad -> (Bad, s')+++-- | @good a@ always succeeds without consuming any input and has+-- result a. This provides the implementation for+-- 'Control.Monad.Monad.return' and+-- 'Control.Applicative.Applicative.pure'.+good :: a -> Parser a+good a = Parser $ \s -> (Good a, s)+++-- | @throwString s@ always fails without consuming any input. The+-- failure contains a record of the string passed in by s. This+-- provides the implementation for 'Control.Monad.Monad.fail'.+throwString :: String -> Parser a+throwString e = Parser $ \s ->+  let err = StrMsg e+      s' = s { errors = err : errors s }+  in (Bad, s')+++-- | @parserMap f p@ applies function f to the result of parser+-- p. First parser p is run. If it succeeds, function f is applied to+-- the result and another parser is returned with the result. If it+-- fails, f is not applied and a failed parser is returned. This+-- provides the implementation for 'Prelude.Functor.fmap'.+parserMap :: (a -> b) -> Parser a -> Parser b+parserMap f l = Parser $ \s ->+  let (r, s') = runParser l s+  in case r of+    Good g -> (Good (f g), s')+    Bad -> (Bad, s')+++-- | apply l r applies the function found in parser l to the result of+-- parser r. First the l parser is run. If it succeeds, it has a+-- resulting function. Then the r parser is run. If it succeeds, the+-- function from the l parser is applied to the result of the r+-- parser, and a new parser is returned with the result. If either+-- parser l or parser r fails, then a failed parser is returned. This+-- provides the implementation for '<*>' in+-- 'Control.Applicative.Applicative'.+apply :: Parser (a -> b) -> Parser a -> Parser b+apply fa a = Parser $ \s ->+  let (r, s') = runParser fa s+  in case r of+    Good g ->+      let (ra, sa) = runParser a s'+      in case ra of+        Good ga -> (Good (g ga), sa)+        Bad -> (Bad, sa)+    Bad -> (Bad, s')+++-- | Fail with an unhelpful error message. Usually throw is more+-- useful, but this is handy to implement some typeclass instances.+genericThrow :: Parser a+genericThrow = throw UnknownError++-- | throw e always fails without consuming any input and returns a+-- failed parser with error state e.+throw :: Message -> Parser a+throw e = Parser $ \s ->+  (Bad, s { errors = e : errors s })++noConsumed :: ParseSt -> ParseSt -> Bool+noConsumed old new = counter old >= counter new++-- | Runs the first parser. If it fails without consuming any input,+-- then runs the second parser. If the first parser succeeds, then+-- returns the result of the first parser. If the first parser fails+-- and consumes input, then returns the result of the first+-- parser. This provides the implementation for+-- '<|>' in 'Control.Applicative.Alternative'.+choice :: Parser a -> Parser a -> Parser a+choice a b = Parser $ \sOld ->+  let (ra, sa) = runParser a sOld+  in case ra of+    Good g ->+      let sNew = sa { errors = [] }+      in (Good g, sNew)+    Bad ->+      if noConsumed sOld sa+      then let sNew = sOld { errors = errors sa }+               (rb, sb) = runParser b sNew+           in case rb of+             Good g' -> let sb' = sb { errors = [] }+                        in (Good g', sb')+             Bad -> (Bad, sb)+      else (Bad, sa)+++-- | Runs the parser given. If it fails /without consuming any input/,+-- then applies the given function to the list of messages and replaces+-- the list of messages with the list returned by the+-- function. Otherwise, returns the result of the parser.+(<??>) :: Parser a -> ([Message] -> [Message]) -> Parser a+(<??>) l f = Parser $ \s ->+  let (r, s') = runParser l s+  in case r of+    Good g -> (Good g, s')+    Bad ->+      if noConsumed s s'+      then let s'' = s' { errors = f $ errors s' }+           in (Bad, s'')+      else (Bad, s')++infix 0 <??>++increment :: ParseSt -> ParseSt+increment old = old { counter = succ . counter $ old }++-- | Parses only pending short options. Fails without consuming any+-- input if there has already been a stopper or if there are no+-- pending short options. Fails without consuming any input if there+-- is a pending short option, but it does not match the short option+-- given. Succeeds and consumes a pending short option if it matches+-- the short option given.++pendingShortOpt :: ShortOpt -> Parser ()+pendingShortOpt so = Parser $ \s ->+  let err = Expected ("pending short option: " ++ [(unShortOpt so)])+      es = (Bad, s { errors = err : errors s })+      gd newSt = (Good (), newSt)+  in maybe es gd $ do+    when (sawStopper s) Nothing+    (first, rest) <- case pendingShort s of+      [] -> Nothing+      x:xs -> return (x, xs)+    when (unShortOpt so /= first) Nothing+    return (increment s { pendingShort = rest })++-- | Parses only non-pending short options. Fails without consuming+-- any input if, in order:+--+-- * there are pending short options+--+-- * there has already been a stopper+--+-- * there are no arguments left to parse+--+-- * the next argument is an empty string+--+-- * the next argument does not begin with a dash+--+-- * the next argument is a single dash+--+-- * the next argument is a short option but it does not match+--   the one given+--+-- * the next argument is a stopper+--+-- Otherwise, consumes the next argument, puts any remaining letters+-- from the argument into a pending short, and removes the first word+-- from remaining arguments to be parsed.+nonPendingShortOpt :: ShortOpt -> Parser ()+nonPendingShortOpt so = Parser $ \s ->+  let err = Expected (msg ++ [unShortOpt so])+      msg = "non pending short option: "+      errRet = (Bad, s { errors = err : errors s })+      gd n = (Good (), n)+  in maybe errRet gd $ do+    guard (noPendingShorts s)+    guard (noStopper s)+    (a, s') <- nextWord s+    (maybeDash, word) <- case a of+      [] -> Nothing+      x:xs -> return (x, xs)+    guard (maybeDash == '-')+    (letter, arg) <- case word of+      [] -> Nothing+      x:xs -> return (x, xs)+    guard (letter == unShortOpt so)+    let s'' = s' { pendingShort = arg }+    return s''++-- | Parses an exact long option. That is, the text of the+-- command-line option must exactly match the text of the+-- option. Returns the option, and any argument that is attached to+-- the same word of the option with an equal sign (for example,+-- @--follow=\/dev\/random@ will return @Just \"\/dev\/random\"@ for the+-- argument.) If there is no equal sign, returns Nothing for the+-- argument. If there is an equal sign but there is nothing after it,+-- returns @Just \"\"@ for the argument.+--+-- If you do not want your long option to have equal signs and+-- GNU-style option arguments, wrap this parser in something that will+-- fail if there is an option argument.+--+-- Fails without consuming any input if:+--+-- * there are pending short options+--+-- * a stopper has been parsed+--+-- * there are no arguments left on the command line+--+-- * the next argument on the command line does not begin with+--   two dashes+--+-- * the next argument on the command line is @--@ (a stopper)+--+-- * the next argument on the command line does begin with two+--   dashes but its text does not match the argument we're looking for+exactLongOpt :: LongOpt -> Parser (Maybe String)+exactLongOpt lo = Parser $ \s ->+  let ert = (Bad, err)+      err = s { errors = Expected msg : errors s } where+        msg = "long option: " ++ unLongOpt lo+      gd (g, n) = (Good g, n)+  in maybe ert gd $ do+    guard (noPendingShorts s)+    guard (noStopper s)+    (x, s') <- nextWord s+    (word, afterEq) <- getLongOption x+    guard (word == unLongOpt lo)+    return (afterEq, s')++-- | Takes a single String and returns a tuple, where the first element+-- is the first two letters, the second element is everything from the+-- third letter to the equal sign, and the third element is Nothing if+-- there is no equal sign, or Just String with everything after the+-- equal sign if there is one.+splitLongWord :: String -> (String, String, Maybe String)+splitLongWord t = (f, s, r) where+  (f, rest) = L.splitAt 2 t+  (s, withEq) = L.break (== '=') rest+  r = case withEq of+    [] -> Nothing+    _:xs -> Just xs+++noPendingShorts :: ParseSt -> Bool+noPendingShorts st = case pendingShort st of+  [] -> True+  _ -> False++noStopper :: ParseSt -> Bool+noStopper = not . sawStopper++getLongOption :: String -> Maybe (String, Maybe String)+getLongOption str = do+  guard (str /= "--")+  let (pre, word, afterEq) = splitLongWord str+  guard (pre == "--")+  return (word, afterEq)+  ++nextWord :: ParseSt -> Maybe (String, ParseSt)+nextWord st = case remaining st of+  [] -> Nothing+  x:xs ->+    let s' = increment st { remaining = xs }+    in return (x, s')++approxLongOptError ::+  Set LongOpt+  -> ParseSt+  -> ParseSt+approxLongOptError set st = st { errors = newE : errors st } where+  newE = Expected ex+  ex = "a long option: " ++ longs+  longs = concat . L.intersperse ", " $ opts+  opts = fmap unLongOpt . Set.toList $ set++-- | Examines the next word. If it matches a Text in the set+-- unambiguously, returns a tuple of the word actually found and the+-- matching word in the set and the accompanying text after the equal+-- sign (if any). If the Set is empty, this parser will always fail.+approxLongOpt ::+  Set LongOpt+  -> Parser (String, LongOpt, Maybe String)+approxLongOpt ts = Parser $ \s ->+  let err = (Bad, approxLongOptError ts s)+      gd (g, newSt) = (Good g, newSt)+  in maybe err gd $ do+    guard (noPendingShorts s)+    (x, s') <- nextWord s+    (word, afterEq) <- getLongOption x+    opt <- makeLongOpt word+    if Set.member opt ts+      then return ((word, opt, afterEq), s')+      else do+      let p t = word `isPrefixOf` (unLongOpt t)+          matches = Set.filter p ts+      case Set.toList matches of+        [] -> Nothing+        (m:[]) -> return ((word, m, afterEq), s')+        _ -> Nothing++-- | Parses only pending short option arguments. For example, for the+-- @tail@ command, if you enter the option @-c25@, then after parsing+-- the @-c@ option the @25@ becomes a pending short option argument+-- because it was in the same command line argument as the @-c@.+--+-- Fails without consuming any input if:+--+-- * a stopper has already been parsed+--+-- * there are no pending short option arguments+--+-- On success, returns the String of the pending short option argument+-- (this String will never be empty).+pendingShortOptArg :: Parser String+pendingShortOptArg = Parser $ \s ->+  let ert = (Bad, err)+      err = s { errors = Expected msg : errors s } where+        msg = "pending short option argument"+      gd (g, newSt) = (Good g, newSt)+  in maybe ert gd $ do+    guard (noStopper s)+    case pendingShort s of+      [] -> Nothing+      xs ->+        let newSt = increment s { pendingShort = "" }+        in return (xs, newSt)+++-- | Parses a \"stopper\" - that is, a double dash. Changes the internal+-- state of the parser to reflect that a stopper has been seen.+stopper :: Parser ()+stopper = Parser $ \s ->+  let err = s { errors = Expected msg : errors s } where+        msg = "stopper"+      ert = (Bad, err)+      gd (g, newSt) = (Good g, newSt)+  in maybe ert gd $ do+    guard (noPendingShorts s)+    guard (noStopper s)+    (x, s') <- nextWord s+    guard (x == "--")+    let s'' = s' { sawStopper = True }+    return ((), s'')++-- | If a stopper has already been seen, change the internal state+-- back to indicating that no stopper has been seen.+resetStopper :: Parser ()+resetStopper = Parser $ \s ->+  let s' = s { sawStopper = False }+  in (Good (), s')++-- | try p behaves just like p, but if p fails, try p will not consume+-- any input.+try :: Parser a -> Parser a+try a = Parser $ \s ->+  let (r, s') = runParser a s+  in case r of+    Good g -> (Good g, s')+    Bad -> (Bad, s'') where+      s'' = s { errors = errors s' }+      ++-- | Returns the next string on the command line as long as there are+-- no pendings. Be careful - this will return the next string even if+-- it looks like an option (that is, it starts with a dash.) Consider+-- whether you should be using nonOptionPosArg instead. However this+-- can be useful when parsing command line options after a stopper.+nextArg :: Parser String+nextArg = Parser $ \s ->+  let ert = (Bad, err)+      err = s { errors = Expected msg : errors s } where+        msg = "next argument"+      gd (g, newSt) = (Good g, newSt)+  in maybe ert gd $ do+    guard (noPendingShorts s)+    nextWord s+++-- | If there are pending short options, fails without consuming any input.+--+-- Otherwise, if a stopper has NOT already been parsed, then returns+-- the next word if it is either a single dash or any other word that+-- does not begin with a dash. If the next word does not meet these+-- criteria, fails without consuming any input.+--+-- Otherwise, if a stopper has already been parsed, then returns the+-- next word, regardless of whether it begins with a dash or not.+nonOptionPosArg :: Parser String+nonOptionPosArg = Parser $ \s ->+  let ert = (Bad, err)+      err = s { errors = Expected msg : errors s } where+        msg = "non option positional argument"+      gd (g, newSt) = (Good g, newSt)+  in maybe ert gd $ do+    guard (noPendingShorts s)+    (x, s') <- nextWord s+    result <-+      if sawStopper s+      then return x+      else case x of+        [] -> return x+        '-':[] -> return "-"+        f:_ -> if f == '-'+               then Nothing+               else return x+    return (result, s')+++-- | manyTill p e runs parser p repeatedly until parser e succeeds.+--+-- More precisely, first it runs parser e. If parser e succeeds, then+-- manyTill returns the result of all the preceding successful parses+-- of p. If parser e fails (it does not matter whether e consumed any+-- input or not), manyTill runs parser p again. What happens next+-- depends on whether p succeeded or failed. If p succeeded, then the+-- loop starts over by running parser e again. If p failed (it does+-- not matter whether it consumed any input or not), then manyTill+-- fails. The state of the parser is updated to reflect its state+-- after the failed run of p, and the parser is left in a failed+-- state.+--+-- Should parser e succeed (as it will on a successful application of+-- manyTill), then the parser state will reflect that parser e+-- succeeded--that is, if parser e consumes input, that input will be+-- consumed in the parser that is returned. Wrap e inside of+-- @lookAhead@ if that is undesirable.+--+-- Be particularly careful to get the order of the arguments+-- correct. Applying this function to reversed arguments will yield+-- bugs that are very difficult to diagnose.+manyTill :: Parser a -> Parser end -> Parser [a]+manyTill (Parser r) (Parser f) = Parser $ \s ->+  let Till g lS lF = parseTill s r f+  in if lF then (Bad, lS) else (Good g, lS)+++data Till a =+  Till { _goods :: [a]+       , _lastSt :: ParseSt+       , _lastRunFailed :: Bool }++parseTill ::+  ParseSt+  -> (ParseSt -> (Result a, ParseSt))+  -> (ParseSt -> (Result b, ParseSt))+  -> Till a+parseTill s fr ff =+  case ff s of+    (Good _, s') -> Till [] s' False+    (Bad, _) ->+      case fr s of+        (Bad, s'') -> Till [] s'' True+        (Good g, s'') ->+          let Till gs lS lF = parseTill s'' fr ff+          in if counter s'' == counter s+             then parseTillErr+             else Till (g:gs) lS lF++parseTillErr :: a+parseTillErr =+  error "parseTill applied to parser that takes empty list"+++-- | several p runs parser p zero or more times and returns all the+-- results. This proceeds like this: parser p is run and, if it+-- succeeds, the result is saved and parser p is run+-- again. Repeat. Eventually this will have to fail. If the last run+-- of parser p fails without consuming any input, then several p runs+-- successfully. The state of the parser is updated to reflect the+-- successful runs of p. If the last run of parser p fails but it+-- consumed input, then several p fails. The state of the parser is+-- updated to reflect the state up to and including the run that+-- partially consumed input. The parser is left in a failed state.+--+-- This semantic can come in handy. For example you might run a parser+-- multiple times that parses an option and arguments to the+-- option. If the arguments fail to parse, then several will fail.+--+-- This function provides the implementation for+-- 'Control.Applicative.Alternative.many'.+several :: Parser a -> Parser [a]+several (Parser l) = Parser $ \s ->+  let (result, finalGoodSt, finalBadSt) = parseRepeat s l+  in if noConsumed finalGoodSt finalBadSt+     then (Good result, finalGoodSt)+     else (Bad, finalBadSt)+++parseRepeat ::+  ParseSt+  -> (ParseSt -> (Result a, ParseSt))+  -> ([a], ParseSt, ParseSt)+parseRepeat st1 f =+  case f st1 of+    (Good a, st') ->+      if noConsumed st1 st'+      then error $ "several applied to parser that succeeds without"+           ++ " consuming any input"+      else+        let (ls, finalGoodSt, finalBadSt) = parseRepeat st' f+        in (a : ls, finalGoodSt, finalBadSt)+    (Bad, st') -> ([], st1, st')+    ++-- | Succeeds if there is no more input left.+end :: Parser ()+end = Parser $ \s ->+  let ert = (Bad, err)+      err = s { errors = Expected msg : errors s } where+        msg = "end of input"+      gd (g, newSt) = (Good g, newSt)+  in maybe ert gd $ do+    guard (noPendingShorts s)+    guard (null . remaining $ s)+    return ((), s)
+ System/Console/MultiArg/SampleParser.hs view
@@ -0,0 +1,63 @@+-- | This is sample code using "System.Console.MultiArg". This could+-- be a command-line parser for the version of the Unix command @tail@+-- that is included with GNU coreutils version 8.5. "main" simply gets+-- the command line arguments, parses them, and prints out what was+-- parsed. To test it out, simply compile an executable that looks+-- like this and then feed it different options:+--+-- > import System.Console.MultiArg.SampleParser+-- > main = sampleMain Intersperse+--+-- or:+--+-- > import System.Console.MultiArg.SampleParser+-- > main = sampleMain StopOptions+--+-- The code in the module is the sample code; the sample code is not+-- in the Haddock documentation! If you're reading this in Haddock,+-- you will want to also take a look at the actual source code.+module System.Console.MultiArg.SampleParser (+  Flag(..)+  , specs+  , P.Intersperse(..)+  , sampleMain+  ) where++import System.Console.MultiArg.SimpleParser as P++data Flag =+  Bytes String+  | Follow (Maybe String)+  | Retry+  | Lines String+  | Stats String+  | Pid String+  | Quiet+  | Sleep String+  | Verbose+  | Help+  | Version+  | Filename String+  deriving Show++specs :: [P.OptSpec Flag]++specs =+  [ P.OptSpec ["bytes"]                     ['c']     (P.OneArg Bytes)+  , P.OptSpec ["follow"]                    ['f']     (P.OptionalArg Follow)+  , P.OptSpec ["follow-retry"]              ['F']     (P.NoArg Retry)+  , P.OptSpec ["lines"]                     ['n']     (P.OneArg Lines)+  , P.OptSpec ["max-unchanged-stats"]       []        (P.OneArg Stats)+  , P.OptSpec ["pid"]                       []        (P.OneArg Pid)+  , P.OptSpec ["quiet"]                     ['q']     (P.NoArg Quiet)+  , P.OptSpec ["sleep-interval"]            ['s']     (P.OneArg Sleep)+  , P.OptSpec ["verbose"]                   ['v']     (P.NoArg Verbose)+  , P.OptSpec ["help"]                      []        (P.NoArg Help)+  , P.OptSpec ["version"]                   []        (P.NoArg Version)+  ]++sampleMain :: P.Intersperse -> IO ()+sampleMain i = do+  as <- P.getArgs+  let r = P.parse i specs Filename as+  print r
+ System/Console/MultiArg/SimpleParser.hs view
@@ -0,0 +1,105 @@+-- | 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 = do+  opts <- parseOptsNoIntersperse optParser+  _ <- optional P.stopper+  args <- many P.nextArg+  return $ opts ++ (map p args)+++-- | @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 = P.nonOptionPosArg >>= return . Just . p+      po = optParser >>= return . Just+      ps = P.stopper *> return Nothing+      parser = po <|> ps <|> pa+  in P.manyTill parser P.end >>= return . catMaybes
− doc/sample.hs
@@ -1,4 +0,0 @@-import System.Console.MultiArg.SampleParser--main :: IO ()-main = sampleMain
− lib/System/Console/MultiArg.hs
@@ -1,169 +0,0 @@--- | A combinator library for building command-line parsers.--module System.Console.MultiArg (--  -- | To say this library is inspired by Parsec would probably insult the-  -- creators of Parsec, as this library could not possibly be as-  -- elegant or throughly considered as Parsec is. Nevertheless this-  -- library can be used in a similar style as Parsec, but is-  -- specialized for parsing command lines.-  ---  -- This parser was built because I could not find anything that would-  -- readily parse command lines where the options took more than one-  -- argument. For example, for the @tail@ command on GNU systems, the-  -- --lines option takes one argument to specify how many lines you-  -- want to see. Well, what if you want to build a program with an-  -- option that takes /two/ arguments, like @--foo bar baz@? I found no-  -- such library so I built this one. Nevertheless, using this library-  -- you can build parsers to parse a variety of command line-  -- vocabularies, from simple to complex.--  -- * Terminology-  -  -- | Some terms are used throughout multiarg:-  ---  -- [@word@] When you run your program from the Unix shell prompt,-  -- your shell is responsible for splitting the command line into-  -- words. Typically you separate words with spaces, although quoting-  -- can affect this. multiarg parses lists of words. Each word can-  -- consist of a single long option, a single long option and an-  -- accompanying option argument, a single short option, multiple-  -- short options, and even one or more multiple short options and an-  -- accompanying short option argument. Or, a word can be a-  -- positional argument or a stopper. All these are described below.-  ---  -- [@option@] Options allow a user to specify ways to tune the-  -- operation of a program. Typically options are indeed optional,-  -- although some programs do sport \"required options\" (a bit of an-  -- oxymoron). Options can be either short options or long-  -- options. Also, options can take arguments.-  ---  -- [@short option@] An option that is specified with a single hyphen-  -- and a single letter. For example, for the program @tail(1)@,-  -- possible short options include @n@ and @v@. With multiarg it is-  -- possible to easily parse short options that are specified in-  -- different words or in the same word. For example, if a user wants-  -- to run @tail@ with two options, he might type @tail -v -f@ or he-  -- might type @tail -vf@.-  ---  -- [@long option@] An option that is specified using two hyphens and-  -- what is usually a mnemonic word, though it could be as short as a-  -- single letter. For example, @tail(1)@ has long options including-  -- @follow@ and @verbose@. The user would specify these on the-  -- command line by typing @tail --follow --verbose@.-  ---  -- [@option argument@] Some options take additional arguments that-  -- are specific to the option and change what the option does. For-  -- instance, the @lines@ option to @tail(1)@ takes a single,-  -- optional argument, which is the number of lines to show. Option-  -- arguments can be optional or required, and a single option can-  -- take a mulitple, fixed number of arguments and it can take a-  -- variable number of arguments. Option arguments can be given in-  -- various ways. They can be specified in the same word as a long-  -- option by using an equals sign; they can also be specified in the-  -- same word as a short option simply by placing them in the same-  -- word, or they can be specified in the following word. For-  -- example, these different command lines all mean the same thing;-  -- @tail --verbose --lines=20@, @tail --verbose --lines 20@, @tail-  -- -vn 20@, @tail -v -n20@, @tail -vn20@, and @tail -v -n 20@, and-  -- numerous other combinations also have the same meaning.-  ---  -- [@GNU-style option argument@] A long option with an argument-  -- given with an equal sign, such as [@lines=20@].-  ---  -- [@positional argument@] A word on the command line that is not an-  -- option or an argument to an option. For instance, with @tail(1)@,-  -- you specify the files you want to see by using positional-  -- arguments. In the command @tail -n 10 myfile@, @myfile@ is a-  -- positional argument. For some programs, such as @git@ or @darcs@,-  -- a positional argument might be a \"command\" or a \"mode\", such-  -- as the @commit@ in @git commit@ or the @whatsnew@ in @darcs-  -- whatsnew@. multiarg has no primitive parsers that treat these-  -- positional arguments specially but it is trivial to build a-  -- parser for command lines such as this, too.-  ---  -- [@stopper@] A single word consisting solely of two hyphens,-  -- @--@. The user types this to indicate that all subsequent words-  -- on the command line are positional arguments, even if they begin-  -- with hyphens and therefore look like they might be options.-  ---  -- [@pending@] The user might specify more than one short option, or-  -- a short option and a short option argument, in a single word. For-  -- example, she might type @tail -vl20@. After parsing the @v@-  -- option, the Parser makes @l20@ into a \"pending\". The next-  -- parser can then treat @l20@ as an option argument to the @v@-  -- option (which is probably not what was wanted) or the next parser-  -- can parse @l@ as a short option. This would result in a-  -- \"pending\" of @20@. Then, the next parser can treat @20@ as an-  -- option argument. After that parse there will be no pendings.-  -  -- * Getting started--  -- |If your needs are simple to moderately complicated just look at the-  -- "System.Console.MultiArg.SimpleParser" module, which uses the-  -- underlying combinators to build a simple parser for you. That-  -- module is already exported from this module for easy usage. For-  -- maximum flexibility you will want to start with the-  -- "System.Console.MultiArg.Prim" module.-  ---  -- Using the parsers and combinators in-  -- "System.Console.MultiArg.Prim", you can easily build parsers that-  -- are quite complicated. The parsers can check for errors along the-  -- way, simplifying the sometimes complex task of ensuring that data-  -- a user supplied on the command line is good. You can easily build-  -- parsers for programs that take no options, take dozens of-  -- options, require that options be given in a particular order,-  -- require that some options be given, or bar some combinations of-  -- options. You might also require particular positional-  -- arguments. You can also easily parse command lines for programs-  -- that have multiple \"modes\", like @git@ or @darcs@. If you're-  -- doing this, of course first start by reading the documentation-  -- for "System.Console.MultiArg.Prim" and-  -- "System.Console.MultiArg.Combinator". You will also want to look-  -- at the source code for "System.Console.MultiArg.Combinator" and-  -- "System.Console.Multiarg.SimpleParser", as these show some ways-  -- to use the primitive parsers and combinators.--  -- * Non-features and shortcomings-  ---  -- | multiarg isn't perfect; no software is. multiarg does not-  -- automatically make online help for your command line-  -- parsers. Getting this right would be tricky given the nature of-  -- the code and I don't even want to bother trying, as I just write-  -- my own online help in a text editor.-  ---  -- multiarg partially embraces \"The Tao of Option Parsing\" that-  -- Python's Optik (<http://optik.sourceforge.net/>) follows. Read-  -- \"The Tao of Option Parsing\" here:-  ---  -- <http://optik.sourceforge.net/doc/1.5/tao.html>-  ---  -- multiarg's philosophy is similar to that of Optik, which-  -- means you won't be able to use multiarg to (easily) build a clone-  -- to the UNIX @find(1)@ command. (You could do it, but multiarg won't-  -- help you very much.)-  ---  -- multiarg can be complicated, although I'd like to believe this is-  -- because it addresses a complicated problem in a flexible way.-  ---  -- Internally the combinators in "System.Console.MultiArg.Prim" use-  -- strict "Data.Text" values rather than "String"s. That is because-  -- this library was built for an application that sometimes parses an-  -- enormous amount of command line data, and I thought that using-  -- Data.Text would yield some memory savings while retaining Unicode-  -- safety. Though I cannot remember whether this actually yielded any-  -- space savings (it did not lead to more space usage, at least) it-  -- also made the parser consistent with the rest of that program,-  -- which also uses Data.Text. I have considered making this library-  -- use either Data.Text or Strings but that makes it a lot more-  -- complicated for little gain. The SimpleParser module, however,-  -- wraps the "Data.Text" values up and exposes only Strings in the-  -- interface, keeping things nice and simple. This does mean that-  -- Strings have to be converted to Data.Text and back again, but the-  -- performance hit will not be significant unless you are parsing an-  -- obscene amount of data--and if you're doing that, you might want to-  -- use Data.Text anyway :)--  module System.Console.MultiArg.SimpleParser ) where--import System.Console.MultiArg.SimpleParser
− lib/System/Console/MultiArg/Combinator.hs
@@ -1,364 +0,0 @@--- | Combinators that are useful for building command-line--- parsers. These build off the functions in--- "System.Console.MultiArg.Prim". Unlike those functions, these--- functions have no access to the internals of the parser.-module System.Console.MultiArg.Combinator (-  -- * Parser combinators-  option,-  optionMaybe,-  notFollowedBy,-  -  -- * Short options-  shortNoArg,-  shortOptionalArg,-  shortOneArg,-  shortTwoArg,-  shortVariableArg,--  -- * Long options-  nonGNUexactLongOpt,-  matchApproxLongOpt,-  matchNonGNUApproxLongOpt,-  longNoArg,-  longOptionalArg,-  longOneArg,-  longTwoArg,-  longVariableArg,-  -  -- * Mixed options-  mixedNoArg,-  mixedOptionalArg,-  mixedOneArg,-  mixedTwoArg,-  mixedVariableArg,-  -  -- * Other words-  matchApproxWord ) where-  -import Data.Text ( Text, isPrefixOf )-import Data.Set ( Set )-import qualified Data.Set as Set-import Control.Monad ( liftM )--import System.Console.MultiArg.Prim-  ( ParserT, throw, try, approxLongOpt,-    nextArg, pendingShortOptArg, nonOptionPosArg,-    pendingShortOpt, nonPendingShortOpt,-    exactLongOpt, nextArg, (<?>))-import System.Console.MultiArg.Option-  ( LongOpt, ShortOpt )-import qualified System.Console.MultiArg.Error as E-import System.Console.MultiArg.Error-  ( Error, parseErr )-import Control.Applicative ((<|>), many)-import Control.Monad ( void )-import Data.Monoid ( mconcat )---- | @option x p@ runs parser p. If p fails without consuming any--- input, returns x. Otherwise, returns p.-option :: (Error e, Monad m) =>-          a-          -> ParserT s e m a-          -> ParserT s e m a-option x p = p <|> return x---- | @optionMaybe p@ runs parser p. If p fails without returning any--- input, returns Nothing. If p succeeds, returns the result of p--- wrapped in a Just. If p fails but consumes input, optionMaybe--- fails.-optionMaybe :: (Error e, Monad m)-               => ParserT s e m a-               -> ParserT s e m (Maybe a)-optionMaybe p = option Nothing (liftM Just p)---- | @notFollowedBy p@ succeeds only if parser p fails. If p fails,--- notFollowedBy succeeds without consuming any input. If p succeeds--- and consumes input, notFollowedBy fails and consumes input. If p--- succeeds and does not consume any input, notFollowedBy fails and--- does not consume any input.-notFollowedBy :: (Error e, Monad m)-                 => ParserT s e m a-                 -> ParserT s e m ()-notFollowedBy p =-  void $ ((try p >> throw (E.parseErr E.ExpNotFollowedBy E.SawFollowedBy))-          <|> return ())----- | Parses only a non-GNU style long option (that is, one that does--- not take option arguments by attaching them with an equal sign,--- such as @--lines=20@).-nonGNUexactLongOpt :: (Error e, Monad m)-                      => LongOpt-                      -> ParserT s e m LongOpt-nonGNUexactLongOpt l = try $ do-  (lo, maybeArg) <- exactLongOpt l-  case maybeArg of-    Nothing -> return lo-    (Just t) ->-      throw (parseErr (E.ExpNonGNUExactLong l)-            (E.SawGNULongOptArg t))---- | Takes a long option and a set of long options. If the next word--- on the command line unambiguously starts with the name of the long--- option given, returns the actual text found on the command line,--- the long option, and the text of any GNU-style option--- argument. Make sure that the long option you are looking for is--- both the first argument and that it is included in the set;--- otherwise this parser will always fail.-matchApproxLongOpt :: (Error e, Monad m)-                      => LongOpt-                      -> Set LongOpt-                      -> ParserT s e m (Text, LongOpt, Maybe Text)-matchApproxLongOpt l s = try $ do-  a@(t, lo, _) <- approxLongOpt s-  if lo == l-    then return a-    else throw (parseErr (E.ExpMatchingApproxLong l s)-               (E.SawNotMatchingApproxLong t lo))---- | Like matchApproxLongOpt but only parses non-GNU-style long--- options.-matchNonGNUApproxLongOpt :: (Error e, Monad m)-                            => LongOpt-                            -> Set LongOpt-                            -> ParserT s e m (Text, LongOpt)-matchNonGNUApproxLongOpt l s = try $ do-  (t, lo, arg) <- matchApproxLongOpt l s-  let err b = throw (parseErr (E.ExpNonGNUMatchingApproxLong l s)-                    (E.SawMatchingApproxLongWithArg b))-  maybe (return (t, lo)) err arg---- | Examines the possible words in Set. If there are no pendings,--- then get the next word and see if it matches one of the words in--- Set. If so, returns the word actually parsed and the matching word--- from Set. If there is no match, fails without consuming any input.-matchApproxWord :: (Error e, Monad m)-                   => Set Text-                   -> ParserT s e m (Text, Text)-matchApproxWord s = try $ do-  a <- nextArg-  let p t = a `isPrefixOf` t-      matches = Set.filter p s-      err saw = throw (parseErr (E.ExpApproxWord s) saw)-  case Set.toList matches of-    [] -> err (E.SawNoMatches a)-    (x:[]) -> return (a, x)-    _ -> err (E.SawMultipleApproxMatches matches a)---- | Parses short options that do not take any argument. (It is--- however okay for the short option to be combined with other short--- options in the same word.)-shortNoArg :: (Error e, Monad m)-            => ShortOpt-            -> ParserT s e m ShortOpt-shortNoArg s = pendingShortOpt s <|> nonPendingShortOpt s---- | Parses short options that take an optional argument. The argument--- can be combined in the same word with the short option (@-c42@) or--- can be in the ext word (@-c 42@).-shortOptionalArg :: (Error e, Monad m)-                 => ShortOpt-                 -> ParserT s e m (ShortOpt, Maybe Text)-shortOptionalArg s = do-  so <- shortNoArg s-  a <- optionMaybe (pendingShortOptArg <|> nonOptionPosArg)-  return (so, a)---- | Parses short options that take a required argument.  The argument--- can be combined in the same word with the short option (@-c42@) or--- can be in the ext word (@-c 42@).-shortOneArg :: (Error e, Monad m) =>-               ShortOpt-               -> ParserT s e m (ShortOpt, Text)-shortOneArg s = do-  so <- shortNoArg s-  a <- pendingShortOptArg <|> nextArg-  return (so, a)---- | Parses short options that take two required arguments. The first--- argument can be combined in the same word with the short option--- (@-c42@) or can be in the ext word (@-c 42@). The next argument--- will have to be in a separate word.-shortTwoArg :: (Error e, Monad m)-               => ShortOpt-               -> ParserT s e m (ShortOpt, Text, Text)-shortTwoArg s = do-  (so, a1) <- shortOneArg s-  a2 <- nextArg-  return (so, a1, a2)---- | Parses short options that take a variable number of--- arguments. This will keep on parsing option arguments until it--- encounters one that does not "look like" an option--that is, until--- it encounters one that begins with a dash. Therefore, the only way--- to terminate a variable argument option if it is the last option is--- with a stopper. The first argument can be combined in the same word--- with the short option (@-c42@) or can be in the ext word (@-c--- 42@). Subsequent arguments will have to be in separate words.-shortVariableArg :: (Error e, Monad m)-                 => ShortOpt-                 -> ParserT s e m (ShortOpt, [Text])-shortVariableArg s = do-  so <- shortNoArg s-  firstArg <- optionMaybe pendingShortOptArg-  rest <- many nonOptionPosArg-  let result = maybe rest ( : rest ) firstArg-  return (so, result)---- | Parses long options that do not take any argument.-longNoArg :: (Error e, Monad m)-           => LongOpt-           -> ParserT s e m LongOpt-longNoArg = nonGNUexactLongOpt---- | Parses long options that take a single, optional argument. The--- single argument can be given GNU-style (@--lines=20@) or non-GNU--- style in separate words (@lines 20@).-longOptionalArg :: (Error e, Monad m)-                   => LongOpt-                   -> ParserT s e m (LongOpt, Maybe Text)-longOptionalArg = exactLongOpt---- | Parses long options that take a single, required argument. The--- single argument can be given GNU-style (@--lines=20@) or non-GNU--- style in separate words (@lines 20@).-longOneArg :: (Error e, Monad m)-                 => LongOpt-                 -> ParserT s e m (LongOpt, Text)-longOneArg l = do-  (lo, mt) <- longOptionalArg l-  case mt of-    (Just t) -> return (lo, t)-    Nothing -> do-      a <- nextArg <?> E.parseErr E.ExpLongOptArg E.SawNoArgsLeft-      return (l, a)---- | Parses long options that take a double, required argument. The--- first argument can be given GNU-style (@--lines=20@) or non-GNU--- style in separate words (@lines 20@). The second argument will have--- to be in a separate word.-longTwoArg :: (Error e, Monad m)-                 => LongOpt-                 -> ParserT s e m (LongOpt, Text, Text)-longTwoArg l = do-  (lo, mt) <- longOptionalArg l-  case mt of-    (Just t) -> do-      a2 <- nextArg-      return (lo, t, a2)-    Nothing -> do-      a1 <- nextArg-      a2 <- nextArg-      return (lo, a1, a2)---- | Parses long options that take a variable number of--- arguments. This will keep on parsing option arguments until it--- encounters one that does not "look like" an option--that is, until--- it encounters one that begins with a dash. Therefore, the only way--- to terminate a variable argument option if it is the last option is--- with a stopper. The first argument can be combined in the same word--- with the short option (@--lines=20@) or can be in the ext word--- (@--lines 42@). Subsequent arguments will have to be in separate--- words.-longVariableArg :: (Error e, Monad m)-                   => LongOpt-                   -> ParserT s e m (LongOpt, [Text])-longVariableArg l = do-  (lo, mt) <- longOptionalArg l-  rest <- many nonOptionPosArg-  return (lo, maybe rest (:rest) mt)---- | Parses at least one long option and a variable number of short--- and long options that take no arguments.-mixedNoArg :: (Error e, Monad m)-              => LongOpt-              -> [LongOpt]-              -> [ShortOpt]-              -> ParserT s e m (Either ShortOpt LongOpt)-mixedNoArg l ls ss = mconcat ([f] ++ longs ++ shorts) where-  toLong lo = do-    r <- longNoArg lo-    return $ Right r-  toShort so = do-    s <- shortNoArg so-    return $ Left s-  f = toLong l-  longs = map toLong ls-  shorts = map toShort ss---- | Parses at least one long option and a variable number of short--- and long options that take an optional argument.-mixedOptionalArg ::-  (Error e, Monad m)-  => LongOpt-  -> [LongOpt]-  -> [ShortOpt]-  -> ParserT s e m ((Either ShortOpt LongOpt), Maybe Text)-mixedOptionalArg l ls ss = mconcat ([f] ++ longs ++ shorts) where-  toLong lo = do-    (o, a) <- longOptionalArg lo-    return $ (Right o, a)-  toShort so = do-    (o, a) <- shortOptionalArg so-    return $ (Left o, a)-  f = toLong l-  longs = map toLong ls-  shorts = map toShort ss---- | Parses at least one long option and additional long and short--- options that take one argument.-mixedOneArg ::-  (Error e, Monad m)-  => LongOpt-  -> [LongOpt]-  -> [ShortOpt]-  -> ParserT s e m ((Either ShortOpt LongOpt), Text)-mixedOneArg l ls ss = mconcat ([f] ++ longs ++ shorts) where-  toLong lo = do-    (o, a) <- longOneArg lo-    return (Right o, a)-  toShort lo = do-    (o, a) <- shortOneArg lo-    return (Left o, a)-  f = toLong l-  longs = map toLong ls-  shorts = map toShort ss---- | Parses at least one long option and additonal long and short--- options that take two arguments.-mixedTwoArg ::-  (Error e, Monad m)-  => LongOpt-  -> [LongOpt]-  -> [ShortOpt]-  -> ParserT s e m ((Either ShortOpt LongOpt), Text, Text)-mixedTwoArg l ls ss = mconcat ([f] ++ longs ++ shorts) where-  toLong lo = do-    (o, a1, a2) <- longTwoArg lo-    return (Right o, a1, a2)-  toShort lo = do-    (o, a1, a2) <- shortTwoArg lo-    return (Left o, a1, a2)-  f = toLong l-  longs = map toLong ls-  shorts = map toShort ss---- | Parses at least one long option and additional long and short--- options that take a variable number of arguments.-mixedVariableArg ::-  (Error e, Monad m)-  => LongOpt-  -> [LongOpt]-  -> [ShortOpt]-  -> ParserT s e m ((Either ShortOpt LongOpt), [Text])-mixedVariableArg l ls ss = mconcat ([f] ++ longs ++ shorts) where-  toLong lo = do-    (o, a) <- longVariableArg lo-    return (Right o, a)-  toShort lo = do-    (o, a) <- shortVariableArg lo-    return (Left o, a)-  f = toLong l-  longs = map toLong ls-  shorts = map toShort ss-
− lib/System/Console/MultiArg/Error.hs
@@ -1,215 +0,0 @@--- | Errors. Parsing a command line when a user has entered it--- correctly is easy; doing something sensible when an incorrect line--- has been entered is a bit more difficult. This module exports an--- 'Error' typeclass, which you can declare instances of in order to--- have your own type to represent errors. Or you can use--- 'SimpleError', which is already an instance of 'Error'.-module System.Console.MultiArg.Error where--import System.Console.MultiArg.Option-  ( LongOpt, ShortOpt, unLongOpt, unShortOpt )-import System.Console.MultiArg.TextNonEmpty-  ( TextNonEmpty ( TextNonEmpty ) )-import Data.Text ( Text, pack, append, singleton, intercalate,-                   snoc )-import Data.Set ( Set )-import qualified Data.Set as Set---- | Instances of this typeclass represent multiarg errors. You can--- declare instances of this typeclass so that you can use your own--- type for errors. This makes multiarg easy to integrate into your--- own programs. Then you can also easily add other errors, which you--- can report from the parsers you build by calling--- 'System.Console.MultiArg.Prim.throw'.-class Error e where-  -- | Store an error in your Error instance.-  parseErr :: Expecting -> Saw -> e--instance Error Text where-  parseErr e s =-    pack "command line parser error.\n"-    `append` pack "expecting: " `append` printExpecting e-    `snoc` '\n'-    `append` pack "saw: " `append` printSaw s-    `snoc` '\n'---- | A simple type that is already an instance of 'Error'.-data SimpleError = SimpleError Expecting Saw deriving (Show, Eq)---- | Generates error messages.-printError :: SimpleError -> Text-printError (SimpleError e s) =-  pack "Error parsing command line input.\n"-  `append` pack "expected to see: "-  `append` printExpecting e `snoc` '\n'-  `append` pack "actually saw: "-  `append` printSaw s `snoc` '\n'--instance Error SimpleError where-  parseErr = SimpleError---- | Each error consists of two parts: what the parser was expecting--- to see, and what it actually saw. This type holds what the parser--- expected to see. If you just want to give some text to be used in--- an error message, use 'ExpTextError'. To generate a generic error,--- use 'ExpOtherFailure'.-data Expecting = ExpPendingShortOpt ShortOpt-               | ExpExactLong LongOpt-               | ExpApproxLong (Set LongOpt)-               | ExpLongOptArg-               | ExpPendingShortArg-               | ExpStopper-               | ExpNextArg-               | ExpNonOptionPosArg-               | ExpEnd-               | ExpNonGNUExactLong LongOpt-               | ExpMatchingApproxLong LongOpt (Set LongOpt)-               | ExpNonGNUMatchingApproxLong LongOpt (Set LongOpt)-               | ExpApproxWord (Set Text)-               | ExpOptionOrPosArg-               | ExpTextError Text-               | ExpNonPendingShortOpt ShortOpt-               | ExpNotFollowedBy-               | ExpOtherFailure-               deriving (Show, Eq)---- | Generates an error message from an Expecting.-printExpecting :: Expecting -> Text-printExpecting e = case e of-  (ExpPendingShortOpt s) ->-    (pack "short option: ") `append` (singleton . unShortOpt $ s)-  (ExpExactLong l) ->-    (pack "long option: ") `append` (unLongOpt $ l)-  (ExpApproxLong ls) ->-    (pack "approximate long option matching one of: ") `append`-    intercalate (pack ", ") (map unLongOpt . Set.toList $ ls)-  ExpLongOptArg -> pack "argument to long option"-  ExpPendingShortArg -> pack "argument to short option"-  ExpStopper -> pack "stopper (\"--\")"-  ExpNextArg -> pack "next word on command line"-  ExpNonOptionPosArg ->-    pack "word on command line not starting with a hyphen"-  ExpEnd -> pack "end of command line input"-  (ExpNonGNUExactLong lo) ->-    pack "long option without an included argument: "-    `append` (unLongOpt lo)-  (ExpMatchingApproxLong l ls) ->-    pack "abbreviated long option named: " `append` (unLongOpt l)-    `append` pack "from possible abbreviated long options named: "-    `append` (intercalate (pack ", ")-              (map unLongOpt . Set.toList $ ls))-  (ExpNonGNUMatchingApproxLong l ls) ->-    pack "abbreviated long without an included argument named: "-    `append` (unLongOpt l)-    `append` pack "from possible abbreviated long options named: "-    `append` (intercalate (pack ", ")-              (map unLongOpt . Set.toList $ ls))-  (ExpApproxWord ws) ->-    pack "one of these abbreviated words: "-    `append` (intercalate (pack ", ") (Set.toList $ ws))-  ExpOptionOrPosArg ->-    pack "option or positional argument"-  (ExpTextError t) -> t-  (ExpNonPendingShortOpt s) ->-    (pack "short option: ") `append` (singleton . unShortOpt $ s)-  ExpNotFollowedBy ->-    pack "not followed by"-  (ExpOtherFailure) -> pack "general failure"------ | What the parser actually saw. To give some text to be used in the--- error message, use 'SawTextError'. To generate a generic error, use--- 'SawOtherFailure'.-data Saw = SawNoPendingShorts-         | SawWrongPendingShort Char-         | SawNoArgsLeft-         | SawEmptyArg-         | SawSingleDashArg-         | SawStillPendingShorts TextNonEmpty-         | SawNotShortArg Text-         | SawWrongShortArg Char-         | SawNotLongArg Text-         | SawWrongLongArg Text-         | SawNoMatches Text-         | SawMultipleMatches (Set LongOpt) Text-         | SawNoPendingShortArg-         | SawAlreadyStopper-         | SawNewStopper-         | SawNotStopper-         | SawLeadingDashArg Text-         | SawMoreInput-         | SawGNULongOptArg Text-         | SawNotMatchingApproxLong Text LongOpt-         | SawMatchingApproxLongWithArg Text -- Text of the argument-         | SawMultipleApproxMatches (Set Text) Text-         | SawNoOption-         | SawNoOptionOrPosArg-         | SawTextError Text-         | SawFollowedBy-         | SawOtherFailure-         deriving (Show, Eq)---- | Generates error messages from a 'Saw'.-printSaw :: Saw -> Text-printSaw s = case s of-  SawNoPendingShorts -> pack "no pending short options"-  (SawWrongPendingShort c) ->-    pack "unexpected short option: " `snoc` c-  SawNoArgsLeft -> pack "no command line words remaining"-  SawEmptyArg -> pack "command line word that is the empty string"-  SawSingleDashArg ->-    pack "command line word that is a single hyphen (\"-\")"-  (SawStillPendingShorts (TextNonEmpty first rest)) ->-    pack "pending short options: " `snoc` first-    `append` rest-  (SawNotShortArg t) ->-    pack "word that is not a short option: " `append` t-  (SawWrongShortArg c) ->-    pack "wrong short option: " `snoc` c-  (SawNotLongArg t) ->-    pack "word that is not a long option: " `append` t-  (SawWrongLongArg t) ->-    pack "wrong long option: " `append` t-  (SawNoMatches t) ->-    pack "word that does not match the available choices: "-    `append` t-  (SawMultipleMatches ss t) ->-    pack "word matches more than one of the available choices. "-    `append` pack "word given: " `append` t-    `append` pack " matches these words: "-    `append` (intercalate (pack ", ") (map unLongOpt . Set.toList $ ss))-  SawNoPendingShortArg -> pack "no short argument"-  SawAlreadyStopper ->-    pack "already seen a stopper (\"--\")"-  SawNewStopper ->-    pack "new stopper (\"--\")"-  SawNotStopper ->-    pack "word that is not a stopper (\"--\")"-  (SawLeadingDashArg t) ->-    pack "word with a leading hyphen: " `append` t-  SawMoreInput ->-    pack "additional words remaining on command line"-  (SawGNULongOptArg t) ->-    pack "attached argument for option that does not take one: "-    `append` t-  (SawNotMatchingApproxLong t lo) ->-    pack "long argument that does not match expected one. "-    `append` pack "argument given: " `append` t-    `append` pack "argument expected: " `append` unLongOpt lo-  (SawMatchingApproxLongWithArg t) ->-    pack "long argument that matches expected long argument, but it "-    `append` pack "has an attached argument. Text of argument: "-    `append` t-  (SawMultipleApproxMatches ms m) ->-    pack "multiple words match the one given. Word given: " `append` m-    `append` pack "possible matches: "-    `append` (intercalate (pack ", ") (Set.toList ms))-  SawNoOption ->-    pack "word that is not an option"-  SawNoOptionOrPosArg ->-    pack "not an option or positional argument"-  (SawTextError t) -> t-  SawFollowedBy -> pack "followed by"-  (SawOtherFailure) -> pack "general failure"-
− lib/System/Console/MultiArg/GetArgs.hs
@@ -1,68 +0,0 @@-{-# LANGUAGE CPP #-}---- | Get the arguments from the command line, ensuring they are--- properly encoded into Unicode.------ base 4.3.1.0 has a System.Environment.getArgs that does not return--- a Unicode string. Instead, it simply puts each octet into a--- different Char. Thus its getArgs is broken on UTF-8 and nearly any--- non-ASCII encoding. As a workaround I use--- System.Environment.UTF8. The downside of this is that it requires--- that the command line be encoded in UTF8, regardless of what the--- default system encoding is.------ Unlike base 4.3.1.0, base 4.4.0.0 actually returns a proper Unicode--- string when you call System.Environment.getArgs. (base 4.3.1.0--- comes with ghc 7.0.4; base 4.4.0.0 comes with ghc 7.2.) The string--- is encoded depending on the default system locale. The only problem--- is that System.Environment.UTF8 apparently simply uses--- System.Environment.getArgs and then assumes that the string it--- returns has not been decoded. In other words,--- System.Environment.UTF8 assumes that System.Environment.getArgs is--- broken, and when System.Environment.getArgs was fixed in base--- 4.4.0.0, it likely will break System.Environment.UTF8.------ One obvious solution to this problem is to find some other way to--- get the command line that will not break when base is updated. But--- it was not easy to find such a thing. The other libraries I saw on--- hackage (as of January 6, 2012) had problems, such as breakage on--- ghc 7.2. There is a package that has a simple interface to the UNIX--- setlocale(3) function, but I'm not sure that what it returns easily--- and reliably maps to character encodings that you can use with,--- say, iconv.------ So by use of Cabal and preprocessor macors, the code uses--- utf8-string if base is less than 4.4, and uses--- System.Environment.getArgs if base is at least 4.4.------ The GHC bug is here:------ <http://hackage.haskell.org/trac/ghc/ticket/3309>--module System.Console.MultiArg.GetArgs ( getArgs, getProgName ) where--#if MIN_VERSION_base(4,4,0)-import qualified System.Environment as E ( getArgs, getProgName )-#else-import qualified System.Environment.UTF8 as E ( getArgs, getProgName )-#endif---- | Gets the command-line arguments supplied by the program's--- user. If the @base@ package is older than version 4.4, then this--- function assumes the command line is encoded in UTF-8, which is--- true for many newer Unix systems; however, many older systems may--- use single-byte encodings like ISO-8859. In such cases, this--- function will give erroneous results.------ If the @base@ package is version 4.4.0 or newer, this function--- simply uses the getArgs that comes with @base@. That getArgs--- detects the system's default encoding and uses that, so it should--- give accurate results on most systems.-getArgs :: IO [String]-getArgs = E.getArgs---- | Gets the name of the program that the user invoked. See--- documentation for 'getArgs' for important caveats that also apply--- to this function.-getProgName :: IO String-getProgName = E.getProgName
− lib/System/Console/MultiArg/Option.hs
@@ -1,61 +0,0 @@--- | These types represent options. They are abstract and in a--- separate module to prevent you from accidentally making an option--- with an invalid name. Option names cannot have a dash as their--- first or second character, and long option names cannot have an--- equals sign anywhere in the name.-module System.Console.MultiArg.Option (-  ShortOpt,-  unShortOpt,-  makeShortOpt,-  LongOpt,-  unLongOpt,-  makeLongOpt )-  where--import qualified Data.Text as X-import Data.Text ( Text, unpack, index )-import Control.Monad ( when )---- | Short options. Options that are preceded with a single dash on--- the command line and consist of a single letter. That single letter--- cannot be a dash. Any other Unicode character is good (including--- pathological ones like newlines).-newtype ShortOpt = ShortOpt { unShortOpt :: Char } deriving (Show, Eq, Ord)---- | This function is partial. It calls error if its argument is a--- single dash. This is the only way to make a short option so it--- prevents you from making one that is invalid.-makeShortOpt :: Char -> ShortOpt-makeShortOpt c = case c of-  '-' -> error "short option must not be a dash"-  x -> ShortOpt x---- | Long options. Options that are preceded with two dashes on the--- command line and typically consist of an entire mnemonic word, such--- as @lines@. However, anything that is at least one letter long is--- fine for a long option name. The name must not have a dash as--- either the first or second character and it must be at least one--- character long. It cannot have an equal sign anywhere in its--- name. Otherwise any Unicode character is good (including--- pathological ones like newlines).-data LongOpt = LongOpt { unLongOpt :: Text } deriving (Show, Eq, Ord)---- | This function is partial. It calls error if its argument contains--- text that is not a valid long option. This is the only way to make--- a long option so it prevents you from making invalid ones.-makeLongOpt :: Text -> LongOpt-makeLongOpt t = case isValidLongOptText t of-  True -> LongOpt t-  False -> error $ "invalid long option: " ++ unpack t--isValidLongOptText :: Text -> Bool-isValidLongOptText t = maybe False (const True) $ do-  when (X.null t) Nothing-  when ((t `index` 0) == '-') Nothing-  when ((X.length t > 1) && ((t `index` 1) == '-')) Nothing-  case X.find (== '=') t of-    (Just _) -> Nothing-    Nothing -> return ()-  return ()--
− lib/System/Console/MultiArg/Prim.hs
@@ -1,962 +0,0 @@--- | Parser primitives. These are the only functions that have access--- to the internals of the parser.-module System.Console.MultiArg.Prim (-    -- * Parser types-  Parser,-  ParserE,-  ParserSE,-  ParserT,-  -  -- * Running a parser-  -  -- | Each parser runner is applied to a list of Text, which are the-  -- command line arguments to parse. If there is any chance that you-  -- will be parsing Unicode strings, see the documentation in-  -- 'System.Console.MultiArg.GetArgs' before you use-  -- 'System.Environment.getArgs'.-  parse,-  parseE,-  parseSE,-  parseT,-  -  -- * Higher-level parser combinators-  parserMap,-  good,-  apply,-  choice,-  combine,-  lookAhead,-  -  -- ** Running parsers multiple times-  several,-  manyTill,-  feed,--  -- ** Monad lifting-  parserLift,-  parserIO,--  -- ** Failure and errors-  throw,-  throwString,-  genericThrow,-  (<?>),-  try,-  -  -- * Parsers-  -- ** Short options and arguments-  pendingShortOpt,-  nonPendingShortOpt,-  pendingShortOptArg,  -  -  -- ** Long options and arguments-  exactLongOpt,-  approxLongOpt,--  -- ** Stoppers-  stopper,-  -  -- ** Positional (non-option) arguments-  nextArg,-  nonOptionPosArg,-  -  -- ** Miscellaneous-  end,-  -  -- * User state-  get,-  put,-  modify-  ) where---import qualified System.Console.MultiArg.Error as E-import System.Console.MultiArg.Option-  (ShortOpt,-    unShortOpt,-    LongOpt,-    unLongOpt )-import System.Console.MultiArg.TextNonEmpty-  ( TextNonEmpty ( TextNonEmpty ) )-import Control.Applicative ( Applicative, Alternative )-import qualified Control.Applicative-import Control.Monad.Exception.Synchronous-  (Exceptional(Success, Exception), switch )-import qualified Control.Monad.Exception.Synchronous as S-import Data.Functor.Identity ( runIdentity )-import Data.Text ( Text, pack, isPrefixOf, cons )-import qualified Data.Text as X-import qualified Data.Set as Set-import Data.Set ( Set )-import Control.Monad ( when, MonadPlus(mzero, mplus) )-import Control.Monad.Trans.Class ( lift )-import Data.Maybe ( isNothing )-import Data.Monoid ( Monoid ( mempty, mappend ) )-import Data.Functor.Identity ( Identity )-import Control.Monad.Trans.Class ( MonadTrans )-import Control.Monad.IO.Class ( MonadIO ( liftIO ) )---- | Takes the head of a Text. Returns Nothing if the Text is empty.-textHead :: Text -> Maybe (Char, Text)-textHead t = case X.null t of-  True -> Nothing-  False -> Just (X.head t, X.tail t)---- | Converts a Text to a TextNonEmpty. Returns Nothing if the Text is--- empty.-toTextNonEmpty :: Text -> Maybe TextNonEmpty-toTextNonEmpty t = case textHead t of-  Nothing -> Nothing-  (Just (c, r)) -> Just $ TextNonEmpty c r---- | Carries the internal state of the parser. The counter is a simple--- way to determine whether the remaining list one ParseSt has been--- modified from another. When parsers modify remaining, they--- increment the counter.-data ParseSt s = ParseSt { pendingShort :: Maybe TextNonEmpty-                         , remaining :: [Text]-                         , sawStopper :: Bool-                         , userState :: s-                         , counter :: Int-                         } deriving (Show, Eq)---- | Load up the ParseSt with an initial user state and a list of--- commmand line arguments.-defaultState :: s -> [Text] -> ParseSt s-defaultState s ts = ParseSt { pendingShort = Nothing-                            , remaining = ts-                            , sawStopper = False-                            , userState = s-                            , counter = 0 }---- | Carries the result of each parse.-data Result e a = Bad e | Good a---- | @ParserT s e m a@ is a parser with user state s, error type e,--- underlying monad m, and result type a. Internally the parser is a--- state monad which keeps track of what is remaining to be--- parsed. Since the parser has an internal state anyway, the user can--- add to this state (this is called the user state.) The parser--- ignores this user state so you can use it however you wish. If you--- do not need a user state, just make it the unit type ().------ The parser also includes the notion of failure. Any parser can--- fail; a failed parser affects the behavior of combinators such as--- combine. The failure type should be a instance of--- System.Console.MultiArg.Error.Error. This allows you to define your--- own type and use it for the failure type, which can be useful when--- combining MultiArg with your own program.------ The underlying monad is m. This makes ParserT into a monad--- transformer; you can layer it on top of other monads. For instance--- you might layer it on top of the IO monad so that your parser can--- perform IO (for example, by examining the disk to see if arguments--- that specify files are valid.) If you don't need a monad--- transformer, just layer ParserT on top of Identity.-data ParserT s e m a =-  ParserT { runParserT :: ParseSt s -> m (Result e a, ParseSt s) }--instance (Monad m) => Functor (ParserT s e m) where-  fmap = parserMap--instance (Monad m) => Applicative (ParserT s e m) where-  pure = good-  (<*>) = apply--instance (Monad m, E.Error e) => Monoid (ParserT s e m a) where-  mempty = genericThrow-  mappend = choice--instance (Monad m, E.Error e) => Alternative (ParserT s e m) where-  empty = genericThrow-  (<|>) = choice-  many = several--instance (E.Error e, Monad m) => Monad (ParserT s e m) where-  (>>=) = combine-  return = good-  fail = throwString--instance (Monad m, E.Error e) => MonadPlus (ParserT s e m) where-  mzero = genericThrow-  mplus = choice--instance MonadTrans (ParserT s e) where-  lift = parserLift--instance (MonadIO m, E.Error e) => MonadIO (ParserT s e m) where-  liftIO = parserIO---- | @ParserSE s e a@ is a parser with user state s, error type e,--- underlying monad Identity, and result type a.-type ParserSE s e a = ParserT s e Identity a---- | @ParserE e a@ is a parser with user state (), error type e,--- underlying monad Identity, and result type a.-type ParserE e a = ParserT () e Identity a---- | @Parser a@ is a parser with user state (), error type--- SimpleError, underlying monad Identity, and result type a.-type Parser a = ParserT () E.SimpleError Identity a---- | Runs a parser that has a user state and an underlying monad--- Identity.-parseSE ::-  s-  -- ^ The initial user state-  -  -> [Text]-  -- ^ Command line arguments--  -> ParserSE s e a-  -- ^ Parser to run-  -  -> (Exceptional e a, s)-  -- ^ Success or failure, and the final user state-  -parseSE s ts p =-  let r = runIdentity (runParserT p (defaultState s ts))-      (result, st') = r-  in case result of-    (Good g) -> (Success g, userState st')-    (Bad e) -> (Exception e, userState st')---- | Runs a parser that has no user state and an underlying monad of--- Identity and is parameterized on the error type.-parseE ::-  [Text]-  -- ^ Command line arguments to parse-  -  -> ParserE e a-  -- ^ Parser to run-  -  -> Exceptional e a-  -- ^ Success or failure--parseE ts p =-  let r = runIdentity (runParserT p (defaultState () ts))-      (result, _) = r-  in case result of-    (Good g) -> Success g-    (Bad e) -> Exception e---- | The simplest parser runner; has no user state, an underlying--- monad Identity, and error type SimpleError.-parse :: [Text]-         -- ^ Command line arguments to parse-         -         -> Parser a-         -- ^ Parser to run--         -> Exceptional E.SimpleError a-         -- ^ Successful result or an error-parse = parseE---- | The most complex parser runner. Runs a parser with a user-defined--- state, error type, and underlying monad. Returns the final parse--- result and the final user state, inside of the underlying monad.-parseT ::-  (Monad m)-  => s-  -- ^ Initial user state--  -> [Text]-  -- ^ Command line arguments to parse--  -> ParserT s e m a-  -- ^ Parser to run-  -  -> m (Exceptional e a, s)-  -- ^ Success or failure and the final user state, inside of the-  -- underlying monad--parseT s ts p = runParserT p (defaultState s ts) >>= \r ->-  let (result, st') = r-  in case result of-    (Good g) -> return (Success g, userState st')-    (Bad e) -> return (Exception e, userState st')---- | Lifts a computation of the underlying monad into the ParserT--- monad. This provides the implementation for--- 'Control.Monad.Trans.Class.lift'.-parserLift ::-  Monad m-  => m a-  -> ParserT s e m a-parserLift c = ParserT $ \s ->-  c >>= \a -> return (Good a, s)---- | Lifts a computation from the IO monad into the ParserT--- monad. This provides the implementation for--- 'Control.Monad.IO.Class.liftIO'.-parserIO ::-  (MonadIO m, E.Error e)-  => IO a-  -> ParserT s e m a-parserIO c = parserLift . liftIO $ c---- | Combines two parsers into a single parser. The second parser can--- optionally depend upon the result from the first parser.------ This applies the first parser. If the first parser succeeds,--- combine then takes the result from the first parser, applies the--- function given to the result from the first parser, and then--- applies the resulting parser.------ If the first parser fails, combine will not apply the second--- function but instead will bypass the second parser.------ This provides the implementation for '>>=' in--- 'Control.Monad.Monad'.-combine ::-  (Monad m)-  => ParserT s e m a-  -> (a -> ParserT s e m b)-  -> ParserT s e m b-combine (ParserT l) f = ParserT $ \s ->-  l s >>= \(r, s') ->-  case r of-    (Bad e) -> return (Bad e, s')-    (Good g) ->-      let (ParserT fr) = f g-      in fr s'---- | @lookAhead p@ runs parser p. If p succeeds, lookAhead p succeeds--- without consuming any input. If p fails without consuming any--- input, so does lookAhead. If p fails and consumes input, lookAhead--- also fails and consumes input. If this is undesirable, combine with--- "try".-lookAhead ::-  (Monad m)-  => ParserT s e m a-  -> ParserT s e m a-lookAhead (ParserT p) = ParserT $ \s ->-  p s >>= \(r, s') ->-  return $ case r of-    (Good g) -> (Good g, s)-    (Bad e) -> (Bad e, s')---- | @good a@ always succeeds without consuming any input and has--- result a. This provides the implementation for--- 'Control.Monad.Monad.return' and--- 'Control.Applicative.Applicative.pure'.-good ::-  (Monad m)-  => a-  -> ParserT s e m a-good a = ParserT $ \s ->-  return (Good a, s)---- | @throwString s@ always fails without consuming any input. The--- failure contains a record of the string passed in by s. This--- provides the implementation for 'Control.Monad.Monad.fail'.-throwString ::-  (E.Error e, Monad m)-  => String-  -> ParserT s e m a-throwString e = ParserT $ \s ->-  return (Bad (E.parseErr E.ExpOtherFailure-               (E.SawTextError (pack e))), s)---- | @parserMap f p@ applies function f to the result of parser--- p. First parser p is run. If it succeeds, function f is applied to--- the result and another parser is returned with the result. If it--- fails, f is not applied and a failed parser is returned. This--- provides the implementation for 'Prelude.Functor.fmap'.-parserMap ::-  (Monad m)-  => (a -> b)-  -> ParserT s e m a-  -> ParserT s e m b-parserMap f (ParserT l) = ParserT $ \s ->-  l s >>= \r ->-  let (result, st') = r-  in case result of-    (Good g) -> return (Good (f g), st')-    (Bad e) -> return (Bad e, st')---- | apply l r applies the function found in parser l to the result of--- parser r. First the l parser is run. If it succeeds, it has a--- resulting function. Then the r parser is run. If it succeeds, the--- function from the l parser is applied to the result of the r--- parser, and a new parser is returned with the result. If either--- parser l or parser r fails, then a failed parser is returned. This--- provides the implementation for '<*>' in--- 'Control.Applicative.Applicative'.-apply ::-  (Monad m)-  => ParserT s e m (a -> b)-  -> ParserT s e m a-  -> ParserT s e m b-apply (ParserT x) (ParserT y) = ParserT $ \s ->-  x s >>= \r ->-  let (result, st') = r-  in case result of-    (Good f) -> y st' >>= \r' ->-      let (result', st'') = r'-      in case result' of-        (Good a) -> return (Good (f a), st'')-        (Bad e) -> return (Bad e, st'')-    (Bad e) -> return (Bad e, st')---- | Fail with an unhelpful error message. Usually throw is more--- useful, but this is handy to implement some typeclass instances.-genericThrow ::-  (Monad m, E.Error e)-  => ParserT s e m a-genericThrow = throw (E.parseErr E.ExpOtherFailure E.SawOtherFailure)---- | throw e always fails without consuming any input and returns a--- failed parser with error state e.-throw :: (Monad m) => e -> ParserT s e m a-throw e = ParserT $ \s ->-  return (Bad e, s)--noConsumed :: ParseSt s -> ParseSt s -> Bool-noConsumed old new = counter old >= counter new---- | Runs the first parser. If it fails without consuming any input,--- then runs the second parser. If the first parser succeeds, then--- returns the result of the first parser. If the first parser fails--- and consumes input, then returns the result of the first--- parser. This provides the implementation for--- '<|>' in 'Control.Applicative.Alternative'.-choice ::-  (Monad m)-  => ParserT s e m a-  -> ParserT s e m a-  -> ParserT s e m a-choice (ParserT l) (ParserT r) = ParserT $ \sOld ->-  l sOld >>= \(a, s') ->-  case a of-    (Good g) -> return (Good g, s')-    (Bad e) ->-      if noConsumed sOld s'-      then r sOld-      else return (Bad e, s')---- | Runs the parser given. If it succeeds, then returns the result of--- the parser. If it fails and consumes input, returns the result of--- the parser. If it fails without consuming any input, then changes--- the error using the function given.-(<?>) ::-  (Monad m)-  => ParserT s e m a-  -> e-  -> ParserT s e m a-(<?>) (ParserT l) e = ParserT $ \s ->-  l s >>= \(r, s') ->-  case r of-    (Good g) -> return (Good g, s')-    (Bad err) ->-      if noConsumed s s'-      then return (Bad e, s)-      else return (Bad err, s')--infix 0 <?>--increment :: ParseSt s -> ParseSt s-increment old = old { counter = succ . counter $ old }---- | Parses only pending short options. Fails without consuming any--- input if there has already been a stopper or if there are no--- pending short options. Fails without consuming any input if there--- is a pending short option, but it does not match the short option--- given. Succeeds and consumes a pending short option if it matches--- the short option given; returns the short option parsed.-pendingShortOpt ::-  (Monad m, E.Error e)-  => ShortOpt-  -> ParserT s e m ShortOpt-pendingShortOpt so = ParserT $ \s ->-  let err saw = return (Bad (E.parseErr (E.ExpPendingShortOpt so) saw), s)-      gd (res, newSt) = return (Good res, newSt)-  in switch err gd $ do-    when (sawStopper s) $ S.throw E.SawAlreadyStopper-    (TextNonEmpty first rest) <--      maybe (S.throw E.SawNoPendingShorts) return (pendingShort s)-    when (unShortOpt so /= first)-      (S.throw $ E.SawWrongPendingShort first)-    return (so, increment s { pendingShort = toTextNonEmpty rest })---- | Parses only non-pending short options. Fails without consuming--- any input if, in order:------ * there are pending short options------ * there has already been a stopper------ * there are no arguments left to parse------ * the next argument is an empty string------ * the next argument does not begin with a dash------ * the next argument is a single dash------ * the next argument is a short option but it does not match---   the one given------ * the next argument is a stopper------ Otherwise, consumes the next argument, puts any remaining letters--- from the argument into a pending short, and removes the first word--- from remaining arguments to be parsed. Returns the short option--- parsed.-nonPendingShortOpt ::-  (E.Error e, Monad m)-  => ShortOpt-  -> ParserT s e m ShortOpt-nonPendingShortOpt so = ParserT $ \s ->-  let err saw =-        return (Bad (E.parseErr (E.ExpNonPendingShortOpt so) saw), s)-      gd (g, n) = return (Good g, n)-  in switch err gd $ do-    maybe (return ()) (S.throw . E.SawStillPendingShorts) (pendingShort s)-    when (sawStopper s) (S.throw E.SawAlreadyStopper)-    (a:as) <- case remaining s of-      [] -> S.throw E.SawNoArgsLeft-      x -> return x-    (maybeDash, word) <- case textHead a of-      Nothing -> S.throw E.SawEmptyArg-      (Just w) -> return w-    when (maybeDash /= '-') $ S.throw (E.SawNotShortArg a)-    (letter, arg) <- case textHead word of-      Nothing -> S.throw E.SawSingleDashArg-      (Just w) -> return w-    when (letter /= unShortOpt so) $ S.throw (E.SawWrongShortArg letter)-    when (letter == '-') $ S.throw E.SawNewStopper-    let s' = increment s { pendingShort = toTextNonEmpty arg-                         , remaining = as }-    return (so, s')---- | Parses an exact long option. That is, the text of the--- command-line option must exactly match the text of the--- option. Returns the option, and any argument that is attached to--- the same word of the option with an equal sign (for example,--- @--follow=\/dev\/random@ will return @Just \"\/dev\/random\"@ for the--- argument.) If there is no equal sign, returns Nothing for the--- argument. If there is an equal sign but there is nothing after it,--- returns @Just \"\"@ for the argument.------ If you do not want your long option to have equal signs and--- GNU-style option arguments, wrap this parser in something that will--- fail if there is an option argument.------ Fails without consuming any input if:------ * there are pending short options------ * a stopper has been parsed------ * there are no arguments left on the command line------ * the next argument on the command line does not begin with---   two dashes------ * the next argument on the command line is @--@ (a stopper)------ * the next argument on the command line does begin with two---   dashes but its text does not match the argument we're looking for-exactLongOpt ::-  (E.Error e, Monad m)-  => LongOpt-  -> ParserT s e m (LongOpt, Maybe Text)-exactLongOpt lo = ParserT $ \s ->-  let err saw = return (Bad (E.parseErr (E.ExpExactLong lo) saw), s)-      gd (g, n) = return (Good g, n)-  in switch err gd $ do-    maybe (return ()) (S.throw . E.SawStillPendingShorts) (pendingShort s)-    when (sawStopper s) (S.throw E.SawAlreadyStopper)-    (x:xs) <- case remaining s of-      [] -> S.throw E.SawNoArgsLeft-      ls -> return ls-    let (pre, word, afterEq) = splitLongWord x-    when (pre /= pack "--") $ S.throw (E.SawNotLongArg x)-    when (X.null word && isNothing afterEq) (S.throw E.SawNewStopper)-    when (word /= unLongOpt lo) $ S.throw (E.SawWrongLongArg word)-    let s' = increment s { remaining = xs }-    return ((lo, afterEq), s')---- | Takes a single Text and returns a tuple, where the first element--- is the first two letters, the second element is everything from the--- third letter to the equal sign, and the third element is Nothing if--- there is no equal sign, or Just Text with everything after the--- equal sign if there is one.-splitLongWord :: Text -> (Text, Text, Maybe Text)-splitLongWord t = (f, s, r) where-  (f, rest) = X.splitAt 2 t-  (s, withEq) = X.break (== '=') rest-  r = case textHead withEq of-    Nothing -> Nothing-    (Just (_, afterEq)) -> Just afterEq---- | Examines the next word. If it matches a Text in the set--- unambiguously, returns a tuple of the word actually found and the--- matching word in the set.-approxLongOpt ::-  (E.Error e, Monad m)-  => Set LongOpt-  -> ParserT s e m (Text, LongOpt, Maybe Text)-approxLongOpt ts = ParserT $ \s ->-  let err saw = return (Bad (E.parseErr (E.ExpApproxLong ts) saw), s)-      gd (g, newSt) = return (Good g, newSt)-  in switch err gd $ do-    maybe (return ()) (S.throw . E.SawStillPendingShorts) (pendingShort s)-    (x:xs) <- case remaining s of-      [] -> S.throw E.SawNoArgsLeft-      r -> return r-    let (pre, word, afterEq) = splitLongWord x-    when (pre /= pack "--") (S.throw (E.SawNotLongArg x))-    when (X.null word && isNothing afterEq) (S.throw E.SawNewStopper)-    let p t = word `isPrefixOf` (unLongOpt t)-        matches = Set.filter p ts-    case Set.toList matches of-      [] -> S.throw (E.SawNoMatches word)-      (m:[]) -> let s' = increment s { remaining = xs }-                in return ((word, m, afterEq), s')-      _ -> S.throw (E.SawMultipleMatches matches word)---- | Parses only pending short option arguments. For example, for the--- @tail@ command, if you enter the option @-c25@, then after parsing--- the @-c@ option the @25@ becomes a pending short option argument--- because it was in the same command line argument as the @-c@.------ Fails without consuming any input if:------ * a stopper has already been parsed------ * there are no pending short option arguments------ On success, returns the text of the pending short option argument--- (this text cannot be empty).-pendingShortOptArg ::-  (E.Error e, Monad m)-  => ParserT s e m Text-pendingShortOptArg = ParserT $ \s ->-  let err saw = return (Bad (E.parseErr E.ExpPendingShortArg saw), s)-      gd (g, newSt) = return (Good g, newSt)-  in switch err gd $ do-    when (sawStopper s) (S.throw E.SawAlreadyStopper)-    let f (TextNonEmpty c t) = return (c `cons` t)-    a <- maybe (S.throw E.SawNoPendingShortArg) f (pendingShort s)-    let newSt = increment s { pendingShort = Nothing }-    return (a, newSt)---- | Parses a "stopper" - that is, a double dash. Changes the internal--- state of the parser to reflect that a stopper has been seen.-stopper ::-  (E.Error e, Monad m)-  => ParserT s e m ()-stopper = ParserT $ \s ->-  let err saw = return (Bad (E.parseErr E.ExpStopper saw), s)-      gd (g, newSt) = return (Good g, newSt)-  in switch err gd $ do-    maybe (return ()) (S.throw . E.SawStillPendingShorts) (pendingShort s)-    when (sawStopper s) $ S.throw E.SawAlreadyStopper-    (x:xs) <- case remaining s of-      [] -> S.throw E.SawNoArgsLeft-      r -> return r-    when (not $ pack "--" `isPrefixOf` x) (S.throw E.SawNotStopper)-    when (X.length x /= 2) (S.throw E.SawNotStopper)-    let s' = increment s { sawStopper = True-                         , remaining = xs }-    return ((), s')---- | try p behaves just like p, but if p fails, try p will not consume--- any input.-try :: Monad m => ParserT s e m a -> ParserT s e m a-try (ParserT l) = ParserT $ \s ->-  l s >>= \(r, s') ->-  case r of-    (Good g) -> return (Good g, s')-    (Bad e) -> return (Bad e, s)---- | Returns the next string on the command line as long as there are--- no pendings. Be careful - this will return the next string even if--- it looks like an option (that is, it starts with a dash.) Consider--- whether you should be using nonOptionPosArg instead. However this--- can be useful when parsing command line options after a stopper.-nextArg ::-  (E.Error e, Monad m)-  => ParserT s e m Text-nextArg = ParserT $ \s ->-  let err saw = return (Bad (E.parseErr E.ExpNextArg saw), s)-      gd (g, newSt) = return (Good g, newSt)-  in switch err gd $ do-    maybe (return ()) (S.throw . E.SawStillPendingShorts) (pendingShort s)-    (x:xs) <- case remaining s of-      [] -> S.throw E.SawNoArgsLeft-      r -> return r-    let newSt = increment s { remaining = xs }-    return (x, newSt)---- | Returns the next string on the command line as long as there are--- no pendings and as long as the next string does not begin with a--- dash. If there has already been a stopper, then will return the--- next string even if it starts with a dash.-nonOptionPosArg ::-  (E.Error e, Monad m)-  => ParserT s e m Text-nonOptionPosArg = ParserT $ \s ->-  let err saw = return (Bad (E.parseErr E.ExpNonOptionPosArg saw), s)-      gd (g, newSt) = return (Good g, newSt)-  in switch err gd $ do-    maybe (return ()) (S.throw . E.SawStillPendingShorts) (pendingShort s)-    (x:xs) <- case remaining s of-      [] -> S.throw E.SawNoArgsLeft-      r -> return r-    result <- if sawStopper s-              then return x-              else case textHead x of-                Just ('-', _) -> S.throw $ E.SawLeadingDashArg x-                _ -> return x-    let newSt = increment s { remaining = xs }-    return (result, newSt)----- | manyTill p e runs parser p repeatedly until parser e succeeds.------ More precisely, first it runs parser e. If parser e succeeds, then--- manyTill returns the result of all the preceding successful parses--- of p. If parser e fails (it does not matter whether e consumed any--- input or not), manyTill runs parser p again. What happens next--- depends on whether p succeeded or failed. If p succeeded, then the--- loop starts over by running parser e again. If p failed (it does--- not matter whether it consumed any input or not), then manyTill--- fails. The state of the parser is updated to reflect its state--- after the failed run of p, and the parser is left in a failed--- state.------ Should parser e succeed (as it will on a successful application of--- manyTill), then the parser state will reflect that parser e--- succeeded--that is, if parser e consumes input, that input will be--- consumed in the parser that is returned. Wrap e inside of--- @lookAhead@ if that is undesirable.------ Be particularly careful to get the order of the arguments--- correct. Applying this function to reversed arguments will yield--- bugs that are very difficult to diagnose.-manyTill ::-  Monad m-  => ParserT s e m a-  -> ParserT s e m end-  -> ParserT s e m [a]-manyTill (ParserT r) (ParserT f) = ParserT $ \s ->-  parseTill s r f >>= \till ->-  case lastFailure till of-    Nothing -> return (Good (goods till), lastSt till)-    (Just e) -> return (Bad e, lastSt till)--data Till s e a =-  Till { goods :: [a]-       , lastSt :: ParseSt s-       , lastFailure :: Maybe e }--parseTill ::-  (Monad m)-  => ParseSt s-  -> (ParseSt s -> m (Result e a, ParseSt s))-  -> (ParseSt s -> m (Result e b, ParseSt s))-  -> m (Till s e a)-parseTill s fr ff = ff s >>= \r ->-  case r of-    (Good _, s') -> return $ Till [] s' Nothing-    (Bad _, _) ->-      fr s >>= \r' ->-      case r' of-        (Bad e, s') -> return $ Till [] s' (Just e)-        (Good g, s') ->-          parseTill s' fr ff >>= \r'' ->-          let (Till gs lS lF) = r''-          in if counter s' == counter s-             then error "parseTill applied to parser that takes empty list"-             else return $ Till (g:gs) lS lF---- It is impossible to implement several and manyTill in terms of--- feed, as there is no easy way to specify what the starting value of--- the state for feed would be.---- | several p runs parser p zero or more times and returns all the--- results. This proceeds like this: parser p is run and, if it--- succeeds, the result is saved and parser p is run--- again. Repeat. Eventually this will have to fail. If the last run--- of parser p fails without consuming any input, then several p runs--- successfully. The state of the parser is updated to reflect the--- successful runs of p. If the last run of parser p fails but it--- consumed input, then several p fails. The state of the parser is--- updated to reflect the state up to and including the run that--- partially consumed input. The parser is left in a failed state.------ This semantic can come in handy. For example you might run a parser--- multiple times that parses an option and arguments to the--- option. If the arguments fail to parse, then several will fail.------ This function provides the implementation for--- 'Control.Applicative.Alternative.many'.-several ::-  (Monad m)-  => ParserT s e m a-  -> ParserT s e m [a]-several (ParserT l) = ParserT $ \s ->-  parseRepeat s l >>= \r ->-  let (result, finalGoodSt, failure, finalBadSt) = r-  in if noConsumed finalGoodSt finalBadSt-     then return (Good result, finalGoodSt)-     else return (Bad failure, finalBadSt)--parseRepeat ::-  (Monad m)-  => ParseSt s-  -> (ParseSt s -> m (Result e a, ParseSt s))-  -> m ([a], ParseSt s, e, ParseSt s)-parseRepeat st1 f = f st1 >>= \r ->-  case r of-    (Good a, st') ->-      if noConsumed st1 st'-      then error $ "several applied to parser that succeeds without"-           ++ " consuming any input"-      else-        parseRepeat st' f >>= \r' ->-        let (ls, finalGoodSt, failure, finalBadSt) = r'-        in return (a : ls, finalGoodSt, failure, finalBadSt)-    (Bad e, st') -> return ([], st1, e, st')---- | feed runs in a recursive loop. Each loop starts with three--- variables: a function @f@ that takes an input @i@ and returns a--- parser @p@, a function @g@ that takes an input @i@ and returns a--- parser @e@ that must succeed for the recursion to end, and an--- initial input @i@. This proceeds as follows:------ 1. Apply @g@ to @i@ and run resulting parser @e@. If this parser--- succeeds, feed succeeds and returns a list of all successful runs--- of @p@. The result of @e@ is not returned, but otherwise the parser--- returned reflects the updated internal parser state from the--- running of @e@. (If that is a problem, wrap @e@ in 'lookAhead'.) If--- @e@ fails and consumes input, feed fails and returns a failed--- parser whose internal state reflects the state after @e@ fails. If--- @e@ fails without consuming any input, proceed with the following--- steps.------ 2. Apply function @f@ to input @i@, yielding a parser @p@. Run--- parser @p@. If @p@ fails, feed also fails. If @p@ succeeds, it--- yields a new input, @i'@.------ 3. If @p@ succeeded without consuming any input, an infinite loop--- will result, so apply @error@.------ 4. Repeat from step 1, but with the new input retured from @p@,--- @i'@.------ For the initial application of feed, you supply the function @f@,--- the end parser @e@, and the initial state @i@.------ This function is useful for running multiple times a parser that--- depends on the result of previous runs of the parser. You could--- implement something similar using the user state feature, but for--- various reasons sometimes it is more useful to use 'feed' instead.--feed ::-  Monad m-  => (a -> ParserT s e m a)-  -> (a -> ParserT s e m end)-  -> a-  -> ParserT s e m [a]-feed f e i = ParserT $ \s ->-  feedRecurse s f e i >>= \(s', lf) ->-  let res = case lf of-        EndFailure err -> Bad err-        RepeatFailure err -> Bad err-        RepeatSuccess ls -> Good ls-  in return (res, s')--data LastFeed e a =-  EndFailure e-  -- ^ The last run of the end parser failed and consumed input.-  -  | RepeatFailure e-    -- ^ The last run of the repetitive parser failed (whether or not-    -- it consumed any input).--  | RepeatSuccess [a]-    -- ^ The last run of the repetitive parser succeeded; here are all-    -- the results.---- | Takes an initial state, a function @f@ that returns a parser @p@--- to run repetitively, a parser @e@ that must succeed to stop the--- recursion, and an input for @f@. Returns: @m (s, ei)@, where: ------ * @m@ is the inner monad------ * @s@ is the state after the last application of either @e@ or @p@.------ * @lf@ is a 'LastFeed' (see above).-feedRecurse ::-  Monad m-  => ParseSt s-  -> (a -> ParserT s e m a)-  -> (a -> ParserT s e m end)-  -> a-  -> m (ParseSt s, LastFeed e a)-feedRecurse st f fe i =-  runParserT (fe i) st >>= \(eResult, eSt) ->-  case eResult of-    Good _ -> return (eSt, RepeatSuccess [])-    Bad b ->-      if noConsumed st eSt-      then-        runParserT (f i) st >>= \(pResult, pSt) ->-        case pResult of-          Good g ->-            if noConsumed st pSt-            then feedRecurseError-            else-              feedRecurse pSt f fe g >>= \(recSt, lf) ->-              let res = case lf of-                    RepeatSuccess ls -> RepeatSuccess (g:ls)-                    failed -> failed-              in return (recSt, res)-          Bad badRepeat -> return (pSt, RepeatFailure badRepeat)-      else-        return (eSt, EndFailure b)--feedRecurseError :: a-feedRecurseError =-  error $ "feedRecurse applied to parser that succeeds without"-  ++ " consuming any input"----- | Succeeds if there is no more input left.-end ::-  (E.Error e, Monad m)-  => ParserT s e m ()-end = ParserT $ \s ->-  let err saw = return (Bad (E.parseErr E.ExpEnd saw), s)-      gd (g, newSt) = return (Good g, newSt)-  in switch err gd $ do-    maybe (return ()) (S.throw . E.SawStillPendingShorts) (pendingShort s)-    when (not . null . remaining $ s) (S.throw E.SawMoreInput)-    return ((), s)---- | Gets the user state.-get ::-  (Monad m)-  => ParserT s e m s-get = ParserT $ \s ->-  return (Good (userState s), s)---- | Puts a new user state.-put ::-  (Monad m)-  => s-  -> ParserT s e m ()-put newUserSt = ParserT $ \s ->-  return (Good (), s { userState = newUserSt })---- | Modify the user state.-modify ::-  (Monad m)-  => (s -> s)-  -> ParserT s e m ()-modify f = ParserT $ \s ->-  return (Good (), s { userState = f (userState s) })
− lib/System/Console/MultiArg/SampleParser.hs
@@ -1,30 +0,0 @@--- | This is sample code using "System.Console.MultiArg". This could--- be a command-line parser for the version of the Unix command @tail@--- that is included with GNU coreutils version 8.5. "main" simply gets--- the command line arguments, parses them, and prints out what was--- parsed. To test it out, there is a @sample.hs@ file in the--- @binaries@ directory of the multiarg archive that you can compile.-module System.Console.MultiArg.SampleParser where--import System.Console.MultiArg--specs :: [OptSpec]--specs = [ OptSpec "bytes"               "c" []          oneArg-        , OptSpec "follow"              "f" []          optionalArg-        , OptSpec "follow-retry"        "F" []          noArg-        , OptSpec "lines"               "n" []          oneArg-        , OptSpec "max-unchanged-stats" ""  []          oneArg-        , OptSpec "pid"                 ""  []          oneArg-        , OptSpec "quiet"               "q" ["silent"]  noArg-        , OptSpec "sleep-interval"      "s" []          oneArg-        , OptSpec "verbose"             "v" []          noArg-        , OptSpec "help"                ""  []          noArg-        , OptSpec "version"             ""  []          noArg-        ]--sampleMain :: IO ()-sampleMain = do-  as <- getArgs-  let r = parse Intersperse specs as-  print r
− lib/System/Console/MultiArg/SimpleParser.hs
@@ -1,255 +0,0 @@--- | 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 (-  OptSpec(..),-  Intersperse(..),-  Result(..),-  Args(..),-  noArg,-  optionalArg,-  oneArg,-  twoArg,-  variableArg,-  SimpleError,-  getArgs,-  System.Console.MultiArg.SimpleParser.parse ) where--import System.Console.MultiArg.Prim (-  Parser, manyTill, lookAhead, nextArg, nonOptionPosArg,-  end, (<?>), stopper, nonOptionPosArg, try )-import qualified System.Console.MultiArg.Prim as Prim-import System.Console.MultiArg.Combinator (-  mixedNoArg, mixedOptionalArg, mixedOneArg, mixedTwoArg,-  mixedVariableArg )-import System.Console.MultiArg.Option (-  makeLongOpt, makeShortOpt )-import Control.Monad.Exception.Synchronous ( toEither )-import System.Console.MultiArg.Error ( SimpleError )-import Data.Text ( pack, unpack )-import System.Environment ( getArgs )-import Data.Monoid ( mconcat )-import Control.Applicative ( many, (<|>) )---- | Specifies each option that your program accepts.-data OptSpec = OptSpec {-  longOpt :: String-  -- ^ Each option must have at least one long option, which you-  -- specify here. Your program's users specify long options by-  -- preceding them with two dashes, such as @--verbose@. When writing-  -- your code you omit the dashes, so you would specify @verbose@-  -- here; including the dashes in your code results in a runtime-  -- error.--  , shortOpts :: [Char]-    -- ^ Additional, synonymous short options may be specified-    -- here. For instance if you want your users to be able to specify-    -- @-v@ in addition to @--verbose@, include @v@ in this list.-    -  , longOpts :: [String]-    -- ^ Additional synonymous long options may be specified here. For-    -- instance, if you specified @quiet@ for @longOpt@, you might-    -- want to include @silent@ in this list.--  , argSpec :: Args-    -- ^ Specifies what arguments, if any, this option takes.-  }-             deriving Show---- | This datatype does dual duty. When part of an 'OptSpec', you use--- it to specify how many arguments, if any, an option takes. When you--- use it for this purpose, it only matters which data constructor you--- use; the fields can be any value, even 'undefined'.------ When part of a Result, 'Args' indicates what arguments the user--- supplied to the option.-data Args =-  NoArg-  -- ^ This option takes no arguments-          -  | OptionalArg  { oArg :: Maybe String }--    -- ^ This option takes an optional argument. As noted in \"The Tao-    -- of Option Parsing\", optional arguments can result in some-    -- ambiguity. (Read it here:-    -- <http://optik.sourceforge.net/doc/1.5/tao.html>) If option @a@-    -- takes an optional argument, and @b@ is also an option, what-    -- does @-ab@ mean? SimpleParser resolves this ambiguity by-    -- assuming that @b@ is an argument to @a@. If the user does not-    -- like this, she can specify @-a -b@ (in such an instance @-b@ is-    -- not parsed as an option to @-a@, because @-b@ begins with a-    -- hyphen and therefore \"looks like\" an option.) Certainly-    -- though, optional arguments lead to ambiguity, so if you don't-    -- like it, don't use them :)--  | OneArg       { sArg1 :: String }-    -- ^ This option takes one argument. Here, if option @a@ takes one-    -- argument, @-a -b@ will be parsed with @-b@ being an argument to-    -- option @a@, even though @-b@ starts with a hyphen and therefore-    -- \"looks like\" an option.-    -  | TwoArg       { tArg1 :: String-                 , tArg2 :: String }-    -- ^ This option takes two arguments. Parsed similarly to 'OneArg'.-    -  | VariableArg { vArgs :: [String] }-    -- ^ This option takes a variable number of arguments--zero or-    -- more. Option arguments continue until the command line contains-    -- a word that begins with a hyphen. For example, if option @a@-    -- takes a variable number of arguments, then @-a one two three-    -- -b@ will be parsed as @a@ taking three arguments, and @-a -b@-    -- will be parsed as @a@ taking no arguments. If the user enters-    -- @-a@ as the last option on the command line, then the only way-    -- to indicate the end of arguments for @a@ and the beginning of-    -- positional argments is with a stopper.-    -  deriving Show---- | Specify that this option takes no arguments.-noArg :: Args-noArg = NoArg---- | Specify that this option takes an optional argument.-optionalArg :: Args-optionalArg = OptionalArg Nothing---- | Specify that this option takes one argument.-oneArg :: Args-oneArg = OneArg ""---- | Specify that this option takes two arguments.-twoArg :: Args-twoArg = TwoArg "" ""---- | Specify that this option takes a variable number of arguments.-variableArg :: Args-variableArg = VariableArg []---- | Holds the result of command line parsing. Each option (along with--- its option arguments) or positional argument is assigned to its own--- Result.-data Result =-  PosArg   { posArg :: String }-  | Stopper-  | Option {-    label :: String-    -- ^ Each option must have at least one long option. So that you-    -- can distinguish one option from another, the name of that long-    -- option is returned here.-    , args :: Args }-              deriving Show---- | 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-  -> [OptSpec]-  -> [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.--  -> Either SimpleError [Result]-parse i os ss = toEither $ Prim.parse (map pack ss) (f os) where-  f = case i of Intersperse -> parseIntersperse-                StopOptions -> parseNoIntersperse--parseNoIntersperse :: [OptSpec] -> Parser [Result]-parseNoIntersperse os = do-  let opts = mconcat . map optSpec $ os-  rs <- manyTill opts (try $ lookAhead afterArgs)-  firstArg <- afterArgs-  case firstArg of-    EndOfInput -> return rs-    (FirstArg s) -> do-      as <- noIntersperseArgs-      let first = PosArg s-      return $ rs ++ ( first : as )-    AAStopper -> do-      as <- noIntersperseArgs-      let first = Stopper-      return $ rs ++ ( first : as )--noIntersperseArgs :: Parser [Result]-noIntersperseArgs = do-  as <- many nextArg-  let r = map PosArg . map unpack $ as-  return r--data AfterArgs = EndOfInput | FirstArg String | AAStopper--afterArgs :: Parser AfterArgs-afterArgs = parseFirst <|> parseEnd <|> parseStopper where-  parseFirst = do-    a <- nonOptionPosArg-    let aS = unpack a-    return $ FirstArg aS-  parseEnd = do-    end-    return EndOfInput-  parseStopper = do-    _ <- stopperParser-    return AAStopper--parseIntersperse :: [OptSpec] -> Parser [Result]-parseIntersperse os = do-  let optsAndStopper = foldl1 (<|>) $ optSpecs ++ rest-      rest = [stopperParser, posArgParser]-      optSpecs = map optSpec os-  rs <- manyTill optsAndStopper end-  end <?> error "the end parser should always succeed"-  return rs--stopperParser :: Parser Result-stopperParser = stopper >> return Stopper--posArgParser :: Parser Result-posArgParser = do-  a <- nonOptionPosArg-  return $ PosArg (unpack a)--optSpec :: OptSpec -> Parser Result-optSpec o = let-  lo = makeLongOpt . pack . longOpt $ o-  ss = map makeShortOpt . shortOpts $ o-  ls = map makeLongOpt . map pack . longOpts $ o-  opt = return . Option (longOpt o)-  in case argSpec o of-    NoArg -> do-      _ <- mixedNoArg lo ls ss-      opt NoArg-    (OptionalArg {}) -> do-      (_, a) <- mixedOptionalArg lo ls ss-      opt (OptionalArg . fmap unpack $ a)-    (OneArg {}) -> do-      (_, a) <- mixedOneArg lo ls ss-      opt (OneArg . unpack $ a)-    (TwoArg {}) -> do-      (_, a1, a2) <- mixedTwoArg lo ls ss-      opt (TwoArg (unpack a1) (unpack a2))-    (VariableArg {}) -> do-      (_, as) <- mixedVariableArg lo ls ss-      opt (VariableArg . map unpack $ as)-
− lib/System/Console/MultiArg/TextNonEmpty.hs
@@ -1,6 +0,0 @@-module System.Console.MultiArg.TextNonEmpty where--import Data.Text ( Text )--data TextNonEmpty = TextNonEmpty Char Text-                    deriving (Show, Eq)
multiarg.cabal view
@@ -1,5 +1,5 @@ Name: multiarg-Version: 0.2.0.0+Version: 0.4.0.0 Cabal-version: >=1.8 Build-Type: Simple License: MIT@@ -12,8 +12,7 @@ Category: Console, Parsing License-File: LICENSE synopsis: Combinators to build command line parsers-extra-source-files:-        doc/sample.hs, NEWS+extra-source-files: NEWS  description: multiarg is a parser combinator library to build command  line parsers. With it you can easily create parsers with options@@ -21,13 +20,11 @@  multiarg due to the apparent lack of such ability amongst other  parsers. Its basic design is loosely inspired by Parsec.  .- Provides ParserT, a monad you use to build parsers. ParserT is a monad- transformer, so you can layer it on top of other monads. For instance- you could layer it on the IO monad so that your parser can perform IO.- .- It also has a simple, pre-built parser built with the underlying- combinators, which works for many situtations and shields you from the- underlying complexity if you don't need it.+ Provides Parser, a monad you use to build parsers. This monad exposes+ multiarg's full functionality. The library also has a simple,+ pre-built parser built with the underlying combinators, which works+ for many situtations and shields you from the underlying complexity+ if you don't need it.  .  See the documentation in the System.Console.MultiArg module for  details.@@ -40,14 +37,10 @@     location: git://github.com/massysett/multiarg.git  Library-    hs-source-dirs: lib-     Build-depends:         base ==4.*,-        text ==0.11.*,         explicit-exception ==0.1.*,-        containers ==0.4.*,-        transformers == 0.2.*+        containers ==0.4.*              -- See documentation in System.Console.MultiArg.GetArgs for details     if flag(newbase)@@ -61,12 +54,10 @@     Exposed-modules:         System.Console.MultiArg,         System.Console.MultiArg.Combinator,-        System.Console.MultiArg.Error,         System.Console.MultiArg.GetArgs,         System.Console.MultiArg.Option,         System.Console.MultiArg.Prim,         System.Console.MultiArg.SampleParser,-        System.Console.MultiArg.SimpleParser,-        System.Console.MultiArg.TextNonEmpty+        System.Console.MultiArg.SimpleParser      ghc-options: -Wall