Your lexer's definition is completely fine as far as I can tell. Assuming there are no bugs there, the only problems you need to fix are in your parser's configuration. The first thing is that the lexer you are using is the wrong one. While that function is the interface to the Alex lexer, it has the type
alexMonadScan :: Alex result
But the lexer Happy wants is of type
lexer :: (Token -> P a) -> P a
Where P
is the monad we are using. What this is saying is that the lexer should provide us an Alex a
when given a continuation. A simple wrapper is what we need here:
lexwrap :: (Token -> Alex a) -> Alex a
lexwrap cont = do
token <- alexMonadScan
cont token
or equivalently
lexwrap = (alexMonadScan >>=)
Second, using alexEOF
in the %lexer
directive will cause your parser to fail on every input. The name you supply there is inserted in to a branch of a case statement in generated code, so you must use the name of a data constructor rather than a value --- in particular, you need to use the data constructor that Alex will emit to signal EOF.
This makes our lexer line in the parser a little different.
%lexer {lexwrap} {Eof}
(As a side note, this is the reason that you need to write alexEOF = return Eof
yourself. The data constructor you return inside alexEOF
needs to pattern-match against the data constructor you identify to Happy as the one that ends the file. Alex has no way of knowing what you want to emit, and Happy has no way of knowing what you chose to emit via Alex.)
Now the next problem is that your parseError's type is incorrect. When using just a monad, that is indeed the type you need, but when you add a lexer into the mix, your parseError must have a different type. Also, using fail is probably not advised, so here is a slightly better definition:
parseError :: Token -> Alex a
parseError _ = alexError "Why is using happy and alex so hard"
Finally, the main function is definied a little strange here. what we want to do to call the parser is to invoke it with runAlex. So here is a quick wrapper for it. The string passed in is the string that you wish to parse.
parse :: String -> Either String [Section]
parse s = runAlex s parseIniFile
The type of the function parse is determined by the parseIniFile's definition. Here, it is an Alex [Section]
so an Either String [Section]
is returned.
I think that's everything.