Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parser written in Haskell not working as intended

I was playing around with Haskell's parsec library. I was trying to parse a hexadecimal string of the form "#x[0-9A-Fa-f]*" into an integer. This the code I thought would work:

module Main where

import Control.Monad
import Numeric
import System.Environment
import Text.ParserCombinators.Parsec hiding (spaces)

parseHex :: Parser Integer
parseHex = do
  string "#x"
  x <- many1 hexDigit
  return (fst (head (readHex x)))

testHex :: String -> String
testHex input = case parse parseHex "lisp" input of
  Left err -> "Does not match " ++ show err
  Right val -> "Matched" ++ show val

main :: IO ()
main = do
  args <- getArgs
  putStrLn (testHex (head args))

And then I tried testing the testHex function in Haskell's repl:

GHCi, version 8.6.5: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Main             ( src/Main.hs, interpreted )
Ok, one module loaded.
*Main> testHex "#xcafebeef"
"Matched3405692655"
*Main> testHex "#xnothx"
"Does not match \"lisp\" (line 1, column 3):\nunexpected \"n\"\nexpecting hexadecimal digit"
*Main> testHex "#xcafexbeef"
"Matched51966"

The first and second try work as intended. But in the third one, the string is matching upto the invalid character. I do not want the parser to do this, but rather not match if any digit in the string is not a valid string. Why is this happening, and how do if fix this?

Thank you!

like image 417
Bhargav Kulkarni Avatar asked Sep 29 '21 14:09

Bhargav Kulkarni


1 Answers

You need to place eof at the end.

parseHex :: Parser Integer
parseHex = do
  string "#x"
  x <- many1 hexDigit
  eof
  return (fst (head (readHex x)))

Alternatively, you can compose it with eof where you use it if you want to reuse parseHex in other places.

testHex :: String -> String
testHex input = case parse (parseHex <* eof) "lisp" input of
  Left err -> "Does not match " ++ show err
  Right val -> "Matched" ++ show val
like image 58
snak Avatar answered Nov 03 '22 18:11

snak