Parsing.hs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. -- Do IO with user input.
  2. module Parsing (argHandle, arguments) where
  3. import Numeric (showHex, showIntAtBase)
  4. import Data.List (isInfixOf, intersperse, 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. _:_ -> foldr (++) [] $ intersperse delim (map printFun digits)
  40. -- _:_ -> foldl (.) id (map showString (intersperse delim (map printFun digits))) "" -- Alternative implementation: not sure about speed
  41. [] -> printErr
  42. -- Pull digits in a range.
  43. getDigitsFrom :: Integer -> Integer -> [Integer]
  44. getDigitsFrom low high
  45. | low < 0 = []
  46. | high < 0 = []
  47. | otherwise = genericDrop low . genericTake high $ hexDigits
  48. -- Complain about argument type.
  49. printErr :: String
  50. printErr = "Error: Please give a positive Integer (ex: 3) or a valid range of positive Integers (ex: 3..5)."
  51. -- Arguments to parse.
  52. data Arguments = Arguments
  53. { eval :: Maybe String
  54. , print :: Maybe PrintFunc
  55. , delimiter :: String}
  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. -- Decide which printing function to use.
  67. data PrintFunc = DecPrint | BinPrint
  68. printFunc :: Parser (Maybe PrintFunc)
  69. printFunc = optional (decPrint <|> binPrint)
  70. decPrint :: Parser PrintFunc
  71. decPrint = flag' DecPrint ( long "decimal"
  72. <> short 'd'
  73. <> help "Output in decimal.")
  74. binPrint :: Parser PrintFunc
  75. binPrint = flag' BinPrint ( long "binary"
  76. <> short 'b'
  77. <> help "Output in binary.")
  78. -- Handle args, either prompt or eval & quit.
  79. argHandle :: Arguments -> IO ()
  80. argHandle (Arguments toEval outputType delim) = do
  81. let
  82. printFunIO =
  83. case outputType of
  84. Just DecPrint -> do
  85. putStrLn "Outputting in decimal."
  86. return (\n -> show n ++ "")
  87. Just BinPrint -> do
  88. putStrLn "Outputting in binary."
  89. return (\n -> showIntAtBase 2 (\x -> show x !! 0) n "")
  90. _ -> do
  91. putStrLn "Outputting in hex."
  92. return (\n -> showHex n "")
  93. in do
  94. printFun <- printFunIO
  95. case toEval of
  96. Just s -> putStrLn $ parseIndex printFun delim s
  97. _ -> do
  98. putStrLn "Enter a digit or range (Ctrl-C to exit)."
  99. prompt printFun delim