silly8888 | 8 Aug 2012 21:24
Picon

parsec: parserFail & multiple error messages

I am trying to create a parsec parser that parses an integer and then
checks if that integer has the right size. If not, it generates an
error.
I tried the following:

8<---------------------------------------------------------------
import Text.Parsec
import Text.Parsec.String

integer :: Parser Int
integer  = do s <- many1 digit
              let n = read s
              if n > 65535 then
                  parserFail "integer overflow"
              else
                  return n
8<---------------------------------------------------------------

The problem is that when I try this

parse integer "" "70000"

I get the following error:

Left (line 1, column 6):
unexpected end of input
expecting digit
integer overflow

ie there are three error messages but I only want the last one. Is
(Continue reading)

Nick Vanderweit | 8 Aug 2012 22:09
Picon
Gravatar

Re: parsec: parserFail & multiple error messages

I found a similar question asked in June 2009 on the haskell-beginners 
archives, titled "Clearing Parsec error messages." A hack that was proposed 
(http://www.haskell.org/pipermail/beginners/2009-June/001809.html) was to 
insert a dummy character into the stream, consume it, and then fail. Still, 
I'd like to see if there is a cleaner way to modify the error state in the 
Parsec monad.

NIck

On Wednesday, August 08, 2012 03:24:31 PM silly8888 wrote:
> I am trying to create a parsec parser that parses an integer and then
> checks if that integer has the right size. If not, it generates an
> error.
> I tried the following:
> 
> 8<---------------------------------------------------------------
> import Text.Parsec
> import Text.Parsec.String
> 
> integer :: Parser Int
> integer  = do s <- many1 digit
>               let n = read s
>               if n > 65535 then
>                   parserFail "integer overflow"
>               else
>                   return n
> 8<---------------------------------------------------------------
> 
> The problem is that when I try this
> 
(Continue reading)

silly8888 | 9 Aug 2012 03:26
Picon

Re: parsec: parserFail & multiple error messages

Inserting a character into the stream can be expensive if for example
the stream is a ByteString.
I tried the following crazy solution and it seems that it works:

succeed :: Parser ()
succeed = mkPT $ \st ->
    return $ Consumed $ return $ Ok () st $ unknownError st

succeed is a parser that always succeeds without really consuming any
input but it also resets the error state.

I really have no understating of how mkPT works. Can someone tell me
if this is a bad idea?

On Wed, Aug 8, 2012 at 4:09 PM, Nick Vanderweit
<nick.vanderweit <at> gmail.com> wrote:
> I found a similar question asked in June 2009 on the haskell-beginners
> archives, titled "Clearing Parsec error messages." A hack that was proposed
> (http://www.haskell.org/pipermail/beginners/2009-June/001809.html) was to
> insert a dummy character into the stream, consume it, and then fail. Still,
> I'd like to see if there is a cleaner way to modify the error state in the
> Parsec monad.
>
>
> NIck
>
> On Wednesday, August 08, 2012 03:24:31 PM silly8888 wrote:
>> I am trying to create a parsec parser that parses an integer and then
>> checks if that integer has the right size. If not, it generates an
>> error.
(Continue reading)

Antoine Latter | 9 Aug 2012 05:28
Picon
Gravatar

Re: parsec: parserFail & multiple error messages

On Wed, Aug 8, 2012 at 8:26 PM, silly8888 <silly8888 <at> gmail.com> wrote:
> Inserting a character into the stream can be expensive if for example
> the stream is a ByteString.
> I tried the following crazy solution and it seems that it works:
>
> succeed :: Parser ()
> succeed = mkPT $ \st ->
>     return $ Consumed $ return $ Ok () st $ unknownError st
>
> succeed is a parser that always succeeds without really consuming any
> input but it also resets the error state.
>

Because you're using the 'Consumed' constructor, you're also telling
parsec not the back-track if there any errors following this parsers.

This means that 'succeed >> failingParser' won't backtrack, even if
'failingParser' doesn't consume input.

Are you using your original parser within a larger parser? Are the
error messages also not great?

Antoine
Christian Maeder | 9 Aug 2012 09:59
Picon
Favicon

Re: parsec: parserFail & multiple error messages

The error message can be improved in your examples by using "count 5" 
instead of "many1".

C.

Am 08.08.2012 21:24, schrieb silly8888:
> I am trying to create a parsec parser that parses an integer and then
> checks if that integer has the right size. If not, it generates an
> error.
> I tried the following:
>
> 8<---------------------------------------------------------------
> import Text.Parsec
> import Text.Parsec.String
>
> integer :: Parser Int
> integer  = do s <- many1 digit
>                let n = read s
>                if n > 65535 then
>                    parserFail "integer overflow"
>                else
>                    return n
> 8<---------------------------------------------------------------
>
> The problem is that when I try this
>
> parse integer "" "70000"
>
> I get the following error:
>
(Continue reading)

silly8888 | 9 Aug 2012 17:19
Picon

Re: parsec: parserFail & multiple error messages

On Thu, Aug 9, 2012 at 3:59 AM, Christian Maeder
<Christian.Maeder <at> dfki.de> wrote:
> The error message can be improved in your examples by using "count 5"
> instead of "many1".

Yes, I know. That's what I ended up doing. But this is an ad hoc
solution. I think parsec should offer a more general solution.
Albert Y. C. Lai | 10 Aug 2012 02:15
Favicon

Re: parsec: parserFail & multiple error messages

On 12-08-08 03:24 PM, silly8888 wrote:
> The problem is that when I try this
>
> parse integer "" "70000"
>
> I get the following error:
>
> Left (line 1, column 6):
> unexpected end of input
> expecting digit
> integer overflow
>
> ie there are three error messages but I only want the last one. Is
> there something I can do about this?

import Text.Parsec
import Text.Parsec.String

integer :: Parser Int
integer = try integ3r <?> "number at most 65535"
integ3r  = do s <- many1 digit
               let n = read s
               if n > 65535 then
                   unexpected "number overflow"
               else
                   return n

main = do
   parseTest integer "a70000"
   parseTest integer "70000"
(Continue reading)


Gmane