Parsing.hs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. -- Do IO with user input.
  2. module Parsing (argHandle, arguments) where
  3. import Numeric (showHex, showIntAtBase)
  4. import Data.List (isInfixOf, intercalate, genericTake, genericDrop)
  5. import Data.List.Split (splitOn)
  6. import Text.Read (readMaybe)
  7. import System.IO (stdout, hFlush, hSetBuffering, BufferMode(NoBuffering))
  8. import Logic (hexDigits)
  9. import Options.Applicative
  10. import Data.Semigroup ((<>))
  11. -- Continuously prompt for input.
  12. prompt :: (Integer -> String) -> String -> IO ()
  13. prompt printFun delim = do
  14. putStr ">> "
  15. hFlush stdout -- In case buffering is enabled.
  16. response <- getLine
  17. putStrLn $ parseIndex printFun delim response
  18. prompt printFun delim
  19. -- Check if response is valid, then call the appropriate function.
  20. parseIndex :: (Integer -> String) -> String -> String -> String
  21. parseIndex printFun delim response =
  22. let
  23. digits =
  24. if (isInfixOf ".." response) then
  25. let
  26. range = splitOn ".." response
  27. jLow = readMaybe $ range !! 0 :: Maybe Integer
  28. jHigh = readMaybe $ range !! 1 :: Maybe Integer
  29. in
  30. case (jLow, jHigh) of
  31. (Just low, Just high) -> getDigitsFrom low high
  32. _ -> []
  33. else
  34. case (readMaybe response :: Maybe Integer) of
  35. Just n -> getDigitsFrom n (n+1)
  36. Nothing -> []
  37. in
  38. case digits of
  39. [] -> printErr
  40. _ -> intercalate delim (map printFun digits)
  41. -- Pull digits in a range.
  42. getDigitsFrom :: Integer -> Integer -> [Integer]
  43. getDigitsFrom low high
  44. | low < 0 = []
  45. | high < 0 = []
  46. | otherwise = genericDrop low . genericTake high $ hexDigits
  47. -- Complain about argument type.
  48. printErr :: String
  49. printErr = "Error: Please give a positive Integer (ex: 3) or a valid range of positive Integers (ex: 3..5)."
  50. -- Arguments to parse.
  51. data Arguments = Arguments
  52. { eval :: Maybe String
  53. , print :: Maybe PrintFunc
  54. , delimiter :: String
  55. , buffer :: Bool}
  56. arguments :: Parser Arguments
  57. arguments = Arguments
  58. <$> optional ( argument str (
  59. help "Evaluate an index/range, and exit."
  60. <> (metavar "eval")))
  61. <*> printFunc
  62. <*> strOption ( long "delimiter"
  63. <> metavar "delim"
  64. <> value ""
  65. <> help "Delimiter to separate printed values.")
  66. <*> switch (long "buffer"
  67. <> help "Don't print output as it's calculated.")
  68. -- Decide which printing function to use.
  69. data PrintFunc = DecPrint | BinPrint
  70. printFunc :: Parser (Maybe PrintFunc)
  71. printFunc = optional (decPrint <|> binPrint)
  72. decPrint :: Parser PrintFunc
  73. decPrint = flag' DecPrint ( long "decimal"
  74. <> short 'd'
  75. <> help "Output in decimal.")
  76. binPrint :: Parser PrintFunc
  77. binPrint = flag' BinPrint ( long "binary"
  78. <> short 'b'
  79. <> help "Output in binary.")
  80. -- Handle args, either prompt or eval & quit.
  81. argHandle :: Arguments -> IO ()
  82. argHandle (Arguments toEval outputType delim buff) = do
  83. let
  84. printFunIO =
  85. case outputType of
  86. Just DecPrint -> do
  87. putStrLn "Outputting in decimal."
  88. return (\n -> show n)
  89. Just BinPrint -> do
  90. putStrLn "Outputting in binary."
  91. return (\n -> showIntAtBase 2 (\x -> show x !! 0) n "")
  92. _ -> do
  93. putStrLn "Outputting in hex."
  94. return (\n -> showHex n "")
  95. in do
  96. printFun <- printFunIO
  97. if buff then
  98. return ()
  99. else
  100. hSetBuffering stdout NoBuffering
  101. case toEval of
  102. Just s -> putStrLn $ parseIndex printFun delim s
  103. _ -> do
  104. putStrLn "Enter a digit or range (Ctrl-C to exit)."
  105. prompt printFun delim