I'm trying to parse fixed strings with FParsec. For example parsing null
from the documentation:
open FParsec
type Json = JNull
let jnull : Parser<_> = stringReturn "null" JNull
then running jnull
on "null"
gives the expected result
> run jnull "null";;
val it : ParserResult<Json,unit> = Success: JNull
But if I run it on "nulls"
it also succeeds
> run jnull "nulls";;
val it : ParserResult<Json,unit> = Success: JNull
Then I tried to add the requirement that null
should be followed by a space:
let jnull : Parser<_> = stringReturn "null" JNull >>. spaces
However, this gives me the same result as before.
I also tried to use manyMinMaxSatisfyL
:
let jnull: Parser<_> =
manyMinMaxSatisfyL 4 4 isLower "should be null"
>>. pstring "null"
>>. spaces
This one fails on "nulls"
as it should, but is also fails on "null"
:
> run jnull "nulls";;
val it : ParserResult<unit,unit> =
Failure:
Error in Ln: 1 Col: 5
nulls
^
Expecting: 'null'
> run jnull "null";;
val it : ParserResult<unit,unit> =
Failure:
Error in Ln: 1 Col: 5
null
^
Note: The error occurred at the end of the input stream.
Expecting: 'null'
What am I doing wrong here? Or did I completely misunderstand something about parsing?
In general, parsers always consume some input, produce a result and leave the rest of the input for later processing. This makes it possible to compose them, but it means that it's tricky to write a parser that consumes the whole input.
One way to do what you want is to use notFollowedBy anyChar
like this:
let jnull : Parser<_,unit> =
(stringReturn "null" JNull) >>. notFollowedBy anyChar
run jnull "null" // Success
run jnull "nulls" // Error
The notFollowedBy
parser succeeds if the rest of the input cannot be parsed using the parser given as argument. Here, this means that notFollowedBy anyChar
succeeds only if the rest cannot be parsed using anyChar
, i.e. it is empty.