Writing my own XML parser to learn FParsec I need to test that the XML start and end tags match or have the parser fail.
In the code fragment below ...
- The parsers
xStartTagandxKeyreturnstrings which I want to match. - The parser
xContent_UntilCloseTagjust returns whatever is between the tags. wsskips whitespace andstr(">")skips a '>'.- The
PipeN.pipe10function is an extension of the standard FParsec primitivepipe5to feed the result of 10 parsers into a function.
All these parsers compile and work.
How can I get the following parser of type Parser<XELEMENT, USER_STATE> constructing the type XELEMENT_CONTENT to fail when the start and end tags do not match?
00 let xElement_Content : Parser<XELEMENT, USER_STATE> =
01 (PipeN.pipe10 ws xStartTag ws xContent_UntilCloseTag ws xKey ws (str ">") ws
02 (fun stream -> getUserState stream)
03 (fun x1 x2_startTag x3 x4_content x5 x6_closeTag x7 x8 x9 userState ->
04 if x2_startTag.head = x6_closeTag
05 then
06 (userState.Deeper(x2_startTag.head), x2_startTag, x4_content)
07 else Reply(FatalError, messageError ("in xElementContent: head tag (%s) does not match close tag (%s)", x2_startTag.head, x6_closeTag))
08 ) |>> C_XELEMENT_CONTENT
09 )
Line 07 throws the compiler error ...
FS0001: All branches of an 'if' expreession must return values of the same type as the first branch which here is 'USER_STATE * XHEADandATTRIBUTES_RECORD * string'. This branch returns a value of the type 'Reply<`a>'.
The code compiles fine if I comment out the if-then-else statement (lines 04, 05, and 07) leaving 06. Types agree in that case. I think I understand that.
But I need to throw an error and have the parser fail when the strings returned from xStartTag and xKey don't agree - How?
I don't think knowing the types is necessary for the answer; but just in case here are the various type definitions...
type USER_STATE =
{
tag : string
depth : int
}
type XELEMENT_CONTENT = USER_STATE * XHEADandATTRIBUTES_RECORD * string
type XELEMENT_EMPTY = XHEADandATTRIBUTES_RECORD
type XELEMENT =
| C_XELEMENT_CONTENT of XELEMENT_CONTENT
| C_XELEMENT_NESTED of USER_STATE * XHEADandATTRIBUTES_RECORD * (XELEMENT list)
| C_XELEMENT_EMPTY of XELEMENT_EMPTY
type XELEMENT_NESTED = XHEADandATTRIBUTES_RECORD * (XELEMENT list)
I have reviewed the FParsec documentation in detail (especially the User's Guide on 'Parsing with User State') but maybe I missed something?