I'm writing an FParsec parser for strings in this form:
do[ n times]([ action] | \n([action]\n)*endDo)
in other words this is a "do" statement with an optional time quantifier, and either a single "action" statement or a list of "action"s (each on a new line) with an "end do" at the end (I omitted indentations/trailing space handling for simplicity).
These are examples of valid inputs:
do action
do 3 times action
do
endDo
do 3 times
endDo
do
action
action
endDo
do 3 times
action
action
endDo
This does not look very complicated, but:
Why does this not work?
let statement = pstring "action"
let beginDo = pstring "do"
>>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")
let inlineDo = tuple2 beginDo (spaces >>. statement |>> fun w -> [w])
let expandedDo = (tuple2 (beginDo .>> newline)
(many (statement .>> newline)))
.>> pstring "endDo"
let doExpression = (expandedDo <|> inlineDo)
What is a correct parser for this expression?
You need to use the attempt
function.
I just modified your beginDo
and doExpression
functions.
This is the code:
let statement o=o|> pstring "action"
let beginDo o=
attempt (pstring "do"
>>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")) <|>
(pstring "do" >>% None) <|o
let inlineDo o= tuple2 beginDo (spaces >>. statement |>> fun w -> [w]) <|o
let expandedDo o= (tuple2 (beginDo .>> newline) (many (statement .>> newline)))
.>> pstring "endDo" <|o
let doExpression o= ((attempt expandedDo) <|> inlineDo) .>> eof <|o
I added an eof
at the end. This way it will be easier to test.
I added also dummy o
parameters to avoid the value restriction.