From 7301cd6c4e97b272bd708d4c87d26609510e6ca7 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sat, 25 Feb 2023 17:12:39 -0700 Subject: jsonparse: Define an InvalidCharacterError type instead of using fmt.Errorf --- internal/jsonparse/parse.go | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/internal/jsonparse/parse.go b/internal/jsonparse/parse.go index c641f1b..214e3ba 100644 --- a/internal/jsonparse/parse.go +++ b/internal/jsonparse/parse.go @@ -14,6 +14,15 @@ import ( var ErrParserExceededMaxDepth = errors.New("exceeded max depth") +type InvalidCharacterError struct { + Char rune + Where string +} + +func (e *InvalidCharacterError) Error() string { + return fmt.Sprintf("invalid character %q %s", e.Char, e.Where) +} + func isHex(c rune) bool { return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || @@ -571,7 +580,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { if len(par.barriers) > 0 { return RuneTypeEOF, nil } else { - return RuneTypeError, fmt.Errorf("invalid character %q after top-level value", c) + return RuneTypeError, &InvalidCharacterError{c, "after top-level value"} } } switch par.stack[len(par.stack)-1] { @@ -605,7 +614,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { case 'n': return par.replaceState(RuneTypeNullN), nil default: - return RuneTypeError, fmt.Errorf("invalid character %q looking for beginning of value", c) + return RuneTypeError, &InvalidCharacterError{c, "looking for beginning of value"} } // object ////////////////////////////////////////////////////////////////////////////////// case RuneTypeObjectBeg: // waiting for key to start or '}' @@ -619,7 +628,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { par.popState() return RuneTypeObjectEnd, nil default: - return RuneTypeError, fmt.Errorf("invalid character %q looking for beginning of object key string", c) + return RuneTypeError, &InvalidCharacterError{c, "looking for beginning of object key string"} } case RuneTypeStringEnd: // waiting for ':' switch c { @@ -630,7 +639,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { par.pushState(runeTypeAny) return RuneTypeObjectColon, nil default: - return RuneTypeError, fmt.Errorf("invalid character %q after object key", c) + return RuneTypeError, &InvalidCharacterError{c, "after object key"} } case RuneTypeObjectComma: // waiting for ',' or '}' switch c { @@ -643,7 +652,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { par.popState() return RuneTypeObjectEnd, nil default: - return RuneTypeError, fmt.Errorf("invalid character %q after object key:value pair", c) + return RuneTypeError, &InvalidCharacterError{c, "after object key:value pair"} } // array /////////////////////////////////////////////////////////////////////////////////// case RuneTypeArrayBeg: // waiting for item to start or ']' @@ -669,7 +678,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { par.popState() return RuneTypeArrayEnd, nil default: - return RuneTypeError, fmt.Errorf("invalid character %q after array element", c) + return RuneTypeError, &InvalidCharacterError{c, "after array element"} } // string ////////////////////////////////////////////////////////////////////////////////// case RuneTypeStringBeg: // waiting for char or '"' @@ -682,7 +691,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { case 0x0020 <= c && c <= 0x10FFFF: return RuneTypeStringChar, nil default: - return RuneTypeError, fmt.Errorf("invalid character %q in string literal", c) + return RuneTypeError, &InvalidCharacterError{c, "in string literal"} } case RuneTypeStringEsc: // waiting for escape char switch c { @@ -692,7 +701,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { case 'u': return par.replaceState(RuneTypeStringEscU), nil default: - return RuneTypeError, fmt.Errorf("invalid character %q in string escape code", c) + return RuneTypeError, &InvalidCharacterError{c, "in string escape code"} } case RuneTypeStringEscU: if !isHex(c) { @@ -762,7 +771,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { case '1', '2', '3', '4', '5', '6', '7', '8', '9': return par.replaceState(RuneTypeNumberIntDig), nil default: - return RuneTypeError, fmt.Errorf("invalid character %q in numeric literal", c) + return RuneTypeError, &InvalidCharacterError{c, "in numeric literal"} } case RuneTypeNumberIntZero: // C switch c { @@ -791,7 +800,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return par.replaceState(RuneTypeNumberFracDig), nil default: - return RuneTypeError, fmt.Errorf("invalid character %q after decimal point in numeric literal", c) + return RuneTypeError, &InvalidCharacterError{c, "after decimal point in numeric literal"} } case RuneTypeNumberFracDig: // F switch c { @@ -810,14 +819,14 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return par.replaceState(RuneTypeNumberExpDig), nil default: - return RuneTypeError, fmt.Errorf("invalid character %q in exponent of numeric literal", c) + return RuneTypeError, &InvalidCharacterError{c, "in exponent of numeric literal"} } case RuneTypeNumberExpSign: // H switch c { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': return par.replaceState(RuneTypeNumberExpDig), nil default: - return RuneTypeError, fmt.Errorf("invalid character %q in exponent of numeric literal", c) + return RuneTypeError, &InvalidCharacterError{c, "in exponent of numeric literal"} } case RuneTypeNumberExpDig: // I switch c { @@ -858,7 +867,7 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { func (par *Parser) expectRune(c, exp rune, typ RuneType, context string, pop bool) (RuneType, error) { if c != exp { - return RuneTypeError, fmt.Errorf("invalid character %q in literal %s (expecting %q)", c, context, exp) + return RuneTypeError, &InvalidCharacterError{c, fmt.Sprintf("in literal %s (expecting %q)", context, exp)} } if pop { par.popState() -- cgit v1.1-4-g5e80