Khanzor
Khanzor

Reputation: 5000

Whitespace sensitive FParsec

I'm trying to implement a whitespace sensitive parser using FParsec, and I'm starting off with the baby step of defining a function which will parse lines of text that start with n chars of whitespace.

Here's what I have so far:

let test: Parser<string list,int>
  = let manyNSatisfy i p = manyMinMaxSatisfy i i p

    let p = fun (stream:CharStream<int>) ->
      let state = stream.UserState

      // Should fail softly if `state` chars wasn't parsed
      let result = attempt <| manyNSatisfy state (System.Char.IsWhiteSpace) <| stream

      if result.Status <> Ok 
        then result
        else restOfLine false <| stream

    sepBy p newline

My issue is that when I run

runParserOnString test 1 "test" " hi\n there\nyou" |> printfn "%A"

I get an error on "you". I was under the impression that attempt would backtrack any state changes, and returning Error as my status would give me soft failure.

How do I get ["hi"; "there"] back from my parser?

Upvotes: 2

Views: 634

Answers (2)

Be Brave Be Like Ukraine
Be Brave Be Like Ukraine

Reputation: 7735

This looks more idiomatic. I have hard-coded 1, but it's easy to extract as parameter.

let skipManyNSatisfy i = skipManyMinMaxSatisfy i i
let pMyText =
    (                                               // 1st rule
        skipManyNSatisfy 1 System.Char.IsWhiteSpace // skip an arbitrary # of WhiteSpaces
        >>. restOfLine false |>> Some               // return the rest as Option
    )
    <|>                                             // If the 1st rule failed...
    (                                               // 2nd rule
        skipRestOfLine false                        // skip till the end of the line
        >>. preturn None                            // no result
    )
    |> sepBy <| newline                             // Wrap both rules, separated by newLine
    |>> Seq.choose id                               // Out of received string option seq, select only Some()

Upvotes: 0

Khanzor
Khanzor

Reputation: 5000

Oh dear, how embarrassing.

I wanted sepEndBy, which is to say that I should terminate the parse on the separator.

Upvotes: 3

Related Questions