I have a parser that seems straightforward enough. I added this subparator to the end to give information about common parsing errors, since all the other subparallels failed -
let readError =
parse {
let! restOfLineStr = restOfLine true
return makeViolation ("Read error on: " + restOfLineStr + ".") }
do readExprRef :=
choice
[attempt readBoolean
attempt readCharacter
attempt readString
attempt readInt
attempt readError]
However, as soon as I add readError as a choice, I get a terrible FParsec error about thread consumption at runtime - The combinator 'many' was applied to a parser that succeeds without consuming input and without changing the parser state in any other way.I don’t understand why I get this, since I use the remainder of the string to be analyzed to create the structure of the error used (here “violation”) .
Can someone help me figure this out? Am I not mistaken for parser signaling errors for the user? If not, how can I fix this?
!
* *
, -
type Expr =
| Violation of Expr
| Boolean of bool
| Character of char
| String of string
| Int of int
let makeViolation str = Violation (String str)
let spaceAsStr = anyOf whitespaceChars |>> fun chr -> string chr
let lineComment = pchar lineCommentChar >>. restOfLine true
let multilineComment =
between
(pstring openMultilineCommentStr)
(pstring closeMultilineCommentStr)
(charsTillString closeMultilineCommentStr false System.Int32.MaxValue)
let whitespace = lineComment <|> multilineComment <|> spaceAsStr
let skipWhitespace = skipMany whitespace
let skipWhitespace1 = skipMany1 whitespace
let readBoolean =
parse {
do! skipWhitespace
let! booleanValue = readStr trueStr <|> readStr falseStr
return Boolean (booleanValue = trueStr) }
let readCharacter =
parse {
do! skipWhitespace
let! chr = between skipSingleQuote skipSingleQuote (manyChars (noneOf "\'"))
return Character chr.[0] }
let readString =
parse {
do! skipWhitespace
let! str = between skipDoubleQuote skipDoubleQuote (manyChars (noneOf "\""))
return String str }
let readInt =
parse {
do! skipWhitespace
let! value = pint32
let! _ = opt (skipString intSuffixStr)
do! notFollowedByLetterOrNameChar
do! notFollowedByDot
return Int value }
. , , , readError. restOfLine , ?
* *
, readError . " ", , -
let readEndOfInput = skipWhitespace >>. eof
let readExprs = many readExpr
let readExprsTillEnd = readExprs .>> readEndOfInput
readExprsTillEnd, exprs .
, !