From d4266b53ed53f59ddf37645813bdc53a56344bbc Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 20 Jan 2022 17:00:00 +0100 Subject: [PATCH] Pretty print errors --- src/test.nim | 56 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/test.nim b/src/test.nim index 7b59e01..d8934bb 100644 --- a/src/test.nim +++ b/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, "") )