Implement choice parser
This commit is contained in:
41
src/test.nim
41
src/test.nim
@@ -24,6 +24,7 @@ type
|
|||||||
tokens: seq[Token]
|
tokens: seq[Token]
|
||||||
|
|
||||||
ParseErrorKind = enum
|
ParseErrorKind = enum
|
||||||
|
choiceMismatchErr
|
||||||
charMismatchErr
|
charMismatchErr
|
||||||
endOfStringErr
|
endOfStringErr
|
||||||
ParserError = ref object
|
ParserError = ref object
|
||||||
@@ -96,6 +97,13 @@ proc `$`*(x: ParserError): string =
|
|||||||
|
|
||||||
&"""Parsing Error (Character Mismatch Error):
|
&"""Parsing Error (Character Mismatch Error):
|
||||||
{original}
|
{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}'"""
|
{errSpace}^ Expected '{expected}' but got '{unexpected}'"""
|
||||||
else: "ParseError"
|
else: "ParseError"
|
||||||
|
|
||||||
@@ -204,6 +212,33 @@ func manyUntil(acceptFn: Parser -> ParserResult, stopFn: Parser -> ParserResult)
|
|||||||
func anyUntil(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
func anyUntil(stopFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
|
||||||
manyUntil(ch(AllChars), stopFn)
|
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 =
|
proc parseSeq(parser: ParserResult, xs: seq[Parser -> ParserResult]): ParserResult =
|
||||||
xs.foldl(a.flatMap(b), parser)
|
xs.foldl(a.flatMap(b), parser)
|
||||||
|
|
||||||
@@ -240,10 +275,8 @@ when isMainModule:
|
|||||||
# xs => xs.foldl(a & b.value, "")
|
# xs => xs.foldl(a & b.value, "")
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
echo initParser("BB").parseSeq(@[
|
||||||
|
choice(@[ch(Digits), ch('B')]),
|
||||||
echo initParser("_FOO___BAR").parseSeq(@[
|
|
||||||
anyUntil(endOfStream),
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user