Pretty print errors
This commit is contained in:
56
src/test.nim
56
src/test.nim
@@ -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, "")
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user