summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@datawire.io>2022-08-15 21:25:06 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-16 00:05:37 -0600
commit67b78f25f76b8ca43d837fb8055ca8e2b06c7d02 (patch)
tree517343e316a24cb2f07b16d23ccbf04570f4ce7c
parent6476b9ae7019bedd9324786ff47bc25693e01b60 (diff)
Get borrowed_scanner_test.go passing [ci-skip]
-rw-r--r--compat/json/compat.go18
-rw-r--r--errors.go13
-rw-r--r--misc.go55
-rw-r--r--reencode.go9
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
}
diff --git a/errors.go b/errors.go
index cee82f7..2d8820e 100644
--- a/errors.go
+++ b/errors.go
@@ -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)
+}
diff --git a/misc.go b/misc.go
index 4d8b136..ad69d91 100644
--- a/misc.go
+++ b/misc.go
@@ -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 {