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.
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)