Assume I’ve this parser:
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
let myStatement =
choice (seq [
pchar '2' >>. pchar '+' .>> pchar '3' .>> pchar ';';
pchar '3' >>. pchar '*' .>> pchar '4' .>> pchar ';';
])
let myProgram = many myStatement
test myProgram "2+3;3*4;3*4;" // Success: ['+'; '*'; '*']
Now, "2+3;2*4;3*4;3+3;" will fail with error around 2*4;. But what is best practice if I want both the error for 2*4; and 3+3;? Basically, I want to scan to the nearest ‘;’ but only if there is a fatal error. And if that happens I want to aggregate the errors.
Kind regards, Lasse Espeholt
Update: recoverWith is a nice solution, thanks! But given:
let myProgram =
(many1 (myStatement |> recoverWith '�')) <|>% []
test myProgram "monkey"
I would expect to get [] with no errors. Or maybe a bit more “fair”:
let myProgram =
(attempt (many1 (myStatement |> recoverWith '�'))) <|>% []
FParsec has no built-in support for recovering from fatal parser errors that would allow you to obtain partial parser results and collect errors from multiple positions. However, it’s pretty easy to define a custom combinator function for this purpose.
For example, to recover from errors in your simple statement parser you could define the following
recoverWithcombinator:You could then use this combinator as follows:
Testing with
test myProgram "2+3;2*4;3*4;3+3"would yield the output:Result with errors: ['+'; '�'; '*'; '�'] Error in Ln: 1 Col: 6 2+3;2*4;3*4;3+3 ^ Expecting: '+' Error in Ln: 1 Col: 14 2+3;2*4;3*4;3+3 ^ Expecting: '*'Update:
Hmm, I thought you wanted to recover from a fatal error in order to collect multiple error messages and maybe produce a partial result. Something that would for example be useful for syntax highlighting or allowing your users to fix more than one error at a time.
Your update seems to suggest that you just want to ignore parts of the input in case of a parser error, which is much simpler:
Update 2:
The following is a version of
recoverWiththat doesn’t aggregate errors and only tries to recover from an error if the argument parser consumed input (or changed the parser state in any other way):