I'm just getting started with FParsec and can't wrap my head around a simple list parser. Given the input
"{
a;b;c
d;
}"
I want to get the result ['a';'b';'c';'d']
If I do
let baseChars = ['0'..'9'] @ ['A'..'Z'] @ ['a'..'z'] @ ['_'; '-']
let chars : Parser<_> = anyOf baseChars
let nameChars : Parser<_> = anyOf (baseChars @ ['.'])
let semiColonList p : Parser<_> = sepBy p (pstring ";")
let pList p : Parser<_> = between (pstring "{") (pstring "}") (semiColonList p)
do """{
a;b;c;
d;
}"""
|> run (parse {
let! data = pList (spaces >>. many1Chars nameChars)
return data
})
|> printfn "%A"
I get a failure on the last } as it's trying to match that on the nameChars parser before closing the between parser. This feels like there is a simple solution that I'm missing, especially since if I delete the last semi-colon after d all works as expected. Any help appreciated.
[edit] Thanks to Fyodor Soikin the following works:
let semiColonList p = many (p .>> (pstring ";" >>. spaces))
let pList p : Parser<_> = between (pstring "{") (pstring "}") (semiColonList p)
"""{
a;b;c;
d;
}"""
|> run (parse {
let! data = pList (spaces >>. many1Chars nameChars)
return data
})
|> printfn "%A"
sepBydoesn't admit a trailing separator. Trymanyinstead. - Fyodor Soikinmany notSemiColonas that will backtrack and then expect the closing } after the first match (a) - Dylanmanyof that parser. - Fyodor SoikinsemiColonList p = many (p .>> pstring ";")- Fyodor SoikinsepBydoesn't allow a trailing separator. BUT there's alsosepEndBywhich allows an optional trailing separator. That might be better for your needs. See quanttec.com/fparsec/reference/primitives.html#members.sepEndBy for details. - rmunn