f# - FParsec failing on many -
i have test program:
open fparsec let test p str = match run p str | success(result, _, _) -> printfn "success: %a" result | failure(errormsg, _, _) -> printfn "failure: %s" errormsg let str s = pstring s let seppart = skipnewline >>. pstring "-" let part = manychars (notfollowedby seppart >>. anychar) [<entrypoint>] let main argv = let s = "aa 12345\nbb 6789\n-----\ncc 9876\ndd 54321\n-----" test part s test (many part) s 0 // return integer exit code
the line {test part s} works expected next line, {test (many part) s} fails , don't understand doing wrong.
edit:
to clarify, trying have {test (many part) s} return ["aa 12345\nbb 6789"; "cc 9876\ndd 54321"]. in words, have input string composed of "pars" or "chunks" separated lines dashes. output want array each element 1 of parts , lines dashes discarded.
when execute example, fparsec throws exception following message:
additional information: (ln: 2, col: 8): combinator 'many' applied parser succeeds without consuming input , without changing parser state in other way. (if no exception had been raised, combinator have entered infinite loop.)
the problem part
parser succeeds, if can parse empty string. can solve problem replacing manychars
in definition of part
many1chars
.
if search e.g. "applied parser succeeds without consuming input" you'll find several discussions of similar errors on internet, including 1 in fparse's user guide: http://www.quanttec.com/fparsec/users-guide/parsing-sequences.html#the-many-parser
update: here's straightforward parser definition works:
let seppart = skipnewline >>? (skipmany1satisfyl ((=) '-') "'-'" >>. (skipnewline <|> eof)) let part = many1charstill anychar seppart let parser = many part
note i'm using >>?
in definition of seppart
allow parser backtrack beginning if newline not followed dash. alternatively use attempt (skipnewline >>. ...)
, backtrack errors after initial dash. documentation many[chars]till p endp
states equivalence many (notfollowedby endp >>. p) .>> endp
not strictly true, because many[chars]till
not backtrack notfollowedby
. clarify documentation.
it's better performance if avoid backtracking using many[chars]till
or notfollowedby
possible. example, parse chunks of lines follows:
let id = manyminmaxsatisfyl 2 2 isupper "id (two capital letters)" let line = id .>>. (pchar ' ' >>. restofline true) let separator = many1satisfyl ((=) '-') "dash separator" >>. (skipnewline <|> eof) let chunk = many1 line let parser = sependby1 chunk separator
note implementation doesn't require last chunk ended separator. if want that, instead use:
let chunk = many line .>> separator let parser = many chunk
if want allow empty chunks sependby
definition, use:
let chunk = many1 line <|> (notfollowedbyeof >>% []) let parser = sependby1 chunk separator
Comments
Post a Comment