sdgfsdh
sdgfsdh

Reputation: 37045

Why are these two FParsec snippets different?

I want to parse a given char twice, but return a string of that character only once.

For example:

aa    ->    a

I have some code that works, but also some code that does not work, and I don't understand why.

Why are these snippets different?

// Works
let parseEscapedQuote (c : char)  =
  let q = string c
  pstring (q + q) >>% q
// Does not work
let parseEscapedQuote (c : char)  =
  let q = string c
  pchar c >>. pchar c >>% q

Upvotes: 1

Views: 48

Answers (1)

Brian Berns
Brian Berns

Reputation: 17038

The second one will successfully parse a repeated character the way you want, but it might not fail the way you expect. If only the first pchar c succeeds, it will leave your parser in an invalid state. To fix this, you can use attempt, which restores the prior state if it fails:

attempt (pchar c >>. pchar c) >>% q

Here's a complete example that illustrates the difference:

open FParsec

let parseTwiceBad (c : char) =
    pchar c >>. pchar c >>% string c

let parseTwiceGood (c : char) =
    attempt (pchar c >>. pchar c) >>% string c

let mkParser parseTwice =
    choice [
        parseTwice 'x'
        anyString 3
    ]

let run parser str =
    let result = runParserOnString parser () "" str
    match result with
        | Success (value, _, _) -> printfn "Success: %A" value
        | Failure (msg, _, _) -> printfn "Failure: %s" msg

let test str =

    printfn ""
    printfn "Parsing \"%s\" with bad parser:" str
    let parser = mkParser parseTwiceBad
    run parser str

    printfn "Parsing \"%s\" with good parser:" str
    let parser = mkParser parseTwiceGood
    run parser str

[<EntryPoint>]
let main argv =
    test "xx"
    test "xAx"
    0

Output:

Parsing "xx" with bad parser:
Success: "x"
Parsing "xx" with good parser:
Success: "x"

Parsing "xAx" with bad parser:
Failure: Error in Ln: 1 Col: 2
xAx
 ^
Expecting: 'x'

Parsing "xAx" with good parser:
Success: "xAx"

Upvotes: 2

Related Questions