Implement choice parser
This commit is contained in:
41
src/test.nim
41
src/test.nim
@@ -24,6 +24,7 @@ type
|
||||
tokens: seq[Token]
|
||||
|
||||
ParseErrorKind = enum
|
||||
choiceMismatchErr
|
||||
charMismatchErr
|
||||
endOfStringErr
|
||||
ParserError = ref object
|
||||
@@ -96,6 +97,13 @@ proc `$`*(x: ParserError): string =
|
||||
|
||||
&"""Parsing Error (Character Mismatch Error):
|
||||
{original}
|
||||
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
|
||||
of choiceMismatchErr(expected: @expected, parser: @parser, index: @index, unexpected: @unexpected):
|
||||
let original = parser.state.stream
|
||||
let errSpace = " ".repeat(max(0, index))
|
||||
|
||||
&"""Parsing Error (Character Mismatch Error):
|
||||
{original}
|
||||
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
|
||||
else: "ParseError"
|
||||
|
||||
@@ -204,6 +212,33 @@ func manyUntil(acceptFn: Parser -> ParserResult, stopFn: Parser -> ParserResult)
|
||||
func anyUntil(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||
manyUntil(ch(AllChars), stopFn)
|
||||
|
||||
func choice(parsers: seq[Parser -> ParserResult]): (Parser -> ParserResult) {.inline.} =
|
||||
return proc(parser: Parser): ParserResult =
|
||||
var errors: seq[ParserResult] = newSeq[ParserResult]()
|
||||
var found = Nothing[ParserResult]()
|
||||
|
||||
for fn in parsers:
|
||||
let fnResult: ParserResult = fn(parser)
|
||||
|
||||
if fnResult.isOk():
|
||||
found = fnResult.just
|
||||
break
|
||||
else:
|
||||
errors = errors & fnResult
|
||||
|
||||
return found
|
||||
.fold(
|
||||
proc(): ParserResult =
|
||||
let prettyErrors = errors.map((x: ParserResult) => x.error().expected)
|
||||
err(ParserError(
|
||||
kind: choiceMismatchErr,
|
||||
expected: &"Choice ({prettyErrors})",
|
||||
unexpected: errors[0].error().unexpected,
|
||||
parser: parser,
|
||||
)),
|
||||
proc(x: ParserResult): ParserResult = x,
|
||||
)
|
||||
|
||||
proc parseSeq(parser: ParserResult, xs: seq[Parser -> ParserResult]): ParserResult =
|
||||
xs.foldl(a.flatMap(b), parser)
|
||||
|
||||
@@ -240,10 +275,8 @@ when isMainModule:
|
||||
# xs => xs.foldl(a & b.value, "")
|
||||
# )
|
||||
|
||||
|
||||
|
||||
echo initParser("_FOO___BAR").parseSeq(@[
|
||||
anyUntil(endOfStream),
|
||||
echo initParser("BB").parseSeq(@[
|
||||
choice(@[ch(Digits), ch('B')]),
|
||||
])
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user