parsingf#fparsec

FParsec failing at the end of a spaces separated list, expecting another element of the list


I am trying to use FParsec to parse a list of zero or more elements of the form [string] where the string in the middle can be anything (except ] as to disambiguate from the end of the string). Here is my code as is:

let parseArgumentList : Parser<string list, unit> =
    let parseArgument = (skipChar '[') >>. (manySatisfy (fun x -> x <> ']')) .>> (skipChar ']')
    sepBy (parseArgument) (spaces)


[<EntryPoint>]
let main argv =
    let parserResult = run parseArgumentList "[testString] [testString]"

    printfn "%A" parserResult
    0

The output here is:

Failure:
Error in Ln: 1 Col: 26
[testString] [testString]
                         ^
Note: The error occurred at the end of the input stream.
Expecting: '['

It is as if the parser is expecting another set of parenthesis rather than terminating at 2 occurances in sepBy. I tested this by changing the spaces to (skipChar ' ') >>. spaces and sure enough it parses fine. I am however unwilling to remove the option of no spaces between arguments. Any ideas or advice would be greatly appreciated.


Solution

  • I think using sepEndBy instead of sepBy will do what you want:

    let parseArgumentList =
        sepEndBy parseArgument spaces
    

    From the FParser doc: The parser sepEndBy p sep parses zero or more occurrences of p separated and optionally ended by sep. (Emphasis added.)

    Running this on your test input produces the expected result:

    Success: ["testString"; "testString"]
    

    Note that this solution also has the nice side-benefit of consuming trailing spaces, if there are any. E.g. When the input is "[testString] [testString] ".