1
0

Parsing.hs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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 (hFlush, stdout)
  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
  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. arguments :: Parser Arguments
  56. arguments = Arguments
  57. <$> optional ( argument str (
  58. help "Evaluate an index/range, and exit."
  59. <> (metavar "eval")))
  60. <*> printFunc
  61. <*> strOption ( long "delimiter"
  62. <> metavar "delim"
  63. <> value ""
  64. <> help "Delimiter to separate printed values.")
  65. -- Decide which printing function to use.
  66. data PrintFunc = DecPrint | BinPrint
  67. printFunc :: Parser (Maybe PrintFunc)
  68. printFunc = optional (decPrint <|> binPrint)
  69. decPrint :: Parser PrintFunc
  70. decPrint = flag' DecPrint ( long "decimal"
  71. <> short 'd'
  72. <> help "Output in decimal.")
  73. binPrint :: Parser PrintFunc
  74. binPrint = flag' BinPrint ( long "binary"
  75. <> short 'b'
  76. <> help "Output in binary.")
  77. -- Handle args, either prompt or eval & quit.
  78. argHandle :: Arguments -> IO ()
  79. argHandle (Arguments toEval outputType delim) = do
  80. let
  81. printFunIO =
  82. case outputType of
  83. Just DecPrint -> do
  84. putStrLn "Outputting in decimal."
  85. return (\n -> show n)
  86. Just BinPrint -> do
  87. putStrLn "Outputting in binary."
  88. return (\n -> showIntAtBase 2 (\x -> show x !! 0) n "")
  89. _ -> do
  90. putStrLn "Outputting in hex."
  91. return (\n -> showHex n "")
  92. in do
  93. printFun <- printFunIO
  94. case toEval of
  95. Just s -> putStrLn $ parseIndex printFun delim s
  96. _ -> do
  97. putStrLn "Enter a digit or range (Ctrl-C to exit)."
  98. prompt printFun delim