Search code examples
haskellparsec

Parsec error - try doesn't seem to work


I'm currently using the Text.Parsec.Expr module to parse a subset of a scripting language.

Basically, there are two kinds of commands in this language: Assignment of the form $var = expr and a Command of the form $var = $array[$index] - there are of course other commands, but this suffices to explain my problem.

I've created a type Command, to represent this, along with corresponding parsers, where expr for the assignment is handled by Parsec's buildExpressionParser.

Now, the problem. First the parsing code:

main = case parse p "" "$c = $a[$b]" of
          Left err -> putStrLn . show $ err
          Right r  -> putStrLn . show $ r
    where p = (try assignment <|> command) <* eof -- (1)

The whole code (50 lines) is pasted here: Link (should compile if you've parsec installed)

The problem is, that parsing fails, since assignment doesn't successfully parse, even though there is a try before. Reversing the parsing order (try command <|> assignment) solves the problem, but is not possible in my case.

Of course I tried to locate the problem further and it appears to me, that the problem is the expression parser (build by buildExpressionParser), since parsing succeeds if I say expr = fail "". However I can't find anything in the Parsec sources that would explain this behaviour.


Solution

  • You parser fails because in fact assigment does succeeds here consuming $c = $a (try it with plain where p = assignment). Then there is supposed to be eof (or the rest of expr from assigment) hence the error. It seems that the beggining of your 'command' is identical to your 'assignment' in the case when 'assignment''s argument is just a var (like $c = $a). Not sure why you can't reverse command and assignment but another way to make this particular example work would be:

    main = case parse p "" "$c = $a[$b]" of
          Left err -> putStrLn . show $ err
          Right r  -> putStrLn . show $ r
       where p = try (assignment <* eof) <|> (command <* eof)