{- | Helper functions for handling shell/command-line options -} module FST.Arguments ( -- * Commands ADT InteractiveCommand (..), BatchCommand (..), -- * Helper functions parseInteractive, isFST, isDAT, isNET, isTHIS, parseBatch, inputB, outputB, isUpB ) where import System.Console.GetOpt import Data.List import Data.Maybe -- | ADT for a shell command data InteractiveCommand = -- | Build an epsilon-free, deterministic, minimal transducer from a -- loaded/typed regular relation. BuildTransducer -- | Build an epsilon-free, possibly non-deterministic, non-minimal -- transducer from a load/typed regular relation. | BuildNTransducer -- | Minimize a built transducer. | Minimize -- | Determinize a built transducer. | Determinize -- | Read a regular relation from standard input. | StdInReg String -- | Load from FILE. | Load FilePath -- | Load and union two transducers. | LUnion FilePath FilePath -- | Load and concatenate two transducers. | LProduct FilePath FilePath -- | Load and apply Kleene's star on a transducer. | LStar FilePath -- | Load and compose two transducers. | LComposition FilePath FilePath -- | Save to file. | Save FilePath -- | Apply transducer down with loaded input. | ApplyDown -- | Apply transducer up with loaded input. | ApplyUp -- | Apply tranducer down with given symbols. | ApplyD [String] -- | Apply tranducer up with given symbols. | ApplyU [String] -- | View loaded/typed regular relation. | ViewReg -- | View loaded input. | ViewInput -- | View prodeced output. | ViewOutput -- | View loaded/built transducer. | ViewTransducer -- | List commands. | Help -- | Clear loaded transducers/input/output. | ClearMemory -- | Quit the shell | Quit -- | Unparseable command | NoCommand deriving (Eq, Show) -- | Parse input string into a command parseInteractive :: [String] -> InteractiveCommand parseInteractive ["b"] = BuildTransducer parseInteractive ["bn"] = BuildNTransducer parseInteractive ["m"] = Minimize parseInteractive ["det"] = Determinize parseInteractive ("r":xs) = StdInReg (unwords xs) parseInteractive ["d"] = ApplyDown parseInteractive ["u"] = ApplyUp parseInteractive ("d":xs) = ApplyD xs parseInteractive ("u":xs) = ApplyU xs parseInteractive ["l",file] = Load file parseInteractive ["l",file1,"|",file2] = LUnion file1 file2 parseInteractive ["l",file1," ",file2] = LProduct file1 file2 parseInteractive ["l",file, "*"] = LStar file parseInteractive ["l",file1,".o.",file2] = LComposition file1 file2 parseInteractive ["s",file] = Save file parseInteractive ["vt"] = ViewTransducer parseInteractive ["vi"] = ViewInput parseInteractive ["vo"] = ViewOutput parseInteractive ["vr"] = ViewReg parseInteractive ["h"] = Help parseInteractive ["q"] = Quit parseInteractive ["c"] = ClearMemory parseInteractive _ = NoCommand -- | Does the file end with .fst? isFST :: String -> Bool isFST = isSuffixOf ".fst" -- | Does the file end with .dat? isDAT :: String -> Bool isDAT = isSuffixOf ".dat" -- | Does the file end with .net? isNET :: String -> Bool isNET = isSuffixOf ".net" -- | Is the internal transducer being specified? isTHIS :: String -> Bool isTHIS = (== "*") -- | Is apply up? isApplyUp :: [String] -> Bool isApplyUp = elem "-u" -- | Batch command ADT data BatchCommand = -- | Apply down DownB -- | Apply up | UpB -- | Invalid command | InvalidCommand -- | Take input from given file | Input String -- | Write output to file | Output String -- | Display help | HelpB deriving (Eq, Show) -- | Information for parsing batch options batchOptions :: [OptDescr BatchCommand] batchOptions = [ Option ['u'] ["up"] (NoArg UpB) "apply the transducer up (default is down)", Option ['d'] ["down"] (NoArg DownB) "apply the transducer down (default)", Option ['i'] ["input"] (ReqArg Input "FILE") "read input from FILE", Option ['o'] ["output"] (ReqArg Output "FILE") "write output to FILE" ] -- | Parse batch commands parseBatch :: [String] -> Either String (FilePath,[BatchCommand]) parseBatch cmdline = case getOpt Permute batchOptions cmdline of (o, [file], []) -> Right (file, o) (_, _, errs) -> Left (concat errs ++ usageInfo header batchOptions) where header = "Usage: fst [FILE.net or FILE.fst] [OPTIONS...]" -- | Handle batch input command inputB :: [BatchCommand] -> Maybe FilePath inputB cs = listToMaybe [ file | Input file <- cs ] -- | Handle batch output command outputB :: [BatchCommand] -> Maybe FilePath outputB cs = listToMaybe [ file | Output file <- cs ] -- | Is batch command apply up? isUpB :: [BatchCommand] -> Bool isUpB = elem UpB {- ----------------------------------------------------------------------------------------- -- and here a small and hopefully enlightening example: data Flag = Verbose | Version | Name String | Output String | Arg String deriving Show options :: [OptDescr Flag] options = [Option ['v'] ["verbose"] (NoArg Verbose) "verbosely list files", Option ['V','?'] ["version","release"] (NoArg Version) "show version info", Option ['o'] ["output"] (OptArg out "FILE") "use FILE for dump", Option ['n'] ["name"] (ReqArg Name "USER") "only dump USER's files"] out :: Maybe String -> Flag out Nothing = Output "stdout" out (Just o) = Output o test :: ArgOrder Flag -> [String] -> String test order cmdline = case getOpt order options cmdline of (o,n,[] ) -> "options=" ++ show o ++ " args=" ++ show n ++ "\n" (_,_,errs) -> concat errs ++ usageInfo header options where header = "Usage: foobar [OPTION...] files..." -- example runs: -- putStr (test RequireOrder ["foo","-v"]) -- ==> options=[] args=["foo", "-v"] -- putStr (test Permute ["foo","-v"]) -- ==> options=[Verbose] args=["foo"] -- putStr (test (ReturnInOrder Arg) ["foo","-v"]) -- ==> options=[Arg "foo", Verbose] args=[] -- putStr (test Permute ["foo","--","-v"]) -- ==> options=[] args=["foo", "-v"] -- putStr (test Permute ["-?o","--name","bar","--na=baz"]) -- ==> options=[Version, Output "stdout", Name "bar", Name "baz"] args=[] -- putStr (test Permute ["--ver","foo"]) -- ==> option `--ver' is ambiguous; could be one of: -- -v --verbose verbosely list files -- -V, -? --version, --release show version info -- Usage: foobar [OPTION...] files... -- -v --verbose verbosely list files -- -V, -? --version, --release show version info -- -o[FILE] --output[=FILE] use FILE for dump -- -n USER --name=USER only dump USER's files ----------------------------------------------------------------------------------------- test :: ArgOrder BatchCommand -> [String] -> String test order cmdline = case getOpt order batchOptions cmdline of (o,n,[] ) -> "options=" ++ show o ++ " args=" ++ show n ++ "\n" (_,_,errs) -> concat errs ++ usageInfo header batchOptions where header = "Usage: fst [OPTION...] files..." -}