Workarounds for a bug in
Parser
.
The Elm Parser internally keeps track of the current position in two ways:
See the Positions chapter in the Parser documentation for more details.
Normally both kinds of position infos (row and column vs. offset) are in sync with each other. (For a given source string, you can calculate both row and column from the offset and vice versa.)
There's a bug in the Parser code though.
The following parsers break this synchronicity:
lineComment
,
multiComment
,
chompUntil
, and
chompUntilEndOr
.
They set...
Here's an example with chompUntil
:
import Parser exposing ((|.), (|=), Parser)
testParser : Parser { row : Int, col : Int, offset : Int }
testParser =
Parser.succeed (\row col offset -> { row = row, col = col, offset = offset })
|. Parser.chompUntil "token"
|= Parser.getRow
|= Parser.getCol
|= Parser.getOffset
Parser.run testParser "< token >"
--> Ok { row = 1, col = 8, offset = 2 }
The state after the test parser is run:
As a workaround, this package offers xxxBefore
and xxxAfter
parsers which consistently position
both row/column and offset either before or after the (closing) token.
lineCommentBefore
and lineCommentAfter
multiCommentBefore
and multiCommentAfter
chompUntilBefore
and chompUntilAfter
chompUntilEndOrBefore
and chompUntilEndOrAfter
Why are there two different workarounds for each buggy parser?
On the one hand, if you already have working parsers and don't use the row or column information,
then you can replace them with the xxxBefore
variants and they will continue to work.
(There's one exception for the multiComment
parser though, see below.)
On the other hand, most often the xxxAfter
variants are easier to use,
because you don't need to chomp the (closing) token yourself.
So if you write new parsers, you'll likely want to use the xxxAfter
variants.
Plus, if the bug will be fixed, it can be assumed that the
fixed parsers will work like the xxxAfter
variants.
(If you want to know why, you can look at the description of
this pull request.)
If you are unsure whether to use the xxxBefore
or the xxxAfter
parsers
or whether to use the workarounds at all, you could follow these guidelines:
xxxBefore
workarounds.
Then you don't have to change your existing parsers,
but the workarounds maintain an internally consistent state.
This makes it easier to combine them with other parsers later.
(There's one exception for the multiComment
parser though, see below.)xxxAfter
workarounds, because often they are easier to use
and because they implement the intended behavior.
You'll have to modify the surrounding parsers, but they don't work anyhow.xxxAfter
workarounds, because often they are easier to use
and because they implement the intended behavior.There's one exception to the rules above: if the
multiComment
parser is used with
Nestable
comments, then it isn't affected from the bug.
(For this mode it's implemented differently.)
Therefore this parser should be replaced with the multiCommentAfter
workaround to keep the current behavior.
lineCommentBefore : String -> Parser ()
Just like Parser.lineComment
except it consistently stops before the linefeed character.
lineCommentAfter : String -> Parser ()
Just like Parser.lineComment
except it consistently stops after the linefeed character.
multiCommentBefore : String -> String -> Parser.Nestable -> Parser ()
Just like Parser.multiComment
except it consistently stops before the last closing string.
multiCommentAfter : String -> String -> Parser.Nestable -> Parser ()
Just like Parser.multiComment
except it consistently stops after the last closing string.
chompUntilBefore : String -> Parser ()
Just like Parser.chompUntil
except it consistently stops before the string.
chompUntilAfter : String -> Parser ()
Just like Parser.chompUntil
except it consistently stops after the string.
chompUntilEndOrBefore : String -> Parser ()
Just like Parser.chompUntilEndOr
except it consistently stops before the string (if it is found).
chompUntilEndOrAfter : String -> Parser ()
Just like Parser.chompUntilEndOr
except it consistently stops after the string (if it is found).