I'm trying to write a parser for a configuration file and I'm hitting a strange error where the parser just freezes. The code can be seen here. I've ran it in the debugger and it appears to happen in the line
p_server_entry = many settings *> pure ()
At the evaluation of "pure ()". That is, it seems to fail on trying to return from p_server_entry if the debugger behaviour can be trusted. I tried removing the "pure ()" statement and simply returning "[()]" (and adjusting the type signatures obviously) but it seems to hang in the same place. I know Parsec doesn't support left recursion but I don't see that going on here?
What I'm doing is, I'm using Parsec to fill in a Record for me via the user state. For return values I just return () from all functions since the configuration record will be retrieved from state and returned as the result of the parse. An example file that causes the hang is:
[server]
port = 80
I test this by running the Parser.hs file in ghci (though compiling the program and running it gives the same result) and then doing
:m + Data.Monoid
parseConfigFile "test.config" mempty
I appreciate any help anyone can provide.
EDIT: I should mention that this was working almost as is previously. I changed it from returning a special parse tree to simply updating the configuration structure directly.
And I got it. I'll be taking down the code link since that branch shouldn't have been published but the gist of it is: I had a record like
data Config = { port :: Int, {- ... -} } -- "Save edits" doesn't seem to always save edits!
I created a parser that would parse the input and update one of these structures. It threw away the actual parse data because all I wanted was the updated record in any case. The problem was, this threw away the type information as well hindering the compiler from pointing out the error in my logic. For every statement that actually produced data there would be a
*> pure ()
at the end of the statement, throwing away the parsed data. I decided that I probably shouldn't throw away the data, even if I don't need it right now so I created new types to encode what was parsed and end up returning the parse tree along with the updated configuration structure.
Immediately upon completing this the problem was made apparent. I had a statement like
p_server_settings = case someVar of
"server" -> many p_serverSettings
_ -> many p_siteSettings
and both of those combinators were defined as
p_serverSettings = many settings *> pure ()
where settings = {- bunch of possible settings -}
Once I removed the () return and used what was produced I immediately saw that p_server_settings was trying to return [[Setting]] instead of [Setting], which was because I had
many many settings
which is a handy little loop that consumes no input.
Lesson learned: if you throw away your types you're tying the compilers hands.