Pretty print errors

This commit is contained in:
Florian Schroedl
2022-01-20 17:00:00 +01:00
parent dae845d57f
commit d4266b53ed

View File

@@ -11,11 +11,6 @@ import print
{.experimental: "caseStmtMacros".}
type
ParseError = tuple
unexpected: string
expected: seq[string]
state: ParserState
message: string
ParserState* = ref object
stream: string
@@ -27,13 +22,25 @@ type
Parser* = ref object
state: ParserState
tokens: seq[Token]
ParserResult* = Result[Parser, (Parser, string)]
ParseErrorKind = enum
charMismatchErr
endOfStringErr
ParserError = ref object
kind: ParseErrorKind
unexpected: char
expected: char
index: int
parser: Parser
ParserResult* = Result[Parser, ParserError]
# Builder[T]* = ref object
# parser: ParserResult,
# tree: seq[T],
# BuilderResult* = Result[Builder, (Builder, string)]
# func prettyPrintError*(err: ParserErrror,)
func getOrElse*[T, E](self: Result[T, E], otherwise: T): T =
if self.isOk():
self.v
@@ -63,6 +70,18 @@ proc `$`*(x: Parser): string =
tokens: {indentKey($x.tokens, 2)},
)"""
proc `$`*(x: ParserError): string =
case x:
of charMismatchErr(expected: @expected, parser: @parser, index: @index, unexpected: @unexpected):
# TODO: Only works for single line right now
let original = parser.state.stream
let errSpace = " ".repeat(index - 1)
&"""Parsing Error (Character Mismatch Error):
{original}
{errSpace}^ Wanted '{unexpected}' but got '{expected}'"""
else: "ParseError"
proc initParser(str: string): ParserResult =
Parser(
state: ParserState(
@@ -79,10 +98,14 @@ func ch(c1: char): (Parser -> ParserResult) {.inline.} =
let newIndex = state.position + 1
if newIndex > (state.stream.len - 1):
return err((parser, &"Expected {c1} at {newIndex}, got End of string"))
return err(ParserError(
kind: endOfStringErr,
expected: c1,
index: newIndex,
parser: parser,
))
else:
let c2 = state.stream[newIndex]
if c1 == c2:
return Parser(
state: ParserState(
@@ -93,7 +116,13 @@ func ch(c1: char): (Parser -> ParserResult) {.inline.} =
tokens: parser.tokens & Token(value: c2)
).ok()
else:
return err((parser, &"Expected {c2} at {newIndex}, got {c1}"))
return err(ParserError(
kind: charMismatchErr,
unexpected: c2,
expected: c1,
index: newIndex,
parser: parser,
))
func ignore(parserFn: Parser -> ParserResult): (Parser -> ParserResult) {.inline.} =
## Parse characters but throw success tokens away
@@ -126,14 +155,14 @@ func str(s: string): (Parser -> ParserResult) {.inline.} =
proc foldTokens[T](
parserResult: ParserResult,
onError: T,
onError: ParserError -> T,
onSuccess: seq[Token] -> T,
): T =
if parserResult.isOk():
onSuccess(parserResult.unsafeGet().tokens)
else:
onError
# onError(parserResult.error)
let err = parserResult.error()
onError(err)
when isMainModule:
let fooParser = initParser("FOO_BAR")
@@ -141,11 +170,12 @@ when isMainModule:
str("FOO"),
ignore(ch('_')),
ch('B'),
ch('B'),
ch('A'),
ch('R'),
])
.foldTokens(
"Error",
err => $err,
xs => xs.foldl(a & b.value, "")
)