diff options
author | Luke Shumaker <lukeshu@datawire.io> | 2022-08-15 21:25:06 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@datawire.io> | 2022-08-16 00:05:37 -0600 |
commit | 67b78f25f76b8ca43d837fb8055ca8e2b06c7d02 (patch) | |
tree | 517343e316a24cb2f07b16d23ccbf04570f4ce7c | |
parent | 6476b9ae7019bedd9324786ff47bc25693e01b60 (diff) |
Get borrowed_scanner_test.go passing [ci-skip]
-rw-r--r-- | compat/json/compat.go | 18 | ||||
-rw-r--r-- | errors.go | 13 | ||||
-rw-r--r-- | misc.go | 55 | ||||
-rw-r--r-- | reencode.go | 9 |
4 files changed, 66 insertions, 29 deletions
diff --git a/compat/json/compat.go b/compat/json/compat.go index b26914b..04dfb24 100644 --- a/compat/json/compat.go +++ b/compat/json/compat.go @@ -67,8 +67,9 @@ func HTMLEscape(dst *bytes.Buffer, src []byte) { func Compact(dst *bytes.Buffer, src []byte) error { formatter := &lowmemjson.ReEncoder{ - Out: dst, - Compact: true, + Out: dst, + Compact: true, + BackslashEscape: lowmemjson.EscapePreserve, } _, err := formatter.Write(src) return err @@ -76,11 +77,18 @@ func Compact(dst *bytes.Buffer, src []byte) error { func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { formatter := &lowmemjson.ReEncoder{ - Out: dst, - Indent: indent, - Prefix: prefix, + Out: dst, + Indent: indent, + Prefix: prefix, + BackslashEscape: lowmemjson.EscapePreserve, } _, err := formatter.Write(src) + if se, ok := err.(*lowmemjson.ReEncodeSyntaxError); ok { + err = &SyntaxError{ + msg: se.Err.Error(), + Offset: se.Offset + 1, + } + } return err } @@ -137,3 +137,16 @@ func (e *EncodeMethodError) Error() string { } func (e *EncodeMethodError) Unwrap() error { return e.Err } + +// reencode errors ///////////////////////////////////////////////////////////////////////////////// + +// A *ReEncodeSyntaxError is returned from ReEncoder's methods if +// there is a syntax error in the input. +type ReEncodeSyntaxError struct { + Err error + Offset int64 +} + +func (e *ReEncodeSyntaxError) Error() string { + return fmt.Sprintf("json: syntax error at input byte %v: %v", e.Offset, e.Err) +} @@ -107,6 +107,10 @@ func EscapeDefault(c rune, wasEscaped BackslashEscapeMode) BackslashEscapeMode { } } +func EscapePreserve(_ rune, wasEscaped BackslashEscapeMode) BackslashEscapeMode { + return wasEscaped +} + func writeStringUnicodeEscape(w io.Writer, c rune) (int, error) { buf := [6]byte{ '\\', @@ -118,8 +122,25 @@ func writeStringUnicodeEscape(w io.Writer, c rune) (int, error) { } return w.Write(buf[:]) } -func writeStringShortEscape(w io.Writer, c byte) (int, error) { - buf := [2]byte{'\\', c} +func writeStringShortEscape(w io.Writer, c rune) (int, error) { + var b byte + switch c { + case '"', '\\', '/': + b = byte(c) + case '\b': + b = 'b' + case '\f': + b = 'f' + case '\n': + b = 'n' + case '\r': + b = 'r' + case '\t': + b = 't' + default: + panic("should not happen") + } + buf := [2]byte{'\\', b} return w.Write(buf[:]) } func writeStringChar(w io.Writer, c rune, wasEscaped BackslashEscapeMode, escaper func(rune, BackslashEscapeMode) BackslashEscapeMode) (int, error) { @@ -129,38 +150,30 @@ func writeStringChar(w io.Writer, c rune, wasEscaped BackslashEscapeMode, escape switch escaper(c, wasEscaped) { case BackslashEscapeNone: switch { - case c < 0x0020: + case c < 0x0020: // override, gotta escape these switch c { - case '\b': - return writeStringShortEscape(w, 'b') - case '\f': - return writeStringShortEscape(w, 'f') - case '\n': - return writeStringShortEscape(w, 'n') - case '\r': - return writeStringShortEscape(w, 'r') - case '\t': - return writeStringShortEscape(w, 't') + case '\b', '\f', '\n', '\r', '\t': // short-escape if possible + return writeStringShortEscape(w, c) default: return writeStringUnicodeEscape(w, c) } - case c == '"' || c == '\\': - return writeStringShortEscape(w, byte(c)) - default: + case c == '"' || c == '\\': // override, gotta escape these + return writeStringShortEscape(w, c) + default: // obey return writeRune(w, c) } case BackslashEscapeShort: switch c { - case '"', '\\', '/', '\b', '\f', '\n', '\r', '\t': - return writeStringShortEscape(w, byte(c)) - default: + case '"', '\\', '/', '\b', '\f', '\n', '\r', '\t': // obey + return writeStringShortEscape(w, c) + default: // override, can't short-escape these return writeRune(w, c) } case BackslashEscapeUnicode: switch { - case c > 0xFFFF: + case c > 0xFFFF: // override, can't escape these (TODO: unless we use UTF-16 surrogates?) return writeRune(w, c) - default: + default: // obey return writeStringUnicodeEscape(w, c) } default: diff --git a/reencode.go b/reencode.go index 92e870a..bb0dc24 100644 --- a/reencode.go +++ b/reencode.go @@ -79,7 +79,7 @@ func (enc *ReEncoder) Write(p []byte) (int, error) { func (enc *ReEncoder) Close() error { if enc.bufLen > 0 { - return &DecodeSyntaxError{ + return &ReEncodeSyntaxError{ Offset: enc.inputPos, Err: fmt.Errorf("%w: unflushed unicode garbage: %q", io.ErrUnexpectedEOF, enc.buf[:enc.bufLen]), } @@ -111,7 +111,10 @@ func (enc *ReEncoder) WriteRune(c rune) (n int, err error) { } t, err := enc.par.HandleRune(c) if err != nil { - enc.err = err + enc.err = &ReEncodeSyntaxError{ + Err: err, + Offset: enc.inputPos, + } return 0, enc.err } @@ -178,7 +181,7 @@ func (enc *ReEncoder) handleRune(c rune, t RuneType) error { case RuneTypeObjectEnd, RuneTypeArrayEnd: enc.curIndent-- switch enc.lastNonSpace { - case RuneTypeObjectBeg, RuneTypeArrayEnd: + case RuneTypeObjectBeg, RuneTypeArrayBeg: // collapse default: if err := enc.emitNlIndent(); err != nil { |