diff --git a/decode.go b/decode.go index 3208329..2dbb0ee 100644 --- a/decode.go +++ b/decode.go @@ -24,7 +24,7 @@ type Token interface{} type Delim rune type decoder interface { - decode([]byte, int, uintptr) (int, error) + decode([]byte, int64, uintptr) (int64, error) } type Decoder struct { diff --git a/decode_array.go b/decode_array.go index b501ce0..f4e3555 100644 --- a/decode_array.go +++ b/decode_array.go @@ -1,9 +1,5 @@ package json -import ( - "errors" -) - type arrayDecoder struct { elemType *rtype size uintptr @@ -20,8 +16,8 @@ func newArrayDecoder(dec decoder, elemType *rtype, alen int) *arrayDecoder { } } -func (d *arrayDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { - buflen := len(buf) +func (d *arrayDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { + buflen := int64(len(buf)) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -44,10 +40,10 @@ func (d *arrayDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { idx++ continue default: - return 0, errors.New("syntax error array") + return 0, errInvalidCharacter(buf[cursor], "array", cursor) } } } } - return 0, errors.New("unexpected error array") + return 0, errUnexpectedEndOfJSON("array", cursor) } diff --git a/decode_bool.go b/decode_bool.go index 66ccf7d..583bad5 100644 --- a/decode_bool.go +++ b/decode_bool.go @@ -1,7 +1,6 @@ package json import ( - "errors" "unsafe" ) @@ -11,40 +10,40 @@ func newBoolDecoder() *boolDecoder { return &boolDecoder{} } -func (d *boolDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { - buflen := len(buf) +func (d *boolDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { + buflen := int64(len(buf)) cursor = skipWhiteSpace(buf, cursor) switch buf[cursor] { case 't': if cursor+3 >= buflen { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errUnexpectedEndOfJSON("bool(true)", cursor) } if buf[cursor+1] != 'r' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+1], "bool(true)", cursor) } if buf[cursor+2] != 'u' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+2], "bool(true)", cursor) } if buf[cursor+3] != 'e' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+3], "bool(true)", cursor) } cursor += 4 *(*bool)(unsafe.Pointer(p)) = true case 'f': if cursor+4 >= buflen { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errUnexpectedEndOfJSON("bool(false)", cursor) } if buf[cursor+1] != 'a' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+1], "bool(false)", cursor) } if buf[cursor+2] != 'l' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+2], "bool(false)", cursor) } if buf[cursor+3] != 's' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+3], "bool(false)", cursor) } if buf[cursor+4] != 'e' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+4], "bool(false)", cursor) } cursor += 5 *(*bool)(unsafe.Pointer(p)) = false diff --git a/decode_context.go b/decode_context.go index 1bb8f5d..90371c4 100644 --- a/decode_context.go +++ b/decode_context.go @@ -1,9 +1,5 @@ package json -import ( - "errors" -) - var ( isWhiteSpace = [256]bool{} ) @@ -15,7 +11,7 @@ func init() { isWhiteSpace['\r'] = true } -func skipWhiteSpace(buf []byte, cursor int) int { +func skipWhiteSpace(buf []byte, cursor int64) int64 { LOOP: if isWhiteSpace[buf[cursor]] { cursor++ @@ -24,15 +20,15 @@ LOOP: return cursor } -func skipValue(buf []byte, cursor int) (int, error) { +func skipValue(buf []byte, cursor int64) (int64, error) { cursor = skipWhiteSpace(buf, cursor) braceCount := 0 bracketCount := 0 - buflen := len(buf) + buflen := int64(len(buf)) for { switch buf[cursor] { case '\000': - return cursor, errors.New("unexpected error value") + return cursor, errUnexpectedEndOfJSON("value of object", cursor) case '{': braceCount++ case '[': @@ -79,5 +75,5 @@ func skipValue(buf []byte, cursor int) (int, error) { } cursor++ } - return cursor, errors.New("unexpected error value") + return cursor, errUnexpectedEndOfJSON("value of object", cursor) } diff --git a/decode_float.go b/decode_float.go index 1df0fcc..98b3088 100644 --- a/decode_float.go +++ b/decode_float.go @@ -1,7 +1,6 @@ package json import ( - "errors" "strconv" "unsafe" ) @@ -14,8 +13,8 @@ func newFloatDecoder(op func(uintptr, float64)) *floatDecoder { return &floatDecoder{op: op} } -func (d *floatDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { - buflen := len(buf) +func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { + buflen := int64(len(buf)) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -34,10 +33,10 @@ func (d *floatDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { return num, cursor, nil } } - return nil, 0, errors.New("unexpected error number") + return nil, 0, errUnexpectedEndOfJSON("float", cursor) } -func (d *floatDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *floatDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err diff --git a/decode_int.go b/decode_int.go index 6a50e4d..af96458 100644 --- a/decode_int.go +++ b/decode_int.go @@ -1,9 +1,5 @@ package json -import ( - "errors" -) - type intDecoder struct { op func(uintptr, int64) } @@ -53,7 +49,7 @@ var ( } ) -func (d *intDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { +func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { for { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -70,14 +66,13 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { num := buf[start:cursor] return num, cursor, nil default: - goto ERROR + return nil, 0, errInvalidCharacter(buf[cursor], "number(integer)", cursor) } } -ERROR: - return nil, 0, errors.New("unexpected error number") + return nil, 0, errUnexpectedEndOfJSON("number(integer)", cursor) } -func (d *intDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *intDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err diff --git a/decode_interface.go b/decode_interface.go index 91dc699..a0d94b3 100644 --- a/decode_interface.go +++ b/decode_interface.go @@ -1,7 +1,6 @@ package json import ( - "errors" "reflect" "unsafe" ) @@ -21,7 +20,7 @@ var ( ) ) -func (d *interfaceDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *interfaceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { cursor = skipWhiteSpace(buf, cursor) switch buf[cursor] { case '{': @@ -63,62 +62,62 @@ func (d *interfaceDecoder) decode(buf []byte, cursor int, p uintptr) (int, error *(*interface{})(unsafe.Pointer(p)) = *(*string)(unsafe.Pointer(&literal)) return cursor, nil case '\000': - return 0, errors.New("unexpected error string") + return 0, errUnexpectedEndOfJSON("string", cursor) } cursor++ } - return 0, errors.New("unexpected error string") + return 0, errUnexpectedEndOfJSON("string", cursor) case 't': - if cursor+3 >= len(buf) { - return 0, errors.New("unexpected error. invalid bool character") + if cursor+3 >= int64(len(buf)) { + return 0, errUnexpectedEndOfJSON("bool(true)", cursor) } if buf[cursor+1] != 'r' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+1], "bool(true)", cursor) } if buf[cursor+2] != 'u' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+2], "bool(true)", cursor) } if buf[cursor+3] != 'e' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+3], "bool(true)", cursor) } cursor += 4 *(*interface{})(unsafe.Pointer(p)) = true return cursor, nil case 'f': - if cursor+4 >= len(buf) { - return 0, errors.New("unexpected error. invalid bool character") + if cursor+4 >= int64(len(buf)) { + return 0, errUnexpectedEndOfJSON("bool(false)", cursor) } if buf[cursor+1] != 'a' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+1], "bool(false)", cursor) } if buf[cursor+2] != 'l' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+2], "bool(false)", cursor) } if buf[cursor+3] != 's' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+3], "bool(false)", cursor) } if buf[cursor+4] != 'e' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+4], "bool(false)", cursor) } cursor += 5 *(*interface{})(unsafe.Pointer(p)) = false return cursor, nil case 'n': - if cursor+3 >= len(buf) { - return 0, errors.New("unexpected error. invalid bool character") + if cursor+3 >= int64(len(buf)) { + return 0, errUnexpectedEndOfJSON("null", cursor) } if buf[cursor+1] != 'u' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+1], "null", cursor) } if buf[cursor+2] != 'l' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+2], "null", cursor) } if buf[cursor+3] != 'l' { - return 0, errors.New("unexpected error. invalid bool character") + return 0, errInvalidCharacter(buf[cursor+3], "null", cursor) } cursor += 4 *(*interface{})(unsafe.Pointer(p)) = nil return cursor, nil } - return cursor, errors.New("unexpected error value") + return cursor, errNotAtBeginningOfValue(cursor) } diff --git a/decode_map.go b/decode_map.go index e07e1c5..18b5119 100644 --- a/decode_map.go +++ b/decode_map.go @@ -1,7 +1,6 @@ package json import ( - "errors" "unsafe" ) @@ -26,24 +25,24 @@ func makemap(*rtype, int) unsafe.Pointer //go:noescape func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer) -func (d *mapDecoder) setKey(buf []byte, cursor int, key interface{}) (int, error) { +func (d *mapDecoder) setKey(buf []byte, cursor int64, key interface{}) (int64, error) { header := (*interfaceHeader)(unsafe.Pointer(&key)) return d.keyDecoder.decode(buf, cursor, uintptr(header.ptr)) } -func (d *mapDecoder) setValue(buf []byte, cursor int, key interface{}) (int, error) { +func (d *mapDecoder) setValue(buf []byte, cursor int64, key interface{}) (int64, error) { header := (*interfaceHeader)(unsafe.Pointer(&key)) return d.valueDecoder.decode(buf, cursor, uintptr(header.ptr)) } -func (d *mapDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *mapDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { cursor = skipWhiteSpace(buf, cursor) - buflen := len(buf) + buflen := int64(len(buf)) if buflen < 2 { - return 0, errors.New("unexpected error {}") + return 0, errExpected("{} for map", cursor) } if buf[cursor] != '{' { - return 0, errors.New("unexpected error {") + return 0, errExpected("{ character for map value", cursor) } cursor++ mapValue := makemap(d.mapType, 0) @@ -56,11 +55,11 @@ func (d *mapDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { cursor = keyCursor cursor = skipWhiteSpace(buf, cursor) if buf[cursor] != ':' { - return 0, errors.New("unexpected error invalid delimiter for object") + return 0, errExpected("colon after object key", cursor) } cursor++ if cursor >= buflen { - return 0, errors.New("unexpected error missing value") + return 0, errUnexpectedEndOfJSON("map", cursor) } var value interface{} valueCursor, err := d.setValue(buf, cursor, &value) @@ -75,7 +74,7 @@ func (d *mapDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { return cursor, nil } if buf[cursor] != ',' { - return 0, errors.New("unexpected error ,") + return 0, errExpected("semicolon after object value", cursor) } } return cursor, nil diff --git a/decode_ptr.go b/decode_ptr.go index 0144040..6135872 100644 --- a/decode_ptr.go +++ b/decode_ptr.go @@ -16,7 +16,7 @@ func newPtrDecoder(dec decoder, typ *rtype) *ptrDecoder { //go:linkname unsafe_New reflect.unsafe_New func unsafe_New(*rtype) uintptr -func (d *ptrDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *ptrDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { newptr := unsafe_New(d.typ) c, err := d.dec.decode(buf, cursor, newptr) if err != nil { diff --git a/decode_slice.go b/decode_slice.go index e7a7c8e..a8f6381 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -1,7 +1,6 @@ package json import ( - "errors" "reflect" "sync" "unsafe" @@ -48,8 +47,8 @@ func copySlice(elemType *rtype, dst, src reflect.SliceHeader) int //go:linkname newArray reflect.unsafe_NewArray func newArray(*rtype, int) unsafe.Pointer -func (d *sliceDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { - buflen := len(buf) +func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { + buflen := int64(len(buf)) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -97,10 +96,10 @@ func (d *sliceDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { slice.Cap = cap slice.Data = data d.releaseSlice(slice) - return 0, errors.New("syntax error slice") + return 0, errInvalidCharacter(buf[cursor], "slice", cursor) } } } } - return 0, errors.New("unexpected error slice") + return 0, errUnexpectedEndOfJSON("slice", cursor) } diff --git a/decode_string.go b/decode_string.go index 701e00e..7b0aec0 100644 --- a/decode_string.go +++ b/decode_string.go @@ -1,7 +1,6 @@ package json import ( - "errors" "unsafe" ) @@ -12,7 +11,7 @@ func newStringDecoder() *stringDecoder { return &stringDecoder{} } -func (d *stringDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *stringDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err @@ -22,7 +21,7 @@ func (d *stringDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { return cursor, nil } -func (d *stringDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { +func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { for { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -39,24 +38,24 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) cursor++ return literal, cursor, nil case '\000': - return nil, 0, errors.New("unexpected error string") + return nil, 0, errUnexpectedEndOfJSON("string", cursor) } cursor++ } - return nil, 0, errors.New("unexpected error string") + return nil, 0, errUnexpectedEndOfJSON("string", cursor) case 'n': - buflen := len(buf) + buflen := int64(len(buf)) if cursor+3 >= buflen { - return nil, 0, errors.New("unexpected error. invalid bool character") + return nil, 0, errUnexpectedEndOfJSON("null", cursor) } if buf[cursor+1] != 'u' { - return nil, 0, errors.New("unexpected error. invalid bool character") + return nil, 0, errInvalidCharacter(buf[cursor+1], "null", cursor) } if buf[cursor+2] != 'l' { - return nil, 0, errors.New("unexpected error. invalid bool character") + return nil, 0, errInvalidCharacter(buf[cursor+2], "null", cursor) } if buf[cursor+3] != 'l' { - return nil, 0, errors.New("unexpected error. invalid bool character") + return nil, 0, errInvalidCharacter(buf[cursor+3], "null", cursor) } cursor += 5 return []byte{'n', 'u', 'l', 'l'}, cursor, nil @@ -65,5 +64,5 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) } } ERROR: - return nil, 0, errors.New("unexpected error key delimiter") + return nil, 0, errNotAtBeginningOfValue(cursor) } diff --git a/decode_struct.go b/decode_struct.go index 3e08b23..c065211 100644 --- a/decode_struct.go +++ b/decode_struct.go @@ -1,7 +1,6 @@ package json import ( - "errors" "unsafe" ) @@ -22,14 +21,14 @@ func newStructDecoder(fieldMap map[string]*structFieldSet) *structDecoder { } } -func (d *structDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { - buflen := len(buf) +func (d *structDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { + buflen := int64(len(buf)) cursor = skipWhiteSpace(buf, cursor) - if buflen < 2 { - return 0, errors.New("unexpected error {}") - } if buf[cursor] != '{' { - return 0, errors.New("unexpected error {") + return 0, errNotAtBeginningOfValue(cursor) + } + if buflen < 2 { + return 0, errUnexpectedEndOfJSON("object", cursor) } cursor++ for ; cursor < buflen; cursor++ { @@ -40,11 +39,11 @@ func (d *structDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { cursor = c cursor = skipWhiteSpace(buf, cursor) if buf[cursor] != ':' { - return 0, errors.New("unexpected error invalid delimiter for object") + return 0, errExpected("colon after object key", cursor) } cursor++ if cursor >= buflen { - return 0, errors.New("unexpected error missing value") + return 0, errExpected("object value after colon", cursor) } k := *(*string)(unsafe.Pointer(&key)) field, exists := d.fieldMap[k] @@ -67,7 +66,7 @@ func (d *structDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { return cursor, nil } if buf[cursor] != ',' { - return 0, errors.New("unexpected error ,") + return 0, errExpected("comma after object element", cursor) } } return cursor, nil diff --git a/decode_uint.go b/decode_uint.go index b78e7dc..1ba442d 100644 --- a/decode_uint.go +++ b/decode_uint.go @@ -1,9 +1,5 @@ package json -import ( - "errors" -) - type uintDecoder struct { op func(uintptr, uint64) } @@ -28,8 +24,8 @@ func (d *uintDecoder) parseUint(b []byte) uint64 { return sum } -func (d *uintDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { - buflen := len(buf) +func (d *uintDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { + buflen := int64(len(buf)) for ; cursor < buflen; cursor++ { switch buf[cursor] { case ' ', '\n', '\t', '\r': @@ -46,12 +42,14 @@ func (d *uintDecoder) decodeByte(buf []byte, cursor int) ([]byte, int, error) { } num := buf[start:cursor] return num, cursor, nil + default: + return nil, 0, errInvalidCharacter(buf[cursor], "number(unsigned integer)", cursor) } } - return nil, 0, errors.New("unexpected error number") + return nil, 0, errUnexpectedEndOfJSON("number(unsigned integer)", cursor) } -func (d *uintDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *uintDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { bytes, c, err := d.decodeByte(buf, cursor) if err != nil { return 0, err diff --git a/decode_unmarshal_json.go b/decode_unmarshal_json.go index b3fb1e2..dbd796f 100644 --- a/decode_unmarshal_json.go +++ b/decode_unmarshal_json.go @@ -12,7 +12,7 @@ func newUnmarshalJSONDecoder(typ *rtype) *unmarshalJSONDecoder { return &unmarshalJSONDecoder{typ: typ} } -func (d *unmarshalJSONDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *unmarshalJSONDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { cursor = skipWhiteSpace(buf, cursor) start := cursor end, err := skipValue(buf, cursor) diff --git a/decode_unmarshal_text.go b/decode_unmarshal_text.go index b74dda8..dfcec9a 100644 --- a/decode_unmarshal_text.go +++ b/decode_unmarshal_text.go @@ -13,7 +13,7 @@ func newUnmarshalTextDecoder(typ *rtype) *unmarshalTextDecoder { return &unmarshalTextDecoder{typ: typ} } -func (d *unmarshalTextDecoder) decode(buf []byte, cursor int, p uintptr) (int, error) { +func (d *unmarshalTextDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) { cursor = skipWhiteSpace(buf, cursor) start := cursor end, err := skipValue(buf, cursor) diff --git a/error.go b/error.go index 359b467..11cb183 100644 --- a/error.go +++ b/error.go @@ -116,3 +116,25 @@ type UnsupportedValueError struct { func (e *UnsupportedValueError) Error() string { return fmt.Sprintf("json: unsupported value: %s", e.Str) } + +func errNotAtBeginningOfValue(cursor int64) *SyntaxError { + return &SyntaxError{msg: "not at beginning of value", Offset: cursor} +} + +func errUnexpectedEndOfJSON(msg string, cursor int64) *SyntaxError { + return &SyntaxError{ + msg: fmt.Sprintf("unexpected end of JSON input for %s", msg), + Offset: cursor, + } +} + +func errExpected(msg string, cursor int64) *SyntaxError { + return &SyntaxError{msg: fmt.Sprintf("expected %s", msg), Offset: cursor} +} + +func errInvalidCharacter(c byte, context string, cursor int64) *SyntaxError { + return &SyntaxError{ + msg: fmt.Sprintf("invalid character %c as %s", c, context), + Offset: cursor, + } +}