0

I'm trying to write a parser which can parse key value pairs which can vary on the value data type.

KEY1:1,2,3

KEY2:abc

KEY3:123

With the following code

open FParsec
type UserState = unit
type Parser<'t> = Parser<'t,UserState>

let str s = pstring s 
let str_ws s = str s .>> spaces
let stringLiteral : Parser<_> = manyChars (noneOf "\">")

let numList : Parser<_> = sepBy1 (pint32) (str ",")  

let parseHeader inner header = str header >>. str ":" >>. inner
let parseKvps = 
    let strHeader header =  parseHeader stringLiteral header .>> newline  
    let numListHeader header = parseHeader numList header .>> newline 
    let numHeader header = parseHeader pint32 header .>> newline 

    let rest = parse {
        let! key1 = numListHeader "KEY1"
        let! key2 = strHeader "KEY2"
        let! key3 = numHeader "KEY3"
        return key1,key2,key3
    }
    rest

let kvps = "KEY1:1,2,3\nKEY2:abc\nKEY3:123"
run parseKvps kvps

Above gives the following error:

val it : ParserResult<(int32 list * string * int32),unit> =
  Failure:
Error in Ln: 3 Col: 9
KEY3:123
        ^
Note: The error occurred at the end of the input stream.
Expecting: any char not in ‘">’ or newline

I think this has something to do with the numList parser because taking the first key out works as expected.

Appreciate any help! Thanks in advance!

jub0bs
  • 60,866
  • 25
  • 183
  • 186
Pavel
  • 652
  • 7
  • 12

1 Answers1

0

The third parser fails because FParsec did not find a required \n at the end.

There are several options to fix the problem:

  1. Make your data valid by adding \n to the stream:

    let kvps = "KEY1:1,2,3\nKEY2:abc\nKEY3:123\n"
    

    Downside: modifying a source stream is only good for testing, not for the real app.

  2. Make .>> newline optional:

    .>> (optional newline)
    

    Downside: It may lead to errors when two keys at the same source line are attempted to parse.

  3. Try using eof as a possible alternative to newline


Also, a side note. Your code seems to be very hard to support. Think what happens if the keys occur in a wrong order in the source string, or a new key needs to be added over the course of your app development.

Check this and this answers for more details.

Community
  • 1
  • 1
Be Brave Be Like Ukraine
  • 7,596
  • 3
  • 42
  • 66
  • adding the `\n` doesn't work unfortunately. I've tried that and keep getting the same error. It works fine if I remove the first key `KEY1`, something to do with the int list parser my guess. Just not sure how to figure it out. – Pavel Aug 28 '15 at 02:02
  • @Pavel, your `stringLiteral` is also written inaccurately as it overflows the end of line. Did you mean `(restOfLine false)` instead? – Be Brave Be Like Ukraine Aug 28 '15 at 05:50