{-# LANGUAGE DeriveLift#-} module System.Console.Docopt.Types where import Data.Char (isUpper) import Data.List (nub) import Data.Map (Map) import qualified Data.Map as M import Language.Haskell.TH.Syntax (Lift) -- * Usage expression Types type Name = String data Pattern a = Sequence [Pattern a] | OneOf [Pattern a] | Unordered [Pattern a] | Optional (Pattern a) | Repeated (Pattern a) | Atom a deriving (Show, Eq, Lift) atoms :: Eq a => Pattern a -> [a] atoms (Sequence ps) = concatMap atoms ps atoms (OneOf ps) = concatMap atoms $ nub ps atoms (Unordered ps) = concatMap atoms $ nub ps atoms (Optional p) = atoms p atoms (Repeated p) = atoms p atoms (Atom a) = [a] -- | A named leaf node of the usage pattern tree data Option = LongOption Name | ShortOption Char | Command Name | Argument Name | AnyOption deriving (Show, Eq, Ord, Lift) type OptPattern = Pattern Option humanize :: Option -> String humanize opt = case opt of Command name -> name Argument name -> if all isUpper name then name else "<" ++ name ++ ">" LongOption name -> "--"++name ShortOption c -> ['-',c] AnyOption -> "[options]" -- | Used when parsing through the available option descriptions. -- Holds a list of synonymous options, Maybe a default value (if specified), -- an expectsVal :: Bool that indicates whether this option is a flag (--flag) -- or an option that needs an argument (--opt=arg), and isRepeated :: Bool -- that indicates whether this option is always single or needs to be accumulated data OptionInfo = OptionInfo { synonyms :: [Option] , defaultVal :: Maybe String , expectsVal :: Bool , isRepeated :: Bool } deriving (Show, Eq, Lift) fromSynList :: [Option] -> OptionInfo fromSynList opts = OptionInfo { synonyms = opts , defaultVal = Nothing , expectsVal = False , isRepeated = False } -- | Maps each available option to a OptionInfo entry -- (each synonymous option gets its own separate entry, for easy lookup) type OptInfoMap = Map Option OptionInfo -- | Contains all the relevant information parsed out of a usage string. -- Used to build the actual command-line arg parser. type OptFormat = (OptPattern, OptInfoMap) -- | data OptParserState = OptParserState { optInfoMap :: OptInfoMap , parsedArgs :: Arguments , inShortOptStack :: Bool , inTopLevelSequence :: Bool } deriving (Show) fromOptInfoMap :: OptInfoMap -> OptParserState fromOptInfoMap m = OptParserState { optInfoMap = m , parsedArgs = M.empty , inShortOptStack = False , inTopLevelSequence = True } data ArgValue = MultiValue [String] | Value String | NoValue | Counted Int | Present | NotPresent deriving (Show, Eq, Ord) -- | Maps each Option to all of the valued parsed from the command line -- (in order of last to first, if multiple values encountered) type Arguments = Map Option ArgValue -- | An abstract data type which represents Docopt usage patterns. data Docopt = Docopt { optFormat :: OptFormat -- | Retrieve the original usage string. , usage :: String }